Skip to content

Commit

Permalink
Add span start and end options to otelmux configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
mikk2168 committed Mar 7, 2024
1 parent a111e3e commit fa2ff96
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 3 deletions.
18 changes: 18 additions & 0 deletions instrumentation/github.com/gorilla/mux/otelmux/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ type config struct {
PublicEndpoint bool
PublicEndpointFn func(*http.Request) bool
Filters []Filter
SpanStartOptions []oteltrace.SpanStartOption
SpanEndOptions []oteltrace.SpanEndOption
}

// Option specifies instrumentation configuration options.
Expand Down Expand Up @@ -86,6 +88,22 @@ func WithSpanNameFormatter(fn func(routeName string, r *http.Request) string) Op
})
}

// WithSpanStartOption applies options to all the HTTP span created by the
// instrumentation.
func WithSpanStartOption(o ...oteltrace.SpanStartOption) Option {
return optionFunc(func(c *config) {
c.SpanStartOptions = append(c.SpanStartOptions, o...)
})
}

// WithSpanEndOption applies options when ending the HTTP span created by the
// instrumentation.
func WithSpanEndOption(o ...oteltrace.SpanEndOption) Option {
return optionFunc(func(c *config) {
c.SpanEndOptions = append(c.SpanEndOptions, o...)
})
}

// WithFilter adds a filter to the list of filters used by the handler.
// If any filter indicates to exclude a request then the request will not be
// traced. All filters must allow a request to be traced for a Span to be created.
Expand Down
10 changes: 7 additions & 3 deletions instrumentation/github.com/gorilla/mux/otelmux/mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ func Middleware(service string, opts ...Option) mux.MiddlewareFunc {
publicEndpoint: cfg.PublicEndpoint,
publicEndpointFn: cfg.PublicEndpointFn,
filters: cfg.Filters,
SpanStartOptions: cfg.SpanStartOptions,
SpanEndOptions: cfg.SpanEndOptions,
}
}
}
Expand All @@ -68,6 +70,8 @@ type traceware struct {
publicEndpoint bool
publicEndpointFn func(*http.Request) bool
filters []Filter
SpanStartOptions []trace.SpanStartOption
SpanEndOptions []trace.SpanEndOption
}

type recordingResponseWriter struct {
Expand Down Expand Up @@ -141,10 +145,10 @@ func (tw traceware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}

opts := []trace.SpanStartOption{
opts := append(tw.SpanStartOptions, []trace.SpanStartOption{
trace.WithAttributes(semconvutil.HTTPServerRequest(tw.service, r)...),
trace.WithSpanKind(trace.SpanKindServer),
}
}...)

if tw.publicEndpoint || (tw.publicEndpointFn != nil && tw.publicEndpointFn(r.WithContext(ctx))) {
opts = append(opts, trace.WithNewRoot())
Expand All @@ -162,7 +166,7 @@ func (tw traceware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
spanName := tw.spanNameFormatter(routeStr, r)
ctx, span := tw.tracer.Start(ctx, spanName, opts...)
defer span.End()
defer span.End(tw.SpanEndOptions...)
r2 := r.WithContext(ctx)
rrw := getRRW(w)
defer putRRW(rrw)
Expand Down
65 changes: 65 additions & 0 deletions instrumentation/github.com/gorilla/mux/otelmux/test/mux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/http"
"net/http/httptest"
"testing"
"time"

"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -282,3 +283,67 @@ func TestWithPublicEndpointFn(t *testing.T) {
})
}
}

func TestWithSpanStartOptions(t *testing.T) {
sr := tracetest.NewSpanRecorder()
provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))

// Setup
router := mux.NewRouter()
router.Use(otelmux.Middleware("foobar",
otelmux.WithTracerProvider(provider),
otelmux.WithSpanStartOption(
trace.WithAttributes(attribute.String("spanStart", "true")),
),
))

// Configure an empty handler
router.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
})
r := httptest.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, r)
response := w.Result()
assert.Equal(t, http.StatusOK, response.StatusCode)

// Verify that the attribute is set as expected
spans := sr.Ended()
require.Len(t, spans, 1)
span := spans[0]
assert.Equal(t, "/", span.Name())
attr := span.Attributes()
assert.Contains(t, attr, attribute.String("spanStart", "true"))
}

func TestWithSpanEndOptions(t *testing.T) {
sr := tracetest.NewSpanRecorder()
provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))

// Setup
router := mux.NewRouter()
endTime := time.Now()
router.Use(otelmux.Middleware("foobar",
otelmux.WithTracerProvider(provider),
otelmux.WithSpanEndOption(
trace.WithTimestamp(endTime),
),
))

// Configure an empty handler
router.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
})
r := httptest.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, r)
response := w.Result()
assert.Equal(t, http.StatusOK, response.StatusCode)

// Verify that the attribute is set as expected
spans := sr.Ended()
require.Len(t, spans, 1)
span := spans[0]
assert.Equal(t, "/", span.Name())

// Assert that the time set in the SpanEndOptions above matches the EndTime of the span
assert.Equal(t, span.EndTime(), endTime)
}

0 comments on commit fa2ff96

Please sign in to comment.