diff --git a/foxtrace.go b/foxtrace.go index 256f97e..aa2e978 100644 --- a/foxtrace.go +++ b/foxtrace.go @@ -51,7 +51,7 @@ func (t *Tracer) Trace(next fox.HandlerFunc) fox.HandlerFunc { req := c.Request() for _, f := range t.cfg.filters { - if !f(req) { + if f(c) { next(c) return } @@ -59,14 +59,15 @@ func (t *Tracer) Trace(next fox.HandlerFunc) fox.HandlerFunc { savedCtx := req.Context() defer func() { + // rollback to the original context c.SetRequest(req.WithContext(savedCtx)) }() - ctx := t.cfg.propagator.Extract(req.Context(), t.cfg.carrier(req)) + ctx := t.cfg.propagator.Extract(savedCtx, t.cfg.carrier(req)) attributes := httpconv.ServerRequest(t.service, req) if t.cfg.attrsFn != nil { - attributes = append(attributes, t.cfg.attrsFn(req)...) + attributes = append(attributes, t.cfg.attrsFn(c)...) } opts := []trace.SpanStartOption{ @@ -78,7 +79,7 @@ func (t *Tracer) Trace(next fox.HandlerFunc) fox.HandlerFunc { if t.cfg.spanFmt == nil { spanName = c.Path() } else { - spanName = t.cfg.spanFmt(req) + spanName = t.cfg.spanFmt(c) } if spanName == "" { @@ -90,12 +91,12 @@ func (t *Tracer) Trace(next fox.HandlerFunc) fox.HandlerFunc { ctx, span := t.tracer.Start(ctx, spanName, opts...) defer span.End() - cc := c.CloneWith(c.Writer(), req.WithContext(ctx)) - defer cc.Close() + // pass the span through the request context + c.SetRequest(req.WithContext(ctx)) - next(cc) + next(c) - status := cc.Writer().Status() + status := c.Writer().Status() span.SetStatus(httpconv.ServerStatus(status)) if status > 0 { span.SetAttributes(semconv.HTTPStatusCode(status)) diff --git a/foxtrace_test.go b/foxtrace_test.go index f7e6fdd..0cdab03 100644 --- a/foxtrace_test.go +++ b/foxtrace_test.go @@ -19,12 +19,13 @@ import ( func TestGetSpanNotInstrumented(t *testing.T) { router := fox.New() - require.NoError(t, router.Handle(http.MethodGet, "/ping", func(c fox.Context) { + _, err := router.Handle(http.MethodGet, "/ping", func(c fox.Context) { span := trace.SpanFromContext(c.Request().Context()) ok := !span.SpanContext().IsValid() assert.True(t, ok) _ = c.String(http.StatusOK, "ok") - })) + }) + require.NoError(t, err) r := httptest.NewRequest(http.MethodGet, "/ping", nil) w := httptest.NewRecorder() @@ -51,7 +52,7 @@ func TestPropagationWithGlobalPropagators(t *testing.T) { router := fox.New() mw := New("foobar", WithTracerProvider(provider)) - err := router.Handle(http.MethodGet, "/user/{id}", mw.Trace(func(c fox.Context) { + _, err := router.Handle(http.MethodGet, "/user/{id}", mw.Trace(func(c fox.Context) { span := trace.SpanFromContext(c.Request().Context()) assert.Equal(t, sc.TraceID(), span.SpanContext().TraceID()) assert.Equal(t, sc.SpanID(), span.SpanContext().SpanID()) @@ -79,7 +80,7 @@ func TestPropagationWithCustomPropagators(t *testing.T) { router := fox.New() mw := New("foobar", WithTracerProvider(provider), WithPropagators(b3)) - err := router.Handle(http.MethodGet, "/user/{id}", mw.Trace(func(c fox.Context) { + _, err := router.Handle(http.MethodGet, "/user/{id}", mw.Trace(func(c fox.Context) { span := trace.SpanFromContext(c.Request().Context()) assert.Equal(t, sc.TraceID(), span.SpanContext().TraceID()) assert.Equal(t, sc.SpanID(), span.SpanContext().SpanID()) @@ -106,16 +107,22 @@ func TestWithSpanAttributes(t *testing.T) { otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header)) router := fox.New() - mw := New("foobar", WithTracerProvider(provider), WithSpanAttributes(func(r *http.Request) []attribute.KeyValue { - attrs := make([]attribute.KeyValue, 1) + mw := New("foobar", WithTracerProvider(provider), WithSpanAttributes(func(c fox.Context) []attribute.KeyValue { + attrs := make([]attribute.KeyValue, 1, 2) attrs[0] = attribute.String("http.target", r.URL.String()) + for annotation := range c.Route().Annotations() { + attrs = append(attrs, attribute.KeyValue{ + Key: attribute.Key(annotation.Key), + Value: attribute.StringValue(annotation.Value.(string)), + }) + } return attrs })) - err := router.Handle(http.MethodGet, "/user/{id}", mw.Trace(func(c fox.Context) { + _, err := router.Handle(http.MethodGet, "/user/{id}", mw.Trace(func(c fox.Context) { span := trace.SpanFromContext(c.Request().Context()) assert.Equal(t, sc.TraceID(), span.SpanContext().TraceID()) assert.Equal(t, sc.SpanID(), span.SpanContext().SpanID()) - })) + }), fox.WithAnnotation("foo", "bar")) require.NoError(t, err) router.ServeHTTP(w, r) diff --git a/go.mod b/go.mod index 8c660fa..4968146 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,10 @@ go 1.23 require ( github.com/stretchr/testify v1.9.0 - github.com/tigerwill90/fox v0.16.0 - go.opentelemetry.io/contrib/propagators/b3 v1.30.0 - go.opentelemetry.io/otel v1.30.0 - go.opentelemetry.io/otel/trace v1.30.0 + github.com/tigerwill90/fox v0.17.0 + go.opentelemetry.io/contrib/propagators/b3 v1.31.0 + go.opentelemetry.io/otel v1.31.0 + go.opentelemetry.io/otel/trace v1.31.0 ) require ( @@ -16,7 +16,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/otel/metric v1.30.0 // indirect + go.opentelemetry.io/otel/metric v1.31.0 // indirect golang.org/x/sys v0.26.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 676fe0b..573cc69 100644 --- a/go.sum +++ b/go.sum @@ -20,16 +20,16 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tigerwill90/fox v0.16.0 h1:p/1xOID3MTw8rtVMxw+Ji/ogMhACh6tQQg9H5JlNCVM= -github.com/tigerwill90/fox v0.16.0/go.mod h1:ujscTs1DtEAaU/wrPKB7dw65yQiXTIFVJJiNTSFZgBs= -go.opentelemetry.io/contrib/propagators/b3 v1.30.0 h1:vumy4r1KMyaoQRltX7cJ37p3nluzALX9nugCjNNefuY= -go.opentelemetry.io/contrib/propagators/b3 v1.30.0/go.mod h1:fRbvRsaeVZ82LIl3u0rIvusIel2UUf+JcaaIpy5taho= -go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= -go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= -go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= -go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= -go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= -go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= +github.com/tigerwill90/fox v0.17.0 h1:P+YTWtk3ctb82Rk0/PhB0IWSR3YDMF5WBCc+jHMKQnY= +github.com/tigerwill90/fox v0.17.0/go.mod h1:ujscTs1DtEAaU/wrPKB7dw65yQiXTIFVJJiNTSFZgBs= +go.opentelemetry.io/contrib/propagators/b3 v1.31.0 h1:PQPXYscmwbCp76QDvO4hMngF2j8Bx/OTV86laEl8uqo= +go.opentelemetry.io/contrib/propagators/b3 v1.31.0/go.mod h1:jbqfV8wDdqSDrAYxVpXQnpM0XFMq2FtDesblJ7blOwQ= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/option.go b/option.go index 1aa4a33..10eff71 100644 --- a/option.go +++ b/option.go @@ -1,6 +1,7 @@ package otelfox import ( + "github.com/tigerwill90/fox" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/propagation" @@ -19,17 +20,17 @@ func (o optionFunc) apply(c *config) { } // Filter is a function that determines whether a given HTTP request should be traced. -// It returns true to indicate the request should be traced or false otherwise. -type Filter func(r *http.Request) bool +// It returns true to indicate the request should not be traced. +type Filter func(c fox.Context) bool // SpanNameFormatter is a function that formats the span name given the HTTP request. // This allows for dynamic naming of spans based on attributes of the request. -type SpanNameFormatter func(r *http.Request) string +type SpanNameFormatter func(c fox.Context) string // SpanAttributesFunc is a function type that can be used to dynamically // generate span attributes for a given HTTP request. It is used in // conjunction with the WithSpanAttributes middleware option. -type SpanAttributesFunc func(r *http.Request) []attribute.KeyValue +type SpanAttributesFunc func(c fox.Context) []attribute.KeyValue type config struct { provider trace.TracerProvider @@ -90,7 +91,7 @@ func WithSpanNameFormatter(fn SpanNameFormatter) Option { } // WithFilter appends the provided filters to the middleware's filter list. -// A filter returning false will exclude the request from being traced. If no filters +// A filter returning true will exclude the request from being traced. If no filters // are provided, all requests will be traced. Keep in mind that filters are invoked for each request, // so they should be simple and efficient. func WithFilter(f ...Filter) Option { diff --git a/version.go b/version.go index 714078a..f055c4a 100644 --- a/version.go +++ b/version.go @@ -2,7 +2,7 @@ package otelfox import "fmt" -const version = "v0.14.0" +const version = "v0.17.0" var semver = fmt.Sprintf("semver:%s", version)