From d5945a9dba3ad6843858fc4989fb1a2064e89013 Mon Sep 17 00:00:00 2001 From: Sam Xie Date: Tue, 30 Apr 2024 10:26:26 -0700 Subject: [PATCH] The stdoutlog exporter prints `DroppedAttributes` field instead of `Limit`s fields (#5272) * Add tests for resource, scope, dropped attributes * Update CHANGELOG * Apply suggestions from code review --------- Co-authored-by: Tyler Yahn --- CHANGELOG.md | 1 + exporters/stdout/stdoutlog/exporter_test.go | 75 +++++++++++++-------- exporters/stdout/stdoutlog/go.mod | 2 +- exporters/stdout/stdoutlog/record.go | 27 ++++---- 4 files changed, 63 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 123c88536cf..bed930b5713 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - The `ForceFlush` and `Shutdown` methods of the exporter returned by `New` in `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` ignore the context cancellation and always return `nil`. (#5189) - Apply the value length limits to `Record` attributes in `go.opentelemetry.io/otel/sdk/log`. (#5230) - De-duplicate map attributes added to a `Record` in `go.opentelemetry.io/otel/sdk/log`. (#5230) +- The `go.opentelemetry.io/otel/exporters/stdout/stdoutlog` exporter won't print `AttributeValueLengthLimit` and `AttributeCountLimit` fields now, instead it prints the `DroppedAttributes` field. (#5272) ## [1.26.0/0.48.0/0.2.0-alpha] 2024-04-24 diff --git a/exporters/stdout/stdoutlog/exporter_test.go b/exporters/stdout/stdoutlog/exporter_test.go index 36c8173df63..45ccf2023cf 100644 --- a/exporters/stdout/stdoutlog/exporter_test.go +++ b/exporters/stdout/stdoutlog/exporter_test.go @@ -11,6 +11,11 @@ import ( "testing" "time" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/sdk/instrumentation" + "go.opentelemetry.io/otel/sdk/log/logtest" + "go.opentelemetry.io/otel/sdk/resource" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -178,7 +183,7 @@ func getJSON(now *time.Time) string { timestamps = "\"Timestamp\":" + string(serializedNow) + ",\"ObservedTimestamp\":" + string(serializedNow) + "," } - return "{" + timestamps + "\"Severity\":9,\"SeverityText\":\"INFO\",\"Body\":{},\"Attributes\":[{\"Key\":\"key\",\"Value\":{}},{\"Key\":\"key2\",\"Value\":{}},{\"Key\":\"key3\",\"Value\":{}},{\"Key\":\"key4\",\"Value\":{}},{\"Key\":\"key5\",\"Value\":{}},{\"Key\":\"bool\",\"Value\":{}}],\"TraceID\":\"0102030405060708090a0b0c0d0e0f10\",\"SpanID\":\"0102030405060708\",\"TraceFlags\":\"01\",\"Resource\":null,\"Scope\":{\"Name\":\"\",\"Version\":\"\",\"SchemaURL\":\"\"},\"AttributeValueLengthLimit\":0,\"AttributeCountLimit\":0}\n" + return "{" + timestamps + "\"Severity\":9,\"SeverityText\":\"INFO\",\"Body\":{},\"Attributes\":[{\"Key\":\"key\",\"Value\":{}},{\"Key\":\"key2\",\"Value\":{}},{\"Key\":\"key3\",\"Value\":{}},{\"Key\":\"key4\",\"Value\":{}},{\"Key\":\"key5\",\"Value\":{}},{\"Key\":\"bool\",\"Value\":{}}],\"TraceID\":\"0102030405060708090a0b0c0d0e0f10\",\"SpanID\":\"0102030405060708\",\"TraceFlags\":\"01\",\"Resource\":[{\"Key\":\"foo\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"bar\"}}],\"Scope\":{\"Name\":\"name\",\"Version\":\"version\",\"SchemaURL\":\"https://example.com/custom-schema\"},\"DroppedAttributes\":10}\n" } func getJSONs(now *time.Time) string { @@ -225,14 +230,21 @@ func getPrettyJSON(now *time.Time) string { "TraceID": "0102030405060708090a0b0c0d0e0f10", "SpanID": "0102030405060708", "TraceFlags": "01", - "Resource": null, + "Resource": [ + { + "Key": "foo", + "Value": { + "Type": "STRING", + "Value": "bar" + } + } + ], "Scope": { - "Name": "", - "Version": "", - "SchemaURL": "" + "Name": "name", + "Version": "version", + "SchemaURL": "https://example.com/custom-schema" }, - "AttributeValueLengthLimit": 0, - "AttributeCountLimit": 0 + "DroppedAttributes": 10 } ` } @@ -259,27 +271,34 @@ func getRecord(now time.Time) sdklog.Record { traceID, _ := trace.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10") spanID, _ := trace.SpanIDFromHex("0102030405060708") - // Setup records - record := sdklog.Record{} - record.SetTimestamp(now) - record.SetObservedTimestamp(now) - record.SetSeverity(log.SeverityInfo1) - record.SetSeverityText("INFO") - record.SetBody(log.StringValue("test")) - record.SetAttributes([]log.KeyValue{ - // More than 5 attributes to test back slice - log.String("key", "value"), - log.String("key2", "value"), - log.String("key3", "value"), - log.String("key4", "value"), - log.String("key5", "value"), - log.Bool("bool", true), - }...) - record.SetTraceID(traceID) - record.SetSpanID(spanID) - record.SetTraceFlags(trace.FlagsSampled) - - return record + rf := logtest.RecordFactory{ + Timestamp: now, + ObservedTimestamp: now, + Severity: log.SeverityInfo1, + SeverityText: "INFO", + Body: log.StringValue("test"), + Attributes: []log.KeyValue{ + // More than 5 attributes to test back slice + log.String("key", "value"), + log.String("key2", "value"), + log.String("key3", "value"), + log.String("key4", "value"), + log.String("key5", "value"), + log.Bool("bool", true), + }, + TraceID: traceID, + SpanID: spanID, + TraceFlags: trace.FlagsSampled, + + Resource: resource.NewWithAttributes( + "https://example.com/custom-resource-schema", + attribute.String("foo", "bar"), + ), + InstrumentationScope: instrumentation.Scope{Name: "name", Version: "version", SchemaURL: "https://example.com/custom-schema"}, + DroppedAttributes: 10, + } + + return rf.NewRecord() } func TestExporterConcurrentSafe(t *testing.T) { diff --git a/exporters/stdout/stdoutlog/go.mod b/exporters/stdout/stdoutlog/go.mod index 8246e569f6d..691c351531b 100644 --- a/exporters/stdout/stdoutlog/go.mod +++ b/exporters/stdout/stdoutlog/go.mod @@ -4,6 +4,7 @@ go 1.21 require ( github.com/stretchr/testify v1.9.0 + go.opentelemetry.io/otel v1.26.0 go.opentelemetry.io/otel/log v0.2.0-alpha go.opentelemetry.io/otel/sdk v1.26.0 go.opentelemetry.io/otel/sdk/log v0.2.0-alpha @@ -15,7 +16,6 @@ require ( github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/otel v1.26.0 // indirect go.opentelemetry.io/otel/metric v1.26.0 // indirect golang.org/x/sys v0.19.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/exporters/stdout/stdoutlog/record.go b/exporters/stdout/stdoutlog/record.go index 581aad9c2e4..31a511dc15a 100644 --- a/exporters/stdout/stdoutlog/record.go +++ b/exporters/stdout/stdoutlog/record.go @@ -15,19 +15,18 @@ import ( // recordJSON is a JSON-serializable representation of a Record. type recordJSON struct { - Timestamp *time.Time `json:",omitempty"` - ObservedTimestamp *time.Time `json:",omitempty"` - Severity log.Severity - SeverityText string - Body log.Value - Attributes []log.KeyValue - TraceID trace.TraceID - SpanID trace.SpanID - TraceFlags trace.TraceFlags - Resource *resource.Resource - Scope instrumentation.Scope - AttributeValueLengthLimit int - AttributeCountLimit int + Timestamp *time.Time `json:",omitempty"` + ObservedTimestamp *time.Time `json:",omitempty"` + Severity log.Severity + SeverityText string + Body log.Value + Attributes []log.KeyValue + TraceID trace.TraceID + SpanID trace.SpanID + TraceFlags trace.TraceFlags + Resource *resource.Resource + Scope instrumentation.Scope + DroppedAttributes int } func (e *Exporter) newRecordJSON(r sdklog.Record) recordJSON { @@ -45,6 +44,8 @@ func (e *Exporter) newRecordJSON(r sdklog.Record) recordJSON { Resource: &res, Scope: r.InstrumentationScope(), + + DroppedAttributes: r.DroppedAttributes(), } r.WalkAttributes(func(kv log.KeyValue) bool {