Skip to content

fix: name outbound HTTP client spans METHOD host/path for Datadog - #792

Merged
shyim merged 2 commits into
mainfrom
cursor/http-client-span-names-e202
Aug 12, 2026
Merged

fix: name outbound HTTP client spans METHOD host/path for Datadog#792
shyim merged 2 commits into
mainfrom
cursor/http-client-span-names-e202

Conversation

@shyim

@shyim shyim commented Aug 12, 2026

Copy link
Copy Markdown
Member

Problem

In Datadog production, ~520k+ worker spans / 6h collapse to resource_name:GET (and similarly bare POST). Useful low-cardinality data is already on the spans as http.host + http.path_group (e.g. host api.shopware.com, path /pluginStore/pluginsByName), but Datadog’s resource name comes from the span name — and otelhttp’s default client formatter is effectively just the HTTP method.

Root cause

httputil.wrapTransport wrapped outbound clients with otelhttp.NewTransport(base) and no WithSpanNameFormatter. The library default names client spans from the method alone (HTTP GET → Datadog resource GET).

Separately, the Shopware Admin client started a manual Internal span named method+" "+path around each request. That duplicated the otelhttp client span and still showed up poorly in Datadog as a bare GET resource.

Fix

  • Add httputil.ClientSpanName and wire it via otelhttp.WithSpanNameFormatter so outbound client spans are named METHOD host/path
    • Strips query strings (tokens / shop IDs in query never enter the resource)
    • Keeps only known shared hosts literal (api.shopware.com, releases.shopware.com, store.shopware.com, raw.githubusercontent.com); other peers (per-shop Admin API, SSO IdPs, etc.) collapse to {host}
    • Replaces UUID / numeric / long-hex path segments with {id}
    • Falls back to METHOD /path when host is missing; empty path becomes /
  • Remove the redundant Shopware Admin Internal HTTP span so each request has one clear otelhttp client span
  • Unit-test the formatter (shared host, tenant host collapse, query strip, empty path, UUID/numeric/hex path grouping)

server.address is already set by otelhttp’s client semconv — no extra attributes added.

No HTTP behavior, timeout, SSRF, or User-Agent changes. No metrics-exporter work (separate task). DB span naming from #791 is untouched.

Open in Web Open in Cursor 

otelhttp's default client formatter collapses outbound spans to bare GET/POST
in Datadog. Format span names as METHOD host/path (no query), and drop the
Shopware Admin client's redundant Internal HTTP spans so each request has one
clear client span.

Co-authored-by: Soner <github@shyim.de>
@shyim
shyim marked this pull request as ready for review August 12, 2026 06:14
@greptile-apps

greptile-apps Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds a shared outbound HTTP span-name formatter and removes the redundant manual Shopware request span.

  • Names otelhttp client spans using the HTTP method and a grouped host/path.
  • Collapses tenant hosts and selected identifier-shaped path segments.
  • Removes duplicate internal tracing from Shopware Admin API requests.
  • Adds formatter coverage for host, path, query, port, and identifier handling.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains.

No blocking failure remains.

Important Files Changed

Filename Overview
api/internal/httputil/client.go Wires the shared span-name formatter into every wrapped otelhttp transport.
api/internal/httputil/client_span_name.go Adds host/path normalization and identifier grouping for outbound span names.
api/internal/httputil/client_span_name_test.go Covers the formatter’s intended host, query, path, port, and identifier behavior.
api/internal/shopware/client.go Removes the redundant manual span while preserving HTTP request and error behavior.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant HTTP as httputil client
  participant OTel as otelhttp transport
  participant Peer as Outbound service
  Caller->>HTTP: Do(request)
  HTTP->>OTel: RoundTrip with User-Agent
  OTel->>OTel: ClientSpanName(method, request)
  OTel->>Peer: Send request
  Peer-->>OTel: Response
  OTel-->>Caller: Response with one client span
Loading

Reviews (2): Last reviewed commit: "fix: bound HTTP client span resource car..." | Re-trigger Greptile

Comment thread api/internal/httputil/client_span_name.go Outdated
Collapse tenant/peer hosts to {host} (keep known shared hosts literal) and
replace UUID/numeric/long-hex path segments with {id} so Datadog resources
stay low-cardinality.

Co-authored-by: Soner <github@shyim.de>
@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

Addressed Greptile’s cardinality note in 94bc08b: shared hosts stay literal; tenant/peer hosts collapse to {host}; UUID/numeric/long-hex path segments become {id}. Review thread resolved.

@shyim
shyim merged commit c77b980 into main Aug 12, 2026
6 checks passed
@shyim
shyim deleted the cursor/http-client-span-names-e202 branch August 12, 2026 06:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants