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) { span := t.telemetry. 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()), ) defer span.End() ctx := span.Context() req = req.WithContext(ctx) if t.forwardTrace { t.telemetry.InjectIntoHeaders(ctx, req.Header) } for _, header := range t.tracedRequestHeaders { if v := req.Header.Get(header); v != "" { span.AddAttributes(attribute.String(fmt.Sprintf("http.request.header.%s", header), v)) } } resp, err := t.Transport.RoundTrip(req) if err != nil { if hub := sentry.GetHubFromContext(ctx); hub != nil { hub.CaptureException(err) } return resp, err } span. AddAttributes(semconv.HTTPResponseStatusCode(resp.StatusCode)). SetStatus(httpStatusToSpanStatus(resp.StatusCode, false), "") for _, header := range t.tracedResponseHeaders { if v := resp.Header.Get(header); v != "" { span.AddAttributes(attribute.String(fmt.Sprintf("http.response.header.%s", header), v)) } } return resp, err }