github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/conf/http/helper_logger.go (about) 1 package http 2 3 import ( 4 "net/http" 5 "net/url" 6 "strconv" 7 "time" 8 9 "github.com/pkg/errors" 10 "go.opentelemetry.io/contrib/propagators/b3" 11 "go.opentelemetry.io/otel/propagation" 12 "go.opentelemetry.io/otel/trace" 13 14 "github.com/machinefi/w3bstream/pkg/depends/conf/logger" 15 "github.com/machinefi/w3bstream/pkg/depends/kit/httptransport/httpx" 16 "github.com/machinefi/w3bstream/pkg/depends/kit/logr" 17 "github.com/machinefi/w3bstream/pkg/depends/kit/metax" 18 "github.com/machinefi/w3bstream/pkg/depends/x/misc/timer" 19 ) 20 21 func TraceLogHandler(tr trace.Tracer) func(http.Handler) http.Handler { 22 return func(next http.Handler) http.Handler { 23 return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { 24 ctx := r.Context() 25 ctx = b3.New().Extract(r.Context(), propagation.HeaderCarrier(r.Header)) 26 27 ctx, span := tr.Start(ctx, "Operator", trace.WithTimestamp(time.Now())) 28 defer func() { 29 span.End(trace.WithTimestamp(time.Now())) 30 }() 31 32 var ( 33 l = logger.SpanLogger(span) 34 lrw = NewLoggerResponseWriter(rw) 35 ) 36 37 b3.New(b3.WithInjectEncoding(b3.B3SingleHeader)).Inject(ctx, propagation.HeaderCarrier(lrw.Header())) 38 meta := metax.ParseMeta(lrw.Header().Get("X-Meta")) 39 meta["_id"] = []string{span.SpanContext().TraceID().String()} 40 41 ctx = metax.ContextWithMeta(ctx, meta) 42 ctx = logr.WithLogger(ctx, l) 43 44 cost := timer.Start() 45 next.ServeHTTP(lrw, r.WithContext(ctx)) 46 duration := strconv.FormatInt(cost().Microseconds(), 10) + "μs" 47 48 operator := metax.ParseMeta(lrw.Header().Get("X-Meta")).Get("operator") 49 if operator == "" { 50 operator = lrw.Header().Get("X-Meta") 51 } 52 if operator != "" { 53 span.SetName(operator) 54 } 55 56 kvs := []interface{}{ 57 "@tag", "access", 58 "@rmt", httpx.ClientIP(r), 59 "@cst", duration, 60 "@mtd", r.Method, 61 "@url", OmitAuthorization(r.URL), 62 "@code", lrw.code, 63 } 64 65 if lrw.err != nil { 66 if lrw.code >= http.StatusInternalServerError { 67 l.WithValues(kvs...).Error(lrw.err) 68 } else { 69 l.WithValues(kvs...).Warn(lrw.err) 70 } 71 } else { 72 l.WithValues(kvs...).Info("") 73 } 74 }) 75 } 76 } 77 78 func NewLoggerResponseWriter(rw http.ResponseWriter) *LoggerResponseWriter { 79 lrw := &LoggerResponseWriter{ResponseWriter: rw} 80 if v, ok := rw.(http.Hijacker); ok { 81 lrw.Hijacker = v 82 } 83 if v, ok := rw.(http.Flusher); ok { 84 lrw.Flusher = v 85 } 86 return lrw 87 } 88 89 type LoggerResponseWriter struct { 90 http.ResponseWriter 91 http.Hijacker 92 http.Flusher 93 94 written bool 95 code int 96 err error 97 } 98 99 func (rw *LoggerResponseWriter) Header() http.Header { 100 return rw.ResponseWriter.Header() 101 } 102 103 func (rw *LoggerResponseWriter) WriteHeader(sc int) { 104 if !rw.written { 105 rw.ResponseWriter.WriteHeader(sc) 106 rw.code = sc 107 rw.written = true 108 } 109 } 110 111 func (rw *LoggerResponseWriter) Write(data []byte) (int, error) { 112 if rw.err == nil && rw.code >= http.StatusBadRequest { 113 rw.err = errors.New(string(data)) 114 } 115 return rw.ResponseWriter.Write(data) 116 } 117 118 func OmitAuthorization(u *url.URL) string { 119 query := u.Query() 120 query.Del("authorization") 121 u.RawQuery = query.Encode() 122 return u.String() 123 }