diff options
Diffstat (limited to 'vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go')
-rw-r--r-- | vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go b/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go new file mode 100644 index 000000000..6e445967b --- /dev/null +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go @@ -0,0 +1,142 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Based on https://github.com/DataDog/dd-trace-go/blob/8fb554ff7cf694267f9077ae35e27ce4689ed8b6/contrib/gin-gonic/gin/gintrace.go + +package otelgin // import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" + +import ( + "fmt" + + "github.com/gin-gonic/gin" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/codes" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/propagation" + semconv "go.opentelemetry.io/otel/semconv/v1.17.0" + "go.opentelemetry.io/otel/semconv/v1.17.0/httpconv" + oteltrace "go.opentelemetry.io/otel/trace" +) + +const ( + tracerKey = "otel-go-contrib-tracer" + tracerName = "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" +) + +// 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, opts ...Option) gin.HandlerFunc { + cfg := config{} + for _, opt := range opts { + opt.apply(&cfg) + } + if cfg.TracerProvider == nil { + cfg.TracerProvider = otel.GetTracerProvider() + } + tracer := cfg.TracerProvider.Tracer( + tracerName, + oteltrace.WithInstrumentationVersion(SemVersion()), + ) + if cfg.Propagators == nil { + cfg.Propagators = otel.GetTextMapPropagator() + } + return func(c *gin.Context) { + for _, f := range cfg.Filters { + if !f(c.Request) { + // Serve the request to the next middleware + // if a filter rejects the request. + c.Next() + return + } + } + c.Set(tracerKey, tracer) + savedCtx := c.Request.Context() + defer func() { + c.Request = c.Request.WithContext(savedCtx) + }() + ctx := cfg.Propagators.Extract(savedCtx, propagation.HeaderCarrier(c.Request.Header)) + opts := []oteltrace.SpanStartOption{ + oteltrace.WithAttributes(httpconv.ServerRequest(service, c.Request)...), + oteltrace.WithSpanKind(oteltrace.SpanKindServer), + } + var spanName string + if cfg.SpanNameFormatter == nil { + spanName = c.FullPath() + } else { + spanName = cfg.SpanNameFormatter(c.Request) + } + if spanName == "" { + spanName = fmt.Sprintf("HTTP %s route not found", c.Request.Method) + } else { + rAttr := semconv.HTTPRoute(spanName) + opts = append(opts, oteltrace.WithAttributes(rAttr)) + } + ctx, span := tracer.Start(ctx, spanName, opts...) + defer span.End() + + // pass the span through the request context + c.Request = c.Request.WithContext(ctx) + + // serve the request to the next middleware + c.Next() + + status := c.Writer.Status() + span.SetStatus(httpconv.ServerStatus(status)) + if status > 0 { + span.SetAttributes(semconv.HTTPStatusCode(status)) + } + if len(c.Errors) > 0 { + span.SetAttributes(attribute.String("gin.errors", c.Errors.String())) + } + } +} + +// HTML will trace the rendering of the template as a child of the +// span in the given context. This is a replacement for +// gin.Context.HTML function - it invokes the original function after +// setting up the span. +func HTML(c *gin.Context, code int, name string, obj interface{}) { + var tracer oteltrace.Tracer + tracerInterface, ok := c.Get(tracerKey) + if ok { + tracer, ok = tracerInterface.(oteltrace.Tracer) + } + if !ok { + tracer = otel.GetTracerProvider().Tracer( + tracerName, + oteltrace.WithInstrumentationVersion(SemVersion()), + ) + } + savedContext := c.Request.Context() + defer func() { + c.Request = c.Request.WithContext(savedContext) + }() + opt := oteltrace.WithAttributes(attribute.String("go.template", name)) + _, span := tracer.Start(savedContext, "gin.renderer.html", opt) + defer func() { + if r := recover(); r != nil { + err := fmt.Errorf("error rendering template:%s: %s", name, r) + span.RecordError(err) + span.SetStatus(codes.Error, "template failure") + span.End() + panic(r) + } else { + span.End() + } + }() + c.HTML(code, name, obj) +} |