Skip to content

Limit growth of OTLP trace buffer#12052

Open
mcculls wants to merge 1 commit into
masterfrom
mcculls/limit-otlp-buffer-growth
Open

Limit growth of OTLP trace buffer#12052
mcculls wants to merge 1 commit into
masterfrom
mcculls/limit-otlp-buffer-growth

Conversation

@mcculls

@mcculls mcculls commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

What Does This Do

Motivation

Avoids the following exception when large amounts of trace data is collected:

java.lang.IllegalArgumentException
  at java.base/java.nio.Buffer.createCapacityException(Buffer.java:279)
  at java.base/java.nio.ByteBuffer.allocate(ByteBuffer.java:362)
  at datadog.trace.agent.core.otlp.common.OtlpProtoBuffer.checkCapacity(OtlpProtoBuffer.java:128)
  at datadog.trace.agent.core.otlp.common.OtlpProtoBuffer.recordMessage(OtlpProtoBuffer.java:60)
  at datadog.trace.agent.core.otlp.trace.OtlpTraceProto.recordSpanMessage(OtlpTraceProto.java:166)
  at datadog.trace.agent.core.otlp.trace.OtlpTraceProtoCollector.completeSpan(OtlpTraceProtoCollector.java:170)
  at datadog.trace.agent.core.otlp.trace.OtlpTraceProtoCollector.completeScope(OtlpTraceProtoCollector.java:155)
  at datadog.trace.agent.core.otlp.trace.OtlpTraceProtoCollector.completePayload(OtlpTraceProtoCollector.java:133)
  at datadog.trace.agent.core.otlp.trace.OtlpTraceProtoCollector.collectTraces(OtlpTraceProtoCollector.java:73)
  at datadog.trace.agent.common.writer.OtlpPayloadDispatcher.flush(OtlpPayloadDispatcher.java:32)
  at datadog.trace.agent.common.writer.TraceProcessingWorker$TraceSerializingHandler.flushIfNecessary(TraceProcessingWorker.java:226)
  at datadog.trace.agent.common.writer.TraceProcessingWorker$TraceSerializingHandler.runDutyCycle(TraceProcessingWorker.java:176)
  at datadog.trace.agent.common.writer.TraceProcessingWorker$TraceSerializingHandler.run(TraceProcessingWorker.java:162)
  at java.base/java.lang.Thread.run(Thread.java:840)

Contributor Checklist

Jira ticket: [PROJ-IDENT]

@mcculls mcculls added type: feature Enhancements and improvements tag: performance Performance related changes inst: opentelemetry OpenTelemetry instrumentation labels Jul 23, 2026
@mcculls
mcculls requested a review from Copilot July 23, 2026 10:00
@mcculls

mcculls commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR improves OTLP trace export robustness in dd-trace-core by tracking buffered payload size to proactively flush before scheduled intervals, enforcing a hard OTLP protobuf buffer cap, and preventing flush failures from terminating the trace-processing thread.

Changes:

  • Add sizeInBytes() to OtlpTraceCollector and implement it for JSON and protobuf OTLP collectors (leveraging new JsonWriter.sizeInBytes() and OtlpProtoBuffer.sizeInBytes()).
  • Proactively flush OTLP traces in OtlpPayloadDispatcher when buffered size crosses ~5 MiB.
  • Add a 64 MiB hard cap to OtlpProtoBuffer growth and guard TraceProcessingWorker.flushIfNecessary() against flush exceptions.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
