Skip to content

Commit 35d271f

Browse files
rehanpfmrdmathieu
andauthored
feat: Add *gin.Context Filter parameter (#5743)
Issue: #3070 last PR status: #4444 --------- Signed-off-by: Rehan Pasha <[email protected]> Signed-off-by: Brian Warner <[email protected]> Signed-off-by: rehanpfmr <[email protected]> Co-authored-by: Damien Mathieu <[email protected]>
1 parent a32ef13 commit 35d271f

File tree

4 files changed

+58
-1
lines changed

4 files changed

+58
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1919
- Support for the `OTEL_HTTP_CLIENT_COMPATIBILITY_MODE=http/dup` environment variable in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` to emit attributes for both the v1.20.0 and v1.26.0 semantic conventions. (#5401)
2020
- The `go.opentelemetry.io/contrib/bridges/otelzerolog` module.
2121
This module provides an OpenTelemetry logging bridge for `github.com/rs/zerolog`. (#5405)
22+
- Add `WithGinFilter` filter parameter in `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin` to allow filtering requests with `*gin.Context`. (#5743)
2223

2324
### Removed
2425

instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ func Middleware(service string, opts ...Option) gin.HandlerFunc {
5252
return
5353
}
5454
}
55+
for _, f := range cfg.GinFilters {
56+
if !f(c) {
57+
// Serve the request to the next middleware
58+
// if a filter rejects the request.
59+
c.Next()
60+
return
61+
}
62+
}
5563
c.Set(tracerKey, tracer)
5664
savedCtx := c.Request.Context()
5765
defer func() {

instrumentation/github.com/gin-gonic/gin/otelgin/option.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ package otelgin // import "go.opentelemetry.io/contrib/instrumentation/github.co
88
import (
99
"net/http"
1010

11+
"github.com/gin-gonic/gin"
12+
1113
"go.opentelemetry.io/otel/propagation"
1214
oteltrace "go.opentelemetry.io/otel/trace"
1315
)
@@ -16,13 +18,18 @@ type config struct {
1618
TracerProvider oteltrace.TracerProvider
1719
Propagators propagation.TextMapPropagator
1820
Filters []Filter
21+
GinFilters []GinFilter
1922
SpanNameFormatter SpanNameFormatter
2023
}
2124

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

29+
// Adding new Filter parameter (*gin.Context)
30+
// gin.Context has FullPath() method, which returns a matched route full path.
31+
type GinFilter func(*gin.Context) bool
32+
2633
// SpanNameFormatter is used to set span name by http.request.
2734
type SpanNameFormatter func(r *http.Request) string
2835

@@ -60,7 +67,7 @@ func WithTracerProvider(provider oteltrace.TracerProvider) Option {
6067

6168
// WithFilter adds a filter to the list of filters used by the handler.
6269
// If any filter indicates to exclude a request then the request will not be
63-
// traced. All filters must allow a request to be traced for a Span to be created.
70+
// traced. All gin and net/http filters must allow a request to be traced for a Span to be created.
6471
// If no filters are provided then all requests are traced.
6572
// Filters will be invoked for each processed request, it is advised to make them
6673
// simple and fast.
@@ -70,6 +77,13 @@ func WithFilter(f ...Filter) Option {
7077
})
7178
}
7279

80+
// WithGinFilter adds a gin filter to the list of filters used by the handler.
81+
func WithGinFilter(f ...GinFilter) Option {
82+
return optionFunc(func(c *config) {
83+
c.GinFilters = append(c.GinFilters, f...)
84+
})
85+
}
86+
7387
// WithSpanNameFormatter takes a function that will be called on every
7488
// request and the returned string will become the Span Name.
7589
func WithSpanNameFormatter(f func(r *http.Request) string) Option {

instrumentation/github.com/gin-gonic/gin/otelgin/test/gintrace_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,37 @@ func TestWithFilter(t *testing.T) {
287287
assert.Len(t, sr.Ended(), 1)
288288
})
289289
}
290+
291+
func TestWithGinFilter(t *testing.T) {
292+
t.Run("custom filter filtering route", func(t *testing.T) {
293+
sr := tracetest.NewSpanRecorder()
294+
otel.SetTracerProvider(sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)))
295+
296+
router := gin.New()
297+
f := func(c *gin.Context) bool { return c.Request.URL.Path != "/healthcheck" }
298+
router.Use(otelgin.Middleware("foobar", otelgin.WithGinFilter(f)))
299+
router.GET("/healthcheck", func(c *gin.Context) {})
300+
301+
r := httptest.NewRequest("GET", "/healthcheck", nil)
302+
w := httptest.NewRecorder()
303+
304+
router.ServeHTTP(w, r)
305+
assert.Len(t, sr.Ended(), 0)
306+
})
307+
308+
t.Run("custom filter not filtering route", func(t *testing.T) {
309+
sr := tracetest.NewSpanRecorder()
310+
otel.SetTracerProvider(sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)))
311+
312+
router := gin.New()
313+
f := func(c *gin.Context) bool { return c.Request.URL.Path != "/user/:id" }
314+
router.Use(otelgin.Middleware("foobar", otelgin.WithGinFilter(f)))
315+
router.GET("/user/:id", func(c *gin.Context) {})
316+
317+
r := httptest.NewRequest("GET", "/user/123", nil)
318+
w := httptest.NewRecorder()
319+
320+
router.ServeHTTP(w, r)
321+
assert.Len(t, sr.Ended(), 1)
322+
})
323+
}

0 commit comments

Comments
 (0)