Skip to content

Commit fe523bd

Browse files
authored
logtest: add Transform (#6794)
Fixes #6491 Fixes #6489 Towards #6341 Per #6774 (comment)
1 parent e578799 commit fe523bd

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
2222
- Add `Values` method to `HeaderCarrier` to implement the new `ValuesGetter` interface in `go.opentelemetry.io/otel/propagation`. (#5973)
2323
- Update `Baggage` in `go.opentelemetry.io/otel/propagation` to retrieve multiple values for a key when the carrier implements `ValuesGetter`. (#5973)
2424
- Add `AssertEqual` function in `go.opentelemetry.io/otel/log/logtest`. (#6662)
25+
- Add `Transform` option in `go.opentelemetry.io/otel/log/logtest`. (#6794)
2526

2627
### Removed
2728

log/logtest/assert.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,24 @@ type testingT interface {
2525
Errorf(format string, args ...any)
2626
}
2727

28-
func assertEqual[T Recording | Record](t testingT, want, got T, _ ...AssertOption) bool {
28+
func assertEqual[T Recording | Record](t testingT, want, got T, opts ...AssertOption) bool {
2929
if h, ok := t.(interface{ Helper() }); ok {
3030
h.Helper()
3131
}
3232

33+
var cfg assertConfig
34+
for _, opt := range opts {
35+
cfg = opt.apply(cfg)
36+
}
37+
3338
cmpOpts := []cmp.Option{
3439
cmp.Comparer(func(x, y context.Context) bool { return x == y }), // Compare context.
3540
cmpopts.SortSlices(
3641
func(a, b log.KeyValue) bool { return a.Key < b.Key },
3742
), // Unordered compare of the key values.
3843
cmpopts.EquateEmpty(), // Empty and nil collections are equal.
3944
}
45+
cmpOpts = append(cmpOpts, cfg.cmpOpts...)
4046

4147
if diff := cmp.Diff(want, got, cmpOpts...); diff != "" {
4248
t.Errorf("mismatch (-want +got):\n%s", diff)
@@ -45,9 +51,27 @@ func assertEqual[T Recording | Record](t testingT, want, got T, _ ...AssertOptio
4551
return true
4652
}
4753

48-
type assertConfig struct{}
54+
type assertConfig struct {
55+
cmpOpts []cmp.Option
56+
}
4957

5058
// AssertOption allows for fine grain control over how AssertEqual operates.
5159
type AssertOption interface {
5260
apply(cfg assertConfig) assertConfig
5361
}
62+
63+
type fnOption func(cfg assertConfig) assertConfig
64+
65+
func (fn fnOption) apply(cfg assertConfig) assertConfig {
66+
return fn(cfg)
67+
}
68+
69+
// Transform applies a transformation f function that
70+
// converts values of a certain type into that of another.
71+
// f must not mutate A in any way.
72+
func Transform[A, B any](f func(A) B) AssertOption {
73+
return fnOption(func(cfg assertConfig) assertConfig {
74+
cfg.cmpOpts = append(cfg.cmpOpts, cmp.Transformer("", f))
75+
return cfg
76+
})
77+
}

log/logtest/assert_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,22 @@ func TestAssertEqualRecord(t *testing.T) {
155155
},
156156
want: false,
157157
},
158+
{
159+
name: "Transform to ignore timestamps",
160+
a: Record{
161+
Attributes: []log.KeyValue{log.Int("n", 1), log.String("foo", "bar")},
162+
},
163+
b: Record{
164+
Timestamp: y2k,
165+
Attributes: []log.KeyValue{log.String("foo", "bar"), log.Int("n", 1)},
166+
},
167+
opts: []AssertOption{
168+
Transform(func(time.Time) time.Time {
169+
return time.Time{}
170+
}),
171+
},
172+
want: true,
173+
},
158174
}
159175

160176
for _, tc := range tests {

log/logtest/example_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package logtest_test
5+
6+
import (
7+
"context"
8+
"testing"
9+
"time"
10+
11+
"go.opentelemetry.io/otel/log"
12+
"go.opentelemetry.io/otel/log/logtest"
13+
)
14+
15+
func Example() {
16+
t := &testing.T{} // Provided by testing framework.
17+
18+
// Create a recorder.
19+
rec := logtest.NewRecorder()
20+
21+
// Emit a log record (code under test).
22+
l := rec.Logger("Example")
23+
ctx := context.Background()
24+
r := log.Record{}
25+
r.SetTimestamp(time.Now())
26+
r.SetSeverity(log.SeverityInfo)
27+
r.SetBody(log.StringValue("Hello there"))
28+
r.AddAttributes(log.String("foo", "bar"))
29+
r.AddAttributes(log.Int("n", 1))
30+
l.Emit(ctx, r)
31+
32+
// Verify that the expected and actual log records match.
33+
want := logtest.Recording{
34+
logtest.Scope{Name: "Example"}: []logtest.Record{
35+
{
36+
Context: context.Background(),
37+
Severity: log.SeverityInfo,
38+
Body: log.StringValue("Hello there"),
39+
Attributes: []log.KeyValue{
40+
log.Int("n", 1),
41+
log.String("foo", "bar"),
42+
},
43+
},
44+
},
45+
}
46+
got := rec.Result()
47+
logtest.AssertEqual(t, want, got,
48+
// Ignore Timestamps.
49+
logtest.Transform(func(time.Time) time.Time {
50+
return time.Time{}
51+
}),
52+
)
53+
// Output:
54+
//
55+
}

0 commit comments

Comments
 (0)