Skip to content

Commit 3259e72

Browse files
authored
Merge pull request #12 from vadimi/main
Set span status to Error when http status is >= 500
2 parents a9468a6 + 6cce414 commit 3259e72

3 files changed

Lines changed: 59 additions & 2 deletions

File tree

extrator.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ import (
1111
"time"
1212

1313
"go.opentelemetry.io/otel/attribute"
14+
"go.opentelemetry.io/otel/codes"
1415
"go.opentelemetry.io/otel/metric"
15-
)
1616

17-
import (
1817
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
1918
"go.opentelemetry.io/otel/semconv/v1.39.0/httpconv"
2019
)
@@ -560,3 +559,13 @@ func SpanNameFormatter(v Values) string {
560559
}
561560
return method
562561
}
562+
563+
func spanStatus(code int) (codes.Code, string) {
564+
if code < 100 || code >= 600 {
565+
return codes.Error, fmt.Sprintf("Invalid HTTP status code %d", code)
566+
}
567+
if code >= 500 {
568+
return codes.Error, ""
569+
}
570+
return codes.Unset, ""
571+
}

otel.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ func (config Config) ToMiddleware() (echo.MiddlewareFunc, error) {
228228
if resp != nil {
229229
ev.HTTPResponseBodySize = resp.Size
230230
}
231+
span.SetStatus(spanStatus(status))
231232

232233
endAttributes := ev.SpanEndAttributes()
233234
if config.SpanEndAttributes != nil {

otel_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"go.opentelemetry.io/otel"
1515
"go.opentelemetry.io/otel/attribute"
1616
"go.opentelemetry.io/otel/metric"
17+
"go.opentelemetry.io/otel/codes"
1718
"go.opentelemetry.io/otel/propagation"
1819
"go.opentelemetry.io/otel/semconv/v1.39.0/httpconv"
1920
"go.opentelemetry.io/otel/trace"
@@ -24,6 +25,8 @@ import (
2425
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
2526
"go.opentelemetry.io/otel/sdk/metric/metricdata"
2627
"go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest"
28+
sdktrace "go.opentelemetry.io/otel/sdk/trace"
29+
"go.opentelemetry.io/otel/sdk/trace/tracetest"
2730
)
2831

2932
func TestGetSpanNotInstrumented(t *testing.T) {
@@ -446,6 +449,50 @@ func TestNewMiddlewareWithConfig_Metric(t *testing.T) {
446449
}, sm.Metrics[0], metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue(), metricdatatest.IgnoreExemplars())
447450
}
448451

452+
func TestSpanStatusOnHTTP500(t *testing.T) {
453+
tests := []struct {
454+
name string
455+
handler echo.HandlerFunc
456+
}{
457+
{
458+
name: "handler writes 500 status code directly",
459+
handler: func(c *echo.Context) error {
460+
return c.String(http.StatusInternalServerError, "internal server error")
461+
},
462+
},
463+
{
464+
name: "handler returns echo HTTP error with 500",
465+
handler: func(c *echo.Context) error {
466+
return echo.NewHTTPError(http.StatusInternalServerError, "internal server error")
467+
},
468+
},
469+
}
470+
471+
for _, tt := range tests {
472+
t.Run(tt.name, func(t *testing.T) {
473+
exporter := tracetest.NewInMemoryExporter()
474+
tp := sdktrace.NewTracerProvider(sdktrace.WithSyncer(exporter))
475+
476+
e := echo.New()
477+
e.Use(NewMiddlewareWithConfig(Config{
478+
ServerName: "foobar",
479+
TracerProvider: tp,
480+
}))
481+
e.GET("/error", tt.handler)
482+
483+
r := httptest.NewRequest(http.MethodGet, "/error", http.NoBody)
484+
w := httptest.NewRecorder()
485+
e.ServeHTTP(w, r)
486+
487+
assert.Equal(t, http.StatusInternalServerError, w.Result().StatusCode)
488+
489+
spans := exporter.GetSpans()
490+
assert.Len(t, spans, 1)
491+
assert.Equal(t, codes.Error, spans[0].Status.Code)
492+
})
493+
}
494+
}
495+
449496
func TestConfig_OnNextError(t *testing.T) {
450497
tests := []struct {
451498
name string

0 commit comments

Comments
 (0)