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  }