Add a JSON schema for the /v1.0/traces endpoint (ETP/v1) - #7448
Draft
darccio wants to merge 4 commits into
Draft
Conversation
/v1.0/traces had no schema file, and SchemaValidator silently skips any endpoint whose /library/<path>-request.json is missing, so every ETP/v1 payload bypassed schema validation entirely. Describe the payload as deserialize_v1_trace produces it: payload metadata, chunks[], spans[], span_links[], span_events[], and the attributes object shared by all of them. The structural differences with v0.4/v0.5 are enforced: a single attributes object instead of meta/metrics, hex encoded string trace ids, boolean error, and integer span_kind. Also add a TEST_THE_TEST test that runs a full featured payload through the real deserializer and SchemaValidator: the schema is otherwise only exercised by APM_TRACING_EFFICIENT_PAYLOAD, which needs docker and a v1-capable tracer. Co-Authored-By: Claude <noreply@anthropic.com>
Contributor
|
|
|
…unk origin The new /v1.0/traces schema exposed a deserializer bug: _uncompress_keys never resolved integer string-table references for top-level fields (app_version, container_id, ...), and _uncompress_chunks only checked the origin ref-resolution condition under the spans branch, which is never true for the origin key itself. Tracers that stream these fields as string-table indices (e.g. golang, java native image) surfaced as schema errors like "3 is not of type 'string' on instance $.app_version". Co-Authored-By: Claude <noreply@anthropic.com>
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.
Motivation
/v1.0/traces(ETP/v1, "efficient trace payload") had no schema file undertests/schemas/utils/library/, which hadv0.1,v0.4,v0.5,v0.6andv0.7but nov1.0.SchemaValidator.get_errorsderives the schema id from the request path and returns no error atall when that file is missing:
So
Test_DdtraceSchemas::test_librarywas green on ETP/v1 payloads not because they were valid,but because nothing was ever checked. Every v1 payload bypassed schema validation entirely,
including the fields the v1 format changed — which is exactly where a tracer is most likely to
deviate.
Changes
tests/schemas/utils/library/v1.0/traces-request.json(new). No wiring code is needed: theschema id is derived from the path, so the file being present at the conventional location is
the wiring — same as every other trace endpoint. Conventions followed:
$idequal to the pathbelow
tests/schemas/utils(asserted by_get_schemas_store), the internaldefinitions+#/definitions/...style ofv0.7/config-request.json, and the per-fielddescriptions ofv0.6/stats-request.json.The schema describes the payload as
deserialize_v1_traceproduces it, which is the wholetracer payload and not a single trace: payload metadata →
chunks[]→spans[]→span_links[]/span_events[], plus oneattributesdefinition shared by all five levels.Worth noting for review, since it is easy to conflate the two: the top-level
spans/trace_id/priority/sampling_mechanismthattests/test_v1_payloads.pyasserts on liveon the chunk, because
DataDogLibraryTrace.from_v1is called once per chunk inutils/interfaces/_library/core.py:109.The structural v1-vs-v0.4/v0.5 differences are enforced rather than described:
meta+metricsattributesobjecttrace_id^0x[0-9A-F]{32}$(16 raw bytes, hex encoded by the deserializer)errorspan_kindmetaSpanKind)chunks[]requirestrace_id+spans, spans requirename(as v0.4 does), span links requiretrace_id+span_id, span events requirename+time_unix_nano. Well-known attributes aretyped where v1 post-processing guarantees a shape:
_dd.appsec.jsonobject,_dd.span_linksarray,
_dd.top_levelnumber.tests/test_the_test/test_deserializer.py— addedtest_deserialize_v1_trace_validates_against_schema: it runs a payload exercising everydocumented key through the real
deserialize_v1_traceand the realSchemaValidator, thenasserts that a v0.4-style integer
erroris reported as$.chunks[].spans[].error. Withoutit the schema would only ever run inside
APM_TRACING_EFFICIENT_PAYLOAD(docker + a v1-capabletracer);
TEST_THE_TESTruns on every PR.Verification
./format.sh --check: mypy (528 files),ruff format,ruff check, trailing whitespace allpass. yamllint and
utils/manifest/validate.pypass too (run separately — locally the scriptaborts earlier on a pre-existing
yamlfmtdisagreement aboutmanifests/python.yml, a filethis PR does not touch).
./run.sh TEST_THE_TEST: 366 passed. The only 2 failures aretest_load_binary.py::Test_LoadBinaryC,which fail identically on
mainon macOS (bash 3.2 vs"${array[@]}"underset -u).tests/schemas/test_schemas.py::Test_DdtraceSchemas::test_librarycollects inAPM_TRACING_EFFICIENT_PAYLOAD, confirming the schema is reached there. I could not executethat scenario locally (needs a built weblog + a v1-capable tracer), so instead I drove the
repo's own
SchemaValidatorover 4 valid and 24 hand-built invalid payloads, JSONround-tripped through the proxy's
ObjectDumpEncoderexactly as the runner does.Notes for the reviewer
The field most likely to surface a surprise is
error: boolean. I typed it from the v1 RFC,from the deserializer's own fixture (
8: True), and from the"Error field must be boolean"assertion in
tests/test_v1_payloads.py— but no existing test can actually tell bool from intthere, because Python evaluates
True == 1as true. If a tracer sends an integer, this schemawill be the first thing to say so; the fix is then either loosening that one field or a
SchemaBugentry with a real ticket.Two deliberately loose spots, both driven by deserializer behaviour rather than by the protocol:
trace_stateaccepts an integer, because_uncompress_span_links_listkeeps the rawstring-table index alongside the resolved
tracestateit adds;required, becausedeserialize_v1_tracereturns{}as its sentinelfor a payload it cannot parse (it already warns), and the schema should not double-report that
as a missing
chunks.Scope-wise this only touches
tests/, and only adds — no scenario, manifest or framework change.