Skip to content

Commit 4140f6d

Browse files
authored
Promotes trace and span IDs to top level (#329)
* Promotes trace and span IDs to top level * Add tests too * Show that we handle garbage * Make test slightly more insightful * Remove commentted code * APPEASE THE LINTER * Need to specify lower case d
1 parent 3d03e54 commit 4140f6d

File tree

2 files changed

+97
-20
lines changed

2 files changed

+97
-20
lines changed

processor/loghouseprocessor/processor.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
package loghouseprocessor // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/loghouseprocessor"
55
import (
66
"context"
7+
"encoding/hex"
8+
"errors"
79
"fmt"
810
"regexp"
911
"strconv"
@@ -135,12 +137,65 @@ func parseSeverity(l *plog.LogRecord) error {
135137
func processJSONLog(l *plog.LogRecord) {
136138
_ = parseSeverity(l)
137139
extractBody(l)
140+
promoteTraceAndSpan(l)
138141
isCH := parseCHTimestamp(l)
139142
if isCH {
140143
parseCHSeverity(l)
141144
}
142145
}
143146

147+
// Both funcs copied from: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/ottl/contexts/internal/ids.go#L25
148+
149+
func ParseSpanID(spanIDStr string) (pcommon.SpanID, error) {
150+
var id pcommon.SpanID
151+
if hex.DecodedLen(len(spanIDStr)) != len(id) {
152+
return pcommon.SpanID{}, errors.New("span ids must be 16 hex characters")
153+
}
154+
_, err := hex.Decode(id[:], []byte(spanIDStr))
155+
if err != nil {
156+
return pcommon.SpanID{}, err
157+
}
158+
return id, nil
159+
}
160+
161+
func ParseTraceID(traceIDStr string) (pcommon.TraceID, error) {
162+
var id pcommon.TraceID
163+
if hex.DecodedLen(len(traceIDStr)) != len(id) {
164+
return pcommon.TraceID{}, errors.New("trace ids must be 32 hex characters")
165+
}
166+
_, err := hex.Decode(id[:], []byte(traceIDStr))
167+
if err != nil {
168+
return pcommon.TraceID{}, err
169+
}
170+
return id, nil
171+
}
172+
173+
func promoteTraceAndSpan(l *plog.LogRecord) {
174+
var (
175+
traceID pcommon.TraceID
176+
spanID pcommon.SpanID
177+
)
178+
if tid, ok := l.Attributes().Get("traceId"); ok {
179+
parsed, err := ParseTraceID(tid.Str())
180+
if err != nil {
181+
return
182+
}
183+
traceID = parsed
184+
}
185+
if sid, ok := l.Attributes().Get("spanId"); ok {
186+
parsed, err := ParseSpanID(sid.Str())
187+
if err != nil {
188+
return
189+
}
190+
spanID = parsed
191+
}
192+
// No point having one or the other, we must always do both
193+
if !traceID.IsEmpty() && !spanID.IsEmpty() {
194+
l.SetTraceID(traceID)
195+
l.SetSpanID(spanID)
196+
}
197+
}
198+
144199
var (
145200
k8sTimestampRe = regexp.MustCompile(`\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d*Z`)
146201
chTimestampRe = regexp.MustCompile(`\d{4}.\d{2}.\d{2} \d{2}:\d{2}:\d{2}.\d*`)

processor/loghouseprocessor/processor_test.go

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package loghouseprocessor
66
import (
77
"testing"
88

9+
"go.opentelemetry.io/collector/pdata/pcommon"
10+
911
"github.com/stretchr/testify/assert"
1012
"go.opentelemetry.io/collector/pdata/plog"
1113
)
@@ -244,23 +246,43 @@ func Test_processLine(t *testing.T) {
244246
})
245247
}
246248

247-
// func assertAttr(t *testing.T, expected, key string, log *plog.LogRecord) {
248-
// val, ok := log.Attributes().Get(key)
249-
// assert.True(t, ok)
250-
// assert.Equal(t, expected, val.Str())
251-
// }
252-
// TODO for testing that metrics get updated
253-
// func getCounter() metric.Int64Counter {
254-
// meterProvider := sdkmetric.NewMeterProvider()
255-
//
256-
// meter := meterProvider.Meter("xoyo-logs")
257-
// observedLogsCtr, err := meter.Int64Counter(
258-
// "loghouse_observed_logs",
259-
// metric.WithDescription("Number of log records that were not routed to some or all exporters"),
260-
// )
261-
// if err != nil {
262-
// panic(err)
263-
// }
264-
// return observedLogsCtr
265-
//
266-
// }
249+
func Test_promoteTraceAndSpan(t *testing.T) {
250+
type expect struct {
251+
trace pcommon.TraceID
252+
span pcommon.SpanID
253+
}
254+
tests := []struct {
255+
name string
256+
args map[string]any
257+
expected expect
258+
}{
259+
{name: "missing both", args: map[string]any(nil), expected: expect{
260+
trace: pcommon.TraceID{},
261+
span: pcommon.SpanID{},
262+
}},
263+
{name: "have both", args: map[string]any{"traceId": "00000000000000000000000000000001", "spanId": "0000000000000001"}, expected: expect{
264+
trace: pcommon.TraceID{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01},
265+
span: pcommon.SpanID{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01},
266+
}},
267+
{name: "one passed it, so ignore", args: map[string]any{"traceId": "00000000000000000000000000000001"}, expected: expect{
268+
trace: pcommon.TraceID{},
269+
span: pcommon.SpanID{},
270+
}},
271+
{name: "garbage, also ignore", args: map[string]any{"traceId": "00000000000000000000000000000001", "spanId": "blah"}, expected: expect{
272+
trace: pcommon.TraceID{},
273+
span: pcommon.SpanID{},
274+
}},
275+
}
276+
for _, tt := range tests {
277+
t.Run(tt.name, func(t *testing.T) {
278+
l := plog.NewLogRecord()
279+
err := l.Attributes().FromRaw(tt.args)
280+
if err != nil {
281+
t.Fatalf("failed to parse from the args")
282+
}
283+
promoteTraceAndSpan(&l)
284+
assert.Equal(t, tt.expected.span, l.SpanID())
285+
assert.Equal(t, tt.expected.trace, l.TraceID())
286+
})
287+
}
288+
}

0 commit comments

Comments
 (0)