...

Source file src/github.com/linkerd/linkerd2/pkg/prometheus/prometheus.go

Documentation: github.com/linkerd/linkerd2/pkg/prometheus

     1  package prometheus
     2  
     3  import (
     4  	"net/http"
     5  
     6  	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
     7  	"github.com/prometheus/client_golang/prometheus"
     8  	"github.com/prometheus/client_golang/prometheus/promhttp"
     9  	"go.opencensus.io/plugin/ocgrpc"
    10  	"go.opencensus.io/plugin/ochttp"
    11  	"google.golang.org/grpc"
    12  )
    13  
    14  var (
    15  	// RequestLatencyBucketsSeconds represents latency buckets to record (seconds)
    16  	RequestLatencyBucketsSeconds = append(append(append(
    17  		prometheus.LinearBuckets(0.01, 0.01, 5),
    18  		prometheus.LinearBuckets(0.1, 0.1, 5)...),
    19  		prometheus.LinearBuckets(1, 1, 5)...),
    20  		prometheus.LinearBuckets(10, 10, 5)...)
    21  
    22  	// ResponseSizeBuckets represents response size buckets (bytes)
    23  	ResponseSizeBuckets = append(append(append(
    24  		prometheus.LinearBuckets(100, 100, 5),
    25  		prometheus.LinearBuckets(1000, 1000, 5)...),
    26  		prometheus.LinearBuckets(10000, 10000, 5)...),
    27  		prometheus.LinearBuckets(1000000, 1000000, 5)...)
    28  
    29  	// server metrics
    30  	serverCounter = prometheus.NewCounterVec(
    31  		prometheus.CounterOpts{
    32  			Name: "http_server_requests_total",
    33  			Help: "A counter for requests to the wrapped handler.",
    34  		},
    35  		[]string{"code", "method"},
    36  	)
    37  
    38  	serverLatency = prometheus.NewHistogramVec(
    39  		prometheus.HistogramOpts{
    40  			Name:    "http_server_request_latency_seconds",
    41  			Help:    "A histogram of latencies for requests in seconds.",
    42  			Buckets: RequestLatencyBucketsSeconds,
    43  		},
    44  		[]string{"code", "method"},
    45  	)
    46  
    47  	serverResponseSize = prometheus.NewHistogramVec(
    48  		prometheus.HistogramOpts{
    49  			Name:    "http_server_response_size_bytes",
    50  			Help:    "A histogram of response sizes for requests.",
    51  			Buckets: ResponseSizeBuckets,
    52  		},
    53  		[]string{"code", "method"},
    54  	)
    55  
    56  	// client metrics
    57  	clientCounter = prometheus.NewCounterVec(
    58  		prometheus.CounterOpts{
    59  			Name: "http_client_requests_total",
    60  			Help: "A counter for requests from the wrapped client.",
    61  		},
    62  		[]string{"client", "code", "method"},
    63  	)
    64  
    65  	clientErrorCounter = prometheus.NewCounterVec(
    66  		prometheus.CounterOpts{
    67  			Name: "http_client_errors_total",
    68  			Help: "A counter for errors from the wrapped client.",
    69  		},
    70  		[]string{"client", "method"},
    71  	)
    72  
    73  	clientLatency = prometheus.NewHistogramVec(
    74  		prometheus.HistogramOpts{
    75  			Name:    "http_client_request_latency_seconds",
    76  			Help:    "A histogram of request latencies.",
    77  			Buckets: RequestLatencyBucketsSeconds,
    78  		},
    79  		[]string{"client", "code", "method"},
    80  	)
    81  
    82  	clientInFlight = prometheus.NewGaugeVec(
    83  		prometheus.GaugeOpts{
    84  			Name: "http_client_in_flight_requests",
    85  			Help: "A gauge of in-flight requests for the wrapped client.",
    86  		},
    87  		[]string{"client"},
    88  	)
    89  	clientQPS = prometheus.NewGaugeVec(
    90  		prometheus.GaugeOpts{
    91  			Name: "http_client_qps",
    92  			Help: "Max QPS used for the client config.",
    93  		},
    94  		[]string{"client"},
    95  	)
    96  	clientBurst = prometheus.NewGaugeVec(
    97  		prometheus.GaugeOpts{
    98  			Name: "http_client_burst",
    99  			Help: "Burst used for the client config.",
   100  		},
   101  		[]string{"client"},
   102  	)
   103  )
   104  
   105  func init() {
   106  	prometheus.MustRegister(
   107  		serverCounter, serverLatency, serverResponseSize, clientCounter,
   108  		clientLatency, clientInFlight, clientQPS, clientBurst, clientErrorCounter,
   109  	)
   110  }
   111  
   112  // NewGrpcServer returns a grpc server pre-configured with prometheus interceptors and oc-grpc handler
   113  func NewGrpcServer(opt ...grpc.ServerOption) *grpc.Server {
   114  	server := grpc.NewServer(
   115  		append([]grpc.ServerOption{
   116  			grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor),
   117  			grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor),
   118  			grpc.StatsHandler(&ocgrpc.ServerHandler{}),
   119  		}, opt...)...,
   120  	)
   121  
   122  	grpc_prometheus.EnableHandlingTimeHistogram()
   123  	grpc_prometheus.Register(server)
   124  	return server
   125  }
   126  
   127  // WithTelemetry instruments the HTTP server with prometheus and oc-http handler
   128  func WithTelemetry(handler http.Handler) http.Handler {
   129  	return &ochttp.Handler{
   130  		Handler: promhttp.InstrumentHandlerDuration(serverLatency,
   131  			promhttp.InstrumentHandlerResponseSize(serverResponseSize,
   132  				promhttp.InstrumentHandlerCounter(serverCounter, handler))),
   133  	}
   134  }
   135  
   136  // ClientWithTelemetry instruments the HTTP client with prometheus
   137  func ClientWithTelemetry(name string, wt func(http.RoundTripper) http.RoundTripper) func(http.RoundTripper) http.RoundTripper {
   138  	latency := clientLatency.MustCurryWith(prometheus.Labels{"client": name})
   139  	counter := clientCounter.MustCurryWith(prometheus.Labels{"client": name})
   140  	inFlight := clientInFlight.With(prometheus.Labels{"client": name})
   141  	errors := clientErrorCounter.MustCurryWith(prometheus.Labels{"client": name})
   142  
   143  	return func(rt http.RoundTripper) http.RoundTripper {
   144  		if wt != nil {
   145  			rt = wt(rt)
   146  		}
   147  
   148  		return InstrumentErrorCounter(errors,
   149  			promhttp.InstrumentRoundTripperInFlight(inFlight,
   150  				promhttp.InstrumentRoundTripperCounter(counter,
   151  					promhttp.InstrumentRoundTripperDuration(latency, rt),
   152  				),
   153  			),
   154  		)
   155  	}
   156  }
   157  
   158  func InstrumentErrorCounter(counter *prometheus.CounterVec, next http.RoundTripper) promhttp.RoundTripperFunc {
   159  	return func(r *http.Request) (*http.Response, error) {
   160  		resp, err := next.RoundTrip(r)
   161  		if err != nil {
   162  			counter.With(prometheus.Labels{"method": r.Method}).Inc()
   163  		}
   164  		return resp, err
   165  	}
   166  }
   167  
   168  func SetClientQPS(name string, qps float32) {
   169  	clientQPS.With(prometheus.Labels{"client": name}).Set(float64(qps))
   170  }
   171  
   172  func SetClientBurst(name string, burst int) {
   173  	clientBurst.With(prometheus.Labels{"client": name}).Set(float64(burst))
   174  }
   175  

View as plain text