Add DI snapshot payload size pruning (RFC C6) - #6224
Conversation
|
👋 Hey @p-datadog, please fill "Change log entry" section in the pull request description. If changes need to be present in CHANGELOG.md you can state it this way **Change log entry**
Yes. A brief summary to be placed into the CHANGELOG.md(possible answers Yes/Yep/Yeah) Or you can opt out like that **Change log entry**
None.(possible answers No/Nope/None) Visited at: 2026-08-27 19:38:44 UTC |
|
BenchmarksBenchmark execution time: 2026-08-24 14:34:43 Comparing candidate commit 1db49c8 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 48 metrics, 1 unstable metrics.
|
Add Datadog::DI::SnapshotPruner.prune, a Hash walker that fits an
oversized serialized snapshot under the 1 MB per-event cap by replacing
the largest top-level captured values (the {type:...} objects under
locals/arguments/throwable in the captures subtree) with
{"pruned":true} markers, preserving variable names and the structural
envelope. Measures each captured value by encoding it (JSON.dump is
deterministic, so a subtree's standalone encoding is byte-identical to
its span in the full dump), sorts by size descending, and replaces the
largest until the overage is reclaimed, then re-encodes once. Returns
nil when no captured values can be pruned or pruning cannot fit.
Replace the drop-if-too-big check in
DI::Transport::Input::Transport#send_input with prune-if-too-big:
an oversized snapshot is pruned (captured values replaced with
{"pruned":true}) and sent when it fits under
MAX_SERIALIZED_SNAPSHOT_SIZE, and dropped only when pruning cannot
bring it under the cap. Switch the cap check from encoded.length
(character count) to encoded.bytesize (the 1 MB network limit is a
byte limit; .length undercounted multibyte UTF-8). Increment a
snapshots_pruned_by_payload_size telemetry counter on each prune.
51cbbfd to
1db49c8
Compare
Oversized snapshots are pruned (largest captured variables replaced with a pruned marker) and delivered partially, and dropped only when pruning cannot bring them under the 1 MB limit.
Typing analysisNote: Ignored files are excluded from the next sections. Untyped methodsThis PR introduces 6 partially typed methods, and clears 31 partially typed methods. It increases the percentage of typed methods from 70.06% to 71.16% (+1.1%). Partially typed methods (+6-31)❌ Introduced:Untyped other declarationsThis PR clears 2 partially typed other declarations. It increases the percentage of typed other declarations from 85.33% to 85.68% (+0.35%). Partially typed other declarations (+0-2)✅ Cleared:If you believe a method or an attribute is rightfully untyped or partially typed, you can add |
Implements backlog item
payload-size-prune(DEBUG-6077). RFC area: C6 (per-event payload size cap + pruning/slicing). Design:design/payload-size-prune.mdin p-datadog/claude-projects.What
Caps each serialized DI snapshot at 1 MB and prunes an oversized snapshot (replaces its largest captured values with
{"pruned":true}) so a portion of the captured data is still sent, instead of dropping it whole. Drops only when pruning cannot bring the snapshot under the cap.How
Datadog::DI::SnapshotPruner.prune(snapshot, max_size)— a Ruby Hash walker (not a JSON-string tokenizer): collects the top-level captured value objects ({type:...}underlocals/arguments/throwablein thecapturessubtree), measures each by encoding it, and replaces the largest with{"pruned":trueuntil the overage is reclaimed, then re-encodes once. Variable names are preserved; the structural envelope (service,debugger.snapshot.probe,stack) is never pruned.transport/input.rb#send_inputreplaces drop-if-too-big with prune-if-too-big; switches the cap check fromencoded.length(character count) toencoded.bytesize(the 1 MB network limit is a byte limit;.lengthundercounted multibyte UTF-8).dynamic_instrumentation.snapshots_pruned_by_payload_sizetelemetry counter.Why a Hash walker, not a JSON-string pruner
The transport holds the snapshot as a Ruby Hash before
encoder.encode. Walking the Hash and replacing captured values is idiomatic Ruby and avoids a hand-rolled JSON tokenizer. Node.js and Java prune the encoded string because that is the form they hold; Ruby adapts the same protocol to the form its transport holds (design rule: adapt architecture to the target language, do not copy another tracer's code structure).Non-goals / follow-ups
{"pruned":true}, matching Node.js.MAX_SERIALIZED_SNAPSHOT_SIZE.Tests
Local (Ruby 3.3.12): snapshot_pruner (8), transport/input (15), plus the full DI suite (instrumenter, builder, capture_expression_evaluator, circuit_breaker, el/evaluator, serializer, probe) — 389 examples, 0 failures. standard/steep deferred to PR CI.
System test
Test_Debugger_Snapshot_Size_Guardrail(DataDog/system-tests#7287) ismissing_featureuntil the Ruby weblog gains the/debugger/snapshot/limitsfixture andSnapshotLimitsline mapping and the manifest is flipped (separate system-tests work).Customer documentation
docs/DynamicInstrumentation.md(Data Capture Limits → Snapshot Size) nowstates that a snapshot exceeding 1 MB is pruned (largest captured variables
replaced with a
{"pruned": true}marker) and delivered partially, anddropped only when pruning cannot bring it under the limit.
Change log entry
Yes. Dynamic Instrumentation: a snapshot exceeding the 1 MB payload limit is
now pruned and delivered partially instead of being dropped entirely; it is
dropped only when pruning cannot bring it under the limit.