feat(otel): system-tests for HTTP OpenTelemetry semantic conventions (DD_TRACE_OTEL_SEMANTICS_ENABLED)#7139
Draft
khanayan123 wants to merge 9 commits into
Draft
feat(otel): system-tests for HTTP OpenTelemetry semantic conventions (DD_TRACE_OTEL_SEMANTICS_ENABLED)#7139khanayan123 wants to merge 9 commits into
khanayan123 wants to merge 9 commits into
Conversation
…tests Add an end-to-end scenario and cross-language tests asserting that HTTP server and client spans honor the OpenTelemetry HTTP semantic conventions when DD_TRACE_OTEL_SEMANTICS_ENABLED=true. - OTEL_SEMANTICS EndToEndScenario sets DD_TRACE_OTEL_SEMANTICS_ENABLED=true - tests/test_otel_http_semantics.py validates the OTel attribute names are emitted and the legacy Datadog names are absent (the flag is mutually exclusive), for both server (url.path/url.scheme) and client (url.full, no url.path/url.query) spans - manifests: dotnet and java left active; other languages marked missing_feature until their tracers ship the flag Validates DataDog/dd-trace-dotnet#8791 and DataDog/dd-trace-java#11652. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
|
|
|
…ked vs tracer PRs Verified assertions against the actual implementations in dd-trace-dotnet#8791 (SpanMetadataOTelRules.cs, HttpOtelHelper.cs) and dd-trace-java#11652 (OtelHttpSemantics.java): - server url.query test (was http.query.string) — present when a query is sent - server error.type test on 5xx — set to the status-code string. java emits this; dd-trace-dotnet does not map error status to error.type, so it is gated missing_feature for dotnet (per-language manifest) - server client.address / network.peer.address validated only when present (Recommended-level), with a clarifying note on the requirement-level approach - left client server.port as an if-present check: dotnet omits default ports and java falls back to 80/443, so always-present would be wrong Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Round out the OTel HTTP semantic-convention coverage:
- server http.route: asserts the low-cardinality route template (not the raw
URL path), using the established /sample_rate_route/{i} endpoint. http.route
is unchanged by the feature but the spec requires it be a template.
- client error.type on a 5xx distant call (java emits; gated missing_feature
for dd-trace-dotnet, which does not map error status to error.type).
- network.peer.address / network.peer.port validated when present (Recommended)
on both server and client spans.
15 tests total (9 server, 6 client). ruff + manifest validator + meta-tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s-meta ports
Verified the resource/span-name behavior across all three tracer PRs
(dd-trace-dotnet#8791, dd-trace-java#11652, dd-trace-js#8933):
- test_resource_name: the server entry-span resource is the low-cardinality
"{method} {http.route}", never the raw URL path. java rewrites the resource to
this form; dotnet and nodejs leave the already-compliant DD resource unchanged.
Expected value derived from the same span's http.route so per-tracer template
syntax ({i} / {i:int} / :i) cancels out. Gated on the root web span so the java
spring.handler child (also type==web) is excluded.
- nodejs activated: dd-trace-js#8933 implements the full feature including
error.type, so its missing_feature gates are removed (now dotnet+java+nodejs).
- numeric attributes (server.port, network.peer.port) read from meta OR metrics:
dd-trace-js routes numerics into metrics, java/dotnet keep them in meta strings.
16 tests total. ruff + manifest validator + meta-tests green; collect-only passes
for both dotnet and nodejs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ation)
Principle: the system-tests are the authoritative harness — assert exactly what
the OTel HTTP spec requires and record tracer divergences as manifest gates
rather than weakening the assertions. Behavior verified against all three PRs
(dd-trace-dotnet#8791, dd-trace-java#11652, dd-trace-js#8933).
- client server.port: now asserted present (Required per spec; the distant-call
URL uses a non-default port so every compliant tracer emits it).
- test_no_route_resource: resource is the bare "{method}", never the URL path.
java + js compliant; dd-trace-dotnet keeps the path -> bug gate.
- test_request_method_normalization: unknown method -> http.request.method=_OTHER
+ http.request.method_original. Only java implements it; dotnet + js -> missing_feature.
- test_other_method_span_name: per spec the _OTHER resource must be "HTTP". No
tracer complies yet (java keeps raw method -> bug; dotnet/js -> missing_feature) —
kept as a fully-gated spec anchor that activates as tracers comply.
19 tests total. ruff + manifest validator + meta-tests green; collect-only passes
for dotnet, java, and nodejs.
Note: the unknown-method tests are the first in system-tests to send a non-standard
verb; verified by static analysis, pending a live OTEL_SEMANTICS run to confirm each
weblog produces a span for an unknown method (else gate that language incomplete_test_app).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
link04
added a commit
to DataDog/dd-trace-java
that referenced
this pull request
Jun 16, 2026
Per the OTel HTTP spec, when http.request.method resolves to _OTHER the span name's method component MUST be the literal "HTTP", not the raw verb. Add OtelHttpSemantics.spanNameMethod() and use it when naming server and client spans, while the http.request.method=_OTHER tag and http.request.method_original keep the raw value. Verified against system-tests OTEL_SEMANTICS (DataDog/system-tests#7139): the previously-gated Test_HttpServerOtelSemantics::test_other_method_span_name now passes (19/19). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…query-drop) Running OTEL_SEMANTICS against dd-trace-js#8933 locally revealed that the express weblog's /make_distant_call drops the target URL's query string, so a distant call to /status?code=500 actually hit /status (no code) and returned 400. The PR was correct (it set error.type="400"); the test was hardcoded to "500". Fix: distant-call an unmatched route (/no_such_route_xyz -> 404, no query needed) and assert error.type equals the span's own status code for any 4xx/5xx client response. Verified end-to-end vs dd-trace-js#8933 (nodejs@6.0.0-pre, express4): 17 passed, 2 xfailed (the _OTHER method-normalization tests, correctly gated missing_feature for nodejs), 0 failed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…crash
Two things:
1. OTEL_SEMANTICS_OTLP scenario — the OTel-semantics flag plus the APM_TRACING_OTLP
exporter env, so HTTP attributes are validated as *typed* OpenTelemetry values
(http.response.status_code / server.port as int; method / url.* / server.address /
user_agent.original as string) which the Datadog agent protocol cannot represent.
- tests/test_otel_http_semantics_otlp.py reads typed attributes via
interfaces.open_telemetry.get_otel_spans().
- utils/proxy/traces/otlp_v1.py: coerce OTLP intValue to a Python int so the type is
comparable regardless of JSON vs binary OTLP encoding.
- Verified e2e vs dd-trace-js#8933 (nodejs@6.0.0-pre): server+client names and types
pass; status_code-is-int xfails -> the PR emits http.response.status_code as a STRING
instead of an int (finding for the JS PR; the DD-agent path masks this).
- Gated the new classes missing_feature for languages where the feature is unimplemented
(python/golang/php/ruby/rust) or OTLP is unverified (dotnet/java); nodejs active.
2. Fix the "Test the test" CI crash: two manifest entries used `bug (<text>)` with a
non-JIRA reason. add_pytest_marker -> _ensure_jira_ticket_as_reason calls pytest.exit
during collection, which aborted the whole TEST_THE_TEST run (surfacing as an unrelated
test_library_conf remote-config INTERNALERROR). Changed them to `missing_feature`
(dotnet test_no_route_resource, java test_other_method_span_name). TEST_THE_TEST now
collects and deselects correctly (288 passed, 2311 deselected locally).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
link04
added a commit
to DataDog/dd-trace-java
that referenced
this pull request
Jun 16, 2026
Addresses the repo policy (no new Spock tests): the new OTel semantic-convention logic now lives in the OtelHttpSemantics helper, covered by a JUnit5 OtelHttpSemanticsTest (method _OTHER normalization, "HTTP" span-name, url.full credential redaction, query/fragment stripping, default server.port, error.type). The Spock decorator test files are restored to their upstream state. The decorator flag-gating integration is covered end-to-end by system-tests (DataDog/system-tests#7139) and the serialized status-key rename by DDSpanContextTest. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ate OTLP int tests The HTTP tracer PR now emits http.response.status_code as a numeric metric (int-typed, so OTLP serializes it as intValue) rather than a meta string — which is what the spec requires. Update the DD-agent server/client test_response_status_code and test_error_type to read the value via the existing _numeric_tag(meta-or-metrics) helper instead of meta only, and compare error.type against the stringified int. Now that the tracer emits an int, the OTLP test_status_code_is_int checks pass, so drop their nodejs missing_feature gates. Verified by replay against the HTTP+DB tracer build: OTEL_SEMANTICS 19 passed, 2 xfailed (method-normalization gates) OTEL_SEMANTICS_OTLP 8 passed Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…elopment dd-trace-dotnet branches merging
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
system-tests coverage for the opt-in OpenTelemetry HTTP semantic-conventions feature (
DD_TRACE_OTEL_SEMANTICS_ENABLED=true), across two export paths.Spec: https://opentelemetry.io/docs/specs/semconv/http/http-spans/
Principle: the system-tests are the authoritative harness — assertions encode exactly what the spec requires; where a tracer diverges it's recorded as a per-language manifest gate.
Validates three tracer PRs, cross-checked against their actual code and run end-to-end against dd-trace-js#8933:
Two scenarios
OTEL_SEMANTICShttp.route, resource form,error.type— the primary customer pathOTEL_SEMANTICS_OTLPstatus_code/server.port= int;method/url.*/server.address/user_agent.original= string) — only possible on OTLP; the agent protocol flattens everything to meta-strings/metrics-numberstests/test_otel_http_semantics.py(DD-agent) andtests/test_otel_http_semantics_otlp.py(OTLP, viainterfaces.open_telemetry.get_otel_spans()). A one-line proxy fix (otlp_v1.py) coerces OTLPintValueto a Python int so types are comparable across JSON/binary encodings.Findings surfaced (for the tracer teams)
http.response.status_codeas a string; per semconv it must be an int. Caught byOTEL_SEMANTICS_OTLP(the DD-agent path masks it). Also: no unknown-method_OTHERnormalization (and Node's HTTP parser rejects unknown methods at 400 with no span, so it isn't end-to-end testable on Node — gatedincomplete).{method}); no_OTHERnormalization; noerror.typemapping._OTHER(should beHTTP).E2E verification (dd-trace-js#8933, express4)
OTEL_SEMANTICS: 17 passed, 2 xfailed (the_OTHERcases, gated).OTEL_SEMANTICS_OTLP: 4 passed, 2 xfailed (thestatus_code-is-int finding, gated).CI fix included
The "Test the test" job was failing because two manifest entries used
bug (<free text>)—bugdeclarations require a JIRA ticket, so_ensure_jira_ticket_as_reasoncalledpytest.exit()during collection and aborted the whole run (surfacing as an unrelatedtest_library_confremote-configINTERNALERROR). Changed those two tomissing_feature.TEST_THE_TESTnow collects/deselects correctly (288 passed, 2311 deselected locally).Verification
ruffclean;Manifest.validate()passes;test_the_testmeta-tests pass; both scenarios collect + run e2e against the JS PR.🤖 Generated with Claude Code