@@ -2,16 +2,24 @@ package middlewares
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
5
6
"net/http"
6
7
"time"
7
8
8
9
"github.com/0xdeafcafe/bloefish/libraries/cher"
9
10
"github.com/0xdeafcafe/bloefish/libraries/clog"
11
+ "github.com/0xdeafcafe/bloefish/libraries/contexts"
10
12
"github.com/0xdeafcafe/bloefish/libraries/errfuncs"
11
13
"github.com/0xdeafcafe/bloefish/libraries/merr"
12
14
"github.com/0xdeafcafe/bloefish/libraries/mlog"
13
15
"github.com/0xdeafcafe/bloefish/libraries/slicefuncs"
14
16
"github.com/sirupsen/logrus"
17
+ "go.opentelemetry.io/otel"
18
+ "go.opentelemetry.io/otel/propagation"
19
+ "go.opentelemetry.io/otel/semconv/v1.13.0/httpconv"
20
+ "go.opentelemetry.io/otel/trace"
21
+
22
+ semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
15
23
)
16
24
17
25
type responseWriter struct {
@@ -39,7 +47,7 @@ func (rw *responseWriter) Write(bytes []byte) (int, error) {
39
47
return rw .ResponseWriter .Write (bytes )
40
48
}
41
49
42
- // Logger returns a middleware handler that wraps subsequent middleware/handlers and logs
50
+ // Telemetry returns a middleware handler that wraps subsequent middleware/handlers and logs
43
51
// request information AFTER the request has completed. It also injects a request-scoped
44
52
// logger on the context which can be set, read and updated using clog lib
45
53
//
@@ -57,10 +65,27 @@ func (rw *responseWriter) Write(bytes []byte) (int, error) {
57
65
// - Response in bytes (http_response_bytes)
58
66
// - Client Version header (http_client_version)
59
67
// - User Agent header (http_user_agent)
60
- func Logger (log * logrus.Entry ) func (http.Handler ) http.Handler {
68
+ func Telemetry (log * logrus.Entry ) func (http.Handler ) http.Handler {
69
+ propagator := otel .GetTextMapPropagator ()
70
+ tracer := otel .Tracer (
71
+ "github.com/0xdeafcafe/bloefish/libraries/crpc" ,
72
+ )
73
+
61
74
return func (next http.Handler ) http.Handler {
62
75
return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
63
- ctx := r .Context ()
76
+ ctx , span := tracer .Start (
77
+ propagator .Extract (r .Context (), propagation .HeaderCarrier (r .Header )),
78
+ "crpc" , // Placeholder, this will be updates below
79
+ trace .WithSpanKind (trace .SpanKindServer ),
80
+ )
81
+ defer span .End ()
82
+
83
+ // inject the span context into the response headers
84
+ propagator .Inject (ctx , propagation .HeaderCarrier (w .Header ()))
85
+
86
+ // update the span name with the service name and endpoint
87
+ svcCtx := contexts .MustGetServiceInfo (ctx )
88
+ span .SetName (fmt .Sprintf ("crpc (%s%s)" , svcCtx .ServiceHTTPName , r .URL .Path ))
64
89
65
90
// create a mutable logger instance which will persist for the request
66
91
// inject pointer to the logger into the request context
@@ -70,6 +95,7 @@ func Logger(log *logrus.Entry) func(http.Handler) http.Handler {
70
95
// panics inside handlers will be logged to standard before propagation
71
96
defer clog .HandlePanic (ctx , true )
72
97
98
+ // set useful log fields for the request
73
99
clog .SetFields (ctx , clog.Fields {
74
100
"http_remote_addr" : r .RemoteAddr ,
75
101
"http_user_agent" : r .UserAgent (),
@@ -87,18 +113,26 @@ func Logger(log *logrus.Entry) func(http.Handler) http.Handler {
87
113
next .ServeHTTP (res , r )
88
114
tEnd := time .Now ()
89
115
116
+ // set useful log fields from the response
90
117
clog .SetFields (ctx , clog.Fields {
91
118
"http_duration" : tEnd .Sub (tStart ).String (),
92
119
"http_duration_us" : int64 (tEnd .Sub (tStart ) / time .Microsecond ),
93
120
"http_status" : res .Status ,
94
121
"http_response_bytes" : res .Bytes ,
95
122
})
96
123
124
+ // set the span attributes and status
125
+ span .SetAttributes (semconv .HTTPResponseStatusCode (res .Status ))
126
+ span .SetStatus (httpconv .ServerStatus (res .Status ))
127
+
128
+ // get the error if one is set on the log entry
97
129
err := getError (clog .Get (ctx ))
98
130
if err == nil {
99
131
mlog .Info (ctx , merr .New (ctx , "request_completed" , nil ))
100
132
return
101
133
}
134
+
135
+ // if appropriate, log the error at the appropriate level
102
136
var fn func (context.Context , merr.Merrer )
103
137
switch clog .DetermineLevel (err , clog .TimeoutsAsErrors (ctx )) {
104
138
case
0 commit comments