From a2505aa68c800c8566a4068f6541e8ca7cc67939 Mon Sep 17 00:00:00 2001 From: Damien Mathieu Date: Thu, 6 Jun 2024 17:28:28 +0200 Subject: [PATCH] log/logtest: provide record with their context (#5468) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So the instrumentation tests can check the provided context. See https://github.com/open-telemetry/opentelemetry-go-contrib/pull/5707 --------- Co-authored-by: Robert PajÄ…k Co-authored-by: Sam Xie --- CHANGELOG.md | 1 + log/logtest/factory_test.go | 25 +++++++++++++++++++++++++ log/logtest/recorder.go | 22 ++++++++++++++++++---- log/logtest/recorder_test.go | 23 ++++++++++++++++++----- 4 files changed, 62 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14cd297b68f..01684fbe614 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm The package contains semantic conventions from the `v1.26.0` version of the OpenTelemetry Semantic Conventions. (#5476) - The `IsEmpty` method is added to the `Instrument` type in `go.opentelemetry.io/otel/sdk/metric`. This method is used to check if an `Instrument` instance is a zero-value. (#5431) +- Store and provide the emitted `context.Context` in `ScopeRecords` of `go.opentelemetry.io/otel/sdk/log/logtest`. (#5468) ### Changed diff --git a/log/logtest/factory_test.go b/log/logtest/factory_test.go index 358087028a9..6fa61049aae 100644 --- a/log/logtest/factory_test.go +++ b/log/logtest/factory_test.go @@ -67,6 +67,31 @@ func TestRecordFactoryMultiple(t *testing.T) { assertAttributes(t, attrs, record1) } +func assertRecord(t *testing.T, want log.Record, got log.Record) { + t.Helper() + + if !want.Timestamp().Equal(got.Timestamp()) { + t.Errorf("Timestamp value is not equal:\nwant: %v\ngot: %v", want.Timestamp(), got.Timestamp()) + } + if !want.ObservedTimestamp().Equal(got.ObservedTimestamp()) { + t.Errorf("ObservedTimestamp value is not equal:\nwant: %v\ngot: %v", want.ObservedTimestamp(), got.ObservedTimestamp()) + } + if want.Severity() != got.Severity() { + t.Errorf("Severity value is not equal:\nwant: %v\ngot: %v", want.Severity(), got.Severity()) + } + if want.SeverityText() != got.SeverityText() { + t.Errorf("SeverityText value is not equal:\nwant: %v\ngot: %v", want.SeverityText(), got.SeverityText()) + } + assertBody(t, want.Body(), got) + + var attrs []log.KeyValue + want.WalkAttributes(func(kv log.KeyValue) bool { + attrs = append(attrs, kv) + return true + }) + assertAttributes(t, attrs, got) +} + func assertBody(t *testing.T, want log.Value, r log.Record) { t.Helper() got := r.Body() diff --git a/log/logtest/recorder.go b/log/logtest/recorder.go index 5cdb0f290f4..b3d45d647ae 100644 --- a/log/logtest/recorder.go +++ b/log/logtest/recorder.go @@ -67,8 +67,22 @@ type ScopeRecords struct { // SchemaURL of the telemetry emitted by the scope. SchemaURL string - // Records are the log records this instrumentation scope recorded. - Records []log.Record + // Records are the log records, and their associated context this + // instrumentation scope recorded. + Records []EmittedRecord +} + +// EmittedRecord holds a log record the instrumentation received, alongside its +// context. +type EmittedRecord struct { + log.Record + + ctx context.Context +} + +// Context provides the context emitted with the record. +func (rwc EmittedRecord) Context() context.Context { + return rwc.ctx } // Recorder is a recorder that stores all received log records @@ -150,11 +164,11 @@ func (l *logger) Enabled(ctx context.Context, record log.Record) bool { } // Emit stores the log record. -func (l *logger) Emit(_ context.Context, record log.Record) { +func (l *logger) Emit(ctx context.Context, record log.Record) { l.mu.Lock() defer l.mu.Unlock() - l.scopeRecord.Records = append(l.scopeRecord.Records, record) + l.scopeRecord.Records = append(l.scopeRecord.Records, EmittedRecord{record, ctx}) } // Reset clears the in-memory log records. diff --git a/log/logtest/recorder_test.go b/log/logtest/recorder_test.go index 33af64cb92b..a66ebe96cf1 100644 --- a/log/logtest/recorder_test.go +++ b/log/logtest/recorder_test.go @@ -115,17 +115,30 @@ func TestRecorderEmitAndReset(t *testing.T) { r1 := log.Record{} r1.SetSeverity(log.SeverityInfo) - l.Emit(context.Background(), r1) - assert.Equal(t, r.Result()[0].Records, []log.Record{r1}) + ctx := context.Background() + + l.Emit(ctx, r1) + assert.Equal(t, r.Result()[0].Records, []EmittedRecord{ + {r1, ctx}, + }) nl := r.Logger("test") assert.Empty(t, r.Result()[1].Records) r2 := log.Record{} r2.SetSeverity(log.SeverityError) - nl.Emit(context.Background(), r2) - assert.Equal(t, r.Result()[0].Records, []log.Record{r1}) - assert.Equal(t, r.Result()[1].Records, []log.Record{r2}) + // We want a non-background context here so it's different from `ctx`. + ctx2, cancel := context.WithCancel(ctx) + defer cancel() + + nl.Emit(ctx2, r2) + assert.Len(t, r.Result()[0].Records, 1) + assertRecord(t, r.Result()[0].Records[0].Record, r1) + assert.Equal(t, r.Result()[0].Records[0].Context(), ctx) + + assert.Len(t, r.Result()[1].Records, 1) + assertRecord(t, r.Result()[1].Records[0].Record, r2) + assert.Equal(t, r.Result()[1].Records[0].Context(), ctx2) r.Reset() assert.Empty(t, r.Result()[0].Records)