Skip to content

Commit 932c4e2

Browse files
authored
refactor(tracing): simplifies span generic impl (#1622)
**Description** This simplifies the span generic implementation by removing unnecessary indirection **Related Issues/PRs (if applicable)** Follow up on #1582 --------- Signed-off-by: Takeshi Yoneda <[email protected]>
1 parent a2ba2c9 commit 932c4e2

File tree

2 files changed

+21
-52
lines changed

2 files changed

+21
-52
lines changed

internal/tracing/api/api.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ type (
9898
type (
9999
// SpanRecorder standardizes recorder implementations for non-MCP tracers.
100100
SpanRecorder[ReqT any, RespT any, RespChunkT any] interface {
101+
SpanResponseRecorder[RespT, RespChunkT]
101102
// StartParams returns the name and options to start the span with.
102103
//
103104
// Parameters:
@@ -108,6 +109,11 @@ type (
108109
StartParams(req *ReqT, body []byte) (spanName string, opts []trace.SpanStartOption)
109110
// RecordRequest records request attributes to the span.
110111
RecordRequest(span trace.Span, req *ReqT, body []byte)
112+
}
113+
// SpanResponseRecorder standardizes response recording for non-MCP tracers.
114+
//
115+
// It is separated from SpanRecorder to allow reusing response recording logic.
116+
SpanResponseRecorder[RespT, RespChunkT any] interface {
111117
// RecordResponse records response attributes to the span.
112118
RecordResponse(span trace.Span, resp *RespT)
113119
// RecordResponseOnError ends recording the span with an error status.

internal/tracing/span.go

Lines changed: 15 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -14,78 +14,41 @@ import (
1414
tracing "github.com/envoyproxy/ai-gateway/internal/tracing/api"
1515
)
1616

17-
type responseRecorder[RespT any] interface {
18-
RecordResponse(trace.Span, *RespT)
19-
RecordResponseOnError(trace.Span, int, []byte)
20-
}
21-
22-
type streamResponseRecorder[RespT, ChunkT any] interface {
23-
responseRecorder[RespT]
24-
RecordResponseChunks(trace.Span, []*ChunkT)
25-
}
26-
27-
type noopChunkRecorder[ChunkT any] struct{}
28-
29-
func (noopChunkRecorder[ChunkT]) RecordResponseChunk(*ChunkT) {}
30-
31-
type streamingSpan[RespT, ChunkT any] struct {
17+
type span[RespT, ChunkT any] struct {
3218
span trace.Span
33-
recorder streamResponseRecorder[RespT, ChunkT]
19+
recorder tracing.SpanResponseRecorder[RespT, ChunkT]
3420
chunks []*ChunkT
3521
}
3622

37-
func (s *streamingSpan[RespT, ChunkT]) RecordResponseChunk(resp *ChunkT) {
23+
// RecordResponseChunk implements [tracing.Span.RecordResponseChunk]
24+
func (s *span[RespT, ChunkT]) RecordResponseChunk(resp *ChunkT) {
3825
s.chunks = append(s.chunks, resp)
3926
}
4027

41-
func (s *streamingSpan[RespT, ChunkT]) RecordResponse(resp *RespT) {
28+
// RecordResponse implements [tracing.Span.RecordResponse]
29+
func (s *span[RespT, ChunkT]) RecordResponse(resp *RespT) {
4230
s.recorder.RecordResponse(s.span, resp)
4331
}
4432

45-
func (s *streamingSpan[RespT, ChunkT]) EndSpan() {
33+
// EndSpan implements [tracing.Span.EndSpan]
34+
func (s *span[RespT, ChunkT]) EndSpan() {
4635
if len(s.chunks) > 0 {
4736
s.recorder.RecordResponseChunks(s.span, s.chunks)
4837
}
4938
s.span.End()
5039
}
5140

52-
func (s *streamingSpan[RespT, ChunkT]) EndSpanOnError(statusCode int, body []byte) {
53-
s.recorder.RecordResponseOnError(s.span, statusCode, body)
54-
s.span.End()
55-
}
56-
57-
type responseSpan[RespT, ChunkT any] struct {
58-
noopChunkRecorder[ChunkT]
59-
span trace.Span
60-
recorder streamResponseRecorder[RespT, ChunkT]
61-
}
62-
63-
func (s *responseSpan[RespT, ChunkT]) RecordResponse(resp *RespT) {
64-
s.recorder.RecordResponse(s.span, resp)
65-
}
66-
67-
func (s *responseSpan[RespT, ChunkT]) EndSpan() {
68-
s.span.End()
69-
}
70-
71-
func (s *responseSpan[RespT, ChunkT]) EndSpanOnError(statusCode int, body []byte) {
41+
// EndSpanOnError implements [tracing.Span.EndSpanOnError]
42+
func (s *span[RespT, ChunkT]) EndSpanOnError(statusCode int, body []byte) {
7243
s.recorder.RecordResponseOnError(s.span, statusCode, body)
7344
s.span.End()
7445
}
7546

7647
// Type aliases tying generic implementations to concrete recorder contracts.
7748
type (
78-
chatCompletionSpan = streamingSpan[openai.ChatCompletionResponse, openai.ChatCompletionResponseChunk]
79-
completionSpan = streamingSpan[openai.CompletionResponse, openai.CompletionResponse]
80-
embeddingsSpan = responseSpan[openai.EmbeddingResponse, struct{}]
81-
imageGenerationSpan = responseSpan[openaisdk.ImagesResponse, struct{}]
82-
rerankSpan = responseSpan[cohereschema.RerankV2Response, struct{}]
83-
)
84-
85-
var (
86-
_ tracing.ChatCompletionSpan = (*chatCompletionSpan)(nil)
87-
_ tracing.CompletionSpan = (*completionSpan)(nil)
88-
_ tracing.EmbeddingsSpan = (*embeddingsSpan)(nil)
89-
_ tracing.ImageGenerationSpan = (*imageGenerationSpan)(nil)
90-
_ tracing.RerankSpan = (*rerankSpan)(nil)
49+
chatCompletionSpan = span[openai.ChatCompletionResponse, openai.ChatCompletionResponseChunk]
50+
completionSpan = span[openai.CompletionResponse, openai.CompletionResponse]
51+
embeddingsSpan = span[openai.EmbeddingResponse, struct{}]
52+
imageGenerationSpan = span[openaisdk.ImagesResponse, struct{}]
53+
rerankSpan = span[cohereschema.RerankV2Response, struct{}]
9154
)

0 commit comments

Comments
 (0)