diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c65386dc4a..428b7696f95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Changed - Improve performance by reducing allocations in the gRPC stats handler in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc`. (#8035) +- Export the `ReadEvents` and `WriteEvents` constants in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` so they can be used in `WithMessageEvents`. (#8153) ### Deprecated diff --git a/instrumentation/net/http/otelhttp/config.go b/instrumentation/net/http/otelhttp/config.go index 6107728d412..c3be78616b2 100644 --- a/instrumentation/net/http/otelhttp/config.go +++ b/instrumentation/net/http/otelhttp/config.go @@ -144,11 +144,13 @@ func WithFilter(f Filter) Option { }) } -type event int +// Event represents message event types for [WithMessageEvents]. +type Event int // Different types of events that can be recorded, see WithMessageEvents. const ( - ReadEvents event = iota + unspecifiedEvents Event = iota + ReadEvents WriteEvents ) @@ -161,7 +163,7 @@ const ( // using the ReadBytesKey // - WriteEvents: Record the number of bytes written after every http.ResponeWriter.Write // using the WriteBytesKey -func WithMessageEvents(events ...event) Option { +func WithMessageEvents(events ...Event) Option { return optionFunc(func(c *config) { for _, e := range events { switch e { diff --git a/instrumentation/net/http/otelhttp/config_test.go b/instrumentation/net/http/otelhttp/config_test.go index 96e069ef528..152c9f8ba16 100644 --- a/instrumentation/net/http/otelhttp/config_test.go +++ b/instrumentation/net/http/otelhttp/config_test.go @@ -122,3 +122,48 @@ func TestSpanNameFormatter(t *testing.T) { }) } } + +func TestEvent(t *testing.T) { + t.Run("constant values", func(t *testing.T) { + assert.Equal(t, otelhttp.ReadEvents, otelhttp.Event(1), "ReadEvents should be 1") + assert.Equal(t, otelhttp.WriteEvents, otelhttp.Event(2), "WriteEvents should be 2") + }) + + t.Run("unspecifiedEvent", func(t *testing.T) { + var unspecified otelhttp.Event // zero-value + assert.Equal(t, otelhttp.Event(0), unspecified, "unspecifiedEvent should be zero-value Event") + + // Validate that unspecifiedEvent is different from defined events + assert.NotEqual(t, otelhttp.ReadEvents, unspecified, "unspecifiedEvent should not equal ReadEvents") + assert.NotEqual(t, otelhttp.WriteEvents, unspecified, "unspecifiedEvent should not equal WriteEvents") + + // Validate WithMessageEvents accepts unspecifiedEvent + opt := otelhttp.WithMessageEvents(unspecified) + assert.NotNil(t, opt, "WithMessageEvents(unspecifiedEvent) should not return nil") + + // Additional validation: test behavior with unspecified events + optMultiple := otelhttp.WithMessageEvents(unspecified, otelhttp.ReadEvents) + assert.NotNil(t, optMultiple, "WithMessageEvents with unspecified and valid events should not return nil") + }) + + t.Run("WithMessageEvents", func(t *testing.T) { + tests := []struct { + name string + events []otelhttp.Event + }{ + {name: "ReadEvents", events: []otelhttp.Event{otelhttp.ReadEvents}}, + {name: "WriteEvents", events: []otelhttp.Event{otelhttp.WriteEvents}}, + {name: "multiple events", events: []otelhttp.Event{otelhttp.ReadEvents, otelhttp.WriteEvents}}, + {name: "no events", events: []otelhttp.Event{}}, + {name: "unspecified event only", events: []otelhttp.Event{otelhttp.Event(0)}}, + {name: "mixed with unspecified", events: []otelhttp.Event{otelhttp.Event(0), otelhttp.ReadEvents}}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := otelhttp.WithMessageEvents(tt.events...) + assert.NotNil(t, got, "WithMessageEvents(%v) should not return nil", tt.events) + }) + } + }) +}