diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f0259313d0..6b820d39c1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Added support for providing `endpoint`, `pollingIntervalMs` and `initialSamplingRate` using environment variable `OTEL_TRACES_SAMPLER_ARG` in `go.opentelemetry.io/contrib/samples/jaegerremote`. (#6310) - Added support exporting logs via OTLP over gRPC in `go.opentelemetry.io/contrib/config`. (#6340) -### Removed +### Changed -- Removed the redundant handling of panic from the `HTML` function in `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin`. (#6373) +- Record errors instead of setting the `gin.errors` attribute in `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin`. (#6346) ### Fixed @@ -23,6 +23,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Fixed the value for configuring the OTLP exporter to use `grpc` instead of `grpc/protobuf` in `go.opentelemetry.io/contrib/config`. (#6338) - Allow marshaling types in `go.opentelemetry.io/contrib/config`. (#6347) +### Removed + +- Removed the redundant handling of panic from the `HTML` function in `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin`. (#6373) + diff --git a/detectors/aws/eks/go.mod b/detectors/aws/eks/go.mod index bcfb9829a83..9f6704f8d59 100644 --- a/detectors/aws/eks/go.mod +++ b/detectors/aws/eks/go.mod @@ -21,7 +21,7 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.6.0 // indirect diff --git a/detectors/aws/eks/go.sum b/detectors/aws/eks/go.sum index 8174e73fa0b..9ce25cea314 100644 --- a/detectors/aws/eks/go.sum +++ b/detectors/aws/eks/go.sum @@ -23,8 +23,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go b/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go index 242a2863b38..398f0ac7b27 100644 --- a/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go +++ b/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go @@ -94,7 +94,10 @@ func Middleware(service string, opts ...Option) gin.HandlerFunc { span.SetAttributes(semconv.HTTPStatusCode(status)) } if len(c.Errors) > 0 { - span.SetAttributes(attribute.String("gin.errors", c.Errors.String())) + span.SetStatus(codes.Error, c.Errors.String()) + for _, err := range c.Errors { + span.RecordError(err.Err) + } } } } diff --git a/instrumentation/github.com/gin-gonic/gin/otelgin/test/gintrace_test.go b/instrumentation/github.com/gin-gonic/gin/otelgin/test/gintrace_test.go index e648640ab58..f63d1955f0e 100644 --- a/instrumentation/github.com/gin-gonic/gin/otelgin/test/gintrace_test.go +++ b/instrumentation/github.com/gin-gonic/gin/otelgin/test/gintrace_test.go @@ -164,6 +164,9 @@ func TestTrace200(t *testing.T) { assert.Contains(t, attr, attribute.Int("http.status_code", http.StatusOK)) assert.Contains(t, attr, attribute.String("http.method", "GET")) assert.Contains(t, attr, attribute.String("http.route", "/user/:id")) + assert.Empty(t, span.Events()) + assert.Equal(t, codes.Unset, span.Status().Code) + assert.Empty(t, span.Status().Description) } func TestError(t *testing.T) { @@ -177,7 +180,8 @@ func TestError(t *testing.T) { // configure a handler that returns an error and 5xx status // code router.GET("/server_err", func(c *gin.Context) { - _ = c.AbortWithError(http.StatusInternalServerError, errors.New("oh no")) + _ = c.Error(errors.New("oh no one")) + _ = c.AbortWithError(http.StatusInternalServerError, errors.New("oh no two")) }) r := httptest.NewRequest("GET", "/server_err", nil) w := httptest.NewRecorder() @@ -193,9 +197,20 @@ func TestError(t *testing.T) { attr := span.Attributes() assert.Contains(t, attr, attribute.String("net.host.name", "foobar")) assert.Contains(t, attr, attribute.Int("http.status_code", http.StatusInternalServerError)) - assert.Contains(t, attr, attribute.String("gin.errors", "Error #01: oh no\n")) + + // verify the error events + events := span.Events() + require.Len(t, events, 2) + assert.Equal(t, "exception", events[0].Name) + assert.Contains(t, events[0].Attributes, attribute.String("exception.type", "*errors.errorString")) + assert.Contains(t, events[0].Attributes, attribute.String("exception.message", "oh no one")) + assert.Equal(t, "exception", events[1].Name) + assert.Contains(t, events[1].Attributes, attribute.String("exception.type", "*errors.errorString")) + assert.Contains(t, events[1].Attributes, attribute.String("exception.message", "oh no two")) + // server errors set the status assert.Equal(t, codes.Error, span.Status().Code) + assert.Equal(t, "Error #01: oh no one\nError #02: oh no two\n", span.Status().Description) } func TestSpanStatus(t *testing.T) { @@ -224,6 +239,27 @@ func TestSpanStatus(t *testing.T) { assert.Equal(t, tc.wantSpanStatus, sr.Ended()[0].Status().Code, "should only set Error status for HTTP statuses >= 500") }) } + + t.Run("The status code is 200, but an error is returned", func(t *testing.T) { + sr := tracetest.NewSpanRecorder() + provider := sdktrace.NewTracerProvider( + sdktrace.WithSpanProcessor(sr), + ) + + router := gin.New() + router.Use(otelgin.Middleware("foobar", otelgin.WithTracerProvider(provider))) + router.GET("/", func(c *gin.Context) { + _ = c.Error(errors.New("something went wrong")) + c.JSON(http.StatusOK, nil) + }) + + router.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil)) + + require.Len(t, sr.Ended(), 1) + assert.Equal(t, codes.Error, sr.Ended()[0].Status().Code) + require.Len(t, sr.Ended()[0].Events(), 1) + assert.Contains(t, sr.Ended()[0].Events()[0].Attributes, attribute.String("exception.message", "something went wrong")) + }) } func TestSpanName(t *testing.T) {