11package otel
22
33import (
4- "context"
54 "fmt"
65 "net/http"
76
8- "github.com/go-chi/chi/v5"
9- otelapi "go.opentelemetry.io/otel"
107 "go.opentelemetry.io/otel/attribute"
11- "go.opentelemetry.io/otel/codes"
128 sdktrace "go.opentelemetry.io/otel/sdk/trace"
139 "go.opentelemetry.io/otel/trace"
1410)
@@ -26,9 +22,6 @@ func newSuccessfulGETSampler(ratio float64) sdktrace.Sampler {
2622}
2723
2824func (s * successfulGETSampler ) ShouldSample (params sdktrace.SamplingParameters ) sdktrace.SamplingResult {
29- if attrValueFromAttrs (params .Attributes , "sampled_from" ) != "" {
30- return sdktrace.SamplingResult {Decision : sdktrace .RecordAndSample }
31- }
3225 if params .Kind == trace .SpanKindServer && httpMethodFromAttrs (params .Attributes ) == http .MethodGet {
3326 return s .getSampler .ShouldSample (params )
3427 }
@@ -40,95 +33,11 @@ func (s *successfulGETSampler) Description() string {
4033}
4134
4235func httpMethodFromAttrs (attrs []attribute.KeyValue ) string {
43- return attrValueFromAttrs (attrs , "http.method" , "http.request.method" )
44- }
45-
46- func attrValueFromAttrs (attrs []attribute.KeyValue , keys ... string ) string {
4736 for _ , attr := range attrs {
48- for _ , key := range keys {
49- if string (attr .Key ) == key {
50- return attr .Value .AsString ()
51- }
37+ switch string (attr .Key ) {
38+ case "http.method" , "http.request.method" :
39+ return attr .Value .AsString ()
5240 }
5341 }
5442 return ""
5543}
56-
57- type statusCapturingResponseWriter struct {
58- http.ResponseWriter
59- status int
60- wrote bool
61- }
62-
63- func (w * statusCapturingResponseWriter ) WriteHeader (status int ) {
64- if w .wrote {
65- return
66- }
67- w .wrote = true
68- w .status = status
69- w .ResponseWriter .WriteHeader (status )
70- }
71-
72- func (w * statusCapturingResponseWriter ) Write (body []byte ) (int , error ) {
73- if ! w .wrote {
74- w .WriteHeader (http .StatusOK )
75- }
76- return w .ResponseWriter .Write (body )
77- }
78-
79- // NewSuccessfulGETErrorTraceMiddleware records a compact fallback span for GET
80- // requests that were sampled out but still returned an error status.
81- func NewSuccessfulGETErrorTraceMiddleware (serviceName string ) func (http.Handler ) http.Handler {
82- tracer := otelapi .Tracer (serviceName + "/http" )
83-
84- return func (next http.Handler ) http.Handler {
85- return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
86- if r .Method != http .MethodGet {
87- next .ServeHTTP (w , r )
88- return
89- }
90-
91- rw := & statusCapturingResponseWriter {
92- ResponseWriter : w ,
93- status : http .StatusOK ,
94- }
95- next .ServeHTTP (rw , r )
96-
97- if rw .status < http .StatusBadRequest {
98- return
99- }
100-
101- spanCtx := trace .SpanContextFromContext (r .Context ())
102- if spanCtx .IsValid () && spanCtx .IsSampled () {
103- return
104- }
105-
106- route := ""
107- if routeCtx := chi .RouteContext (r .Context ()); routeCtx != nil {
108- route = routeCtx .RoutePattern ()
109- }
110- if route == "" {
111- route = r .URL .Path
112- }
113- if route == "" {
114- route = "/"
115- }
116-
117- _ , span := tracer .Start (
118- context .Background (),
119- route ,
120- trace .WithNewRoot (),
121- trace .WithSpanKind (trace .SpanKindServer ),
122- trace .WithAttributes (
123- attribute .String ("http.method" , r .Method ),
124- attribute .String ("http.route" , route ),
125- attribute .String ("url.path" , r .URL .Path ),
126- attribute .Int ("http.status_code" , rw .status ),
127- attribute .String ("sampled_from" , "unsampled_get_error" ),
128- ),
129- )
130- span .SetStatus (codes .Error , http .StatusText (rw .status ))
131- span .End ()
132- })
133- }
134- }
0 commit comments