 f9212348e4
			
		
	
	f9212348e4
	
	
	
		
			
			This provideds generic grpc metrics via prometheus Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
		
			
				
	
	
		
			158 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2016 Michal Witkowski. All Rights Reserved.
 | |
| // See LICENSE for licensing terms.
 | |
| 
 | |
| package grpc_prometheus
 | |
| 
 | |
| import (
 | |
| 	"time"
 | |
| 
 | |
| 	"google.golang.org/grpc/codes"
 | |
| 
 | |
| 	prom "github.com/prometheus/client_golang/prometheus"
 | |
| 	"google.golang.org/grpc"
 | |
| )
 | |
| 
 | |
| type grpcType string
 | |
| 
 | |
| const (
 | |
| 	Unary        grpcType = "unary"
 | |
| 	ClientStream grpcType = "client_stream"
 | |
| 	ServerStream grpcType = "server_stream"
 | |
| 	BidiStream   grpcType = "bidi_stream"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	serverStartedCounter = prom.NewCounterVec(
 | |
| 		prom.CounterOpts{
 | |
| 			Namespace: "grpc",
 | |
| 			Subsystem: "server",
 | |
| 			Name:      "started_total",
 | |
| 			Help:      "Total number of RPCs started on the server.",
 | |
| 		}, []string{"grpc_type", "grpc_service", "grpc_method"})
 | |
| 
 | |
| 	serverHandledCounter = prom.NewCounterVec(
 | |
| 		prom.CounterOpts{
 | |
| 			Namespace: "grpc",
 | |
| 			Subsystem: "server",
 | |
| 			Name:      "handled_total",
 | |
| 			Help:      "Total number of RPCs completed on the server, regardless of success or failure.",
 | |
| 		}, []string{"grpc_type", "grpc_service", "grpc_method", "grpc_code"})
 | |
| 
 | |
| 	serverStreamMsgReceived = prom.NewCounterVec(
 | |
| 		prom.CounterOpts{
 | |
| 			Namespace: "grpc",
 | |
| 			Subsystem: "server",
 | |
| 			Name:      "msg_received_total",
 | |
| 			Help:      "Total number of RPC stream messages received on the server.",
 | |
| 		}, []string{"grpc_type", "grpc_service", "grpc_method"})
 | |
| 
 | |
| 	serverStreamMsgSent = prom.NewCounterVec(
 | |
| 		prom.CounterOpts{
 | |
| 			Namespace: "grpc",
 | |
| 			Subsystem: "server",
 | |
| 			Name:      "msg_sent_total",
 | |
| 			Help:      "Total number of gRPC stream messages sent by the server.",
 | |
| 		}, []string{"grpc_type", "grpc_service", "grpc_method"})
 | |
| 
 | |
| 	serverHandledHistogramEnabled = false
 | |
| 	serverHandledHistogramOpts    = prom.HistogramOpts{
 | |
| 		Namespace: "grpc",
 | |
| 		Subsystem: "server",
 | |
| 		Name:      "handling_seconds",
 | |
| 		Help:      "Histogram of response latency (seconds) of gRPC that had been application-level handled by the server.",
 | |
| 		Buckets:   prom.DefBuckets,
 | |
| 	}
 | |
| 	serverHandledHistogram *prom.HistogramVec
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	prom.MustRegister(serverStartedCounter)
 | |
| 	prom.MustRegister(serverHandledCounter)
 | |
| 	prom.MustRegister(serverStreamMsgReceived)
 | |
| 	prom.MustRegister(serverStreamMsgSent)
 | |
| }
 | |
| 
 | |
| type HistogramOption func(*prom.HistogramOpts)
 | |
| 
 | |
| // WithHistogramBuckets allows you to specify custom bucket ranges for histograms if EnableHandlingTimeHistogram is on.
 | |
| func WithHistogramBuckets(buckets []float64) HistogramOption {
 | |
| 	return func(o *prom.HistogramOpts) { o.Buckets = buckets }
 | |
| }
 | |
