1 // Copyright 2016 Michal Witkowski. All Rights Reserved.
2 // See LICENSE for licensing terms.
4 package grpc_prometheus
9 "google.golang.org/grpc/codes"
11 prom "github.com/prometheus/client_golang/prometheus"
12 "google.golang.org/grpc"
18 Unary grpcType = "unary"
19 ClientStream grpcType = "client_stream"
20 ServerStream grpcType = "server_stream"
21 BidiStream grpcType = "bidi_stream"
25 serverStartedCounter = prom.NewCounterVec(
29 Name: "started_total",
30 Help: "Total number of RPCs started on the server.",
31 }, []string{"grpc_type", "grpc_service", "grpc_method"})
33 serverHandledCounter = prom.NewCounterVec(
37 Name: "handled_total",
38 Help: "Total number of RPCs completed on the server, regardless of success or failure.",
39 }, []string{"grpc_type", "grpc_service", "grpc_method", "grpc_code"})
41 serverStreamMsgReceived = prom.NewCounterVec(
45 Name: "msg_received_total",
46 Help: "Total number of RPC stream messages received on the server.",
47 }, []string{"grpc_type", "grpc_service", "grpc_method"})
49 serverStreamMsgSent = prom.NewCounterVec(
53 Name: "msg_sent_total",
54 Help: "Total number of gRPC stream messages sent by the server.",
55 }, []string{"grpc_type", "grpc_service", "grpc_method"})
57 serverHandledHistogramEnabled = false
58 serverHandledHistogramOpts = prom.HistogramOpts{
61 Name: "handling_seconds",
62 Help: "Histogram of response latency (seconds) of gRPC that had been application-level handled by the server.",
63 Buckets: prom.DefBuckets,
65 serverHandledHistogram *prom.HistogramVec
69 prom.MustRegister(serverStartedCounter)
70 prom.MustRegister(serverHandledCounter)
71 prom.MustRegister(serverStreamMsgReceived)
72 prom.MustRegister(serverStreamMsgSent)
75 type HistogramOption func(*prom.HistogramOpts)
77 // WithHistogramBuckets allows you to specify custom bucket ranges for histograms if EnableHandlingTimeHistogram is on.
78 func WithHistogramBuckets(buckets []float64) HistogramOption {
79 return func(o *prom.HistogramOpts) { o.Buckets = buckets }
82 // EnableHandlingTimeHistogram turns on recording of handling time of RPCs for server-side interceptors.
83 // Histogram metrics can be very expensive for Prometheus to retain and query.
84 func EnableHandlingTimeHistogram(opts ...HistogramOption) {
85 for _, o := range opts {
86 o(&serverHandledHistogramOpts)
88 if !serverHandledHistogramEnabled {
89 serverHandledHistogram = prom.NewHistogramVec(
90 serverHandledHistogramOpts,
91 []string{"grpc_type", "grpc_service", "grpc_method"},
93 prom.Register(serverHandledHistogram)
95 serverHandledHistogramEnabled = true
98 type serverReporter struct {
105 func newServerReporter(rpcType grpcType, fullMethod string) *serverReporter {
106 r := &serverReporter{rpcType: rpcType}
107 if serverHandledHistogramEnabled {
108 r.startTime = time.Now()
110 r.serviceName, r.methodName = splitMethodName(fullMethod)
111 serverStartedCounter.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc()
115 func (r *serverReporter) ReceivedMessage() {
116 serverStreamMsgReceived.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc()
119 func (r *serverReporter) SentMessage() {
120 serverStreamMsgSent.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc()
123 func (r *serverReporter) Handled(code codes.Code) {
124 serverHandledCounter.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName, code.String()).Inc()
125 if serverHandledHistogramEnabled {
126 serverHandledHistogram.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Observe(time.Since(r.startTime).Seconds())
130 // preRegisterMethod is invoked on Register of a Server, allowing all gRPC services labels to be pre-populated.
131 func preRegisterMethod(serviceName string, mInfo *grpc.MethodInfo) {
132 methodName := mInfo.Name
133 methodType := string(typeFromMethodInfo(mInfo))
134 // These are just references (no increments), as just referencing will create the labels but not set values.
135 serverStartedCounter.GetMetricWithLabelValues(methodType, serviceName, methodName)
136 serverStreamMsgReceived.GetMetricWithLabelValues(methodType, serviceName, methodName)
137 serverStreamMsgSent.GetMetricWithLabelValues(methodType, serviceName, methodName)
138 if serverHandledHistogramEnabled {
139 serverHandledHistogram.GetMetricWithLabelValues(methodType, serviceName, methodName)
141 for _, code := range allCodes {
142 serverHandledCounter.GetMetricWithLabelValues(methodType, serviceName, methodName, code.String())
146 func typeFromMethodInfo(mInfo *grpc.MethodInfo) grpcType {
147 if mInfo.IsClientStream == false && mInfo.IsServerStream == false {
150 if mInfo.IsClientStream == true && mInfo.IsServerStream == false {
153 if mInfo.IsClientStream == false && mInfo.IsServerStream == true {