Skip to content

Commit d4643e4

Browse files
committed
contrib/gin-gonic/gin: error propagation configuration
Don't enable the error propagation by default, so it's stay the same as before.
1 parent add0ce9 commit d4643e4

File tree

3 files changed

+64
-17
lines changed

3 files changed

+64
-17
lines changed

contrib/gin-gonic/gin/gintrace.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func Middleware(service string, opts ...Option) gin.HandlerFunc {
5555
defer func() {
5656
status := c.Writer.Status()
5757
err := c.Errors.Last()
58-
if err != nil && cfg.isStatusError(status) {
58+
if err != nil && cfg.propagateError && cfg.isStatusError(status) {
5959
finishSpans(status, cfg.isStatusError, tracer.WithError(err))
6060
}
6161
finishSpans(status, cfg.isStatusError)

contrib/gin-gonic/gin/gintrace_test.go

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,14 @@ func TestError(t *testing.T) {
179179
mt := mocktracer.Start()
180180
defer mt.Stop()
181181

182-
// setup
183-
router := gin.New()
184-
router.Use(Middleware("foobar"))
185182
responseErr := errors.New("oh no")
186183

187-
t.Run("server error", func(*testing.T) {
184+
t.Run("server error - with error propagation", func(*testing.T) {
188185
defer mt.Reset()
189186

187+
router := gin.New()
188+
router.Use(Middleware("foobar", WithErrorPropagation()))
189+
190190
// configure a handler that returns an error and 5xx status code
191191
router.GET("/server_err", func(c *gin.Context) {
192192
c.AbortWithError(500, responseErr)
@@ -216,9 +216,47 @@ func TestError(t *testing.T) {
216216
assert.Equal(componentName, span.Integration())
217217
})
218218

219+
t.Run("server error - without error propagation", func(*testing.T) {
220+
defer mt.Reset()
221+
222+
router := gin.New()
223+
router.Use(Middleware("foobar"))
224+
225+
// configure a handler that returns an error and 5xx status code
226+
router.GET("/server_err", func(c *gin.Context) {
227+
c.AbortWithError(500, responseErr)
228+
})
229+
r := httptest.NewRequest("GET", "/server_err", nil)
230+
w := httptest.NewRecorder()
231+
router.ServeHTTP(w, r)
232+
response := w.Result()
233+
defer response.Body.Close()
234+
assert.Equal(response.StatusCode, 500)
235+
236+
// verify the errors and status are correct
237+
spans := mt.FinishedSpans()
238+
assert.Len(spans, 1)
239+
if len(spans) < 1 {
240+
t.Fatalf("no spans")
241+
}
242+
span := spans[0]
243+
assert.Equal("http.request", span.OperationName())
244+
assert.Equal("foobar", span.Tag(ext.ServiceName))
245+
assert.Equal("500", span.Tag(ext.HTTPCode))
246+
assert.Equal(fmt.Sprintf("Error #01: %s\n", responseErr), span.Tag("gin.errors"))
247+
// server errors set the ext.ErrorMsg tag
248+
assert.Equal("500: Internal Server Error", span.Tag(ext.ErrorMsg))
249+
assert.Equal(ext.SpanKindServer, span.Tag(ext.SpanKind))
250+
assert.Equal("gin-gonic/gin", span.Tag(ext.Component))
251+
assert.Equal(componentName, span.Integration())
252+
})
253+
219254
t.Run("client error", func(*testing.T) {
220255
defer mt.Reset()
221256

257+
router := gin.New()
258+
router.Use(Middleware("foobar"))
259+
222260
// configure a handler that returns an error and 4xx status code
223261
router.GET("/client_err", func(c *gin.Context) {
224262
c.AbortWithError(418, responseErr)

contrib/gin-gonic/gin/option.go

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ import (
1515
)
1616

1717
type config struct {
18-
analyticsRate float64
19-
resourceNamer func(c *gin.Context) string
20-
serviceName string
21-
ignoreRequest func(c *gin.Context) bool
22-
isStatusError func(statusCode int) bool
23-
headerTags instrumentation.HeaderTags
18+
analyticsRate float64
19+
resourceNamer func(c *gin.Context) string
20+
serviceName string
21+
ignoreRequest func(c *gin.Context) bool
22+
isStatusError func(statusCode int) bool
23+
propagateError bool
24+
headerTags instrumentation.HeaderTags
2425
}
2526

2627
func newConfig(serviceName string) *config {
@@ -29,12 +30,13 @@ func newConfig(serviceName string) *config {
2930
}
3031
rate := instr.AnalyticsRate(true)
3132
return &config{
32-
analyticsRate: rate,
33-
resourceNamer: defaultResourceNamer,
34-
serviceName: serviceName,
35-
ignoreRequest: func(_ *gin.Context) bool { return false },
36-
isStatusError: isServerError,
37-
headerTags: instr.HTTPHeadersAsTags(),
33+
analyticsRate: rate,
34+
resourceNamer: defaultResourceNamer,
35+
serviceName: serviceName,
36+
ignoreRequest: func(_ *gin.Context) bool { return false },
37+
isStatusError: isServerError,
38+
propagateError: false,
39+
headerTags: instr.HTTPHeadersAsTags(),
3840
}
3941
}
4042

@@ -93,6 +95,13 @@ func isServerError(statusCode int) bool {
9395
return statusCode >= 500 && statusCode < 600
9496
}
9597

98+
// WithErrorPropagation enables the propagation of gin's error to the span.
99+
func WithErrorPropagation() OptionFn {
100+
return func(cfg *config) {
101+
cfg.propagateError = true
102+
}
103+
}
104+
96105
// WithHeaderTags enables the integration to attach HTTP request headers as span tags.
97106
// Warning:
98107
// Using this feature can risk exposing sensitive data such as authorization tokens to Datadog.

0 commit comments

Comments
 (0)