dd-trace-core/src/test/java/datadog/trace/common/writer/OtlpPayloadDispatcherTest.java Updates test collector to support size tracking for new proactive-flush behavior.
dd-trace-core/src/main/java/datadog/trace/core/otlp/trace/OtlpTraceProtoCollector.java Exposes protobuf-buffered size via sizeInBytes() for threshold-based flushing.
dd-trace-core/src/main/java/datadog/trace/core/otlp/trace/OtlpTraceJsonCollector.java Exposes JSON-buffered size via JsonWriter.sizeInBytes() for threshold-based flushing.
dd-trace-core/src/main/java/datadog/trace/core/otlp/trace/OtlpTraceCollector.java Adds the sizeInBytes() API to enable dispatcher-side payload growth control.
dd-trace-core/src/main/java/datadog/trace/core/otlp/common/OtlpProtoBuffer.java Adds 64 MiB cap and size reporting to prevent unbounded OTLP protobuf buffering.
dd-trace-core/src/main/java/datadog/trace/common/writer/TraceProcessingWorker.java Prevents flush exceptions from killing the processing loop.
dd-trace-core/src/main/java/datadog/trace/common/writer/OtlpPayloadDispatcher.java Adds proactive flush when collector-reported buffer size exceeds threshold.
components/json/src/main/java/datadog/json/JsonWriter.java Adds sizeInBytes() to measure buffered JSON output (after flushing).
Comments suppressed due to low confidence (2)

dd-trace-core/src/main/java/datadog/trace/core/otlp/common/OtlpProtoBuffer.java:22

  • The class Javadoc says this buffer "doesn't have a bounded length", but the new MAX_CAPACITY_BYTES makes it explicitly bounded. Updating the Javadoc will prevent future confusion about expected behavior.
public final class OtlpProtoBuffer {
  // hard limit to avoid unbounded buffering; matches OTLP spec's recommended default
  private static final int MAX_CAPACITY_BYTES = 64 << 20; // 64 MiB

dd-trace-core/src/main/java/datadog/trace/core/otlp/common/OtlpProtoBuffer.java:146

