123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- // 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
- }
|