Repository navigation
Emit OpenTelemetry semantic conventions on HTTP spans - #12765
zacharycmontoya wants to merge 22 commits into
Conversation
4930519 to
b4d1988
Compare
f6f083f to
1f7dfff
Compare
🟢 Java Benchmark SLOs — All performance SLOs passed
PR vs. master results
Commit: Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion. |
4891a63 to
8cfde98
Compare
e49a183 to
44e132c
Compare
06fde25 to
4788421
Compare
984c8d3 to
f5b4d45
Compare
6906acf to
ed69f54
Compare
| public static final String PATHWAY_HASH = "pathway.hash"; | ||
|
|
||
| public static final String HTTP_QUERY = "http.query.string"; | ||
| public static final String HTTP_QUERY_OTEL_NAME = "url.query"; |
There was a problem hiding this comment.
Could this live in KnownTags instead of DDTags? dd-trace-api is the customer-facing jar, so a public constant here becomes a permanent API contract. Customers can compile against it, and removing or renaming it later is a breaking change for them.
The registry already generates KnownTags.URL_QUERY_NAME / URL_QUERY_ID for this tag (internal-api). That covers the three main-code uses: HttpServerDecorator, QueryObfuscator and LambdaAppSecHandler. The ID form also fits the move to ID-based setters you made elsewhere in this PR.
Written by Claude, reviewed by @dougqh
There was a problem hiding this comment.
I removed DDTags.HTTP_QUERY_OTEL_NAME and replaced all usages to KnownTags.URL_QUERY_NAME in 18c7ce9
There was a problem hiding this comment.
OpenTelemetry HTTP semantics suppresses IAST missing-HSTS detection for eligible HTTPS responses. The shim also introduces attribute-ordering and null-name regressions.
🤖 Bits Code Review · Commit 8a835c3
- Http client error status codes default to 400-600 (instead of 400-500) - The environment variable DD_TRACE_OTEL_SEMANTICS_ENABLED automatically configures the following - OTEL_TRACES_EXPORTER=otlp - DD_WRITER_TYPE=OtlpWriter - DD_TRACE_SPAN_ATTRIBUTE_SCHEMA=v0 - DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=false
http:
- http.request.method_original (OTel)
- server.address (OTel)
- server.port (OTel)
http.server:
- url.path (OTel)
- url.query (OTel)
- url.scheme (OTel)
mixins:
peer:
tags:
- network.peer.address (OTel)
- peer.port (DD) => network.peer.port (OTel)
Map peer port to the OTel network attribute
Fixup http tag conventions. Squash so we can edit the message
- Apache HTTP client - Apache HTTP Async Client - Google HTTP Client - HttpURLConnection - JAX-RS Client - OkHttp - Play WSClient
- Akka-Http Server - JAX-RS Server - Jersey Server - Jetty - Netty HTTP server - Servlet - Play HTTP server - Ratpack HTTP server - Spring MVC - Spring WebFlux - Tomcat - Undertow - Vert.x
- Restore IP tags collection so it is opt-in. The DD->OTel tag mapping remains - Restore query tags collection so it honors the user's query tag opt-out - Improve OtelHttpSemantics.parsePort performance (especially since this can be influenced by a user) - Stores the OTel http client span's "url.full" URL in a lazy wrapper so redaction and query removal only occur at export time
…t span-kind-neutral
…r.port and server.address while keeping the span direction relationships correct HTTP server spans: - http.server: restore "http.hostname" => OTel "server.address" - http.server: add standalone (OTel-only) "server.port" HTTP client spans: - outbound_peer: restore "peer.hostname" => OTel "server.address" - outbound_peer: restore "peer.port" => OTel "server.port"
… DDTags.HTTP_QUERY_OTEL_NAME, which mimics DDTags.HTTP_QUERY so we have one consistent tag name
…-in changes, including:
HttpDecoratorsOtelSemanticsForkedTest.java
- Elasticsearch and OpenSearch spans should be unchanged
- There must not be duplicate attributes for client destination ports (server.port)
- InferredProxySpan should record server.port=443 due to the default https scheme
- When OTel semantics are enabled, Forwarded-header extraction should be run and determine client span attributes, even if DD_TRACE_CLIENT_IP_ENABLED=false or AppSec+AI Guard are disabled
- When OTel semantics are enabled, url.full (OTel equivalent of http.url) decodes the query before storing and sending to QueryObfuscator.
OtelHttpSemanticsTest.java
- When OTel semantics are enabled, url.full (OTel equivalent of http.url) decodes the query before storing and sending to QueryObfuscator.
HttpClientPathMappingOtelSemanticsForkedTest.java
- TRACE_HTTP_CLIENT_PATH_RESOURCE_NAME_MAPPING takes precedence and replaces the http.route placeholder in the OTel HTTP server span name "{http.request.method} {http.route}"
LambdaHttpOtelSemanticsForkedTest.java & LambdaAppSecHandlerTest.java
- Lambda query tags should continue to be obfuscated
GatewayBridgeOtelSemanticsForkedTest.java
- API Security must continue to fall back to the http.url span attribute when the server span does not have an http.route span attribute
- QueryObfuscator: Obfuscate both the DD and OTel query string tags as a preventative measure to make sure we do not store an unobfuscated query string on a span. When OTel semantics mode is enabled, the OTel value will be take precedence as the final recorded value (the DD value will be discarded if present). - Ensure that we record the correct origin port when handling forwarded schemes
- Correct obfuscated-query expectations - Fix the IAST missing-HSTS detection by allowing it to also check the "url.scheme" OTel HTTP server tag to confirm HTTPS, since the "http.url" tag is only emitted with DD semantic conventions
8a835c3 to
fd65cad
Compare
- In the BaseDecorator.setPeerPort methods (used by both clients and servers), set the tag via the directionless KnownTags.PEER_PORT_ID key. - In HttpServerDecorator, strip the query and fragment from the URL before setting the OTel attribute "url.path". Also, set the OTel attribute "url.query" if a query string is present - In AxwayHTTPPluginDecorator make sure to honor the query opt-out before setting the OTel attribute "url.query"
…KnownTags.URL_QUERY_NAME (OTel "url.query") in its place
…the url-based tags on http clients and servers, for both Datadog and OTel semantics. Key details include: - HttpServerUrl is created as an abstract class to expose a consistent interface for accessing underlying URL facts from various request objects -- there is no equivalent for client spans as the logic is simple enough that operating on a URL object is sufficient - OtelServerUrl and DatadogServerUrl implement TagExtractor<HttpServerUrl> to provide the "OTEL_SEMANTICS branching" for populating http server span tags - DatadogClientUrl and OtelClientUrl implement TagExtractor<URI> to provide the "OTEL_SEMANTICS branching" for populating http client span tags - The host and hostPort calculations from OtelHttpSemantics.setServerAddressAndPort are migrated to HttpServerUrl.Origin.resolve - Additional logic from OtelHttpSemantics is ported to the new UrlExtractors, so a handful of tests in OtelHttpSemanticsTest.java are simply ported to HttpUrlExtractorsTest.java - HttpUrlExtractorsTest.java provides testing of the TagExtractor implementations
|
Update: I've responded to the highlighted bugs from human and automated code reviewers. I've also done one (AI-facilitated) pass to move much of the logic out of the decorators themselves and into TagExtractors -- and the existing tests provided confidence in the newly refactored logic. It's important that these tags can be used for tag-based sampling rules, so I think this TagExtractor implementation satisfies that while improving maintenance. How much more polish / refinement would you like to see on this PR? I think export-time tag extractors may be out of scope for this PR, but y'all are the experts here 😄 |
This comment has been minimized.
This comment has been minimized.
Preserve existing query concatenation for captured URLs with decoded path characters when OTel semantics are disabled. Restore port-based service splitting precedence and skip the OTel-only Host header lookup in that mode. Add regression coverage for all three issues. Each new regression failed before the fixes; all 102 selected query obfuscator and decorator tests now pass, including existing OTel and client path-mapping coverage.
Use string concatenation and trailing substrings when inserting or removing queries while retaining fragments. Verify query obfuscation, HTTP semantics helpers, URL extractors, and OTel decorators with their existing tests and formatting checks.
What Does This Do
This PR updates HTTP client and server spans produced by the shared automatic-instrumentation decorators so that their span names, attributes, and error handling follow the OpenTelemetry HTTP semantic conventions when
DD_TRACE_OTEL_SEMANTICS_ENABLED=true.Behavior remains unchanged when OpenTelemetry semantics are disabled.
The latest updates take a dependency on the latest tag registry work in #12731.
Implementation Details
Configuration
Enabling
DD_TRACE_OTEL_SEMANTICS_ENABLEDoverrides the effective values of the following settings:OTEL_TRACES_EXPORTER=otlpDD_WRITER_TYPE=OtlpWriterDD_TRACE_SPAN_ATTRIBUTE_SCHEMA=v0DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=falseDD_HTTP_CLIENT_ERROR_STATUSES=400-599(in line with the OpenTelemetry specification)HTTP client changes
When
DD_TRACE_OTEL_SEMANTICS_ENABLED=true:{method}instead of{method} {path}.HTTPas the span name, emit_OTHERashttp.request.method, and preserve the original method inhttp.request.method_original.url.fullinstead ofhttp.url, with credentials redacted and query parameters obfuscated.server.addressandserver.port, including default ports 80 and 443.error.typeto the status code unless a more specific error type already exists.HTTP server changes
When
DD_TRACE_OTEL_SEMANTICS_ENABLED=true:{method} {http.route}when a route is available, or{method}otherwise. Request paths and404are no longer used as naming fallbacks.HTTPas the span name, emit_OTHERashttp.request.method, and preserve the original method inhttp.request.method_original.url.scheme,url.path, and the obfuscatedurl.query, rather than a singularhttp.url.server.addressandserver.port, honoring forwarded protocol, host, and port headers.client.addressandnetwork.peer.address.error.typeto the status code unless a more specific error type already exists.url.pathwhen the legacyhttp.urlattribute is absentTest coverage
Unit and component tests
OtelHttpSemanticsTestcovers method normalization, URL credential redaction, query removal, fragment preservation, default ports, and error-type behavior.HttpDecoratorsOtelSemanticsForkedTestcovers client and server decorator output, route naming, status handling, forwarded origins, explicit forwarded ports, and IPv6 hosts.ConfigTestverifies the forced OpenTelemetry settings, calculated configuration values, and client error-status defaults.QueryObfuscatorTestverifies sanitized clienturl.fullreconstruction and server/client handling ofurl.query.HttpEndpointPostProcessorTestverifies endpoint discovery fromurl.path.KnownTagsTestandOtlpTraceJsonCollectorTestverify tag registration and the OpenTelemetry names emitted over OTLP.Instrumentation tests
The shared HTTP test suites run in a forked JVM with OpenTelemetry semantics enabled for:
HTTP clients:
HTTP servers:
System tests
This is being tested by this PR: DataDog/system-tests#7919 . Currently the only test skips across all web servers are for Akka and Play servers, where the
http.routeneeds to be set on the root span. I added this below as follow-up work so the majority of frameworks could be served here without being blocked.Motivation
When
DD_TRACE_OTEL_SEMANTICS_ENABLED=true, the Java tracer should produce HTTP spans that align with the OpenTelemetry semantic conventions instead of emitting a mixture of Datadog and OpenTelemetry naming and attributes. This lets users switch between OpenTelemetry and Datadog automatic instrumentation with reduced updates to dashboards, monitors, or downstream processing.Additional Notes
This PR is easiest to review commit-by-commit: configuration, tag registration, client behavior, server behavior, client integration coverage, and server integration coverage are separated into focused commits.
Related .NET implementations: HTTP client spans and HTTP server spans.
Follow-up work requires the following:
http.routeContributor Checklist
type:and (comp:orinst:) labels in addition to any other useful labelsclose,fix, or any linking keywords when referencing an issueUse
solvesinstead, and assign the PR milestone to the issueJira ticket(s): [https://datadoghq.atlassian.net/browse/APMAPI-2038], [https://datadoghq.atlassian.net/browse/APMAPI-2039]