Skip to content

Commit 291140b

Browse files
arjun7579pellared
andauthored
log: Add Record.Clone (#7001)
Fixes #6986 This PR adds a `Clone()` method to the `log.Record` type. The `Clone` method returns a copy of the record with no shared state, allowing both the original and the clone to be modified independently. This functionality mirrors the existing `sdk/log.Record.Clone()` behavior and includes a corresponding unit test (`TestRecordClone`) to ensure correctness. --------- Co-authored-by: Robert Pająk <[email protected]>
1 parent 55d2e69 commit 291140b

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
4141
- `RPCGRPCResponseMetadata`
4242
- Add `ErrorType` attribute helper function to the `go.opentelmetry.io/otel/semconv/v1.34.0` package. (#6962)
4343
- Add `WithAllowKeyDuplication` in `go.opentelemetry.io/otel/sdk/log` which can be used to disable deduplication for log records. (#6968)
44+
- Add `Clone` method to `Record` in `go.opentelemetry.io/otel/log` that returns a copy of the record with no shared state. (#7001)
4445

4546
### Changed
4647

log/record.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,11 @@ func (r *Record) AddAttributes(attrs ...KeyValue) {
142142
func (r *Record) AttributesLen() int {
143143
return r.nFront + len(r.back)
144144
}
145+
146+
// Clone returns a copy of the record with no shared state.
147+
// The original record and the clone can both be modified without interfering with each other.
148+
func (r *Record) Clone() Record {
149+
res := *r
150+
res.back = slices.Clone(r.back)
151+
return res
152+
}

log/record_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,64 @@ func TestRecordAllocationLimits(t *testing.T) {
160160
// Convince the linter these values are used.
161161
_, _, _, _, _, _ = tStamp, sev, text, body, n, attr
162162
}
163+
164+
func TestRecordClone(t *testing.T) {
165+
now0 := time.Now()
166+
sev0 := log.SeverityInfo
167+
text0 := "text"
168+
val0 := log.BoolValue(true)
169+
attr0 := log.Bool("0", true)
170+
171+
r0 := log.Record{}
172+
r0.SetTimestamp(now0)
173+
r0.SetObservedTimestamp(now0)
174+
r0.SetSeverity(sev0)
175+
r0.SetSeverityText(text0)
176+
r0.SetBody(val0)
177+
r0.AddAttributes(attr0)
178+
179+
// Clone and modify the clone
180+
now1 := now0.Add(time.Second)
181+
sev1 := log.SeverityDebug
182+
text1 := "string"
183+
val1 := log.IntValue(1)
184+
attr1 := log.Int64("1", 2)
185+
186+
r1 := r0.Clone()
187+
r1.SetTimestamp(now1)
188+
r1.SetObservedTimestamp(now1)
189+
r1.SetSeverity(sev1)
190+
r1.SetSeverityText(text1)
191+
r1.SetBody(val1)
192+
r1.AddAttributes(attr1)
193+
194+
// Assertions on original record (r0)
195+
assert.Equal(t, now0, r0.Timestamp())
196+
assert.Equal(t, now0, r0.ObservedTimestamp())
197+
assert.Equal(t, sev0, r0.Severity())
198+
assert.Equal(t, text0, r0.SeverityText())
199+
assert.True(t, val0.Equal(r0.Body()))
200+
201+
var r0Attrs []log.KeyValue
202+
r0.WalkAttributes(func(kv log.KeyValue) bool {
203+
r0Attrs = append(r0Attrs, kv)
204+
return true
205+
})
206+
assert.Contains(t, r0Attrs, attr0)
207+
assert.NotContains(t, r0Attrs, attr1)
208+
209+
// Assertions on cloned record (r1)
210+
assert.Equal(t, now1, r1.Timestamp())
211+
assert.Equal(t, now1, r1.ObservedTimestamp())
212+
assert.Equal(t, sev1, r1.Severity())
213+
assert.Equal(t, text1, r1.SeverityText())
214+
assert.True(t, val1.Equal(r1.Body()))
215+
216+
var r1Attrs []log.KeyValue
217+
r1.WalkAttributes(func(kv log.KeyValue) bool {
218+
r1Attrs = append(r1Attrs, kv)
219+
return true
220+
})
221+
assert.Contains(t, r1Attrs, attr0)
222+
assert.Contains(t, r1Attrs, attr1)
223+
}

0 commit comments

Comments
 (0)