mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-01-30 04:40:41 +02:00
Fix duplicate logs across resources (#5803)
1. Create scope map with resource key to map the correct log record. 2. Add test case with different resource and scope combination Fixes #5782 ### Benchmarks ``` goos: darwin goarch: arm64 pkg: go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/internal/transform │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ ResourceLogs-8 3.266µ ± 3% 1.100µ ± 5% -66.33% (p=0.000 n=10) │ old.txt │ new.txt │ │ B/op │ B/op vs base │ ResourceLogs-8 8.297Ki ± 0% 2.430Ki ± 0% -70.72% (p=0.000 n=10) │ old.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ ResourceLogs-8 178.00 ± 0% 52.00 ± 0% -70.79% (p=0.000 n=10) ``` --------- Co-authored-by: Sam Xie <sam@samxie.me>
This commit is contained in:
parent
42fd8fe325
commit
534ce5ab09
@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- The race condition for multiple `FixedSize` exemplar reservoirs identified in #5814 is resolved. (#5819)
|
- The race condition for multiple `FixedSize` exemplar reservoirs identified in #5814 is resolved. (#5819)
|
||||||
|
- Fix log records duplication in case of heterogeneous resource attributes by correctly mapping each log record to it's resource and scope. (#5803)
|
||||||
|
|
||||||
<!-- Released section -->
|
<!-- Released section -->
|
||||||
<!-- Don't change this section unless doing release -->
|
<!-- Don't change this section unless doing release -->
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/internal/transform"
|
package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/internal/transform"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
cpb "go.opentelemetry.io/proto/otlp/common/v1"
|
cpb "go.opentelemetry.io/proto/otlp/common/v1"
|
||||||
@ -28,71 +27,25 @@ func ResourceLogs(records []log.Record) []*lpb.ResourceLogs {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
resMap := resourceLogsMapPool.Get().(map[attribute.Distinct]*lpb.ResourceLogs)
|
resMap := make(map[attribute.Distinct]*lpb.ResourceLogs)
|
||||||
defer func() {
|
|
||||||
clear(resMap)
|
|
||||||
resourceLogsMapPool.Put(resMap)
|
|
||||||
}()
|
|
||||||
resourceLogsMap(&resMap, records)
|
|
||||||
|
|
||||||
out := make([]*lpb.ResourceLogs, 0, len(resMap))
|
type key struct {
|
||||||
for _, rl := range resMap {
|
r attribute.Distinct
|
||||||
out = append(out, rl)
|
is instrumentation.Scope
|
||||||
}
|
}
|
||||||
return out
|
scopeMap := make(map[key]*lpb.ScopeLogs)
|
||||||
}
|
|
||||||
|
|
||||||
var resourceLogsMapPool = sync.Pool{
|
var resources int
|
||||||
New: func() any {
|
|
||||||
return make(map[attribute.Distinct]*lpb.ResourceLogs)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceLogsMap(dst *map[attribute.Distinct]*lpb.ResourceLogs, records []log.Record) {
|
|
||||||
for _, r := range records {
|
for _, r := range records {
|
||||||
res := r.Resource()
|
res := r.Resource()
|
||||||
rl, ok := (*dst)[res.Equivalent()]
|
rKey := res.Equivalent()
|
||||||
if !ok {
|
|
||||||
rl = new(lpb.ResourceLogs)
|
|
||||||
if res.Len() > 0 {
|
|
||||||
rl.Resource = &rpb.Resource{
|
|
||||||
Attributes: AttrIter(res.Iter()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rl.SchemaUrl = res.SchemaURL()
|
|
||||||
(*dst)[res.Equivalent()] = rl
|
|
||||||
}
|
|
||||||
rl.ScopeLogs = ScopeLogs(records)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScopeLogs returns a slice of OTLP ScopeLogs generated from records.
|
|
||||||
func ScopeLogs(records []log.Record) []*lpb.ScopeLogs {
|
|
||||||
scopeMap := scopeLogsMapPool.Get().(map[instrumentation.Scope]*lpb.ScopeLogs)
|
|
||||||
defer func() {
|
|
||||||
clear(scopeMap)
|
|
||||||
scopeLogsMapPool.Put(scopeMap)
|
|
||||||
}()
|
|
||||||
scopeLogsMap(&scopeMap, records)
|
|
||||||
|
|
||||||
out := make([]*lpb.ScopeLogs, 0, len(scopeMap))
|
|
||||||
for _, sl := range scopeMap {
|
|
||||||
out = append(out, sl)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
var scopeLogsMapPool = sync.Pool{
|
|
||||||
New: func() any {
|
|
||||||
return make(map[instrumentation.Scope]*lpb.ScopeLogs)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func scopeLogsMap(dst *map[instrumentation.Scope]*lpb.ScopeLogs, records []log.Record) {
|
|
||||||
for _, r := range records {
|
|
||||||
scope := r.InstrumentationScope()
|
scope := r.InstrumentationScope()
|
||||||
sl, ok := (*dst)[scope]
|
k := key{
|
||||||
if !ok {
|
r: rKey,
|
||||||
|
is: scope,
|
||||||
|
}
|
||||||
|
sl, iOk := scopeMap[k]
|
||||||
|
if !iOk {
|
||||||
sl = new(lpb.ScopeLogs)
|
sl = new(lpb.ScopeLogs)
|
||||||
var emptyScope instrumentation.Scope
|
var emptyScope instrumentation.Scope
|
||||||
if scope != emptyScope {
|
if scope != emptyScope {
|
||||||
@ -102,10 +55,34 @@ func scopeLogsMap(dst *map[instrumentation.Scope]*lpb.ScopeLogs, records []log.R
|
|||||||
}
|
}
|
||||||
sl.SchemaUrl = scope.SchemaURL
|
sl.SchemaUrl = scope.SchemaURL
|
||||||
}
|
}
|
||||||
(*dst)[scope] = sl
|
scopeMap[k] = sl
|
||||||
}
|
}
|
||||||
|
|
||||||
sl.LogRecords = append(sl.LogRecords, LogRecord(r))
|
sl.LogRecords = append(sl.LogRecords, LogRecord(r))
|
||||||
|
rl, rOk := resMap[rKey]
|
||||||
|
if !rOk {
|
||||||
|
resources++
|
||||||
|
rl = new(lpb.ResourceLogs)
|
||||||
|
if res.Len() > 0 {
|
||||||
|
rl.Resource = &rpb.Resource{
|
||||||
|
Attributes: AttrIter(res.Iter()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rl.SchemaUrl = res.SchemaURL()
|
||||||
|
resMap[rKey] = rl
|
||||||
|
}
|
||||||
|
if !iOk {
|
||||||
|
rl.ScopeLogs = append(rl.ScopeLogs, sl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transform the categorized map into a slice
|
||||||
|
resLogs := make([]*lpb.ResourceLogs, 0, resources)
|
||||||
|
for _, rl := range resMap {
|
||||||
|
resLogs = append(resLogs, rl)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resLogs
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogRecord returns an OTLP LogRecord generated from record.
|
// LogRecord returns an OTLP LogRecord generated from record.
|
||||||
|
@ -30,73 +30,106 @@ var (
|
|||||||
ts = time.Date(2000, time.January, 0o1, 0, 0, 0, 0, time.FixedZone("GMT", 0))
|
ts = time.Date(2000, time.January, 0o1, 0, 0, 0, 0, time.FixedZone("GMT", 0))
|
||||||
obs = ts.Add(30 * time.Second)
|
obs = ts.Add(30 * time.Second)
|
||||||
|
|
||||||
|
tom = api.String("user", "tom")
|
||||||
|
jerry = api.String("user", "jerry")
|
||||||
// A time before unix 0.
|
// A time before unix 0.
|
||||||
negativeTs = time.Date(1969, 7, 20, 20, 17, 0, 0, time.UTC)
|
negativeTs = time.Date(1969, 7, 20, 20, 17, 0, 0, time.UTC)
|
||||||
|
|
||||||
alice = api.String("user", "alice")
|
pbTom = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
||||||
bob = api.String("user", "bob")
|
Value: &cpb.AnyValue_StringValue{StringValue: "tom"},
|
||||||
|
|
||||||
pbAlice = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "alice"},
|
|
||||||
}}
|
}}
|
||||||
pbBob = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
pbJerry = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "bob"},
|
Value: &cpb.AnyValue_StringValue{StringValue: "jerry"},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
sevA = api.SeverityInfo
|
sevC = api.SeverityInfo
|
||||||
sevB = api.SeverityError
|
sevD = api.SeverityError
|
||||||
|
|
||||||
pbSevA = lpb.SeverityNumber_SEVERITY_NUMBER_INFO
|
pbSevC = lpb.SeverityNumber_SEVERITY_NUMBER_INFO
|
||||||
pbSevB = lpb.SeverityNumber_SEVERITY_NUMBER_ERROR
|
pbSevD = lpb.SeverityNumber_SEVERITY_NUMBER_ERROR
|
||||||
|
|
||||||
bodyA = api.StringValue("a")
|
bodyC = api.StringValue("c")
|
||||||
bodyB = api.StringValue("b")
|
bodyD = api.StringValue("d")
|
||||||
|
|
||||||
pbBodyA = &cpb.AnyValue{
|
pbBodyC = &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{
|
Value: &cpb.AnyValue_StringValue{
|
||||||
StringValue: "a",
|
StringValue: "c",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
pbBodyB = &cpb.AnyValue{
|
pbBodyD = &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{
|
Value: &cpb.AnyValue_StringValue{
|
||||||
StringValue: "b",
|
StringValue: "d",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
spanIDA = []byte{0, 0, 0, 0, 0, 0, 0, 1}
|
spanIDC = []byte{0, 0, 0, 0, 0, 0, 0, 1}
|
||||||
spanIDB = []byte{0, 0, 0, 0, 0, 0, 0, 2}
|
spanIDD = []byte{0, 0, 0, 0, 0, 0, 0, 2}
|
||||||
traceIDA = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
|
traceIDC = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
|
||||||
traceIDB = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}
|
traceIDD = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}
|
||||||
flagsA = byte(1)
|
flagsC = byte(1)
|
||||||
flagsB = byte(0)
|
flagsD = byte(0)
|
||||||
|
|
||||||
scope = instrumentation.Scope{
|
scope = instrumentation.Scope{
|
||||||
Name: "test/code/path",
|
Name: "otel/test/code/path1",
|
||||||
Version: "v0.1.0",
|
Version: "v0.1.1",
|
||||||
SchemaURL: semconv.SchemaURL,
|
SchemaURL: semconv.SchemaURL,
|
||||||
}
|
}
|
||||||
|
scope2 = instrumentation.Scope{
|
||||||
|
Name: "otel/test/code/path2",
|
||||||
|
Version: "v0.2.2",
|
||||||
|
SchemaURL: semconv.SchemaURL,
|
||||||
|
}
|
||||||
|
scopeList = []instrumentation.Scope{scope, scope2}
|
||||||
|
|
||||||
pbScope = &cpb.InstrumentationScope{
|
pbScope = &cpb.InstrumentationScope{
|
||||||
Name: "test/code/path",
|
Name: "otel/test/code/path1",
|
||||||
Version: "v0.1.0",
|
Version: "v0.1.1",
|
||||||
|
}
|
||||||
|
pbScope2 = &cpb.InstrumentationScope{
|
||||||
|
Name: "otel/test/code/path2",
|
||||||
|
Version: "v0.2.2",
|
||||||
}
|
}
|
||||||
|
|
||||||
res = resource.NewWithAttributes(
|
res = resource.NewWithAttributes(
|
||||||
semconv.SchemaURL,
|
semconv.SchemaURL,
|
||||||
semconv.ServiceName("test server"),
|
semconv.ServiceName("service1"),
|
||||||
semconv.ServiceVersion("v0.1.0"),
|
semconv.ServiceVersion("v0.1.1"),
|
||||||
)
|
)
|
||||||
|
res2 = resource.NewWithAttributes(
|
||||||
|
semconv.SchemaURL,
|
||||||
|
semconv.ServiceName("service2"),
|
||||||
|
semconv.ServiceVersion("v0.2.2"),
|
||||||
|
)
|
||||||
|
resList = []*resource.Resource{res, res2}
|
||||||
|
|
||||||
pbRes = &rpb.Resource{
|
pbRes = &rpb.Resource{
|
||||||
Attributes: []*cpb.KeyValue{
|
Attributes: []*cpb.KeyValue{
|
||||||
{
|
{
|
||||||
Key: "service.name",
|
Key: "service.name",
|
||||||
Value: &cpb.AnyValue{
|
Value: &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "test server"},
|
Value: &cpb.AnyValue_StringValue{StringValue: "service1"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: "service.version",
|
Key: "service.version",
|
||||||
Value: &cpb.AnyValue{
|
Value: &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "v0.1.0"},
|
Value: &cpb.AnyValue_StringValue{StringValue: "v0.1.1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pbRes2 = &rpb.Resource{
|
||||||
|
Attributes: []*cpb.KeyValue{
|
||||||
|
{
|
||||||
|
Key: "service.name",
|
||||||
|
Value: &cpb.AnyValue{
|
||||||
|
Value: &cpb.AnyValue_StringValue{StringValue: "service2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "service.version",
|
||||||
|
Value: &cpb.AnyValue{
|
||||||
|
Value: &cpb.AnyValue_StringValue{StringValue: "v0.2.2"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -105,75 +138,79 @@ var (
|
|||||||
records = func() []log.Record {
|
records = func() []log.Record {
|
||||||
var out []log.Record
|
var out []log.Record
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
for _, r := range resList {
|
||||||
Timestamp: ts,
|
for _, s := range scopeList {
|
||||||
ObservedTimestamp: obs,
|
out = append(out, logtest.RecordFactory{
|
||||||
Severity: sevA,
|
Timestamp: ts,
|
||||||
SeverityText: "A",
|
ObservedTimestamp: obs,
|
||||||
Body: bodyA,
|
Severity: sevC,
|
||||||
Attributes: []api.KeyValue{alice},
|
SeverityText: "C",
|
||||||
TraceID: trace.TraceID(traceIDA),
|
Body: bodyC,
|
||||||
SpanID: trace.SpanID(spanIDA),
|
Attributes: []api.KeyValue{tom},
|
||||||
TraceFlags: trace.TraceFlags(flagsA),
|
TraceID: trace.TraceID(traceIDC),
|
||||||
InstrumentationScope: &scope,
|
SpanID: trace.SpanID(spanIDC),
|
||||||
Resource: res,
|
TraceFlags: trace.TraceFlags(flagsC),
|
||||||
}.NewRecord())
|
InstrumentationScope: &s,
|
||||||
|
Resource: r,
|
||||||
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: ts,
|
Timestamp: ts,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevA,
|
Severity: sevC,
|
||||||
SeverityText: "A",
|
SeverityText: "C",
|
||||||
Body: bodyA,
|
Body: bodyC,
|
||||||
Attributes: []api.KeyValue{bob},
|
Attributes: []api.KeyValue{jerry},
|
||||||
TraceID: trace.TraceID(traceIDA),
|
TraceID: trace.TraceID(traceIDC),
|
||||||
SpanID: trace.SpanID(spanIDA),
|
SpanID: trace.SpanID(spanIDC),
|
||||||
TraceFlags: trace.TraceFlags(flagsA),
|
TraceFlags: trace.TraceFlags(flagsC),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: ts,
|
Timestamp: ts,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevB,
|
Severity: sevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: bodyB,
|
Body: bodyD,
|
||||||
Attributes: []api.KeyValue{alice},
|
Attributes: []api.KeyValue{tom},
|
||||||
TraceID: trace.TraceID(traceIDB),
|
TraceID: trace.TraceID(traceIDD),
|
||||||
SpanID: trace.SpanID(spanIDB),
|
SpanID: trace.SpanID(spanIDD),
|
||||||
TraceFlags: trace.TraceFlags(flagsB),
|
TraceFlags: trace.TraceFlags(flagsD),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: ts,
|
Timestamp: ts,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevB,
|
Severity: sevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: bodyB,
|
Body: bodyD,
|
||||||
Attributes: []api.KeyValue{bob},
|
Attributes: []api.KeyValue{jerry},
|
||||||
TraceID: trace.TraceID(traceIDB),
|
TraceID: trace.TraceID(traceIDD),
|
||||||
SpanID: trace.SpanID(spanIDB),
|
SpanID: trace.SpanID(spanIDD),
|
||||||
TraceFlags: trace.TraceFlags(flagsB),
|
TraceFlags: trace.TraceFlags(flagsD),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: negativeTs,
|
Timestamp: negativeTs,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevB,
|
Severity: sevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: bodyB,
|
Body: bodyD,
|
||||||
Attributes: []api.KeyValue{bob},
|
Attributes: []api.KeyValue{jerry},
|
||||||
TraceID: trace.TraceID(traceIDB),
|
TraceID: trace.TraceID(traceIDD),
|
||||||
SpanID: trace.SpanID(spanIDB),
|
SpanID: trace.SpanID(spanIDD),
|
||||||
TraceFlags: trace.TraceFlags(flagsB),
|
TraceFlags: trace.TraceFlags(flagsD),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}()
|
}()
|
||||||
@ -182,76 +219,90 @@ var (
|
|||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevA,
|
SeverityNumber: pbSevC,
|
||||||
SeverityText: "A",
|
SeverityText: "C",
|
||||||
Body: pbBodyA,
|
Body: pbBodyC,
|
||||||
Attributes: []*cpb.KeyValue{pbAlice},
|
Attributes: []*cpb.KeyValue{pbTom},
|
||||||
Flags: uint32(flagsA),
|
Flags: uint32(flagsC),
|
||||||
TraceId: traceIDA,
|
TraceId: traceIDC,
|
||||||
SpanId: spanIDA,
|
SpanId: spanIDC,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevA,
|
SeverityNumber: pbSevC,
|
||||||
SeverityText: "A",
|
SeverityText: "C",
|
||||||
Body: pbBodyA,
|
Body: pbBodyC,
|
||||||
Attributes: []*cpb.KeyValue{pbBob},
|
Attributes: []*cpb.KeyValue{pbJerry},
|
||||||
Flags: uint32(flagsA),
|
Flags: uint32(flagsC),
|
||||||
TraceId: traceIDA,
|
TraceId: traceIDC,
|
||||||
SpanId: spanIDA,
|
SpanId: spanIDC,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevB,
|
SeverityNumber: pbSevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: pbBodyB,
|
Body: pbBodyD,
|
||||||
Attributes: []*cpb.KeyValue{pbAlice},
|
Attributes: []*cpb.KeyValue{pbTom},
|
||||||
Flags: uint32(flagsB),
|
Flags: uint32(flagsD),
|
||||||
TraceId: traceIDB,
|
TraceId: traceIDD,
|
||||||
SpanId: spanIDB,
|
SpanId: spanIDD,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevB,
|
SeverityNumber: pbSevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: pbBodyB,
|
Body: pbBodyD,
|
||||||
Attributes: []*cpb.KeyValue{pbBob},
|
Attributes: []*cpb.KeyValue{pbJerry},
|
||||||
Flags: uint32(flagsB),
|
Flags: uint32(flagsD),
|
||||||
TraceId: traceIDB,
|
TraceId: traceIDD,
|
||||||
SpanId: spanIDB,
|
SpanId: spanIDD,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: 0,
|
TimeUnixNano: 0,
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevB,
|
SeverityNumber: pbSevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: pbBodyB,
|
Body: pbBodyD,
|
||||||
Attributes: []*cpb.KeyValue{pbBob},
|
Attributes: []*cpb.KeyValue{pbJerry},
|
||||||
Flags: uint32(flagsB),
|
Flags: uint32(flagsD),
|
||||||
TraceId: traceIDB,
|
TraceId: traceIDD,
|
||||||
SpanId: spanIDB,
|
SpanId: spanIDD,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pbScopeLogs = &lpb.ScopeLogs{
|
pbScopeLogsList = []*lpb.ScopeLogs{
|
||||||
Scope: pbScope,
|
{
|
||||||
SchemaUrl: semconv.SchemaURL,
|
Scope: pbScope,
|
||||||
LogRecords: pbLogRecords,
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
LogRecords: pbLogRecords,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Scope: pbScope2,
|
||||||
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
LogRecords: pbLogRecords,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pbResourceLogs = &lpb.ResourceLogs{
|
pbResourceLogsList = []*lpb.ResourceLogs{
|
||||||
Resource: pbRes,
|
{
|
||||||
SchemaUrl: semconv.SchemaURL,
|
Resource: pbRes,
|
||||||
ScopeLogs: []*lpb.ScopeLogs{pbScopeLogs},
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
ScopeLogs: pbScopeLogsList,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Resource: pbRes2,
|
||||||
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
ScopeLogs: pbScopeLogsList,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestResourceLogs(t *testing.T) {
|
func TestResourceLogs(t *testing.T) {
|
||||||
want := []*lpb.ResourceLogs{pbResourceLogs}
|
want := pbResourceLogsList
|
||||||
assert.Equal(t, want, ResourceLogs(records))
|
assert.ElementsMatch(t, want, ResourceLogs(records))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSeverityNumber(t *testing.T) {
|
func TestSeverityNumber(t *testing.T) {
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/internal/transform"
|
package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/internal/transform"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
cpb "go.opentelemetry.io/proto/otlp/common/v1"
|
cpb "go.opentelemetry.io/proto/otlp/common/v1"
|
||||||
@ -28,71 +27,25 @@ func ResourceLogs(records []log.Record) []*lpb.ResourceLogs {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
resMap := resourceLogsMapPool.Get().(map[attribute.Distinct]*lpb.ResourceLogs)
|
resMap := make(map[attribute.Distinct]*lpb.ResourceLogs)
|
||||||
defer func() {
|
|
||||||
clear(resMap)
|
|
||||||
resourceLogsMapPool.Put(resMap)
|
|
||||||
}()
|
|
||||||
resourceLogsMap(&resMap, records)
|
|
||||||
|
|
||||||
out := make([]*lpb.ResourceLogs, 0, len(resMap))
|
type key struct {
|
||||||
for _, rl := range resMap {
|
r attribute.Distinct
|
||||||
out = append(out, rl)
|
is instrumentation.Scope
|
||||||
}
|
}
|
||||||
return out
|
scopeMap := make(map[key]*lpb.ScopeLogs)
|
||||||
}
|
|
||||||
|
|
||||||
var resourceLogsMapPool = sync.Pool{
|
var resources int
|
||||||
New: func() any {
|
|
||||||
return make(map[attribute.Distinct]*lpb.ResourceLogs)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceLogsMap(dst *map[attribute.Distinct]*lpb.ResourceLogs, records []log.Record) {
|
|
||||||
for _, r := range records {
|
for _, r := range records {
|
||||||
res := r.Resource()
|
res := r.Resource()
|
||||||
rl, ok := (*dst)[res.Equivalent()]
|
rKey := res.Equivalent()
|
||||||
if !ok {
|
|
||||||
rl = new(lpb.ResourceLogs)
|
|
||||||
if res.Len() > 0 {
|
|
||||||
rl.Resource = &rpb.Resource{
|
|
||||||
Attributes: AttrIter(res.Iter()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rl.SchemaUrl = res.SchemaURL()
|
|
||||||
(*dst)[res.Equivalent()] = rl
|
|
||||||
}
|
|
||||||
rl.ScopeLogs = ScopeLogs(records)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScopeLogs returns a slice of OTLP ScopeLogs generated from records.
|
|
||||||
func ScopeLogs(records []log.Record) []*lpb.ScopeLogs {
|
|
||||||
scopeMap := scopeLogsMapPool.Get().(map[instrumentation.Scope]*lpb.ScopeLogs)
|
|
||||||
defer func() {
|
|
||||||
clear(scopeMap)
|
|
||||||
scopeLogsMapPool.Put(scopeMap)
|
|
||||||
}()
|
|
||||||
scopeLogsMap(&scopeMap, records)
|
|
||||||
|
|
||||||
out := make([]*lpb.ScopeLogs, 0, len(scopeMap))
|
|
||||||
for _, sl := range scopeMap {
|
|
||||||
out = append(out, sl)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
var scopeLogsMapPool = sync.Pool{
|
|
||||||
New: func() any {
|
|
||||||
return make(map[instrumentation.Scope]*lpb.ScopeLogs)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func scopeLogsMap(dst *map[instrumentation.Scope]*lpb.ScopeLogs, records []log.Record) {
|
|
||||||
for _, r := range records {
|
|
||||||
scope := r.InstrumentationScope()
|
scope := r.InstrumentationScope()
|
||||||
sl, ok := (*dst)[scope]
|
k := key{
|
||||||
if !ok {
|
r: rKey,
|
||||||
|
is: scope,
|
||||||
|
}
|
||||||
|
sl, iOk := scopeMap[k]
|
||||||
|
if !iOk {
|
||||||
sl = new(lpb.ScopeLogs)
|
sl = new(lpb.ScopeLogs)
|
||||||
var emptyScope instrumentation.Scope
|
var emptyScope instrumentation.Scope
|
||||||
if scope != emptyScope {
|
if scope != emptyScope {
|
||||||
@ -102,10 +55,34 @@ func scopeLogsMap(dst *map[instrumentation.Scope]*lpb.ScopeLogs, records []log.R
|
|||||||
}
|
}
|
||||||
sl.SchemaUrl = scope.SchemaURL
|
sl.SchemaUrl = scope.SchemaURL
|
||||||
}
|
}
|
||||||
(*dst)[scope] = sl
|
scopeMap[k] = sl
|
||||||
}
|
}
|
||||||
|
|
||||||
sl.LogRecords = append(sl.LogRecords, LogRecord(r))
|
sl.LogRecords = append(sl.LogRecords, LogRecord(r))
|
||||||
|
rl, rOk := resMap[rKey]
|
||||||
|
if !rOk {
|
||||||
|
resources++
|
||||||
|
rl = new(lpb.ResourceLogs)
|
||||||
|
if res.Len() > 0 {
|
||||||
|
rl.Resource = &rpb.Resource{
|
||||||
|
Attributes: AttrIter(res.Iter()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rl.SchemaUrl = res.SchemaURL()
|
||||||
|
resMap[rKey] = rl
|
||||||
|
}
|
||||||
|
if !iOk {
|
||||||
|
rl.ScopeLogs = append(rl.ScopeLogs, sl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transform the categorized map into a slice
|
||||||
|
resLogs := make([]*lpb.ResourceLogs, 0, resources)
|
||||||
|
for _, rl := range resMap {
|
||||||
|
resLogs = append(resLogs, rl)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resLogs
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogRecord returns an OTLP LogRecord generated from record.
|
// LogRecord returns an OTLP LogRecord generated from record.
|
||||||
|
@ -30,73 +30,106 @@ var (
|
|||||||
ts = time.Date(2000, time.January, 0o1, 0, 0, 0, 0, time.FixedZone("GMT", 0))
|
ts = time.Date(2000, time.January, 0o1, 0, 0, 0, 0, time.FixedZone("GMT", 0))
|
||||||
obs = ts.Add(30 * time.Second)
|
obs = ts.Add(30 * time.Second)
|
||||||
|
|
||||||
|
tom = api.String("user", "tom")
|
||||||
|
jerry = api.String("user", "jerry")
|
||||||
// A time before unix 0.
|
// A time before unix 0.
|
||||||
negativeTs = time.Date(1969, 7, 20, 20, 17, 0, 0, time.UTC)
|
negativeTs = time.Date(1969, 7, 20, 20, 17, 0, 0, time.UTC)
|
||||||
|
|
||||||
alice = api.String("user", "alice")
|
pbTom = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
||||||
bob = api.String("user", "bob")
|
Value: &cpb.AnyValue_StringValue{StringValue: "tom"},
|
||||||
|
|
||||||
pbAlice = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "alice"},
|
|
||||||
}}
|
}}
|
||||||
pbBob = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
pbJerry = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "bob"},
|
Value: &cpb.AnyValue_StringValue{StringValue: "jerry"},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
sevA = api.SeverityInfo
|
sevC = api.SeverityInfo
|
||||||
sevB = api.SeverityError
|
sevD = api.SeverityError
|
||||||
|
|
||||||
pbSevA = lpb.SeverityNumber_SEVERITY_NUMBER_INFO
|
pbSevC = lpb.SeverityNumber_SEVERITY_NUMBER_INFO
|
||||||
pbSevB = lpb.SeverityNumber_SEVERITY_NUMBER_ERROR
|
pbSevD = lpb.SeverityNumber_SEVERITY_NUMBER_ERROR
|
||||||
|
|
||||||
bodyA = api.StringValue("a")
|
bodyC = api.StringValue("c")
|
||||||
bodyB = api.StringValue("b")
|
bodyD = api.StringValue("d")
|
||||||
|
|
||||||
pbBodyA = &cpb.AnyValue{
|
pbBodyC = &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{
|
Value: &cpb.AnyValue_StringValue{
|
||||||
StringValue: "a",
|
StringValue: "c",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
pbBodyB = &cpb.AnyValue{
|
pbBodyD = &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{
|
Value: &cpb.AnyValue_StringValue{
|
||||||
StringValue: "b",
|
StringValue: "d",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
spanIDA = []byte{0, 0, 0, 0, 0, 0, 0, 1}
|
spanIDC = []byte{0, 0, 0, 0, 0, 0, 0, 1}
|
||||||
spanIDB = []byte{0, 0, 0, 0, 0, 0, 0, 2}
|
spanIDD = []byte{0, 0, 0, 0, 0, 0, 0, 2}
|
||||||
traceIDA = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
|
traceIDC = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
|
||||||
traceIDB = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}
|
traceIDD = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}
|
||||||
flagsA = byte(1)
|
flagsC = byte(1)
|
||||||
flagsB = byte(0)
|
flagsD = byte(0)
|
||||||
|
|
||||||
scope = instrumentation.Scope{
|
scope = instrumentation.Scope{
|
||||||
Name: "test/code/path",
|
Name: "otel/test/code/path1",
|
||||||
Version: "v0.1.0",
|
Version: "v0.1.1",
|
||||||
SchemaURL: semconv.SchemaURL,
|
SchemaURL: semconv.SchemaURL,
|
||||||
}
|
}
|
||||||
|
scope2 = instrumentation.Scope{
|
||||||
|
Name: "otel/test/code/path2",
|
||||||
|
Version: "v0.2.2",
|
||||||
|
SchemaURL: semconv.SchemaURL,
|
||||||
|
}
|
||||||
|
scopeList = []instrumentation.Scope{scope, scope2}
|
||||||
|
|
||||||
pbScope = &cpb.InstrumentationScope{
|
pbScope = &cpb.InstrumentationScope{
|
||||||
Name: "test/code/path",
|
Name: "otel/test/code/path1",
|
||||||
Version: "v0.1.0",
|
Version: "v0.1.1",
|
||||||
|
}
|
||||||
|
pbScope2 = &cpb.InstrumentationScope{
|
||||||
|
Name: "otel/test/code/path2",
|
||||||
|
Version: "v0.2.2",
|
||||||
}
|
}
|
||||||
|
|
||||||
res = resource.NewWithAttributes(
|
res = resource.NewWithAttributes(
|
||||||
semconv.SchemaURL,
|
semconv.SchemaURL,
|
||||||
semconv.ServiceName("test server"),
|
semconv.ServiceName("service1"),
|
||||||
semconv.ServiceVersion("v0.1.0"),
|
semconv.ServiceVersion("v0.1.1"),
|
||||||
)
|
)
|
||||||
|
res2 = resource.NewWithAttributes(
|
||||||
|
semconv.SchemaURL,
|
||||||
|
semconv.ServiceName("service2"),
|
||||||
|
semconv.ServiceVersion("v0.2.2"),
|
||||||
|
)
|
||||||
|
resList = []*resource.Resource{res, res2}
|
||||||
|
|
||||||
pbRes = &rpb.Resource{
|
pbRes = &rpb.Resource{
|
||||||
Attributes: []*cpb.KeyValue{
|
Attributes: []*cpb.KeyValue{
|
||||||
{
|
{
|
||||||
Key: "service.name",
|
Key: "service.name",
|
||||||
Value: &cpb.AnyValue{
|
Value: &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "test server"},
|
Value: &cpb.AnyValue_StringValue{StringValue: "service1"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: "service.version",
|
Key: "service.version",
|
||||||
Value: &cpb.AnyValue{
|
Value: &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "v0.1.0"},
|
Value: &cpb.AnyValue_StringValue{StringValue: "v0.1.1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pbRes2 = &rpb.Resource{
|
||||||
|
Attributes: []*cpb.KeyValue{
|
||||||
|
{
|
||||||
|
Key: "service.name",
|
||||||
|
Value: &cpb.AnyValue{
|
||||||
|
Value: &cpb.AnyValue_StringValue{StringValue: "service2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "service.version",
|
||||||
|
Value: &cpb.AnyValue{
|
||||||
|
Value: &cpb.AnyValue_StringValue{StringValue: "v0.2.2"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -105,75 +138,79 @@ var (
|
|||||||
records = func() []log.Record {
|
records = func() []log.Record {
|
||||||
var out []log.Record
|
var out []log.Record
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
for _, r := range resList {
|
||||||
Timestamp: ts,
|
for _, s := range scopeList {
|
||||||
ObservedTimestamp: obs,
|
out = append(out, logtest.RecordFactory{
|
||||||
Severity: sevA,
|
Timestamp: ts,
|
||||||
SeverityText: "A",
|
ObservedTimestamp: obs,
|
||||||
Body: bodyA,
|
Severity: sevC,
|
||||||
Attributes: []api.KeyValue{alice},
|
SeverityText: "C",
|
||||||
TraceID: trace.TraceID(traceIDA),
|
Body: bodyC,
|
||||||
SpanID: trace.SpanID(spanIDA),
|
Attributes: []api.KeyValue{tom},
|
||||||
TraceFlags: trace.TraceFlags(flagsA),
|
TraceID: trace.TraceID(traceIDC),
|
||||||
InstrumentationScope: &scope,
|
SpanID: trace.SpanID(spanIDC),
|
||||||
Resource: res,
|
TraceFlags: trace.TraceFlags(flagsC),
|
||||||
}.NewRecord())
|
InstrumentationScope: &s,
|
||||||
|
Resource: r,
|
||||||
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: ts,
|
Timestamp: ts,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevA,
|
Severity: sevC,
|
||||||
SeverityText: "A",
|
SeverityText: "C",
|
||||||
Body: bodyA,
|
Body: bodyC,
|
||||||
Attributes: []api.KeyValue{bob},
|
Attributes: []api.KeyValue{jerry},
|
||||||
TraceID: trace.TraceID(traceIDA),
|
TraceID: trace.TraceID(traceIDC),
|
||||||
SpanID: trace.SpanID(spanIDA),
|
SpanID: trace.SpanID(spanIDC),
|
||||||
TraceFlags: trace.TraceFlags(flagsA),
|
TraceFlags: trace.TraceFlags(flagsC),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: ts,
|
Timestamp: ts,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevB,
|
Severity: sevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: bodyB,
|
Body: bodyD,
|
||||||
Attributes: []api.KeyValue{alice},
|
Attributes: []api.KeyValue{tom},
|
||||||
TraceID: trace.TraceID(traceIDB),
|
TraceID: trace.TraceID(traceIDD),
|
||||||
SpanID: trace.SpanID(spanIDB),
|
SpanID: trace.SpanID(spanIDD),
|
||||||
TraceFlags: trace.TraceFlags(flagsB),
|
TraceFlags: trace.TraceFlags(flagsD),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: ts,
|
Timestamp: ts,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevB,
|
Severity: sevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: bodyB,
|
Body: bodyD,
|
||||||
Attributes: []api.KeyValue{bob},
|
Attributes: []api.KeyValue{jerry},
|
||||||
TraceID: trace.TraceID(traceIDB),
|
TraceID: trace.TraceID(traceIDD),
|
||||||
SpanID: trace.SpanID(spanIDB),
|
SpanID: trace.SpanID(spanIDD),
|
||||||
TraceFlags: trace.TraceFlags(flagsB),
|
TraceFlags: trace.TraceFlags(flagsD),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: negativeTs,
|
Timestamp: negativeTs,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevB,
|
Severity: sevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: bodyB,
|
Body: bodyD,
|
||||||
Attributes: []api.KeyValue{bob},
|
Attributes: []api.KeyValue{jerry},
|
||||||
TraceID: trace.TraceID(traceIDB),
|
TraceID: trace.TraceID(traceIDD),
|
||||||
SpanID: trace.SpanID(spanIDB),
|
SpanID: trace.SpanID(spanIDD),
|
||||||
TraceFlags: trace.TraceFlags(flagsB),
|
TraceFlags: trace.TraceFlags(flagsD),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}()
|
}()
|
||||||
@ -182,76 +219,90 @@ var (
|
|||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevA,
|
SeverityNumber: pbSevC,
|
||||||
SeverityText: "A",
|
SeverityText: "C",
|
||||||
Body: pbBodyA,
|
Body: pbBodyC,
|
||||||
Attributes: []*cpb.KeyValue{pbAlice},
|
Attributes: []*cpb.KeyValue{pbTom},
|
||||||
Flags: uint32(flagsA),
|
Flags: uint32(flagsC),
|
||||||
TraceId: traceIDA,
|
TraceId: traceIDC,
|
||||||
SpanId: spanIDA,
|
SpanId: spanIDC,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevA,
|
SeverityNumber: pbSevC,
|
||||||
SeverityText: "A",
|
SeverityText: "C",
|
||||||
Body: pbBodyA,
|
Body: pbBodyC,
|
||||||
Attributes: []*cpb.KeyValue{pbBob},
|
Attributes: []*cpb.KeyValue{pbJerry},
|
||||||
Flags: uint32(flagsA),
|
Flags: uint32(flagsC),
|
||||||
TraceId: traceIDA,
|
TraceId: traceIDC,
|
||||||
SpanId: spanIDA,
|
SpanId: spanIDC,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevB,
|
SeverityNumber: pbSevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: pbBodyB,
|
Body: pbBodyD,
|
||||||
Attributes: []*cpb.KeyValue{pbAlice},
|
Attributes: []*cpb.KeyValue{pbTom},
|
||||||
Flags: uint32(flagsB),
|
Flags: uint32(flagsD),
|
||||||
TraceId: traceIDB,
|
TraceId: traceIDD,
|
||||||
SpanId: spanIDB,
|
SpanId: spanIDD,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevB,
|
SeverityNumber: pbSevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: pbBodyB,
|
Body: pbBodyD,
|
||||||
Attributes: []*cpb.KeyValue{pbBob},
|
Attributes: []*cpb.KeyValue{pbJerry},
|
||||||
Flags: uint32(flagsB),
|
Flags: uint32(flagsD),
|
||||||
TraceId: traceIDB,
|
TraceId: traceIDD,
|
||||||
SpanId: spanIDB,
|
SpanId: spanIDD,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: 0,
|
TimeUnixNano: 0,
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevB,
|
SeverityNumber: pbSevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: pbBodyB,
|
Body: pbBodyD,
|
||||||
Attributes: []*cpb.KeyValue{pbBob},
|
Attributes: []*cpb.KeyValue{pbJerry},
|
||||||
Flags: uint32(flagsB),
|
Flags: uint32(flagsD),
|
||||||
TraceId: traceIDB,
|
TraceId: traceIDD,
|
||||||
SpanId: spanIDB,
|
SpanId: spanIDD,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pbScopeLogs = &lpb.ScopeLogs{
|
pbScopeLogsList = []*lpb.ScopeLogs{
|
||||||
Scope: pbScope,
|
{
|
||||||
SchemaUrl: semconv.SchemaURL,
|
Scope: pbScope,
|
||||||
LogRecords: pbLogRecords,
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
LogRecords: pbLogRecords,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Scope: pbScope2,
|
||||||
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
LogRecords: pbLogRecords,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pbResourceLogs = &lpb.ResourceLogs{
|
pbResourceLogsList = []*lpb.ResourceLogs{
|
||||||
Resource: pbRes,
|
{
|
||||||
SchemaUrl: semconv.SchemaURL,
|
Resource: pbRes,
|
||||||
ScopeLogs: []*lpb.ScopeLogs{pbScopeLogs},
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
ScopeLogs: pbScopeLogsList,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Resource: pbRes2,
|
||||||
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
ScopeLogs: pbScopeLogsList,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestResourceLogs(t *testing.T) {
|
func TestResourceLogs(t *testing.T) {
|
||||||
want := []*lpb.ResourceLogs{pbResourceLogs}
|
want := pbResourceLogsList
|
||||||
assert.Equal(t, want, ResourceLogs(records))
|
assert.ElementsMatch(t, want, ResourceLogs(records))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSeverityNumber(t *testing.T) {
|
func TestSeverityNumber(t *testing.T) {
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/internal/transform"
|
package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/internal/transform"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
cpb "go.opentelemetry.io/proto/otlp/common/v1"
|
cpb "go.opentelemetry.io/proto/otlp/common/v1"
|
||||||
@ -28,71 +27,25 @@ func ResourceLogs(records []log.Record) []*lpb.ResourceLogs {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
resMap := resourceLogsMapPool.Get().(map[attribute.Distinct]*lpb.ResourceLogs)
|
resMap := make(map[attribute.Distinct]*lpb.ResourceLogs)
|
||||||
defer func() {
|
|
||||||
clear(resMap)
|
|
||||||
resourceLogsMapPool.Put(resMap)
|
|
||||||
}()
|
|
||||||
resourceLogsMap(&resMap, records)
|
|
||||||
|
|
||||||
out := make([]*lpb.ResourceLogs, 0, len(resMap))
|
type key struct {
|
||||||
for _, rl := range resMap {
|
r attribute.Distinct
|
||||||
out = append(out, rl)
|
is instrumentation.Scope
|
||||||
}
|
}
|
||||||
return out
|
scopeMap := make(map[key]*lpb.ScopeLogs)
|
||||||
}
|
|
||||||
|
|
||||||
var resourceLogsMapPool = sync.Pool{
|
var resources int
|
||||||
New: func() any {
|
|
||||||
return make(map[attribute.Distinct]*lpb.ResourceLogs)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceLogsMap(dst *map[attribute.Distinct]*lpb.ResourceLogs, records []log.Record) {
|
|
||||||
for _, r := range records {
|
for _, r := range records {
|
||||||
res := r.Resource()
|
res := r.Resource()
|
||||||
rl, ok := (*dst)[res.Equivalent()]
|
rKey := res.Equivalent()
|
||||||
if !ok {
|
|
||||||
rl = new(lpb.ResourceLogs)
|
|
||||||
if res.Len() > 0 {
|
|
||||||
rl.Resource = &rpb.Resource{
|
|
||||||
Attributes: AttrIter(res.Iter()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rl.SchemaUrl = res.SchemaURL()
|
|
||||||
(*dst)[res.Equivalent()] = rl
|
|
||||||
}
|
|
||||||
rl.ScopeLogs = ScopeLogs(records)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScopeLogs returns a slice of OTLP ScopeLogs generated from records.
|
|
||||||
func ScopeLogs(records []log.Record) []*lpb.ScopeLogs {
|
|
||||||
scopeMap := scopeLogsMapPool.Get().(map[instrumentation.Scope]*lpb.ScopeLogs)
|
|
||||||
defer func() {
|
|
||||||
clear(scopeMap)
|
|
||||||
scopeLogsMapPool.Put(scopeMap)
|
|
||||||
}()
|
|
||||||
scopeLogsMap(&scopeMap, records)
|
|
||||||
|
|
||||||
out := make([]*lpb.ScopeLogs, 0, len(scopeMap))
|
|
||||||
for _, sl := range scopeMap {
|
|
||||||
out = append(out, sl)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
var scopeLogsMapPool = sync.Pool{
|
|
||||||
New: func() any {
|
|
||||||
return make(map[instrumentation.Scope]*lpb.ScopeLogs)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func scopeLogsMap(dst *map[instrumentation.Scope]*lpb.ScopeLogs, records []log.Record) {
|
|
||||||
for _, r := range records {
|
|
||||||
scope := r.InstrumentationScope()
|
scope := r.InstrumentationScope()
|
||||||
sl, ok := (*dst)[scope]
|
k := key{
|
||||||
if !ok {
|
r: rKey,
|
||||||
|
is: scope,
|
||||||
|
}
|
||||||
|
sl, iOk := scopeMap[k]
|
||||||
|
if !iOk {
|
||||||
sl = new(lpb.ScopeLogs)
|
sl = new(lpb.ScopeLogs)
|
||||||
var emptyScope instrumentation.Scope
|
var emptyScope instrumentation.Scope
|
||||||
if scope != emptyScope {
|
if scope != emptyScope {
|
||||||
@ -102,10 +55,34 @@ func scopeLogsMap(dst *map[instrumentation.Scope]*lpb.ScopeLogs, records []log.R
|
|||||||
}
|
}
|
||||||
sl.SchemaUrl = scope.SchemaURL
|
sl.SchemaUrl = scope.SchemaURL
|
||||||
}
|
}
|
||||||
(*dst)[scope] = sl
|
scopeMap[k] = sl
|
||||||
}
|
}
|
||||||
|
|
||||||
sl.LogRecords = append(sl.LogRecords, LogRecord(r))
|
sl.LogRecords = append(sl.LogRecords, LogRecord(r))
|
||||||
|
rl, rOk := resMap[rKey]
|
||||||
|
if !rOk {
|
||||||
|
resources++
|
||||||
|
rl = new(lpb.ResourceLogs)
|
||||||
|
if res.Len() > 0 {
|
||||||
|
rl.Resource = &rpb.Resource{
|
||||||
|
Attributes: AttrIter(res.Iter()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rl.SchemaUrl = res.SchemaURL()
|
||||||
|
resMap[rKey] = rl
|
||||||
|
}
|
||||||
|
if !iOk {
|
||||||
|
rl.ScopeLogs = append(rl.ScopeLogs, sl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transform the categorized map into a slice
|
||||||
|
resLogs := make([]*lpb.ResourceLogs, 0, resources)
|
||||||
|
for _, rl := range resMap {
|
||||||
|
resLogs = append(resLogs, rl)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resLogs
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogRecord returns an OTLP LogRecord generated from record.
|
// LogRecord returns an OTLP LogRecord generated from record.
|
||||||
|
@ -30,73 +30,106 @@ var (
|
|||||||
ts = time.Date(2000, time.January, 0o1, 0, 0, 0, 0, time.FixedZone("GMT", 0))
|
ts = time.Date(2000, time.January, 0o1, 0, 0, 0, 0, time.FixedZone("GMT", 0))
|
||||||
obs = ts.Add(30 * time.Second)
|
obs = ts.Add(30 * time.Second)
|
||||||
|
|
||||||
|
tom = api.String("user", "tom")
|
||||||
|
jerry = api.String("user", "jerry")
|
||||||
// A time before unix 0.
|
// A time before unix 0.
|
||||||
negativeTs = time.Date(1969, 7, 20, 20, 17, 0, 0, time.UTC)
|
negativeTs = time.Date(1969, 7, 20, 20, 17, 0, 0, time.UTC)
|
||||||
|
|
||||||
alice = api.String("user", "alice")
|
pbTom = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
||||||
bob = api.String("user", "bob")
|
Value: &cpb.AnyValue_StringValue{StringValue: "tom"},
|
||||||
|
|
||||||
pbAlice = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "alice"},
|
|
||||||
}}
|
}}
|
||||||
pbBob = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
pbJerry = &cpb.KeyValue{Key: "user", Value: &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "bob"},
|
Value: &cpb.AnyValue_StringValue{StringValue: "jerry"},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
sevA = api.SeverityInfo
|
sevC = api.SeverityInfo
|
||||||
sevB = api.SeverityError
|
sevD = api.SeverityError
|
||||||
|
|
||||||
pbSevA = lpb.SeverityNumber_SEVERITY_NUMBER_INFO
|
pbSevC = lpb.SeverityNumber_SEVERITY_NUMBER_INFO
|
||||||
pbSevB = lpb.SeverityNumber_SEVERITY_NUMBER_ERROR
|
pbSevD = lpb.SeverityNumber_SEVERITY_NUMBER_ERROR
|
||||||
|
|
||||||
bodyA = api.StringValue("a")
|
bodyC = api.StringValue("c")
|
||||||
bodyB = api.StringValue("b")
|
bodyD = api.StringValue("d")
|
||||||
|
|
||||||
pbBodyA = &cpb.AnyValue{
|
pbBodyC = &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{
|
Value: &cpb.AnyValue_StringValue{
|
||||||
StringValue: "a",
|
StringValue: "c",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
pbBodyB = &cpb.AnyValue{
|
pbBodyD = &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{
|
Value: &cpb.AnyValue_StringValue{
|
||||||
StringValue: "b",
|
StringValue: "d",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
spanIDA = []byte{0, 0, 0, 0, 0, 0, 0, 1}
|
spanIDC = []byte{0, 0, 0, 0, 0, 0, 0, 1}
|
||||||
spanIDB = []byte{0, 0, 0, 0, 0, 0, 0, 2}
|
spanIDD = []byte{0, 0, 0, 0, 0, 0, 0, 2}
|
||||||
traceIDA = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
|
traceIDC = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
|
||||||
traceIDB = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}
|
traceIDD = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}
|
||||||
flagsA = byte(1)
|
flagsC = byte(1)
|
||||||
flagsB = byte(0)
|
flagsD = byte(0)
|
||||||
|
|
||||||
scope = instrumentation.Scope{
|
scope = instrumentation.Scope{
|
||||||
Name: "test/code/path",
|
Name: "otel/test/code/path1",
|
||||||
Version: "v0.1.0",
|
Version: "v0.1.1",
|
||||||
SchemaURL: semconv.SchemaURL,
|
SchemaURL: semconv.SchemaURL,
|
||||||
}
|
}
|
||||||
|
scope2 = instrumentation.Scope{
|
||||||
|
Name: "otel/test/code/path2",
|
||||||
|
Version: "v0.2.2",
|
||||||
|
SchemaURL: semconv.SchemaURL,
|
||||||
|
}
|
||||||
|
scopeList = []instrumentation.Scope{scope, scope2}
|
||||||
|
|
||||||
pbScope = &cpb.InstrumentationScope{
|
pbScope = &cpb.InstrumentationScope{
|
||||||
Name: "test/code/path",
|
Name: "otel/test/code/path1",
|
||||||
Version: "v0.1.0",
|
Version: "v0.1.1",
|
||||||
|
}
|
||||||
|
pbScope2 = &cpb.InstrumentationScope{
|
||||||
|
Name: "otel/test/code/path2",
|
||||||
|
Version: "v0.2.2",
|
||||||
}
|
}
|
||||||
|
|
||||||
res = resource.NewWithAttributes(
|
res = resource.NewWithAttributes(
|
||||||
semconv.SchemaURL,
|
semconv.SchemaURL,
|
||||||
semconv.ServiceName("test server"),
|
semconv.ServiceName("service1"),
|
||||||
semconv.ServiceVersion("v0.1.0"),
|
semconv.ServiceVersion("v0.1.1"),
|
||||||
)
|
)
|
||||||
|
res2 = resource.NewWithAttributes(
|
||||||
|
semconv.SchemaURL,
|
||||||
|
semconv.ServiceName("service2"),
|
||||||
|
semconv.ServiceVersion("v0.2.2"),
|
||||||
|
)
|
||||||
|
resList = []*resource.Resource{res, res2}
|
||||||
|
|
||||||
pbRes = &rpb.Resource{
|
pbRes = &rpb.Resource{
|
||||||
Attributes: []*cpb.KeyValue{
|
Attributes: []*cpb.KeyValue{
|
||||||
{
|
{
|
||||||
Key: "service.name",
|
Key: "service.name",
|
||||||
Value: &cpb.AnyValue{
|
Value: &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "test server"},
|
Value: &cpb.AnyValue_StringValue{StringValue: "service1"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: "service.version",
|
Key: "service.version",
|
||||||
Value: &cpb.AnyValue{
|
Value: &cpb.AnyValue{
|
||||||
Value: &cpb.AnyValue_StringValue{StringValue: "v0.1.0"},
|
Value: &cpb.AnyValue_StringValue{StringValue: "v0.1.1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pbRes2 = &rpb.Resource{
|
||||||
|
Attributes: []*cpb.KeyValue{
|
||||||
|
{
|
||||||
|
Key: "service.name",
|
||||||
|
Value: &cpb.AnyValue{
|
||||||
|
Value: &cpb.AnyValue_StringValue{StringValue: "service2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "service.version",
|
||||||
|
Value: &cpb.AnyValue{
|
||||||
|
Value: &cpb.AnyValue_StringValue{StringValue: "v0.2.2"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -105,75 +138,79 @@ var (
|
|||||||
records = func() []log.Record {
|
records = func() []log.Record {
|
||||||
var out []log.Record
|
var out []log.Record
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
for _, r := range resList {
|
||||||
Timestamp: ts,
|
for _, s := range scopeList {
|
||||||
ObservedTimestamp: obs,
|
out = append(out, logtest.RecordFactory{
|
||||||
Severity: sevA,
|
Timestamp: ts,
|
||||||
SeverityText: "A",
|
ObservedTimestamp: obs,
|
||||||
Body: bodyA,
|
Severity: sevC,
|
||||||
Attributes: []api.KeyValue{alice},
|
SeverityText: "C",
|
||||||
TraceID: trace.TraceID(traceIDA),
|
Body: bodyC,
|
||||||
SpanID: trace.SpanID(spanIDA),
|
Attributes: []api.KeyValue{tom},
|
||||||
TraceFlags: trace.TraceFlags(flagsA),
|
TraceID: trace.TraceID(traceIDC),
|
||||||
InstrumentationScope: &scope,
|
SpanID: trace.SpanID(spanIDC),
|
||||||
Resource: res,
|
TraceFlags: trace.TraceFlags(flagsC),
|
||||||
}.NewRecord())
|
InstrumentationScope: &s,
|
||||||
|
Resource: r,
|
||||||
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: ts,
|
Timestamp: ts,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevA,
|
Severity: sevC,
|
||||||
SeverityText: "A",
|
SeverityText: "C",
|
||||||
Body: bodyA,
|
Body: bodyC,
|
||||||
Attributes: []api.KeyValue{bob},
|
Attributes: []api.KeyValue{jerry},
|
||||||
TraceID: trace.TraceID(traceIDA),
|
TraceID: trace.TraceID(traceIDC),
|
||||||
SpanID: trace.SpanID(spanIDA),
|
SpanID: trace.SpanID(spanIDC),
|
||||||
TraceFlags: trace.TraceFlags(flagsA),
|
TraceFlags: trace.TraceFlags(flagsC),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: ts,
|
Timestamp: ts,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevB,
|
Severity: sevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: bodyB,
|
Body: bodyD,
|
||||||
Attributes: []api.KeyValue{alice},
|
Attributes: []api.KeyValue{tom},
|
||||||
TraceID: trace.TraceID(traceIDB),
|
TraceID: trace.TraceID(traceIDD),
|
||||||
SpanID: trace.SpanID(spanIDB),
|
SpanID: trace.SpanID(spanIDD),
|
||||||
TraceFlags: trace.TraceFlags(flagsB),
|
TraceFlags: trace.TraceFlags(flagsD),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: ts,
|
Timestamp: ts,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevB,
|
Severity: sevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: bodyB,
|
Body: bodyD,
|
||||||
Attributes: []api.KeyValue{bob},
|
Attributes: []api.KeyValue{jerry},
|
||||||
TraceID: trace.TraceID(traceIDB),
|
TraceID: trace.TraceID(traceIDD),
|
||||||
SpanID: trace.SpanID(spanIDB),
|
SpanID: trace.SpanID(spanIDD),
|
||||||
TraceFlags: trace.TraceFlags(flagsB),
|
TraceFlags: trace.TraceFlags(flagsD),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
|
||||||
out = append(out, logtest.RecordFactory{
|
out = append(out, logtest.RecordFactory{
|
||||||
Timestamp: negativeTs,
|
Timestamp: negativeTs,
|
||||||
ObservedTimestamp: obs,
|
ObservedTimestamp: obs,
|
||||||
Severity: sevB,
|
Severity: sevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: bodyB,
|
Body: bodyD,
|
||||||
Attributes: []api.KeyValue{bob},
|
Attributes: []api.KeyValue{jerry},
|
||||||
TraceID: trace.TraceID(traceIDB),
|
TraceID: trace.TraceID(traceIDD),
|
||||||
SpanID: trace.SpanID(spanIDB),
|
SpanID: trace.SpanID(spanIDD),
|
||||||
TraceFlags: trace.TraceFlags(flagsB),
|
TraceFlags: trace.TraceFlags(flagsD),
|
||||||
InstrumentationScope: &scope,
|
InstrumentationScope: &s,
|
||||||
Resource: res,
|
Resource: r,
|
||||||
}.NewRecord())
|
}.NewRecord())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}()
|
}()
|
||||||
@ -182,76 +219,90 @@ var (
|
|||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevA,
|
SeverityNumber: pbSevC,
|
||||||
SeverityText: "A",
|
SeverityText: "C",
|
||||||
Body: pbBodyA,
|
Body: pbBodyC,
|
||||||
Attributes: []*cpb.KeyValue{pbAlice},
|
Attributes: []*cpb.KeyValue{pbTom},
|
||||||
Flags: uint32(flagsA),
|
Flags: uint32(flagsC),
|
||||||
TraceId: traceIDA,
|
TraceId: traceIDC,
|
||||||
SpanId: spanIDA,
|
SpanId: spanIDC,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevA,
|
SeverityNumber: pbSevC,
|
||||||
SeverityText: "A",
|
SeverityText: "C",
|
||||||
Body: pbBodyA,
|
Body: pbBodyC,
|
||||||
Attributes: []*cpb.KeyValue{pbBob},
|
Attributes: []*cpb.KeyValue{pbJerry},
|
||||||
Flags: uint32(flagsA),
|
Flags: uint32(flagsC),
|
||||||
TraceId: traceIDA,
|
TraceId: traceIDC,
|
||||||
SpanId: spanIDA,
|
SpanId: spanIDC,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevB,
|
SeverityNumber: pbSevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: pbBodyB,
|
Body: pbBodyD,
|
||||||
Attributes: []*cpb.KeyValue{pbAlice},
|
Attributes: []*cpb.KeyValue{pbTom},
|
||||||
Flags: uint32(flagsB),
|
Flags: uint32(flagsD),
|
||||||
TraceId: traceIDB,
|
TraceId: traceIDD,
|
||||||
SpanId: spanIDB,
|
SpanId: spanIDD,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: uint64(ts.UnixNano()),
|
TimeUnixNano: uint64(ts.UnixNano()),
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevB,
|
SeverityNumber: pbSevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: pbBodyB,
|
Body: pbBodyD,
|
||||||
Attributes: []*cpb.KeyValue{pbBob},
|
Attributes: []*cpb.KeyValue{pbJerry},
|
||||||
Flags: uint32(flagsB),
|
Flags: uint32(flagsD),
|
||||||
TraceId: traceIDB,
|
TraceId: traceIDD,
|
||||||
SpanId: spanIDB,
|
SpanId: spanIDD,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TimeUnixNano: 0,
|
TimeUnixNano: 0,
|
||||||
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
ObservedTimeUnixNano: uint64(obs.UnixNano()),
|
||||||
SeverityNumber: pbSevB,
|
SeverityNumber: pbSevD,
|
||||||
SeverityText: "B",
|
SeverityText: "D",
|
||||||
Body: pbBodyB,
|
Body: pbBodyD,
|
||||||
Attributes: []*cpb.KeyValue{pbBob},
|
Attributes: []*cpb.KeyValue{pbJerry},
|
||||||
Flags: uint32(flagsB),
|
Flags: uint32(flagsD),
|
||||||
TraceId: traceIDB,
|
TraceId: traceIDD,
|
||||||
SpanId: spanIDB,
|
SpanId: spanIDD,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pbScopeLogs = &lpb.ScopeLogs{
|
pbScopeLogsList = []*lpb.ScopeLogs{
|
||||||
Scope: pbScope,
|
{
|
||||||
SchemaUrl: semconv.SchemaURL,
|
Scope: pbScope,
|
||||||
LogRecords: pbLogRecords,
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
LogRecords: pbLogRecords,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Scope: pbScope2,
|
||||||
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
LogRecords: pbLogRecords,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pbResourceLogs = &lpb.ResourceLogs{
|
pbResourceLogsList = []*lpb.ResourceLogs{
|
||||||
Resource: pbRes,
|
{
|
||||||
SchemaUrl: semconv.SchemaURL,
|
Resource: pbRes,
|
||||||
ScopeLogs: []*lpb.ScopeLogs{pbScopeLogs},
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
ScopeLogs: pbScopeLogsList,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Resource: pbRes2,
|
||||||
|
SchemaUrl: semconv.SchemaURL,
|
||||||
|
ScopeLogs: pbScopeLogsList,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestResourceLogs(t *testing.T) {
|
func TestResourceLogs(t *testing.T) {
|
||||||
want := []*lpb.ResourceLogs{pbResourceLogs}
|
want := pbResourceLogsList
|
||||||
assert.Equal(t, want, ResourceLogs(records))
|
assert.ElementsMatch(t, want, ResourceLogs(records))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSeverityNumber(t *testing.T) {
|
func TestSeverityNumber(t *testing.T) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user