@@ -3,11 +3,13 @@ package otelopenai
33import (
44 "bytes"
55 "encoding/json"
6+ "fmt"
67 "io"
78 "net/http"
89 "path"
910 "strings"
1011
12+ "github.com/0xdeafcafe/bloefish/libraries/langwatch"
1113 oaioption "github.com/openai/openai-go/option"
1214 "go.opentelemetry.io/otel"
1315 "go.opentelemetry.io/otel/attribute"
@@ -31,7 +33,7 @@ func Middleware(name string, opts ...Option) oaioption.Middleware {
3133 if cfg .tracerProvider == nil {
3234 cfg .tracerProvider = otel .GetTracerProvider ()
3335 }
34- tracer := cfg . tracerProvider .Tracer (
36+ tracer := langwatch .Tracer (
3537 tracerName ,
3638 oteltrace .WithInstrumentationVersion (instrumentationVersion ),
3739 oteltrace .WithSchemaURL (semconv .SchemaURL ),
@@ -50,7 +52,7 @@ func Middleware(name string, opts ...Option) oaioption.Middleware {
5052 semconv .HTTPRequestMethodKey .String (req .Method ),
5153 semconv .ServerAddressKey .String (req .URL .Hostname ()),
5254 semconv .URLPathKey .String (req .URL .Path ),
53- attributeGenAISystem .String (openAISystemValue ), // Defined in attributes.go
55+ attributeGenAISystem .String (openAISystemValue ),
5456 attributeGenAIOperation .String (operation ),
5557 ),
5658 oteltrace .WithSpanKind (oteltrace .SpanKindClient ),
@@ -62,17 +64,18 @@ func Middleware(name string, opts ...Option) oaioption.Middleware {
6264 if req .Body != nil && req .Body != http .NoBody {
6365 var errRead error
6466 reqBody , errRead = io .ReadAll (req .Body )
65- // Restore the body so the downstream handler can read it
67+ // Important!: We need to restore the body so the downstream handler can read it
6668 req .Body = io .NopCloser (bytes .NewBuffer (reqBody ))
6769 if errRead == nil {
6870 if cfg .recordInput {
6971 // TODO(afr): Adjust this based on the operation
70- span .SetAttributes ( attributeLangwatchInputValue . String ( string ( reqBody )) )
72+ span .RecordInput ( req . Body )
7173 }
7274 var reqData jsonData
7375 if err := json .Unmarshal (reqBody , & reqData ); err == nil {
7476 if model , ok := getString (reqData , "model" ); ok {
75- span .SetAttributes (attributeGenAIRequestModel .String (model ))
77+ span .SetResponseModel (model )
78+ span .SetName (fmt .Sprintf ("openai.%s.%s" , operation , model ))
7679 }
7780 if temp , ok := getFloat64 (reqData , "temperature" ); ok {
7881 span .SetAttributes (attributeGenAIRequestTemperature .Float64 (temp ))
@@ -100,8 +103,7 @@ func Middleware(name string, opts ...Option) oaioption.Middleware {
100103 span .AddEvent ("Failed to parse OpenAI request body JSON" , oteltrace .WithAttributes (attribute .String ("error" , err .Error ())))
101104 }
102105 } else {
103- span .SetStatus (codes .Error , "failed to read request body" )
104- span .RecordError (errRead )
106+ span .AddEvent ("Failed to read OpenAI request body" , oteltrace .WithAttributes (attribute .String ("error" , errRead .Error ())))
105107 }
106108 }
107109
@@ -118,8 +120,8 @@ func Middleware(name string, opts ...Option) oaioption.Middleware {
118120 if resp != nil {
119121 span .SetAttributes (semconv .HTTPResponseStatusCodeKey .Int (resp .StatusCode ))
120122 if resp .StatusCode >= 400 {
123+ // TODO(afr): Should we read the error here? I think so
121124 span .SetStatus (codes .Error , http .StatusText (resp .StatusCode ))
122- // Potentially read error body here if needed, even for non-JSON
123125 } else {
124126 span .SetStatus (codes .Ok , "" )
125127 }
@@ -140,7 +142,7 @@ func Middleware(name string, opts ...Option) oaioption.Middleware {
140142 contentType := resp .Header .Get ("Content-Type" )
141143 if strings .HasPrefix (contentType , "application/json" ) {
142144 if cfg .recordOutput {
143- span .SetAttributes ( attributeLangwatchOutputValue . String ( string ( respBody )) )
145+ span .RecordOutput ( respBody )
144146 }
145147 var respData jsonData
146148 if err := json .Unmarshal (respBody , & respData ); err == nil {
0 commit comments