gitlab.com/gitlab-org/labkit@v1.21.0/metrics/handler.go (about)

     1  package metrics
     2  
     3  import (
     4  	"net/http"
     5  
     6  	"github.com/prometheus/client_golang/prometheus"
     7  	"github.com/prometheus/client_golang/prometheus/promhttp"
     8  )
     9  
    10  // Metric names for the recorded metrics.
    11  // These are the conventional names prometheus uses for these metrics.
    12  const (
    13  	httpInFlightRequestsMetricName         = "in_flight_requests"
    14  	httpRequestsTotalMetricName            = "requests_total"
    15  	httpRequestDurationSecondsMetricName   = "request_duration_seconds"
    16  	httpRequestSizeBytesMetricName         = "request_size_bytes"
    17  	httpResponseSizeBytesMetricName        = "response_size_bytes"
    18  	httpTimeToWriteHeaderSecondsMetricName = "time_to_write_header_seconds"
    19  )
    20  
    21  // HandlerFactory creates handler middleware instances. Created by NewHandlerFactory.
    22  type HandlerFactory func(next http.Handler, opts ...HandlerOption) http.Handler
    23  
    24  // NewHandlerFactory will create a function for creating metric middlewares.
    25  // The resulting function can be called multiple times to obtain multiple middleware
    26  // instances.
    27  // Each instance can be configured with different options that will be applied to the
    28  // same underlying metrics.
    29  func NewHandlerFactory(opts ...HandlerFactoryOption) HandlerFactory {
    30  	factoryConfig := applyHandlerFactoryOptions(opts)
    31  	var (
    32  		httpInFlightRequests = prometheus.NewGauge(prometheus.GaugeOpts{
    33  			Namespace: factoryConfig.namespace,
    34  			Subsystem: factoryConfig.subsystem,
    35  			Name:      httpInFlightRequestsMetricName,
    36  			Help:      "A gauge of requests currently being served by the http server.",
    37  		})
    38  
    39  		httpRequestsTotal = prometheus.NewCounterVec(
    40  			prometheus.CounterOpts{
    41  				Namespace: factoryConfig.namespace,
    42  				Subsystem: factoryConfig.subsystem,
    43  				Name:      httpRequestsTotalMetricName,
    44  				Help:      "A counter for requests to the http server.",
    45  			},
    46  			factoryConfig.labels,
    47  		)
    48  
    49  		httpRequestDurationSeconds = prometheus.NewHistogramVec(
    50  			prometheus.HistogramOpts{
    51  				Namespace: factoryConfig.namespace,
    52  				Subsystem: factoryConfig.subsystem,
    53  				Name:      httpRequestDurationSecondsMetricName,
    54  				Help:      "A histogram of latencies for requests to the http server.",
    55  				Buckets:   factoryConfig.requestDurationBuckets,
    56  			},
    57  			factoryConfig.labels,
    58  		)
    59  
    60  		httpRequestSizeBytes = prometheus.NewHistogramVec(
    61  			prometheus.HistogramOpts{
    62  				Namespace: factoryConfig.namespace,
    63  				Subsystem: factoryConfig.subsystem,
    64  				Name:      httpRequestSizeBytesMetricName,
    65  				Help:      "A histogram of sizes of requests to the http server.",
    66  				Buckets:   factoryConfig.byteSizeBuckets,
    67  			},
    68  			factoryConfig.labels,
    69  		)
    70  
    71  		httpResponseSizeBytes = prometheus.NewHistogramVec(
    72  			prometheus.HistogramOpts{
    73  				Namespace: factoryConfig.namespace,
    74  				Subsystem: factoryConfig.subsystem,
    75  				Name:      httpResponseSizeBytesMetricName,
    76  				Help:      "A histogram of response sizes for requests to the http server.",
    77  				Buckets:   factoryConfig.byteSizeBuckets,
    78  			},
    79  			factoryConfig.labels,
    80  		)
    81  
    82  		httpTimeToWriteHeaderSeconds = prometheus.NewHistogramVec(
    83  			prometheus.HistogramOpts{
    84  				Namespace: factoryConfig.namespace,
    85  				Subsystem: factoryConfig.subsystem,
    86  				Name:      httpTimeToWriteHeaderSecondsMetricName,
    87  				Help:      "A histogram of request durations until the response headers are written.",
    88  				Buckets:   factoryConfig.timeToWriteHeaderDurationBuckets,
    89  			},
    90  			factoryConfig.labels,
    91  		)
    92  	)
    93  
    94  	prometheus.MustRegister(httpInFlightRequests)
    95  	prometheus.MustRegister(httpRequestsTotal)
    96  	prometheus.MustRegister(httpRequestDurationSeconds)
    97  	prometheus.MustRegister(httpRequestSizeBytes)
    98  	prometheus.MustRegister(httpResponseSizeBytes)
    99  	prometheus.MustRegister(httpTimeToWriteHeaderSeconds)
   100  
   101  	return func(next http.Handler, handlerOpts ...HandlerOption) http.Handler {
   102  		handlerConfig := applyHandlerOptions(handlerOpts)
   103  
   104  		handler := next
   105  
   106  		handler = promhttp.InstrumentHandlerCounter(httpRequestsTotal.MustCurryWith(handlerConfig.labelValues), handler)
   107  		handler = promhttp.InstrumentHandlerDuration(httpRequestDurationSeconds.MustCurryWith(handlerConfig.labelValues), handler)
   108  		handler = promhttp.InstrumentHandlerInFlight(httpInFlightRequests, handler)
   109  		handler = promhttp.InstrumentHandlerRequestSize(httpRequestSizeBytes.MustCurryWith(handlerConfig.labelValues), handler)
   110  		handler = promhttp.InstrumentHandlerResponseSize(httpResponseSizeBytes.MustCurryWith(handlerConfig.labelValues), handler)
   111  		handler = promhttp.InstrumentHandlerTimeToWriteHeader(httpTimeToWriteHeaderSeconds.MustCurryWith(handlerConfig.labelValues), handler)
   112  
   113  		return handler
   114  	}
   115  }