2024-07-23 17:46:15 +02:00
package unitel
import (
"fmt"
"net/http"
"github.com/getsentry/sentry-go"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace"
)
const httpClientTransportClientID = libBase + "#HTTPTansport"
type HTTPTransport struct {
telemetry * Telemetry
forwardTrace bool
tracedRequestHeaders [ ] string
tracedResponseHeaders [ ] string
Transport http . RoundTripper
tracer trace . Tracer
}
func ( t * Telemetry ) NewTracedTransport ( transport http . RoundTripper , forwardTrace bool , tracedRequestHeaders [ ] string , tracedResponseHeaders [ ] string ) * HTTPTransport {
return & HTTPTransport {
telemetry : t ,
forwardTrace : forwardTrace ,
tracedRequestHeaders : tracedRequestHeaders ,
tracedResponseHeaders : tracedResponseHeaders ,
Transport : transport ,
tracer : t . tracerProvider . Tracer ( httpClientTransportClientID , trace . WithInstrumentationVersion ( libVersion ) ) ,
}
}
func ( t * HTTPTransport ) RoundTrip ( req * http . Request ) ( * http . Response , error ) {
2024-08-10 01:51:58 +02:00
s := t . telemetry .
2024-07-23 17:46:15 +02:00
StartSpan ( req . Context ( ) , "http.client" , fmt . Sprintf ( "%s %s" , req . Method , req . URL ) , WithOtelOptions ( trace . WithSpanKind ( trace . SpanKindClient ) ) ) .
AddAttributes (
semconv . HTTPRequestMethodKey . String ( req . Method ) ,
semconv . URLFull ( req . URL . String ( ) ) ,
)
2024-08-10 01:51:58 +02:00
defer s . End ( )
ctx := s . Context ( )
2024-07-23 17:46:15 +02:00
req = req . WithContext ( ctx )
if t . forwardTrace {
t . telemetry . InjectIntoHeaders ( ctx , req . Header )
}
for _ , header := range t . tracedRequestHeaders {
2024-08-10 01:51:58 +02:00
vv := req . Header . Values ( header )
for i , v := range vv {
s . AddAttributes ( attribute . String ( formatHeaderAttribute ( "http.request" , header , vv , i ) , v ) )
2024-07-23 17:46:15 +02:00
}
}
resp , err := t . Transport . RoundTrip ( req )
if err != nil {
2024-08-10 01:51:58 +02:00
s . CaptureBreadcrumb ( SeverityError , BreadcrumbTypeHTTP , BreadcrumbCatagoryHTTP , fmt . Sprintf ( "Failed to send request to %s: %v" , req . URL . String ( ) , err ) , map [ string ] any {
"url" : req . URL . String ( ) ,
"method" : req . Method ,
} )
2024-07-23 17:46:15 +02:00
if hub := sentry . GetHubFromContext ( ctx ) ; hub != nil {
hub . CaptureException ( err )
}
return resp , err
}
2024-08-10 01:51:58 +02:00
{
severity := SeverityDebug
if resp . StatusCode < http . StatusBadRequest {
severity = SeverityInfo
} else if resp . StatusCode < http . StatusInternalServerError {
severity = SeverityError
} else {
severity = SeverityError
}
s . CaptureBreadcrumb ( severity , BreadcrumbTypeHTTP , BreadcrumbCatagoryHTTP , req . URL . String ( ) , map [ string ] any {
"url" : req . URL . String ( ) ,
"method" : req . Method ,
"status" : resp . StatusCode ,
} )
}
s .
2024-07-23 17:46:15 +02:00
AddAttributes ( semconv . HTTPResponseStatusCode ( resp . StatusCode ) ) .
SetStatus ( httpStatusToSpanStatus ( resp . StatusCode , false ) , "" )
for _ , header := range t . tracedResponseHeaders {
2024-08-10 01:51:58 +02:00
vv := resp . Header . Values ( header )
for i , v := range vv {
s . AddAttributes ( attribute . String ( formatHeaderAttribute ( "http.response" , header , vv , i ) , v ) )
2024-07-23 17:46:15 +02:00
}
}
return resp , err
}