diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b88edfbebf..04a4daec961 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - The `Version()` function in `go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace` has been replaced by `const Version`. (#8302) - The `Version()` function in `go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo` has been replaced by `const Version`. (#8370) - The `Version()` function in `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin` has been replaced by `const Version`. (#8341) +- Set `error.type` attribute instead of adding `exception` span events in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp`. (#8386) +- Set `error.type` attribute instead of adding `exception` span events in `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws`. (#8386) diff --git a/instrumentation/README.md b/instrumentation/README.md index 47536fa84eb..d21c53c1d74 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -63,3 +63,23 @@ Additionally the following guidelines for package composition need to be followe - All instrumentation packages MUST NOT provide an option to accept a `Tracer` or `Meter`. - All instrumentation packages MUST define a `ScopeName` constant with a value matching the instrumentation package and use it when creating a `Tracer` or `Meter`. - All instrumentation packages MUST define a `Version` function returning the version of the module containing the instrumentation and use it when creating a `Tracer` or `Meter`. + +### Recording Errors + +When an instrumented operation returns a non-nil `error` and the semantic conventions classify the outcome as an error, the instrumentation: + +1. MUST set the span status to `codes.Error` with a description of `err.Error()`, + +2. SHOULD also set the `error.type` attribute, for example by using the `ErrorType` function from the `semconv` package, + +3. SHOULD NOT use `span.RecordError(err)` for this purpose. + +For example: + +```go +res, err := t.rt.RoundTrip(r) +if err != nil { + span.SetAttributes(semconv.ErrorType(err)) + span.SetStatus(codes.Error, err.Error()) +} +``` diff --git a/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/aws.go b/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/aws.go index 918c18a16b2..5f7e16f77e3 100644 --- a/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/aws.go +++ b/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/aws.go @@ -72,7 +72,7 @@ func (m otelMiddlewares) initializeMiddlewareAfter(stack *middleware.Stack) erro out, metadata, err = next.HandleInitialize(ctx, in) span.SetAttributes(m.buildAttributes(ctx, in, out)...) if err != nil { - span.RecordError(err) + span.SetAttributes(semconv.ErrorType(err)) span.SetStatus(codes.Error, err.Error()) } diff --git a/instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconv/client.go b/instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconv/client.go index c9a107117f8..fbba6b41921 100644 --- a/instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconv/client.go +++ b/instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconv/client.go @@ -12,7 +12,6 @@ import ( "context" "fmt" "net/http" - "reflect" "slices" "strconv" "strings" @@ -165,23 +164,6 @@ func (n HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue return attrs } -func (n HTTPClient) ErrorType(err error) attribute.KeyValue { - t := reflect.TypeOf(err) - var value string - if t.PkgPath() == "" && t.Name() == "" { - // Likely a builtin type. - value = t.String() - } else { - value = fmt.Sprintf("%s.%s", t.PkgPath(), t.Name()) - } - - if value == "" { - return semconv.ErrorTypeOther - } - - return semconv.ErrorTypeKey.String(value) -} - func (n HTTPClient) method(method string) (attribute.KeyValue, attribute.KeyValue) { if method == "" { return semconv.HTTPRequestMethodGet, attribute.KeyValue{} diff --git a/instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconv/httpconvtest_test.go b/instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconv/httpconvtest_test.go index 48570c37f66..e7e6d1de935 100644 --- a/instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconv/httpconvtest_test.go +++ b/instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconv/httpconvtest_test.go @@ -1,5 +1,5 @@ // Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/semconv/httpconv_test.go.tmpl +// source: internal/shared/semconv/httpconvtest_test.go.tmpl // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 @@ -7,7 +7,6 @@ package semconv_test import ( - "errors" "fmt" "net/http" "net/http/httptest" @@ -336,21 +335,6 @@ func TestClientResponse(t *testing.T) { } } -func TestRequestErrorType(t *testing.T) { - testcases := []struct { - err error - want attribute.KeyValue - }{ - {err: errors.New("http: nil Request.URL"), want: attribute.String("error.type", "*errors.errorString")}, - {err: customError{}, want: attribute.String("error.type", "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconv_test.customError")}, - } - - for _, tt := range testcases { - got := semconv.HTTPClient{}.ErrorType(tt.err) - assert.Equal(t, tt.want, got) - } -} - func TestNewClientRecordMetrics(t *testing.T) { currAttrs := attribute.NewSet( attribute.String("http.request.method", "POST"), diff --git a/instrumentation/github.com/gin-gonic/gin/otelgin/internal/semconv/client.go b/instrumentation/github.com/gin-gonic/gin/otelgin/internal/semconv/client.go index b5257eb3cf3..c84fc3b3304 100644 --- a/instrumentation/github.com/gin-gonic/gin/otelgin/internal/semconv/client.go +++ b/instrumentation/github.com/gin-gonic/gin/otelgin/internal/semconv/client.go @@ -12,7 +12,6 @@ import ( "context" "fmt" "net/http" - "reflect" "slices" "strconv" "strings" @@ -165,23 +164,6 @@ func (n HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue return attrs } -func (n HTTPClient) ErrorType(err error) attribute.KeyValue { - t := reflect.TypeOf(err) - var value string - if t.PkgPath() == "" && t.Name() == "" { - // Likely a builtin type. - value = t.String() - } else { - value = fmt.Sprintf("%s.%s", t.PkgPath(), t.Name()) - } - - if value == "" { - return semconv.ErrorTypeOther - } - - return semconv.ErrorTypeKey.String(value) -} - func (n HTTPClient) method(method string) (attribute.KeyValue, attribute.KeyValue) { if method == "" { return semconv.HTTPRequestMethodGet, attribute.KeyValue{} diff --git a/instrumentation/github.com/gin-gonic/gin/otelgin/internal/semconv/httpconvtest_test.go b/instrumentation/github.com/gin-gonic/gin/otelgin/internal/semconv/httpconvtest_test.go index 9ac9d2d53f4..332b058b8d2 100644 --- a/instrumentation/github.com/gin-gonic/gin/otelgin/internal/semconv/httpconvtest_test.go +++ b/instrumentation/github.com/gin-gonic/gin/otelgin/internal/semconv/httpconvtest_test.go @@ -1,5 +1,5 @@ // Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/semconv/httpconv_test.go.tmpl +// source: internal/shared/semconv/httpconvtest_test.go.tmpl // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 @@ -7,7 +7,6 @@ package semconv_test import ( - "errors" "fmt" "net/http" "net/http/httptest" @@ -336,21 +335,6 @@ func TestClientResponse(t *testing.T) { } } -func TestRequestErrorType(t *testing.T) { - testcases := []struct { - err error - want attribute.KeyValue - }{ - {err: errors.New("http: nil Request.URL"), want: attribute.String("error.type", "*errors.errorString")}, - {err: customError{}, want: attribute.String("error.type", "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/internal/semconv_test.customError")}, - } - - for _, tt := range testcases { - got := semconv.HTTPClient{}.ErrorType(tt.err) - assert.Equal(t, tt.want, got) - } -} - func TestNewClientRecordMetrics(t *testing.T) { currAttrs := attribute.NewSet( attribute.String("http.request.method", "POST"), diff --git a/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/client.go b/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/client.go index fc3a075d919..c6619bc2af6 100644 --- a/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/client.go +++ b/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/client.go @@ -12,7 +12,6 @@ import ( "context" "fmt" "net/http" - "reflect" "slices" "strconv" "strings" @@ -165,23 +164,6 @@ func (n HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue return attrs } -func (n HTTPClient) ErrorType(err error) attribute.KeyValue { - t := reflect.TypeOf(err) - var value string - if t.PkgPath() == "" && t.Name() == "" { - // Likely a builtin type. - value = t.String() - } else { - value = fmt.Sprintf("%s.%s", t.PkgPath(), t.Name()) - } - - if value == "" { - return semconv.ErrorTypeOther - } - - return semconv.ErrorTypeKey.String(value) -} - func (n HTTPClient) method(method string) (attribute.KeyValue, attribute.KeyValue) { if method == "" { return semconv.HTTPRequestMethodGet, attribute.KeyValue{} diff --git a/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/httpconvtest_test.go b/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/httpconvtest_test.go index 60d2f268ccb..1adc8929703 100644 --- a/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/httpconvtest_test.go +++ b/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv/httpconvtest_test.go @@ -1,5 +1,5 @@ // Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/semconv/httpconv_test.go.tmpl +// source: internal/shared/semconv/httpconvtest_test.go.tmpl // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 @@ -7,7 +7,6 @@ package semconv_test import ( - "errors" "fmt" "net/http" "net/http/httptest" @@ -336,21 +335,6 @@ func TestClientResponse(t *testing.T) { } } -func TestRequestErrorType(t *testing.T) { - testcases := []struct { - err error - want attribute.KeyValue - }{ - {err: errors.New("http: nil Request.URL"), want: attribute.String("error.type", "*errors.errorString")}, - {err: customError{}, want: attribute.String("error.type", "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/internal/semconv_test.customError")}, - } - - for _, tt := range testcases { - got := semconv.HTTPClient{}.ErrorType(tt.err) - assert.Equal(t, tt.want, got) - } -} - func TestNewClientRecordMetrics(t *testing.T) { currAttrs := attribute.NewSet( attribute.String("http.request.method", "POST"), diff --git a/instrumentation/github.com/labstack/echo/otelecho/example_test.go b/instrumentation/github.com/labstack/echo/otelecho/example_test.go index 742377e3aaa..e77f337abbf 100644 --- a/instrumentation/github.com/labstack/echo/otelecho/example_test.go +++ b/instrumentation/github.com/labstack/echo/otelecho/example_test.go @@ -64,7 +64,6 @@ func ExampleMiddleware() { if err != nil { log.Println("error reading body: ", err) // Record the error in the span and set its status - span.RecordError(err) span.SetStatus(codes.Error, "failed to read request body") return c.String(http.StatusBadRequest, "Bad request") } diff --git a/instrumentation/github.com/labstack/echo/otelecho/internal/semconv/client.go b/instrumentation/github.com/labstack/echo/otelecho/internal/semconv/client.go index e4b824d0100..2143407bded 100644 --- a/instrumentation/github.com/labstack/echo/otelecho/internal/semconv/client.go +++ b/instrumentation/github.com/labstack/echo/otelecho/internal/semconv/client.go @@ -12,7 +12,6 @@ import ( "context" "fmt" "net/http" - "reflect" "slices" "strconv" "strings" @@ -165,23 +164,6 @@ func (n HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue return attrs } -func (n HTTPClient) ErrorType(err error) attribute.KeyValue { - t := reflect.TypeOf(err) - var value string - if t.PkgPath() == "" && t.Name() == "" { - // Likely a builtin type. - value = t.String() - } else { - value = fmt.Sprintf("%s.%s", t.PkgPath(), t.Name()) - } - - if value == "" { - return semconv.ErrorTypeOther - } - - return semconv.ErrorTypeKey.String(value) -} - func (n HTTPClient) method(method string) (attribute.KeyValue, attribute.KeyValue) { if method == "" { return semconv.HTTPRequestMethodGet, attribute.KeyValue{} diff --git a/instrumentation/github.com/labstack/echo/otelecho/internal/semconv/httpconvtest_test.go b/instrumentation/github.com/labstack/echo/otelecho/internal/semconv/httpconvtest_test.go index 1caf2cbd5ad..3eb30a5b7c3 100644 --- a/instrumentation/github.com/labstack/echo/otelecho/internal/semconv/httpconvtest_test.go +++ b/instrumentation/github.com/labstack/echo/otelecho/internal/semconv/httpconvtest_test.go @@ -1,5 +1,5 @@ // Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/semconv/httpconv_test.go.tmpl +// source: internal/shared/semconv/httpconvtest_test.go.tmpl // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 @@ -7,7 +7,6 @@ package semconv_test import ( - "errors" "fmt" "net/http" "net/http/httptest" @@ -336,21 +335,6 @@ func TestClientResponse(t *testing.T) { } } -func TestRequestErrorType(t *testing.T) { - testcases := []struct { - err error - want attribute.KeyValue - }{ - {err: errors.New("http: nil Request.URL"), want: attribute.String("error.type", "*errors.errorString")}, - {err: customError{}, want: attribute.String("error.type", "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho/internal/semconv_test.customError")}, - } - - for _, tt := range testcases { - got := semconv.HTTPClient{}.ErrorType(tt.err) - assert.Equal(t, tt.want, got) - } -} - func TestNewClientRecordMetrics(t *testing.T) { currAttrs := attribute.NewSet( attribute.String("http.request.method", "POST"), diff --git a/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/client.go b/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/client.go index 10895b8db34..fdc385b7593 100644 --- a/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/client.go +++ b/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/client.go @@ -12,7 +12,6 @@ import ( "context" "fmt" "net/http" - "reflect" "slices" "strconv" "strings" @@ -165,23 +164,6 @@ func (n HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue return attrs } -func (n HTTPClient) ErrorType(err error) attribute.KeyValue { - t := reflect.TypeOf(err) - var value string - if t.PkgPath() == "" && t.Name() == "" { - // Likely a builtin type. - value = t.String() - } else { - value = fmt.Sprintf("%s.%s", t.PkgPath(), t.Name()) - } - - if value == "" { - return semconv.ErrorTypeOther - } - - return semconv.ErrorTypeKey.String(value) -} - func (n HTTPClient) method(method string) (attribute.KeyValue, attribute.KeyValue) { if method == "" { return semconv.HTTPRequestMethodGet, attribute.KeyValue{} diff --git a/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/httpconvtest_test.go b/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/httpconvtest_test.go index 8042624e420..2187f13d89d 100644 --- a/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/httpconvtest_test.go +++ b/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/httpconvtest_test.go @@ -1,5 +1,5 @@ // Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/semconv/httpconv_test.go.tmpl +// source: internal/shared/semconv/httpconvtest_test.go.tmpl // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 @@ -7,7 +7,6 @@ package semconv_test import ( - "errors" "fmt" "net/http" "net/http/httptest" @@ -336,21 +335,6 @@ func TestClientResponse(t *testing.T) { } } -func TestRequestErrorType(t *testing.T) { - testcases := []struct { - err error - want attribute.KeyValue - }{ - {err: errors.New("http: nil Request.URL"), want: attribute.String("error.type", "*errors.errorString")}, - {err: customError{}, want: attribute.String("error.type", "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv_test.customError")}, - } - - for _, tt := range testcases { - got := semconv.HTTPClient{}.ErrorType(tt.err) - assert.Equal(t, tt.want, got) - } -} - func TestNewClientRecordMetrics(t *testing.T) { currAttrs := attribute.NewSet( attribute.String("http.request.method", "POST"), diff --git a/instrumentation/net/http/otelhttp/internal/semconv/client.go b/instrumentation/net/http/otelhttp/internal/semconv/client.go index 45d3d934f52..cd1c913e1a3 100644 --- a/instrumentation/net/http/otelhttp/internal/semconv/client.go +++ b/instrumentation/net/http/otelhttp/internal/semconv/client.go @@ -12,7 +12,6 @@ import ( "context" "fmt" "net/http" - "reflect" "slices" "strconv" "strings" @@ -165,23 +164,6 @@ func (n HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue return attrs } -func (n HTTPClient) ErrorType(err error) attribute.KeyValue { - t := reflect.TypeOf(err) - var value string - if t.PkgPath() == "" && t.Name() == "" { - // Likely a builtin type. - value = t.String() - } else { - value = fmt.Sprintf("%s.%s", t.PkgPath(), t.Name()) - } - - if value == "" { - return semconv.ErrorTypeOther - } - - return semconv.ErrorTypeKey.String(value) -} - func (n HTTPClient) method(method string) (attribute.KeyValue, attribute.KeyValue) { if method == "" { return semconv.HTTPRequestMethodGet, attribute.KeyValue{} diff --git a/instrumentation/net/http/otelhttp/internal/semconv/httpconvtest_test.go b/instrumentation/net/http/otelhttp/internal/semconv/httpconvtest_test.go index 98338487b69..05ed7188c0b 100644 --- a/instrumentation/net/http/otelhttp/internal/semconv/httpconvtest_test.go +++ b/instrumentation/net/http/otelhttp/internal/semconv/httpconvtest_test.go @@ -1,5 +1,5 @@ // Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/semconv/httpconv_test.go.tmpl +// source: internal/shared/semconv/httpconvtest_test.go.tmpl // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 @@ -7,7 +7,6 @@ package semconv_test import ( - "errors" "fmt" "net/http" "net/http/httptest" @@ -336,21 +335,6 @@ func TestClientResponse(t *testing.T) { } } -func TestRequestErrorType(t *testing.T) { - testcases := []struct { - err error - want attribute.KeyValue - }{ - {err: errors.New("http: nil Request.URL"), want: attribute.String("error.type", "*errors.errorString")}, - {err: customError{}, want: attribute.String("error.type", "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv_test.customError")}, - } - - for _, tt := range testcases { - got := semconv.HTTPClient{}.ErrorType(tt.err) - assert.Equal(t, tt.want, got) - } -} - func TestNewClientRecordMetrics(t *testing.T) { currAttrs := attribute.NewSet( attribute.String("http.request.method", "POST"), diff --git a/instrumentation/net/http/otelhttp/transport.go b/instrumentation/net/http/otelhttp/transport.go index 1d2f4022116..4391ec7482d 100644 --- a/instrumentation/net/http/otelhttp/transport.go +++ b/instrumentation/net/http/otelhttp/transport.go @@ -16,6 +16,7 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/propagation" + otelsemconv "go.opentelemetry.io/otel/semconv/v1.37.0" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/request" @@ -175,15 +176,7 @@ func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) { }() if err != nil { - // set error type attribute if the error is part of the predefined - // error types. - // otherwise, record it as an exception - if errType := t.semconv.ErrorType(err); errType.Valid() { - span.SetAttributes(errType) - } else { - span.RecordError(err) - } - + span.SetAttributes(otelsemconv.ErrorType(err)) span.SetStatus(codes.Error, err.Error()) span.End() @@ -243,7 +236,7 @@ func (wb *wrappedBody) Write(p []byte) (int, error) { // This will not panic given the guard in newWrappedBody. n, err := wb.body.(io.Writer).Write(p) if err != nil { - wb.span.RecordError(err) + wb.span.SetAttributes(otelsemconv.ErrorType(err)) wb.span.SetStatus(codes.Error, err.Error()) } return n, err @@ -261,7 +254,7 @@ func (wb *wrappedBody) Read(b []byte) (int, error) { wb.recordBytesRead() wb.span.End() default: - wb.span.RecordError(err) + wb.span.SetAttributes(otelsemconv.ErrorType(err)) wb.span.SetStatus(codes.Error, err.Error()) } return n, err diff --git a/instrumentation/net/http/otelhttp/transport_test.go b/instrumentation/net/http/otelhttp/transport_test.go index bb03883c682..5e55d959fad 100644 --- a/instrumentation/net/http/otelhttp/transport_test.go +++ b/instrumentation/net/http/otelhttp/transport_test.go @@ -30,6 +30,7 @@ import ( "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" + semconv "go.opentelemetry.io/otel/semconv/v1.37.0" "go.opentelemetry.io/otel/trace" ) @@ -220,8 +221,8 @@ func (rc readCloser) Close() error { type span struct { trace.Span - ended bool - recordedErr error + ended bool + attributes []attribute.KeyValue statusCode codes.Code statusDesc string @@ -231,8 +232,8 @@ func (s *span) End(...trace.SpanEndOption) { s.ended = true } -func (s *span) RecordError(err error, _ ...trace.EventOption) { - s.recordedErr = err +func (s *span) SetAttributes(kv ...attribute.KeyValue) { + s.attributes = append(s.attributes, kv...) } func (s *span) SetStatus(c codes.Code, d string) { @@ -247,9 +248,9 @@ func (s *span) assert(t *testing.T, ended bool, err error, c codes.Code, d strin } if err == nil { - assert.NoError(t, s.recordedErr, "recorded an error") + assert.Empty(t, s.attributes, "recorded an error") } else { - assert.Equal(t, err, s.recordedErr) + assert.Contains(t, s.attributes, semconv.ErrorType(err), "error type attribute missing") } assert.Equal(t, c, s.statusCode, "status codes not equal") diff --git a/internal/shared/semconv/client.go.tmpl b/internal/shared/semconv/client.go.tmpl index fb102575b1e..5fa8aca0928 100644 --- a/internal/shared/semconv/client.go.tmpl +++ b/internal/shared/semconv/client.go.tmpl @@ -12,7 +12,6 @@ import ( "context" "fmt" "net/http" - "reflect" "slices" "strconv" "strings" @@ -165,23 +164,6 @@ func (n HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue return attrs } -func (n HTTPClient) ErrorType(err error) attribute.KeyValue { - t := reflect.TypeOf(err) - var value string - if t.PkgPath() == "" && t.Name() == "" { - // Likely a builtin type. - value = t.String() - } else { - value = fmt.Sprintf("%s.%s", t.PkgPath(), t.Name()) - } - - if value == "" { - return semconv.ErrorTypeOther - } - - return semconv.ErrorTypeKey.String(value) -} - func (n HTTPClient) method(method string) (attribute.KeyValue, attribute.KeyValue) { if method == "" { return semconv.HTTPRequestMethodGet, attribute.KeyValue{} diff --git a/internal/shared/semconv/httpconvtest_test.go.tmpl b/internal/shared/semconv/httpconvtest_test.go.tmpl index b06ca39cff6..571bf5877d1 100644 --- a/internal/shared/semconv/httpconvtest_test.go.tmpl +++ b/internal/shared/semconv/httpconvtest_test.go.tmpl @@ -1,5 +1,5 @@ // Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/semconv/httpconv_test.go.tmpl +// source: internal/shared/semconv/httpconvtest_test.go.tmpl // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 @@ -7,7 +7,6 @@ package semconv_test import ( - "errors" "fmt" "net/http" "net/http/httptest" @@ -336,21 +335,6 @@ func TestClientResponse(t *testing.T) { } } -func TestRequestErrorType(t *testing.T) { - testcases := []struct { - err error - want attribute.KeyValue - }{ - {err: errors.New("http: nil Request.URL"), want: attribute.String("error.type", "*errors.errorString")}, - {err: customError{}, want: attribute.String("error.type", "{{.pkg}}/internal/semconv_test.customError")}, - } - - for _, tt := range testcases { - got := semconv.HTTPClient{}.ErrorType(tt.err) - assert.Equal(t, tt.want, got) - } -} - func TestNewClientRecordMetrics(t *testing.T) { currAttrs := attribute.NewSet( attribute.String("http.request.method", "POST"),