Repository: open-telemetry/opentelemetry-go
Pull request #6187 (2025-01-21 09:40:28)

log: Add EventName
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/6182
Towards https://github.com/open-telemetry/opentelemetry-go/issues/6184

Towards https://github.com/open-telemetry/opentelemetry-go/issues/6181

Prior-art: https://github.com/open-telemetry/opentelemetry-go/pull/6018

pellared: > Should it be added to the SDK as well? (or is that for a later PR?)

Seperate issue (and PR): https://github.com/open-telemetry/opentelemetry-go/issues/6183

I do not want to make this PR too big. I even hesitated to add enhancements to `logtest` but found out that this is PR should be still easy to review.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 30ada7a3..38c5a900 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
 ### Added
 
 - Add `ValueFromAttribute` and `KeyValueFromAttribute` in `go.opentelemetry.io/otel/log`. (#6180)
+- Add `EventName` and `SetEventName` to `Record` in `go.opentelemetry.io/otel/log`. (#6187)
+- Add `EventName` to `RecordFactory` in `go.opentelemetry.io/otel/log/logtest`. (#6187)
+- `AssertRecordEqual` in `go.opentelemetry.io/otel/log/logtest` checks `Record.EventName`. (#6187)
 
 <!-- Released section -->
 <!-- Don't change this section unless doing release -->
diff --git a/log/record.go b/log/record.go
index 7cf5446a..3f58ce7b 100644
--- a/log/record.go
+++ b/log/record.go
@@ -15,10 +15,12 @@ import (
 const attributesInlineCount = 5
 
 // Record represents a log record.
+// A log record with non-empty event name is interpreted as an event record.
 type Record struct {
 	// Ensure forward compatibility by explicitly making this not comparable.
 	noCmp [0]func() //nolint: unused  // This is indeed used.
 
+	eventName         string
 	timestamp         time.Time
 	observedTimestamp time.Time
 	severity          Severity
@@ -44,6 +46,18 @@ type Record struct {
 	back []KeyValue
 }
 
+// Event returns the event name.
+// A log record with non-empty event name is interpreted as an event record.
+func (r *Record) EventName() string {
+	return r.eventName
+}
+
+// SetEventName sets the event name.
+// A log record with non-empty event name is interpreted as an event record.
+func (r *Record) SetEventName(s string) {
+	r.eventName = s
+}
+
 // Timestamp returns the time when the log record occurred.
 func (r *Record) Timestamp() time.Time {
 	return r.timestamp


Test patch:
diff --git a/log/logtest/assertions.go b/log/logtest/assertions.go
index 8fb72e65..479cc3b0 100644
--- a/log/logtest/assertions.go
+++ b/log/logtest/assertions.go
@@ -15,6 +15,10 @@ import (
 func AssertRecordEqual(t testing.TB, want, got log.Record) bool {
 	t.Helper()
 
+	if want.EventName() != got.EventName() {
+		t.Errorf("EventName value is not equal:\nwant: %v\ngot:  %v", want.EventName(), got.EventName())
+		return false
+	}
 	if !want.Timestamp().Equal(got.Timestamp()) {
 		t.Errorf("Timestamp value is not equal:\nwant: %v\ngot:  %v", want.Timestamp(), got.Timestamp())
 		return false
diff --git a/log/logtest/assertions_test.go b/log/logtest/assertions_test.go
index 7f4e91b6..04d62d15 100644
--- a/log/logtest/assertions_test.go
+++ b/log/logtest/assertions_test.go
@@ -13,10 +13,11 @@ import (
 func TestAssertRecord(t *testing.T) {
 	r1 := log.Record{}
 	r2 := log.Record{}
-	now := time.Now()
-
 	AssertRecordEqual(t, r1, r2)
 
+	now := time.Now()
+	r1.SetEventName("my_event")
+	r2.SetEventName("my_event")
 	r1.SetTimestamp(now)
 	r2.SetTimestamp(now)
 	r1.SetObservedTimestamp(now)
diff --git a/log/logtest/factory.go b/log/logtest/factory.go
index afa97d41..0c3b389c 100644
--- a/log/logtest/factory.go
+++ b/log/logtest/factory.go
@@ -14,6 +14,7 @@ import (
 //
 // Do not use RecordFactory to create records in production code.
 type RecordFactory struct {
+	EventName         string
 	Timestamp         time.Time
 	ObservedTimestamp time.Time
 	Severity          log.Severity
@@ -25,6 +26,7 @@ type RecordFactory struct {
 // NewRecord returns a log record.
 func (b RecordFactory) NewRecord() log.Record {
 	var record log.Record
+	record.SetEventName(b.EventName)
 	record.SetTimestamp(b.Timestamp)
 	record.SetObservedTimestamp(b.ObservedTimestamp)
 	record.SetSeverity(b.Severity)
diff --git a/log/logtest/factory_test.go b/log/logtest/factory_test.go
index 8cfae272..084c31bc 100644
--- a/log/logtest/factory_test.go
+++ b/log/logtest/factory_test.go
@@ -15,6 +15,7 @@ import (
 func TestRecordFactory(t *testing.T) {
 	now := time.Now()
 	observed := now.Add(time.Second)
+	evnt := "my_event"
 	severity := log.SeverityDebug
 	severityText := "DBG"
 	body := log.StringValue("Message")
@@ -25,6 +26,7 @@ func TestRecordFactory(t *testing.T) {
 	}
 
 	got := RecordFactory{
+		EventName:         evnt,
 		Timestamp:         now,
 		ObservedTimestamp: observed,
 		Severity:          severity,
@@ -33,6 +35,7 @@ func TestRecordFactory(t *testing.T) {
 		Attributes:        attrs,
 	}.NewRecord()
 
+	assert.Equal(t, evnt, got.EventName())
 	assert.Equal(t, now, got.Timestamp())
 	assert.Equal(t, observed, got.ObservedTimestamp())
 	assert.Equal(t, severity, got.Severity())
diff --git a/log/record_test.go b/log/record_test.go
index 5a748774..b3f145fe 100644
--- a/log/record_test.go
+++ b/log/record_test.go
@@ -15,6 +15,14 @@ import (
 
 var y2k = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
 
+func TestRecordEventName(t *testing.T) {
+	const text = "testing text"
+
+	var r log.Record
+	r.SetEventName(text)
+	assert.Equal(t, text, r.EventName())
+}
+
 func TestRecordTimestamp(t *testing.T) {
 	var r log.Record
 	r.SetTimestamp(y2k)