  • The new 64 MiB hard cap in checkCapacity() is a significant behavior change, but there is no test coverage ensuring an oversized payload reliably fails fast with the expected exception/message (and without corrupting buffer state). Consider adding a unit test that grows the buffer beyond the cap and asserts the failure mode.
      // (uses long arithmetic so overflow can be detected before allocating)
      long newSize = ((long) oldSize + required + initialCapacity - 1) & -initialCapacity;
      if (newSize > MAX_CAPACITY_BYTES) {
        throw new IllegalStateException(
            "OTLP payload exceeds maximum buffer size of "
                + MAX_CAPACITY_BYTES
                + " bytes: "
                + oldSize
                + " bytes buffered, "
                + required
                + " more requested");
      }
      ByteBuffer newBuffer = ByteBuffer.allocate((int) newSize);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b4cc8f8423

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@dd-octo-sts

dd-octo-sts Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.00 s 13.99 s [-0.9%; +1.0%] (no difference)
startup:insecure-bank:tracing:Agent 12.85 s 12.94 s [-1.4%; +0.0%] (no difference)
startup:petclinic:appsec:Agent 16.87 s 16.74 s [-0.4%; +1.9%] (no difference)
startup:petclinic:iast:Agent 16.89 s 16.93 s [-1.0%; +0.6%] (no difference)
startup:petclinic:profiling:Agent 16.74 s 16.56 s [-0.2%; +2.4%] (no difference)
startup:petclinic:sca:Agent 16.96 s 16.85 s [-0.4%; +1.7%] (no difference)
startup:petclinic:tracing:Agent 16.01 s 16.21 s [-2.2%; -0.2%] (maybe better)

Commit: 7ea79e4a · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@mcculls
mcculls force-pushed the mcculls/limit-otlp-buffer-growth branch from b4cc8f8 to c7effa5 Compare July 23, 2026 10:49
@datadog-prod-us1-4

datadog-prod-us1-4 Bot commented Jul 23, 2026

Copy link
Copy Markdown

🎯 Code Coverage (details)
Patch Coverage: 89.13%
Overall Coverage: 57.34% (-0.21%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 7ea79e4 | Docs | Datadog PR Page | Give us feedback!

@mcculls
mcculls force-pushed the mcculls/limit-otlp-buffer-growth branch from c7effa5 to 56590b8 Compare July 23, 2026 11:11
@mcculls

mcculls commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 56590b87ef

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@mcculls
mcculls force-pushed the mcculls/limit-otlp-buffer-growth branch from 56590b8 to 98c4491 Compare July 23, 2026 11:26
@mcculls
mcculls marked this pull request as ready for review July 23, 2026 11:27
@mcculls
mcculls requested review from a team as code owners July 23, 2026 11:27
@mcculls
mcculls requested review from AlexeyKuznetsov-DD and PerfectSlayer and removed request for a team July 23, 2026 11:27
@dd-octo-sts dd-octo-sts Bot added the tag: ai generated Largely based on code generated by an AI or LLM label Jul 23, 2026
@mcculls
mcculls requested a review from mhlidd July 23, 2026 11:28

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 98c4491b2c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@PerfectSlayer PerfectSlayer 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.

Left minor comments of JSON component

Comment thread components/json/src/main/java/datadog/json/JsonWriter.java Outdated
Comment thread components/json/src/main/java/datadog/json/JsonWriter.java
Comment thread components/json/src/main/java/datadog/json/JsonWriter.java
Comment thread components/json/src/test/java/datadog/json/JsonWriterTest.java Outdated

@datadog-prod-us1-4 datadog-prod-us1-4 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Datadog Autotest: WARN

The new flush path bounds OTLP buffering and the executable JSON accounting check matched emitted bytes for escaped Unicode span values. One resilience hazard remains: flush now catches every Throwable, including fatal JVM errors and sender failures that previously reached worker failure accounting; no additional tests recommended because the existing tests already cover the changed branches and the remaining concern is error-policy behavior.

📊 Validated against 2 scenarios · Open Bits AI session

🤖 Datadog Autotest · Commit 98c4491 · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

@mcculls
mcculls force-pushed the mcculls/limit-otlp-buffer-growth branch from 98c4491 to b098984 Compare July 23, 2026 15:55
* Proactively flush OTLP traces between scheduled flushes to try to keep payload size below 5 MiB
* Add hard limit of 64 MiB to OTLP payloads, as recommended in https://opentelemetry.io/docs/specs/otlp/

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@mcculls
mcculls force-pushed the mcculls/limit-otlp-buffer-growth branch from b098984 to 7ea79e4 Compare July 23, 2026 16:02
@mcculls

mcculls commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

dd-trace-core/src/test/java/datadog/trace/common/writer/OtlpPayloadDispatcherTest.java:120

  • Because collector is a shared field, this test leaves state behind (spansToExport and fakeSizeInBytes) when it intentionally does not flush. That makes the suite order-dependent/flaky (later tests can see leftover spans and/or trigger unexpected proactive flushes). Clear/reset the collector state at the end of the test (or instantiate a new collector per test).
  void belowFlushThresholdDoesNotTriggerProactiveFlush() {
    OtlpPayloadDispatcher dispatcher = new OtlpPayloadDispatcher(sender, collector);
    collector.fakeSizeInBytes = (5 << 20) - 1; // one byte under FLUSH_THRESHOLD_BYTES

    dispatcher.addTrace(singletonList(sampledSpan()));

    verifyNoInteractions(sender);
  }

dd-trace-core/src/test/java/datadog/trace/common/writer/OtlpPayloadDispatcherTest.java:130

  • This test sets collector.fakeSizeInBytes but doesn’t reset it afterwards. Since the same collector instance is reused across tests, this can make later tests order-dependent by triggering unexpected proactive flushes.
  @Test
  void atFlushThresholdTriggersProactiveFlush() {
    OtlpPayloadDispatcher dispatcher = new OtlpPayloadDispatcher(sender, collector);
    collector.fakeSizeInBytes = 5 << 20; // exactly FLUSH_THRESHOLD_BYTES

    dispatcher.addTrace(singletonList(sampledSpan()));

    verify(sender).send(any(OtlpPayload.class));
  }

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ea79e4a7e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

inst: opentelemetry OpenTelemetry instrumentation tag: ai generated Largely based on code generated by an AI or LLM tag: performance Performance related changes type: feature Enhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants