Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
e52793e
log/logtest: Redesign
pellared Feb 19, 2025
17d92c9
Use Time.Equal
pellared Feb 19, 2025
030f8a7
Refactor
pellared Feb 19, 2025
bf915ff
Refactor
pellared Feb 19, 2025
c77a09f
Better printing
pellared Feb 19, 2025
a470236
Fix grammar
pellared Feb 19, 2025
d8c692d
Add examples
pellared Feb 19, 2025
49486c6
Refactor
pellared Feb 19, 2025
c89f6c9
Better comment
pellared Feb 19, 2025
748c27d
Refactor
pellared Feb 19, 2025
96271e9
Test attributes comparison
pellared Feb 19, 2025
e6b7de6
Refactor
pellared Feb 19, 2025
578f9ab
Rename RecordedRecords to Recording
pellared Feb 20, 2025
9d68e80
format time
pellared Feb 20, 2025
e14db7f
Merge branch 'main' into logtest-redesign
pellared Feb 20, 2025
e056b95
Merge branch 'main' into logtest-redesign
pellared Feb 20, 2025
7443c45
Refactor equals methods to functions
pellared Feb 20, 2025
6542559
Refine Result and add tests
pellared Feb 20, 2025
a84ba46
Add example usages
pellared Feb 20, 2025
a4c181d
Fix build
pellared Feb 20, 2025
69a1b37
Fix typo
pellared Feb 20, 2025
c4ac836
Merge branch 'main' into logtest-redesign
pellared Feb 21, 2025
1b0a436
Example to use go-cmp
pellared Feb 24, 2025
178b0db
Refactor tests
pellared Feb 24, 2025
f26e543
Refactor
pellared Feb 24, 2025
f8b7763
Refactor
pellared Feb 24, 2025
59b557a
remove Equal
pellared Feb 24, 2025
9f19f30
gofumpt
pellared Feb 24, 2025
cc5d7aa
Merge branch 'main' into logtest-redesign
pellared Feb 24, 2025
58a907f
go mod tidy
pellared Feb 24, 2025
05acbb6
Make the example stable
pellared Feb 24, 2025
28a6964
Add changlog entry
pellared Feb 24, 2025
16942f1
Update changelog entry
pellared Feb 24, 2025
145ace3
Update changelog
pellared Feb 24, 2025
c42fc68
Make Recorder and Record not comparable
pellared Feb 24, 2025
5846107
Merge branch 'main' into logtest-redesign
pellared Feb 25, 2025
1486ad5
Update example_test.go
pellared Feb 25, 2025
dff04ce
Update example_test.go
pellared Feb 25, 2025
0ead039
Merge branch 'main' into logtest-redesign
pellared Feb 26, 2025
4021498
Update log/logtest/example_test.go
pellared Feb 26, 2025
9bca3f2
Merge branch 'main' into logtest-redesign
pellared Feb 26, 2025
348b615
Fix build and refactor
pellared Feb 26, 2025
e0dcc39
Merge branch 'main' into logtest-redesign
pellared Mar 5, 2025
210fd18
Merge branch 'main' into logtest-redesign
pellared Mar 6, 2025
54d03f4
Merge branch 'main' into logtest-redesign
pellared Mar 6, 2025
3462546
Update CHANGELOG.md
pellared Mar 7, 2025
598170c
Merge branch 'main' into logtest-redesign
pellared Mar 7, 2025
24a6f58
Merge branch 'main' into logtest-redesign
pellared Mar 10, 2025
04a737d
Merge branch 'main' into logtest-redesign
pellared Mar 17, 2025
9c4ddd7
Better way to compare context
pellared Mar 17, 2025
f522d00
Merge branch 'main' into logtest-redesign
pellared Mar 18, 2025
ecbd5f4
Add AssertEqual
pellared Mar 18, 2025
2729657
Merge branch 'main' into logtest-redesign-2ed
pellared Mar 18, 2025
c75f6f0
Merge branch 'main' into logtest-redesign-2ed
pellared Mar 18, 2025
457ca73
Fix AssertEqual
pellared Mar 18, 2025
d33aea9
Fix changelog
pellared Mar 18, 2025
5c9b119
Merge branch 'main' into logtest-redesign-2ed
pellared Mar 19, 2025
524dc94
Merge branch 'main' into logtest-redesign-2ed
pellared Mar 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,32 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased]

### Removed
### Added

- Drop support for [Go 1.22]. (#6381, #6418)
- Add `Recording`, `Scope`, `Record` types in `go.opentelemetry.io/otel/log/logtest`. (#6342)
- Add `AssertEqual` function along with `IgnoreTimestamp` option in `go.opentelemetry.io/otel/log/logtest`. (#6342)
- Add a testable example showing how `go.opentelemetry.io/otel/log/logtest` can be used. (#6342)

### Changed

- ⚠️ Update `github.com/prometheus/client_golang` to `v1.21.1`, which changes the `NameValidationScheme` to `UTF8Validation`.
This allows metrics names to keep original delimiters (e.g. `.`), rather than replacing with underscores.
This can be reverted by setting `github.com/prometheus/common/model.NameValidationScheme` to `LegacyValidation` in `github.com/prometheus/common/model`. (#6433)
- Initialize map with `len(keys)` in `NewAllowKeysFilter` and `NewDenyKeysFilter` to avoid unnecessary allocations in `go.opentelemetry.io/otel/attribute`. (#6455)
- Change `Recorder.Result` to return `Recording`. (#6342)
- `Recorder` no longer separately stores records emitted by loggers with the same instrumentation scope. (#6342)

### Fixes

- Stop percent encoding header environment variables in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#6392)
- Ensure the `noopSpan.tracerProvider` method is not inlined in `go.opentelemetry.io/otel/trace` so the `go.opentelemetry.io/auto` instrumentation can instrument non-recording spans. (#6456)

### Removed

- Drop support for [Go 1.22]. (#6381, #6418)
- Remove `ScopeRecords`, `EmittedRecord`, `RecordFactory` types from `go.opentelemetry.io/otel/log/logtest`. (#6342)
- Remove `AssertRecordEqual` function from `go.opentelemetry.io/otel/log/logtest`. (#6342)

<!-- Released section -->
<!-- Don't change this section unless doing release -->

Expand Down
1 change: 1 addition & 0 deletions log/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.23.0

require (
github.com/go-logr/logr v1.4.2
github.com/google/go-cmp v0.7.0
github.com/stretchr/testify v1.10.0
go.opentelemetry.io/otel v1.35.0
)
Expand Down
75 changes: 75 additions & 0 deletions log/logtest/assert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package logtest // import "go.opentelemetry.io/otel/log/logtest"

import (
"context"
"time"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"

"go.opentelemetry.io/otel/log"
)

// TestingT reports failure messages.
// [testing.T] implements this interface.
type TestingT interface {
Errorf(format string, args ...any)
}

// AssertEqual asserts that the two concrete data-types from the logtest package are equal.
func AssertEqual[T Recording | Record](t TestingT, want, got T, opts ...AssertOption) bool {
if h, ok := t.(interface{ Helper() }); ok {
h.Helper()
}

cmpOpts := []cmp.Option{
cmp.Comparer(func(x, y context.Context) bool { return x == y }), // Compare context.
cmpopts.SortSlices(func(a, b log.KeyValue) bool { return a.Key < b.Key }), // Unordered compare of the key values.
cmpopts.EquateEmpty(), // Empty and nil collections are equal.
}

cfg := newAssertConfig(opts)
if cfg.ignoreTimestamp {
cmpOpts = append(cmpOpts, cmpopts.IgnoreTypes(time.Time{})) // Ignore Timestamps.
}

if diff := cmp.Diff(want, got, cmpOpts...); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
return false
}
return true
}

type assertConfig struct {
ignoreTimestamp bool
}

func newAssertConfig(opts []AssertOption) assertConfig {
var cfg assertConfig
for _, opt := range opts {
cfg = opt.apply(cfg)
}
return cfg
}

// AssertOption allows for fine grain control over how AssertEqual operates.
type AssertOption interface {
Copy link
Member Author

@pellared pellared Mar 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SIG meeting: There was a proposal by @MrAlias to add an option to add additional failure message.

It would be better to add each option as a separate PR.

apply(cfg assertConfig) assertConfig
}

type fnOption func(cfg assertConfig) assertConfig

func (fn fnOption) apply(cfg assertConfig) assertConfig {
return fn(cfg)
}

// IgnoreTimestamp disables checking if timestamps are different.
func IgnoreTimestamp() AssertOption {
return fnOption(func(cfg assertConfig) assertConfig {
cfg.ignoreTimestamp = true
return cfg
})
}
Comment on lines +69 to +75
Copy link
Member Author

@pellared pellared Mar 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SIG meeting: There was a proposal by @MrAlias to add some more generic function that would transform the Record (or any type?) before comparing. This would provide more flexibility e.g.

logtest.AssertEqual(t, want, got, logtest.Mutate(func (r logtest.Record) logtest.Record {
   r.Timestamp = time.Time{}
   return r
}))

Maybe https://pkg.go.dev/github.com/google/go-cmp/cmp#Transformer could used to achieve it.

It would be better to add each option as a separate PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

174 changes: 174 additions & 0 deletions log/logtest/assert_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package logtest

import (
"context"
"testing"
"time"

"go.opentelemetry.io/otel/log"
)

var y2k = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)

type mockTestingT struct {
errors []string
}

func (m *mockTestingT) Errorf(format string, args ...any) {
m.errors = append(m.errors, format)
}

func TestAssertEqualRecording(t *testing.T) {
tests := []struct {
name string
a Recording
b Recording
opts []AssertOption
want bool
}{
{
name: "equal recordings",
a: Recording{
Scope{Name: t.Name()}: []Record{
{Timestamp: y2k, Context: context.Background(), Attributes: []log.KeyValue{log.Int("n", 1), log.String("foo", "bar")}},
},
},
b: Recording{
Scope{Name: t.Name()}: []Record{
{Timestamp: y2k, Context: context.Background(), Attributes: []log.KeyValue{log.String("foo", "bar"), log.Int("n", 1)}},
},
},
want: true,
},
{
name: "different recordings",
a: Recording{
Scope{Name: t.Name()}: []Record{
{Attributes: []log.KeyValue{log.String("foo", "bar")}},
},
},
b: Recording{
Scope{Name: t.Name()}: []Record{
{Attributes: []log.KeyValue{log.Int("n", 1)}},
},
},
want: false,
},
{
name: "equal empty scopes",
a: Recording{
Scope{Name: t.Name()}: nil,
},
b: Recording{
Scope{Name: t.Name()}: []Record{},
},
want: true,
},
{
name: "equal empty attributes",
a: Recording{
Scope{Name: t.Name()}: []Record{
{Body: log.StringValue("msg"), Attributes: []log.KeyValue{}},
},
},
b: Recording{
Scope{Name: t.Name()}: []Record{
{Body: log.StringValue("msg"), Attributes: nil},
},
},
want: true,
},
{
name: "ignore timestamp",
a: Recording{
Scope{Name: t.Name()}: []Record{
{Timestamp: y2k, Attributes: []log.KeyValue{log.String("foo", "bar")}},
},
},
b: Recording{
Scope{Name: t.Name()}: []Record{
{Timestamp: time.Now(), Attributes: []log.KeyValue{log.String("foo", "bar")}},
},
},
opts: []AssertOption{IgnoreTimestamp()},
want: true,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
mockT := &mockTestingT{}
result := AssertEqual(mockT, tc.a, tc.b, tc.opts...)
if result != tc.want {
t.Errorf("AssertEqual() = %v, want %v", result, tc.want)
}
if !tc.want && len(mockT.errors) == 0 {
t.Errorf("expected Errorf call but got none")
}
})
}
}

func TestAssertEqualRecord(t *testing.T) {
tests := []struct {
name string
a Record
b Record
opts []AssertOption
want bool
}{
{
name: "equal records",
a: Record{
Timestamp: y2k,
Context: context.Background(),
Attributes: []log.KeyValue{log.Int("n", 1), log.String("foo", "bar")},
},
b: Record{
Timestamp: y2k,
Context: context.Background(),
Attributes: []log.KeyValue{log.String("foo", "bar"), log.Int("n", 1)},
},
want: true,
},
{
name: "different records",
a: Record{
Attributes: []log.KeyValue{log.String("foo", "bar")},
},
b: Record{
Attributes: []log.KeyValue{log.Int("n", 1)},
},
want: false,
},
{
name: "ignore timestamp",
a: Record{
Timestamp: y2k,
Attributes: []log.KeyValue{log.String("foo", "bar")},
},
b: Record{
Timestamp: time.Now(),
Attributes: []log.KeyValue{log.String("foo", "bar")},
},
opts: []AssertOption{IgnoreTimestamp()},
want: true,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
mockT := &mockTestingT{}
result := AssertEqual(mockT, tc.a, tc.b, tc.opts...)
if result != tc.want {
t.Errorf("AssertEqual() = %v, want %v", result, tc.want)
}
if !tc.want && len(mockT.errors) == 0 {
t.Errorf("expected Errorf call but got none")
}
})
}
}
74 changes: 0 additions & 74 deletions log/logtest/assertions.go

This file was deleted.

Loading
Loading