diff --git a/http/transport/tracing_round_tripper.go b/http/transport/tracing_round_tripper.go index def73d2f..2f2d21f2 100755 --- a/http/transport/tracing_round_tripper.go +++ b/http/transport/tracing_round_tripper.go @@ -3,12 +3,15 @@ package transport import ( - "fmt" "net/http" + "strings" "github.com/getsentry/sentry-go" ) +// The identifier of the HTTP SDK. +const sdkIdentifier = "sentry.go.http" + // TracingRoundTripper implements a chainable round tripper for tracing type TracingRoundTripper struct { transport http.RoundTripper @@ -28,37 +31,60 @@ func (l *TracingRoundTripper) SetTransport(rt http.RoundTripper) { func (l *TracingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { ctx := req.Context() - hub := sentry.GetHubFromContext(ctx) + hub := sentry.GetHubFromContext(req.Context()) if hub == nil { - // Check the concurrency guide for more details: https://docs.sentry.io/platforms/go/concurrency/ hub = sentry.CurrentHub().Clone() ctx = sentry.SetHubOnContext(ctx, hub) } + if client := hub.Client(); client != nil { + client.SetSDKIdentifier(sdkIdentifier) + } + options := []sentry.SpanOption{ - // Set the OP based on values from https://develop.sentry.dev/sdk/performance/span-operations/ + sentry.ContinueTrace(hub, req.Header.Get(sentry.SentryTraceHeader), req.Header.Get(sentry.SentryBaggageHeader)), sentry.WithOpName("http.client"), - sentry.ContinueFromRequest(req), sentry.WithTransactionSource(sentry.SourceURL), + sentry.WithSpanOrigin(sentry.SpanOriginStdLib), } - span := sentry.StartTransaction(ctx, fmt.Sprintf("%s %s", req.Method, req.URL.Path), options...) - defer span.Finish() + transaction := sentry.StartTransaction(ctx, + getHTTPSpanName(req), + options..., + ) + transaction.SetData("http.request.method", req.Method) - ctx = span.Context() + defer transaction.Finish() + + ctx = transaction.Context() resp, err := l.Transport().RoundTrip(req.WithContext(ctx)) attempt := attemptFromCtx(ctx) if attempt > 0 { - span.SetData("attempt", int(attempt)) + transaction.SetData("http.request.attempt", int(attempt)) } if err != nil { - span.SetData("error", err) + transaction.SetData("http.response.error", err) return nil, err } - span.SetData("code", resp.StatusCode) + transaction.SetData("http.response.status_code", resp.StatusCode) return resp, nil } + +// getHTTPSpanName grab needed fields from *http.Request to generate a span name for `http.server` span op. +func getHTTPSpanName(r *http.Request) string { + if r.Pattern != "" { + // If value does not start with HTTP methods, add them. + // The method and the path should be separated by a space. + if parts := strings.SplitN(r.Pattern, " ", 2); len(parts) == 1 { + return r.Method + " " + r.Pattern + } + + return r.Pattern + } + + return r.Method + " " + r.URL.Path +}