feat: capture http errors on spans

This commit is contained in:
Gabe Ruttner
2026-03-15 14:19:19 -04:00
parent fdac15a854
commit a56941bc90
2 changed files with 42 additions and 0 deletions

View File

@@ -1,9 +1,14 @@
package telemetry
import (
"errors"
"fmt"
"github.com/labstack/echo/v4"
"go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
"github.com/hatchet-dev/hatchet/pkg/config/server"
)
@@ -30,3 +35,39 @@ func (m *OTelMiddleware) Middleware() echo.MiddlewareFunc {
otelecho.WithTracerProvider(tracerProvider),
)
}
// ErrorStatusMiddleware marks the current span as Error for any 4xx or 5xx response.
// otelecho only sets Error for 5xx (per OTel semantic conventions). This middleware
// must be registered after otelecho so it runs inside the span. The OTel SDK ignores
// attempts to downgrade from Error to Unset, so otelecho's subsequent status-setting
// for 4xx is a no-op.
func (m *OTelMiddleware) ErrorStatusMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
err := next(c)
span := trace.SpanFromContext(c.Request().Context())
statusCode := 0
if err != nil {
var he *echo.HTTPError
if errors.As(err, &he) {
statusCode = he.Code
}
}
if statusCode == 0 {
statusCode = c.Response().Status
}
if statusCode >= 400 {
span.SetStatus(codes.Error, fmt.Sprintf("HTTP %d", statusCode))
if err != nil {
span.RecordError(err)
}
}
return err
}
}
}

View File

@@ -722,6 +722,7 @@ func (t *APIServer) registerSpec(g *echo.Group, spec *openapi3.T) (*populator.Po
middleware.Recover(),
rateLimitMW.Middleware(),
otelMW.Middleware(),
otelMW.ErrorStatusMiddleware(),
allHatchetMiddleware,
)