| 
 | |
| // EnableHandlingTimeHistogram turns on recording of handling time of RPCs for server-side interceptors.
 | |
| // Histogram metrics can be very expensive for Prometheus to retain and query.
 | |
| func EnableHandlingTimeHistogram(opts ...HistogramOption) {
 | |
| 	for _, o := range opts {
 | |
| 		o(&serverHandledHistogramOpts)
 | |
| 	}
 | |
| 	if !serverHandledHistogramEnabled {
 | |
| 		serverHandledHistogram = prom.NewHistogramVec(
 | |
| 			serverHandledHistogramOpts,
 | |
| 			[]string{"grpc_type", "grpc_service", "grpc_method"},
 | |
| 		)
 | |
| 		prom.Register(serverHandledHistogram)
 | |
| 	}
 | |
| 	serverHandledHistogramEnabled = true
 | |
| }
 | |
| 
 | |
| type serverReporter struct {
 | |
| 	rpcType     grpcType
 | |
| 	serviceName string
 | |
| 	methodName  string
 | |
| 	startTime   time.Time
 | |
| }
 | |
| 
 | |
| func newServerReporter(rpcType grpcType, fullMethod string) *serverReporter {
 | |
| 	r := &serverReporter{rpcType: rpcType}
 | |
| 	if serverHandledHistogramEnabled {
 | |
| 		r.startTime = time.Now()
 | |
| 	}
 | |
| 	r.serviceName, r.methodName = splitMethodName(fullMethod)
 | |
| 	serverStartedCounter.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc()
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| func (r *serverReporter) ReceivedMessage() {
 | |
| 	serverStreamMsgReceived.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc()
 | |
| }
 | |
| 
 | |
| func (r *serverReporter) SentMessage() {
 | |
| 	serverStreamMsgSent.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc()
 | |
| }
 | |
| 
 | |
| func (r *serverReporter) Handled(code codes.Code) {
 | |
| 	serverHandledCounter.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName, code.String()).Inc()
 | |
| 	if serverHandledHistogramEnabled {
 | |
| 		serverHandledHistogram.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Observe(time.Since(r.startTime).Seconds())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // preRegisterMethod is invoked on Register of a Server, allowing all gRPC services labels to be pre-populated.
 | |
| func preRegisterMethod(serviceName string, mInfo *grpc.MethodInfo) {
 | |
| 	methodName := mInfo.Name
 | |
| 	methodType := string(typeFromMethodInfo(mInfo))
 | |
| 	// These are just references (no increments), as just referencing will create the labels but not set values.
 | |
| 	serverStartedCounter.GetMetricWithLabelValues(methodType, serviceName, methodName)
 | |
| 	serverStreamMsgReceived.GetMetricWithLabelValues(methodType, serviceName, methodName)
 | |
| 	serverStreamMsgSent.GetMetricWithLabelValues(methodType, serviceName, methodName)
 | |
| 	if serverHandledHistogramEnabled {
 | |
| 		serverHandledHistogram.GetMetricWithLabelValues(methodType, serviceName, methodName)
 | |
| 	}
 | |
| 	for _, code := range allCodes {
 | |
| 		serverHandledCounter.GetMetricWithLabelValues(methodType, serviceName, methodName, code.String())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func typeFromMethodInfo(mInfo *grpc.MethodInfo) grpcType {
 | |
| 	if mInfo.IsClientStream == false && mInfo.IsServerStream == false {
 | |
| 		return Unary
 | |
| 	}
 | |
| 	if mInfo.IsClientStream == true && mInfo.IsServerStream == false {
 | |
| 		return ClientStream
 | |
| 	}
 | |
| 	if mInfo.IsClientStream == false && mInfo.IsServerStream == true {
 | |
| 		return ServerStream
 | |
| 	}
 | |
| 	return BidiStream
 | |
| }
 |