-
Notifications
You must be signed in to change notification settings - Fork 5.9k
/
server_reporter.go
157 lines (135 loc) · 5.18 KB
/
server_reporter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// 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
}