forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
1package telemetry
2
3import (
4 "fmt"
5 "net/http"
6 "time"
7
8 "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
9 otelmetric "go.opentelemetry.io/otel/metric"
10 "go.opentelemetry.io/otel/semconv/v1.13.0/httpconv"
11)
12
13func (t *Telemetry) RequestDuration() func(next http.Handler) http.Handler {
14 const (
15 metricNameRequestDurationMs = "request_duration_millis"
16 metricUnitRequestDurationMs = "ms"
17 metricDescRequestDurationMs = "Measures the latency of HTTP requests processed by the server, in milliseconds."
18 )
19 histogram, err := t.meter.Int64Histogram(
20 metricNameRequestDurationMs,
21 otelmetric.WithDescription(metricDescRequestDurationMs),
22 otelmetric.WithUnit(metricUnitRequestDurationMs),
23 )
24 if err != nil {
25 panic(fmt.Sprintf("unable to create %s histogram: %v", metricNameRequestDurationMs, err))
26 }
27
28 return func(next http.Handler) http.Handler {
29 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
30 // capture the start time of the request
31 startTime := time.Now()
32
33 // execute next http handler
34 next.ServeHTTP(w, r)
35
36 // record the request duration
37 duration := time.Since(startTime)
38 histogram.Record(
39 r.Context(),
40 int64(duration.Milliseconds()),
41 otelmetric.WithAttributes(
42 httpconv.ServerRequest(t.serviceName, r)...,
43 ),
44 )
45 })
46 }
47}
48
49func (t *Telemetry) RequestInFlight() func(next http.Handler) http.Handler {
50 const (
51 metricNameRequestInFlight = "request_in_flight"
52 metricDescRequestInFlight = "Measures the number of concurrent HTTP requests being processed by the server."
53 metricUnitRequestInFlight = "1"
54 )
55
56 // counter to capture requests in flight
57 counter, err := t.meter.Int64UpDownCounter(
58 metricNameRequestInFlight,
59 otelmetric.WithDescription(metricDescRequestInFlight),
60 otelmetric.WithUnit(metricUnitRequestInFlight),
61 )
62 if err != nil {
63 panic(fmt.Sprintf("unable to create %s counter: %v", metricNameRequestInFlight, err))
64 }
65
66 return func(next http.Handler) http.Handler {
67 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
68 attrs := otelmetric.WithAttributes(httpconv.ServerRequest(t.serviceName, r)...)
69
70 // increase the number of requests in flight
71 counter.Add(r.Context(), 1, attrs)
72
73 // execute next http handler
74 next.ServeHTTP(w, r)
75
76 // decrease the number of requests in flight
77 counter.Add(r.Context(), -1, attrs)
78 })
79 }
80}
81
82func (t *Telemetry) WithRouteTag() func(next http.Handler) http.Handler {
83 return func(next http.Handler) http.Handler {
84 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
85 otelhttp.WithRouteTag(r.URL.Path, next)
86 })
87 }
88}