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
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
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
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
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
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
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
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