unitel/traced_transport.go

101 lines
2.8 KiB
Go

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