Skip to content

Commit

Permalink
Add support for filters to the otelgin package (#2965)
Browse files Browse the repository at this point in the history
* Add support for filters to the otelgin package

* Make WithFilter() accept variadic arguments

* Update CHANGELOG.md

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
  • Loading branch information
Orogenesis and MrAlias committed Nov 9, 2022
1 parent 44d8196 commit 9a9abd4
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- The `WithLogger` option to `go.opentelemetry.io/contrib/samplers/jaegerremote` to allow users to pass a `logr.Logger` and have operations logged. (#2566)
- Add the `messaging.url` & `messaging.system` attributes to all appropriate SQS operations in the `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws` package. (#2879)
- Add example use of the metrics signal to `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/example`. (#2610)
- [otelgin] Add support for filters to the `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin` package to provide the way to control which inbound requests are traced. (#2963)

### Fixed

Expand Down
8 changes: 8 additions & 0 deletions instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go
Expand Up @@ -54,6 +54,14 @@ func Middleware(service string, opts ...Option) gin.HandlerFunc {
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() {
Expand Down
19 changes: 19 additions & 0 deletions instrumentation/github.com/gin-gonic/gin/otelgin/option.go
Expand Up @@ -17,15 +17,22 @@
package otelgin // import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"

import (
"net/http"

"go.opentelemetry.io/otel/propagation"
oteltrace "go.opentelemetry.io/otel/trace"
)

type config struct {
TracerProvider oteltrace.TracerProvider
Propagators propagation.TextMapPropagator
Filters []Filter
}

// Filter is a predicate used to determine whether a given http.request should
// be traced. A Filter must return true if the request should be traced.
type Filter func(*http.Request) bool

// Option specifies instrumentation configuration options.
type Option interface {
apply(*config)
Expand Down Expand Up @@ -57,3 +64,15 @@ func WithTracerProvider(provider oteltrace.TracerProvider) Option {
}
})
}

// 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.
// If no filters are provided then all requests are traced.
// Filters will be invoked for each processed request, it is advised to make them
// simple and fast.
func WithFilter(f ...Filter) Option {
return optionFunc(func(c *config) {
c.Filters = append(c.Filters, f...)
})
}
Expand Up @@ -203,3 +203,37 @@ func TestHTML(t *testing.T) {
require.NotNil(t, tspan)
assert.Contains(t, tspan.Attributes(), attribute.String("go.template", "hello"))
}

func TestWithFilter(t *testing.T) {
t.Run("custom filter filtering route", func(t *testing.T) {
sr := tracetest.NewSpanRecorder()
otel.SetTracerProvider(sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)))

router := gin.New()
f := func(req *http.Request) bool { return req.URL.Path != "/healthcheck" }
router.Use(otelgin.Middleware("foobar", otelgin.WithFilter(f)))
router.GET("/healthcheck", func(c *gin.Context) {})

r := httptest.NewRequest("GET", "/healthcheck", nil)
w := httptest.NewRecorder()

router.ServeHTTP(w, r)
assert.Len(t, sr.Ended(), 0)
})

t.Run("custom filter not filtering route", func(t *testing.T) {
sr := tracetest.NewSpanRecorder()
otel.SetTracerProvider(sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)))

router := gin.New()
f := func(req *http.Request) bool { return req.URL.Path != "/healthcheck" }
router.Use(otelgin.Middleware("foobar", otelgin.WithFilter(f)))
router.GET("/user/:id", func(c *gin.Context) {})

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

router.ServeHTTP(w, r)
assert.Len(t, sr.Ended(), 1)
})
}

0 comments on commit 9a9abd4

Please sign in to comment.