-
Notifications
You must be signed in to change notification settings - Fork 1
/
http.go
91 lines (74 loc) · 2.35 KB
/
http.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
package telemetry
import (
"net/http"
"time"
"github.com/go-chi/chi/v5/middleware"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
"go.opentelemetry.io/otel/trace"
)
var (
requestCounter metric.Int64Counter
requestSeconds metric.Float64Histogram
)
func initMetrics(meter metric.Meter) {
requestCounter = Must(globalMeter.Int64Counter(
"http.request.total",
metric.WithDescription("HTTP requests received"),
metric.WithUnit("requests"),
))
requestSeconds = Must(globalMeter.Float64Histogram(
"http.request.duration.seconds",
metric.WithDescription("HTTP request duration"),
metric.WithUnit("seconds"),
))
}
func NewHandler(handler http.Handler, operation string) http.Handler {
return otelhttp.NewHandler(handler, operation)
}
func NewHandlerMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx, span := globalTracer.StartHTTPResponse(r)
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
start := time.Now()
next.ServeHTTP(ww, r.WithContext(ctx))
attrs := metric.WithAttributes(
semconv.HTTPMethod(r.Method),
semconv.HTTPRoute(r.URL.Path),
semconv.HTTPStatusCode(ww.Status()),
semconv.ServiceName(NAME),
)
requestCounter.Add(ctx, 1, attrs)
requestSeconds.Record(ctx, time.Since(start).Seconds(), attrs)
span.EndWithStatus(ww.Status())
})
}
func NewHandleFunc(fn http.HandlerFunc, operation string) http.Handler {
return NewHandler(fn, operation)
}
type responseWriterSnooper struct {
w http.ResponseWriter
statusCode int
}
func (ws *responseWriterSnooper) WriteHeader(statusCode int) {
ws.statusCode = statusCode
ws.w.WriteHeader(statusCode)
}
func (ws *responseWriterSnooper) Header() http.Header {
return ws.w.Header()
}
func (ws *responseWriterSnooper) Write(data []byte) (int, error) {
return ws.w.Write(data)
}
func HandlerFunc(fn http.HandlerFunc, startOptions []trace.SpanStartOption, endOptions []trace.SpanEndOption) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx, span := globalTracer.StartHTTPResponse(r, startOptions...)
res := responseWriterSnooper{
w: w,
statusCode: http.StatusOK,
}
fn(&res, r.WithContext(ctx))
span.EndWithStatus(res.statusCode, endOptions...)
}
}