Skip to content

Commit 58aa00a

Browse files
fix: short circuit level detection when already detected (#17028)
1 parent a8f65d1 commit 58aa00a

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

‎pkg/distributor/field_detection.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ func (l *FieldDetector) shouldDiscoverGenericFields() bool {
9494
}
9595

9696
func (l *FieldDetector) extractLogLevel(labels labels.Labels, structuredMetadata labels.Labels, entry logproto.Entry) (logproto.LabelAdapter, bool) {
97+
// If the level is already set in the structured metadata, we don't need to do anything.
98+
if structuredMetadata.Has(constants.LevelLabel) {
99+
return logproto.LabelAdapter{}, false
100+
}
101+
97102
levelFromLabel, hasLevelLabel := labelsContainAny(labels, l.allowedLevelLabels)
98103
var logLevel string
99104
if hasLevelLabel {

‎pkg/distributor/field_detection_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,55 @@ func Test_DetectLogLevels(t *testing.T) {
118118
},
119119
}, sm)
120120
})
121+
122+
t.Run("detected_level structured metadata takes precedence over other level detection methods", func(t *testing.T) {
123+
limits, ingester := setup(true)
124+
distributors, _ := prepare(t, 1, 5, limits, func(_ string) (ring_client.PoolClient, error) { return ingester, nil })
125+
126+
// Create a write request with multiple potential level sources:
127+
// 1. A JSON log line with level=error
128+
// 2. A log level in stream labels (level=debug)
129+
// 3. OTLP severity number in structured metadata
130+
// 4. A severity field in structured metadata
131+
// 5. The detected_level field in structured metadata (should take precedence)
132+
writeReq := makeWriteRequestWithLabels(1, 10, []string{`{foo="bar", level="debug"}`}, false, false, false)
133+
writeReq.Streams[0].Entries[0].Line = `{"msg":"this is a test message", "level":"error"}`
134+
writeReq.Streams[0].Entries[0].StructuredMetadata = push.LabelsAdapter{
135+
{
136+
Name: loghttp_push.OTLPSeverityNumber,
137+
Value: fmt.Sprintf("%d", plog.SeverityNumberWarn),
138+
},
139+
{
140+
Name: "severity",
141+
Value: constants.LogLevelCritical,
142+
},
143+
{
144+
Name: constants.LevelLabel, // detected_level
145+
Value: constants.LogLevelTrace,
146+
},
147+
}
148+
149+
_, err := distributors[0].Push(ctx, writeReq)
150+
require.NoError(t, err)
151+
topVal := ingester.Peek()
152+
require.Equal(t, `{foo="bar", level="debug"}`, topVal.Streams[0].Labels)
153+
154+
// Verify that detected_level from structured metadata is preserved and used
155+
sm := topVal.Streams[0].Entries[0].StructuredMetadata
156+
157+
detectedLevelLbls := make([]logproto.LabelAdapter, 0, len(sm))
158+
for _, sm := range sm {
159+
if sm.Name == constants.LevelLabel {
160+
detectedLevelLbls = append(detectedLevelLbls, sm)
161+
}
162+
}
163+
164+
require.Len(t, detectedLevelLbls, 1)
165+
require.Contains(t, detectedLevelLbls, logproto.LabelAdapter{
166+
Name: constants.LevelLabel,
167+
Value: constants.LogLevelTrace,
168+
})
169+
})
121170
}
122171

123172
func Test_detectLogLevelFromLogEntry(t *testing.T) {

0 commit comments

Comments
 (0)