diff --git a/pkg/global/apply_configuration.go b/pkg/global/apply_configuration.go index d60c67ba..a00b49df 100644 --- a/pkg/global/apply_configuration.go +++ b/pkg/global/apply_configuration.go @@ -71,7 +71,11 @@ func (ls *LifecycleState) MarkReadyAndWait(group program.Group) { } group.Go(func(ctx context.Context, siblingsGroup, dependenciesGroup program.Group) error { - if err := bb_http.NewServersFromConfigurationAndServe(ls.config.HttpServers, router, group); err != nil { + if err := bb_http.NewServersFromConfigurationAndServe( + ls.config.HttpServers, + bb_http.NewMetricsHandler(router, "Diagnostics"), + group, + ); err != nil { return util.StatusWrap(err, "Failed to launch diagnostics HTTP server") } return nil diff --git a/pkg/http/BUILD.bazel b/pkg/http/BUILD.bazel index 0161e7c0..27ac7070 100644 --- a/pkg/http/BUILD.bazel +++ b/pkg/http/BUILD.bazel @@ -11,6 +11,7 @@ go_library( "deny_authenticator.go", "header_adding_round_tripper.go", "jwt_authenticator.go", + "metrics_handler.go", "metrics_round_tripper.go", "oidc_authenticator.go", "server.go", diff --git a/pkg/http/metrics_handler.go b/pkg/http/metrics_handler.go new file mode 100644 index 00000000..8bbc624a --- /dev/null +++ b/pkg/http/metrics_handler.go @@ -0,0 +1,36 @@ +package http + +import ( + "net/http" + "sync" + + "github.com/buildbarn/bb-storage/pkg/util" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +var ( + handlerPrometheusMetrics sync.Once + + handlerRequestsDurationSeconds = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: "buildbarn", + Subsystem: "http", + Name: "handler_requests_duration_seconds", + Help: "Amount of time spent per HTTP request, in seconds.", + Buckets: util.DecimalExponentialBuckets(-3, 6, 2), + }, + []string{"name", "code", "method"}) +) + +// NewMetricsHandler creates an adapter for http.Handler that adds basic +// instrumentation in the form of Prometheus metrics. +func NewMetricsHandler(base http.Handler, name string) http.Handler { + handlerPrometheusMetrics.Do(func() { + prometheus.MustRegister(handlerRequestsDurationSeconds) + }) + + return promhttp.InstrumentHandlerDuration( + handlerRequestsDurationSeconds.MustCurryWith(prometheus.Labels{"name": name}), + base) +}