Skip to content

[SLES-2997] fix: stitch split telemetry payloads instead of dropping the batch - #1357

Open
shreyamalpani wants to merge 6 commits into
mainfrom
shreya.malpani/fix-logs-maxbytes
Open

[SLES-2997] fix: stitch split telemetry payloads instead of dropping the batch#1357
shreyamalpani wants to merge 6 commits into
mainfrom
shreya.malpani/fix-logs-maxbytes

Conversation

@shreyamalpani

@shreyamalpani shreyamalpani commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Overview

When a record exceeds the Telemetry API subscription's maxBytes, AWS cuts it mid-value and sends the remainder in the next POST, which repeats the cut record's envelope ahead of the resumed bytes. Neither half is valid JSON on its own, so serde_json failed and the listener discarded the entire batch — sometimes including the platform.runtimeDone that the on-demand loop waits on before calling /next. With that event gone the extension held the invocation open until Lambda killed the sandbox.

Changes

  • extension/telemetry/stitch.rs (new) — buffers the leading fragment and joins the continuation onto it, pairing the two on the repeated envelope (the API gives no sequence number). Joining strips the head's framing and the continuation's repeated envelope.
    • Only payloads cut mid-value are held (serde_json's Eof category); anything else
      takes the existing drop path. One fragment at a time, 2 MiB cap, 1s TTL.
  • maxBytes 256 KiB → 1 MiB (the AWS maximum) — prevention, not the fix. The ~328 KB
    record now arrives in a single POST; stitching covers anything above 1 MiB.

Testing

Manually tested with a repro function emitting a ~330 KB log record, left at the original 256 KiB maxBytes so every invocation splits: every batch reassembled, 0 parse failures, 0 dropped fragments, invocations 65–102 ms against ~62,000 ms beforehand. This fixes the problem at the root, and does not depend on the buffer increase.

Saw debug logs confirming that events were recovered from re-joining the split payload:

{
    "status": "DEBUG",
    "message": "DD_EXTENSION | DEBUG | TELEMETRY API | Reassembled a split payload, recovered 4 events"
}

@datadog-prod-us1-5

datadog-prod-us1-5 Bot commented Sep 3, 2026

Copy link
Copy Markdown

Pipelines

Unblock PR with BitsAI

⚠️ Warnings

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 2 Pipeline jobs failed

Bottlecap (Rust) | Format (ubuntu-22.04) — 🔧 Needs a code fix, caused by this PR

View more details · View in GitHub Actions

Assertion failed: expected 2 events, found 1 at /home/runner/work/datadog-lambda-extension/datadog-lambda-extension/bottlecap/src/extension/telemetry/stitch.rs:285

DataDog/datadog-lambda-extension | cargo fmt — 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

📋 Copy fix prompt
CI on my pull request is failing. Help me find and fix the root cause of each failing job below — they were flagged as caused by changes in this PR, so focus on the diff. For each job, explain the failure and propose a fix.

Before you start, set up the Datadog software-delivery tooling so you can
query the CI data yourself:

1. Check whether you already have the Datadog software-delivery MCP tools
   (e.g. a `search_datadog_ci_pipeline_events` tool) and the `unblock-pr` skill.
2. If either is missing, STOP and ask me for permission before installing
   anything. Do not install or run anything until I have said yes.
3. Only with my explicit approval, set up the Datadog software-delivery MCP
   server and skills by following:
     https://docs.datadoghq.com/getting_started/software_delivery_mcp_tools/
   then restart so the skill is picked up.
4. If I decline, skip all of the above and work from the context below alone.

Then run /unblock-pr — it will pull the CI data itself. The job context below is what we already know.

If /unblock-pr is not available — because I declined the setup above, or it did not install — work from the context below instead.

Datadog has already classified this failure as caused by changes in this PR.
Take that as given and work the fix:

1. Locate the change. Diff this branch against its base and find the change
   that produces this error. Explain the mechanism, don't just name a file:
     git fetch origin && git diff $(git merge-base origin/main HEAD)...HEAD
2. Reproduce it locally. Run the failing job's command or test before
   proposing anything.
3. Propose the smallest fix that addresses the root cause — not a workaround,
   not a broadened assertion, not a disabled or skipped test.
4. Re-run the same command to confirm, and say exactly what you ran.
5. If the failure turns out to be intermittent rather than deterministic, say
   so plainly instead of "fixing" it — that is a flaky test, and patching it
   hides the problem.

If the right move is to re-run the job rather than change code, use the job
link in the context below. For GitHub Actions: `gh run rerun <run-id> --failed`,
where the run ID is the number after `/runs/` in that URL (not the trailing
number, which is the job ID).

Branch: shreya.malpani/fix-logs-maxbytes

Bottlecap (Rust) | Format (ubuntu-22.04)
Commit: bb0251d1a410607fbfe34de4e748e76dd153aa77
Error (code / test):
Assertion failed: expected 2 events, found 1 at /home/runner/work/datadog-lambda-extension/datadog-lambda-extension/bottlecap/src/extension/telemetry/stitch.rs:285
CI job: https://github.com/DataDog/datadog-lambda-extension/actions/runs/33906710191/job/101133226183

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: bb0251d | Docs | View more details | Give us feedback!

@shreyamalpani
shreyamalpani marked this pull request as ready for review September 3, 2026 22:04
@shreyamalpani
shreyamalpani requested a review from a team as a code owner September 3, 2026 22:04
@shreyamalpani
shreyamalpani requested review from lym953 and a lite review from Copilot September 3, 2026 22:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

It still logs full telemetry payload bodies on parse failures (risking sensitive-data exposure/log amplification) and has a couple of edge-case behaviors that can reintroduce dropped batches.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds robust handling for AWS Telemetry API “split JSON” payloads so oversized telemetry records no longer cause entire batches (including platform.runtimeDone) to be dropped and invocations to hang.

Changes:

  • Introduces a fragment buffer + joiner (stitch.rs) to reassemble split telemetry payloads across consecutive POSTs.
  • Increases Telemetry API subscription buffering.maxBytes to 1 MiB and raises the Axum request body limit to accept full-size telemetry posts.
  • Updates the telemetry listener to attempt reassembly on JSON parse errors and adds tests covering split-payload handling.
File summaries
File Description
bottlecap/src/extension/telemetry/stitch.rs New fragment-buffer implementation and unit tests for split-payload reassembly.
bottlecap/src/extension/telemetry/mod.rs Adjusts telemetry subscription buffering settings and subscription logging/behavior.
bottlecap/src/extension/telemetry/listener.rs Uses the stitcher on parse failures, raises request body limit, and adds split-payload handler test.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread bottlecap/src/extension/telemetry/listener.rs Outdated
Comment thread bottlecap/src/extension/telemetry/mod.rs Outdated
Comment thread bottlecap/src/extension/telemetry/stitch.rs Outdated

// Rebuild the cut record's envelope as the continuation will send it: `[` then the
// record's keys, up to the value that got cut. The cut record is the last one here.
let value_start = rfind(&body, RECORD_KEY)? + RECORD_KEY.len();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether it is over concern, but this still locates the envelope with rfind("\"record\":"). Structured function logs can contain nested record fields. If the split occurs after one, the stitcher builds the wrong repeated envelope, such as "[{"record":{"message":{"record":"XYZ}]"
How about replacing the raw rfind logic with a bounded JSON-aware scanner.

@litianningdatadog litianningdatadog left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented.

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.

3 participants