88 "net/http"
99 "runtime/debug"
1010 "slices"
11- "strconv"
1211 "strings"
1312 "time"
1413
@@ -17,6 +16,7 @@ import (
1716 "go.opentelemetry.io/otel/codes"
1817 "go.opentelemetry.io/otel/metric"
1918 "go.opentelemetry.io/otel/propagation"
19+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
2020 "go.opentelemetry.io/otel/trace"
2121)
2222
@@ -102,41 +102,31 @@ func (tm *tracingMiddleware) ServeHTTP( //nolint:gocognit,cyclop,funlen,maintidx
102102 ctx := r .Context ()
103103 span := trace .SpanFromContext (ctx )
104104
105- hostName , rawPort , _ := strings .Cut (r .Host , ":" )
106- port := 80
105+ urlScheme := r .URL .Scheme
106+ if urlScheme == "" {
107+ urlScheme = "http"
108+ }
107109
108- if rawPort != "" {
109- p , err := strconv .Atoi (rawPort )
110- if err == nil {
111- port = p
112- }
113- } else if strings .HasPrefix (r .URL .Scheme , "https" ) {
110+ hostName , port , _ := SplitHostPort (r .Host )
111+
112+ switch {
113+ case port > 0 :
114+ case urlScheme == "https" :
114115 port = 443
116+ default :
117+ port = 80
115118 }
116119
117120 metricAttrs := []attribute.KeyValue {
118- attribute .String ("http.request.method" , r .Method ),
119- attribute .String ("url.scheme" , r .URL .Scheme ),
120- attribute .String ("server.address" , hostName ),
121- attribute .Int ("server.port" , port ),
121+ {
122+ Key : semconv .HTTPRequestMethodKey ,
123+ Value : attribute .StringValue (r .Method ),
124+ },
125+ semconv .URLScheme (urlScheme ),
126+ semconv .ServerAddress (hostName ),
127+ semconv .ServerPort (port ),
128+ semconv .ClientAddress (r .RemoteAddr ),
122129 }
123- requestPathAttr := attribute .String ("http.request.path" , r .URL .Path )
124-
125- if ! tm .Options .HighCardinalityMetricDisabled {
126- metricAttrs = append (metricAttrs , requestPathAttr )
127- }
128-
129- activeRequestsAttrSet := metric .WithAttributeSet (attribute .NewSet (metricAttrs ... ))
130-
131- tm .ActiveRequestsMetric .Add (ctx , 1 , activeRequestsAttrSet )
132-
133- metricAttrs = append (
134- metricAttrs ,
135- attribute .String (
136- "network.protocol.version" ,
137- fmt .Sprintf ("%d.%d" , r .ProtoMajor , r .ProtoMinor ),
138- ),
139- )
140130
141131 if ! slices .Contains (tm .Options .DebugPaths , strings .ToLower (r .URL .Path )) {
142132 ctx , span = tm .Exporters .Tracer .Start (
@@ -157,7 +147,37 @@ func (tm *tracingMiddleware) ServeHTTP( //nolint:gocognit,cyclop,funlen,maintidx
157147 // Add HTTP semantic attributes to the server span
158148 // See: https://opentelemetry.io/docs/specs/semconv/http/http-spans/#http-server-semantic-conventions
159149 span .SetAttributes (metricAttrs ... )
160- span .SetAttributes (requestPathAttr )
150+
151+ if ! tm .Options .HighCardinalityMetricDisabled {
152+ metricAttrs = append (metricAttrs , attribute .String ("http.request.path" , r .URL .Path ))
153+ }
154+
155+ activeRequestsAttrSet := metric .WithAttributeSet (attribute .NewSet (metricAttrs ... ))
156+
157+ tm .ActiveRequestsMetric .Add (ctx , 1 , activeRequestsAttrSet )
158+
159+ protocolAttr := semconv .NetworkProtocolVersion (fmt .Sprintf ("%d.%d" , r .ProtoMajor , r .ProtoMinor ))
160+
161+ metricAttrs = append (
162+ metricAttrs ,
163+ protocolAttr ,
164+ )
165+
166+ span .SetAttributes (
167+ protocolAttr ,
168+ semconv .URLFull (r .URL .String ()),
169+ semconv .UserAgentOriginal (r .UserAgent ()),
170+ )
171+
172+ peer , peerPort , _ := SplitHostPort (r .RemoteAddr )
173+
174+ if peer != "" {
175+ span .SetAttributes (semconv .NetworkPeerAddress (peer ))
176+
177+ if peerPort > 0 {
178+ span .SetAttributes (semconv .NetworkPeerPort (peerPort ))
179+ }
180+ }
161181
162182 requestBodySize := r .ContentLength
163183 requestLogHeaders := NewTelemetryHeaders (r .Header , tm .Options .AllowedRequestHeaders ... )
@@ -198,12 +218,10 @@ func (tm *tracingMiddleware) ServeHTTP( //nolint:gocognit,cyclop,funlen,maintidx
198218 activeRequestsAttrSet ,
199219 )
200220
201- statusCodeAttr := attribute .Int (
202- "http.response.status_code" ,
203- statusCode ,
204- )
205- latency := time .Since (start ).Seconds ()
221+ statusCodeAttr := semconv .HTTPResponseStatusCode (statusCode )
222+ span .SetAttributes (statusCodeAttr )
206223
224+ latency := time .Since (start ).Seconds ()
207225 responseLogData ["status" ] = statusCode
208226
209227 logAttrs := []any {
@@ -215,7 +233,7 @@ func (tm *tracingMiddleware) ServeHTTP( //nolint:gocognit,cyclop,funlen,maintidx
215233 if err != nil {
216234 stack := string (debug .Stack ())
217235 logAttrs = append (logAttrs , slog .Any ("error" , err ), slog .String ("stacktrace" , stack ))
218- span .SetAttributes (statusCodeAttr , attribute . String ( "stacktrace" , stack ))
236+ span .SetAttributes (semconv . ExceptionStacktrace ( stack ))
219237 }
220238
221239 metricAttrs = append (metricAttrs , statusCodeAttr )
@@ -265,7 +283,7 @@ func (tm *tracingMiddleware) ServeHTTP( //nolint:gocognit,cyclop,funlen,maintidx
265283
266284 if requestBodySize > 0 {
267285 requestLogData ["size" ] = requestBodySize
268- span .SetAttributes (attribute . Int64 ( "http.request.body.size" , requestBodySize ))
286+ span .SetAttributes (semconv . HTTPRequestBodySize ( int ( requestBodySize ) ))
269287 }
270288
271289 defer func () {
@@ -284,9 +302,9 @@ func (tm *tracingMiddleware) ServeHTTP( //nolint:gocognit,cyclop,funlen,maintidx
284302
285303 errBytes , jsonErr := json .Marshal (err )
286304 if jsonErr != nil {
287- span .SetAttributes (attribute .String ("error" , fmt .Sprintf ("%v" , err )))
305+ span .SetAttributes (attribute .String ("exception. error" , fmt .Sprintf ("%v" , err )))
288306 } else {
289- span .SetAttributes (attribute .String ("error" , string (errBytes )))
307+ span .SetAttributes (attribute .String ("exception. error" , string (errBytes )))
290308 }
291309 }
292310 }()
@@ -300,7 +318,7 @@ func (tm *tracingMiddleware) ServeHTTP( //nolint:gocognit,cyclop,funlen,maintidx
300318 responseLogData ["size" ] = ww .BytesWritten ()
301319 responseLogData ["headers" ] = responseLogHeaders
302320
303- span .SetAttributes (attribute . Int ( "http.response.body.size" , ww .BytesWritten ()))
321+ span .SetAttributes (semconv . HTTPResponseBodySize ( ww .BytesWritten ()))
304322 SetSpanHeaderAttributes (span , "http.response.header" , responseLogHeaders )
305323
306324 // skip printing very large responses.
0 commit comments