Skip to content

Commit

Permalink
othttp: add WithSpanFormatter option (#617)
Browse files Browse the repository at this point in the history
* othttp: add WithSpanFormatter option

* plugin/othttp: add span formatter test

* remove typo

* preserve operation && change option name

* nil check

* fix comment typo

Co-Authored-By: Rahul Patel <[email protected]>

* add default formatter test case

Co-authored-by: Rahul Patel <[email protected]>
  • Loading branch information
marwan-at-work and rghetia authored Apr 6, 2020
1 parent 367635b commit 6489b07
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 9 deletions.
4 changes: 3 additions & 1 deletion internal/trace/mock_span.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
type MockSpan struct {
sc core.SpanContext
tracer apitrace.Tracer
Name string
}

var _ apitrace.Span = (*MockSpan)(nil)
Expand Down Expand Up @@ -66,8 +67,9 @@ func (ms *MockSpan) End(options ...apitrace.EndOption) {
func (ms *MockSpan) RecordError(ctx context.Context, err error, opts ...apitrace.ErrorOption) {
}

// SetName does nothing.
// SetName sets the span name.
func (ms *MockSpan) SetName(name string) {
ms.Name = name
}

// Tracer returns MockTracer implementation of Tracer.
Expand Down
7 changes: 7 additions & 0 deletions internal/trace/mock_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ type MockTracer struct {

// Sampled specifies if the new span should be sampled or not.
Sampled bool

// OnSpanStarted is called every time a new trace span is started
OnSpanStarted func(span *MockSpan)
}

var _ apitrace.Tracer = (*MockTracer)(nil)
Expand Down Expand Up @@ -77,6 +80,10 @@ func (mt *MockTracer) Start(ctx context.Context, name string, o ...apitrace.Star
span = &MockSpan{
sc: sc,
tracer: mt,
Name: name,
}
if mt.OnSpanStarted != nil {
mt.OnSpanStarted(span)
}

return apitrace.ContextWithSpan(ctx, span), span
Expand Down
34 changes: 26 additions & 8 deletions plugin/othttp/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ type Handler struct {
operation string
handler http.Handler

tracer trace.Tracer
props propagation.Propagators
spanStartOptions []trace.StartOption
readEvent bool
writeEvent bool
filters []Filter
tracer trace.Tracer
props propagation.Propagators
spanStartOptions []trace.StartOption
readEvent bool
writeEvent bool
filters []Filter
spanNameFormatter func(string, *http.Request) string
}

// Option function used for setting *optional* Handler properties
Expand Down Expand Up @@ -140,10 +141,27 @@ func WithMessageEvents(events ...event) Option {
}
}

// WithSpanNameFormatter takes a function that will be called on every
// incoming request and the returned string will become the Span Name
func WithSpanNameFormatter(f func(operation string, r *http.Request) string) Option {
return func(h *Handler) {
h.spanNameFormatter = f
}
}

func defaultFormatter(operation string, _ *http.Request) string {
return operation
}

// NewHandler wraps the passed handler, functioning like middleware, in a span
// named after the operation and with any provided HandlerOptions.
func NewHandler(handler http.Handler, operation string, opts ...Option) http.Handler {
h := Handler{handler: handler, operation: operation}
h := Handler{
handler: handler,
operation: operation,
spanNameFormatter: defaultFormatter,
}

defaultOpts := []Option{
WithTracer(global.Tracer("go.opentelemetry.io/plugin/othttp")),
WithPropagators(global.Propagators()),
Expand All @@ -169,7 +187,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
opts := append([]trace.StartOption{}, h.spanStartOptions...) // start with the configured options

ctx := propagation.ExtractHTTP(r.Context(), h.props, r.Header)
ctx, span := h.tracer.Start(ctx, h.operation, opts...)
ctx, span := h.tracer.Start(ctx, h.spanNameFormatter(h.operation, r), opts...)
defer span.End()

readRecordFunc := func(int64) {}
Expand Down
60 changes: 60 additions & 0 deletions plugin/othttp/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,63 @@ func TestBasicFilter(t *testing.T) {
t.Fatalf("got %q, expected %q", got, expected)
}
}

func TestSpanNameFormatter(t *testing.T) {
var testCases = []struct {
name string
formatter func(s string, r *http.Request) string
operation string
expected string
}{
{
name: "default formatter",
formatter: defaultFormatter,
operation: "test_operation",
expected: "test_operation",
},
{
name: "custom formatter",
formatter: func(s string, r *http.Request) string {
return r.URL.Path
},
operation: "",
expected: "/hello",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
rr := httptest.NewRecorder()
var id uint64
var spanName string
tracer := mocktrace.MockTracer{
StartSpanID: &id,
OnSpanStarted: func(span *mocktrace.MockSpan) {
spanName = span.Name
},
}
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if _, err := io.WriteString(w, "hello world"); err != nil {
t.Fatal(err)
}
})
h := NewHandler(
handler,
tc.operation,
WithTracer(&tracer),
WithSpanNameFormatter(tc.formatter),
)
r, err := http.NewRequest(http.MethodGet, "http://localhost/hello", nil)
if err != nil {
t.Fatal(err)
}
h.ServeHTTP(rr, r)
if got, expected := rr.Result().StatusCode, http.StatusOK; got != expected {
t.Fatalf("got %d, expected %d", got, expected)
}
if got, expected := spanName, tc.expected; got != expected {
t.Fatalf("got %q, expected %q", got, expected)
}
})
}
}

0 comments on commit 6489b07

Please sign in to comment.