diff options
Diffstat (limited to 'vendor/github.com/technologize/otel-go-contrib/otelginmetrics/middleware.go')
-rw-r--r-- | vendor/github.com/technologize/otel-go-contrib/otelginmetrics/middleware.go | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/vendor/github.com/technologize/otel-go-contrib/otelginmetrics/middleware.go b/vendor/github.com/technologize/otel-go-contrib/otelginmetrics/middleware.go new file mode 100644 index 000000000..85479c7f1 --- /dev/null +++ b/vendor/github.com/technologize/otel-go-contrib/otelginmetrics/middleware.go @@ -0,0 +1,94 @@ +package otelginmetrics + +import ( + "net/http" + "time" + + "github.com/gin-gonic/gin" + semconv "go.opentelemetry.io/otel/semconv/v1.7.0" +) + +// Middleware returns middleware that will trace incoming requests. +// The service parameter should describe the name of the (virtual) +// server handling the request. +func Middleware(service string, options ...Option) gin.HandlerFunc { + cfg := defaultConfig() + for _, option := range options { + option.apply(cfg) + } + recorder := cfg.recorder + if recorder == nil { + recorder = GetRecorder("") + } + return func(ginCtx *gin.Context) { + + ctx := ginCtx.Request.Context() + + route := ginCtx.FullPath() + if len(route) <= 0 { + route = "nonconfigured" + } + if !cfg.shouldRecord(service, route, ginCtx.Request) { + ginCtx.Next() + return + } + + start := time.Now() + reqAttributes := cfg.attributes(service, route, ginCtx.Request) + + if cfg.recordInFlight { + recorder.AddInflightRequests(ctx, 1, reqAttributes) + defer recorder.AddInflightRequests(ctx, -1, reqAttributes) + } + + defer func() { + + resAttributes := append(reqAttributes[0:0], reqAttributes...) + + if cfg.groupedStatus { + code := int(ginCtx.Writer.Status()/100) * 100 + resAttributes = append(resAttributes, semconv.HTTPStatusCodeKey.Int(code)) + } else { + resAttributes = append(resAttributes, semconv.HTTPAttributesFromHTTPStatusCode(ginCtx.Writer.Status())...) + } + + recorder.AddRequests(ctx, 1, resAttributes) + + if cfg.recordSize { + requestSize := computeApproximateRequestSize(ginCtx.Request) + recorder.ObserveHTTPRequestSize(ctx, requestSize, resAttributes) + recorder.ObserveHTTPResponseSize(ctx, int64(ginCtx.Writer.Size()), resAttributes) + } + + if cfg.recordDuration { + recorder.ObserveHTTPRequestDuration(ctx, time.Since(start), resAttributes) + } + }() + + ginCtx.Next() + } +} + +func computeApproximateRequestSize(r *http.Request) int64 { + s := 0 + if r.URL != nil { + s = len(r.URL.Path) + } + + s += len(r.Method) + s += len(r.Proto) + for name, values := range r.Header { + s += len(name) + for _, value := range values { + s += len(value) + } + } + s += len(r.Host) + + // N.B. r.Form and r.MultipartForm are assumed to be included in r.URL. + + if r.ContentLength != -1 { + s += int(r.ContentLength) + } + return int64(s) +} |