Skip to content

Commit

Permalink
Merge pull request #1 from tigerwill90/feat/options/span-attribute
Browse files Browse the repository at this point in the history
Add an option to dynamically add custom span attribute
  • Loading branch information
tigerwill90 authored Jul 5, 2023
2 parents 5a40de2 + f45b85a commit 873f39f
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 4 deletions.
7 changes: 6 additions & 1 deletion foxtrace.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,13 @@ func (t *Tracer) Trace(next fox.HandlerFunc) fox.HandlerFunc {

ctx := t.cfg.propagator.Extract(req.Context(), t.cfg.carrier(req))

attributes := httpconv.ServerRequest(t.service, req)
if t.cfg.attrsFn != nil {
attributes = append(attributes, t.cfg.attrsFn(req)...)
}

opts := []trace.SpanStartOption{
trace.WithAttributes(httpconv.ServerRequest(t.service, req)...),
trace.WithAttributes(attributes...),
trace.WithSpanKind(trace.SpanKindServer),
}

Expand Down
33 changes: 33 additions & 0 deletions foxtrace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/tigerwill90/fox"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
"net/http"
Expand Down Expand Up @@ -86,3 +87,35 @@ func TestPropagationWithCustomPropagators(t *testing.T) {
require.NoError(t, err)
router.ServeHTTP(w, r)
}

func TestWithSpanAttributes(t *testing.T) {
provider := trace.NewNoopTracerProvider()
otel.SetTextMapPropagator(b3prop.New())

r := httptest.NewRequest("GET", "/user/123?foo=bar", nil)
w := httptest.NewRecorder()

ctx := context.Background()
sc := trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x01},
SpanID: trace.SpanID{0x01},
})
ctx = trace.ContextWithRemoteSpanContext(ctx, sc)
ctx, _ = provider.Tracer(tracerName).Start(ctx, "test")
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)
attrs[0] = attribute.String("http.target", r.URL.String())
return attrs
}))
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())
}))

require.NoError(t, err)
router.ServeHTTP(w, r)
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.19

require (
github.com/stretchr/testify v1.8.3
github.com/tigerwill90/fox v0.9.1
github.com/tigerwill90/fox v0.9.4
go.opentelemetry.io/contrib/propagators/b3 v1.17.0
go.opentelemetry.io/otel v1.16.0
go.opentelemetry.io/otel/trace v1.16.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tigerwill90/fox v0.9.1 h1:RKRpQhv5uNyqgNu+9e2EnOs9XEBrk8AvVccsmHUQBs4=
github.com/tigerwill90/fox v0.9.1/go.mod h1:frBRK49d4TXcELy3911opGU3RZQSUq++BHQUwhykpQw=
github.com/tigerwill90/fox v0.9.4 h1:uqZqwSDbso1gs1U7kw4Y6srXOLFNgMjKQUNIZWr5kak=
github.com/tigerwill90/fox v0.9.4/go.mod h1:frBRK49d4TXcELy3911opGU3RZQSUq++BHQUwhykpQw=
go.opentelemetry.io/contrib/propagators/b3 v1.17.0 h1:ImOVvHnku8jijXqkwCSyYKRDt2YrnGXD4BbhcpfbfJo=
go.opentelemetry.io/contrib/propagators/b3 v1.17.0/go.mod h1:IkfUfMpKWmynvvE0264trz0sf32NRTZL4nuAN9AbWRc=
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
Expand Down
21 changes: 21 additions & 0 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package otelfox

import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
"net/http"
Expand All @@ -17,16 +18,26 @@ func (o optionFunc) apply(c *config) {
o(c)
}

// 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

// 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

// 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 config struct {
provider trace.TracerProvider
propagator propagation.TextMapPropagator
carrier func(r *http.Request) propagation.TextMapCarrier
spanFmt SpanNameFormatter
filters []Filter
attrsFn SpanAttributesFunc
}

func defaultConfig() *config {
Expand Down Expand Up @@ -87,3 +98,13 @@ func WithFilter(f ...Filter) Option {
c.filters = append(c.filters, f...)
})
}

// WithSpanAttributes specifies a function for generating span attributes.
// The function will be invoked for each request, and its return attributes
// will be added to the span. For example, you can use this option to add
// the http.target attribute to the span.
func WithSpanAttributes(fn SpanAttributesFunc) Option {
return optionFunc(func(c *config) {
c.attrsFn = fn
})
}

0 comments on commit 873f39f

Please sign in to comment.