summaryrefslogtreecommitdiff
path: root/vendor/go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go
diff options
context:
space:
mode:
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.go142
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)
+}