diff --git a/CHANGELOG.md b/CHANGELOG.md index e352379f8b2..684d552e448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,7 @@ * [ENHANCEMENT] Querier: Reduce merge iterator `BatchSize` from 12 to 8. #7823 * [ENHANCEMENT] Upgrade promql-engine to latest. #7841 * [ENHANCEMENT] Ruler: Add new limit `-ruler.list-rules-max-rules` on the total number of rules returned by the Prometheus ListRules API. Responses exceeding the limit are truncated on a rule group boundary and return a `groupNextToken` for retrieving the remaining groups. A rule group is never split, so a single group larger than the limit is still returned whole. Defaults to 0, which is unlimited. #7785 +* [BUGFIX] SpanLogger: Set span error tag when `SpanLogger.Log()` is called with `level=error`, so errors logged through SpanLogger are visible as errors in tracing UIs. #3016 * [BUGFIX] Querier: Fix queryWithRetry and labelsWithRetry returning (nil, nil) on cancelled context by propagating ctx.Err(). #7370 * [BUGFIX] Metrics Helper: Fix non-deterministic bucket order in merged histograms by sorting buckets after map iteration, matching Prometheus client library behavior. #7380 * [BUGFIX] Distributor: Return HTTP 401 Unauthorized when tenant ID resolution fails in the Prometheus Remote Write 2.0 path. #7389 diff --git a/pkg/util/spanlogger/spanlogger.go b/pkg/util/spanlogger/spanlogger.go index aa78dbea7f3..5be9387b607 100644 --- a/pkg/util/spanlogger/spanlogger.go +++ b/pkg/util/spanlogger/spanlogger.go @@ -90,6 +90,15 @@ func (s *SpanLogger) Log(kvps ...any) error { return err } s.LogFields(fields...) + // Mirror level=error onto the span's error tag so tracing UIs surface it. + for i := 0; i+1 < len(kvps); i += 2 { + if k, ok := kvps[i].(string); ok && k == "level" { + if v, ok := kvps[i+1].(string); ok && v == "error" { + ext.Error.Set(s.Span, true) + } + break + } + } return nil } diff --git a/pkg/util/spanlogger/spanlogger_test.go b/pkg/util/spanlogger/spanlogger_test.go index f522fa6f9f5..e13f3569a7e 100644 --- a/pkg/util/spanlogger/spanlogger_test.go +++ b/pkg/util/spanlogger/spanlogger_test.go @@ -60,6 +60,22 @@ func TestSpanCreatedWithoutTenantTag(t *testing.T) { require.False(t, exist) } +func TestSpanLogger_Log_SetsErrorTagOnErrorLevel(t *testing.T) { + mockTracer := mocktracer.New() + opentracing.SetGlobalTracer(mockTracer) + + logger, _ := New(context.Background(), "test") + mockSpan := logger.Span.(*mocktracer.MockSpan) + + // Non-error level should NOT set the error tag. + _ = logger.Log("level", "info", "msg", "hello") + require.Nil(t, mockSpan.Tag("error")) + + // level=error SHOULD set the span error tag. + _ = logger.Log("level", "error", "msg", "something failed") + require.Equal(t, true, mockSpan.Tag("error")) +} + func createSpan(ctx context.Context) *mocktracer.MockSpan { mockTracer := mocktracer.New() opentracing.SetGlobalTracer(mockTracer)