Skip to content

Report OTLP export status in tracer startup log - #12062

Open
bm1549 wants to merge 8 commits into
masterfrom
brian.marks/otlp-export-startup-log
Open

Report OTLP export status in tracer startup log#12062
bm1549 wants to merge 8 commits into
masterfrom
brian.marks/otlp-export-startup-log

Conversation

@bm1549

@bm1549 bm1549 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What Does This Do

Adds three boolean fields to the DATADOG TRACER CONFIGURATION startup log emitted by dd-trace-core's StatusLogger:

Key Backed by Reports
otlp_traces_export_enabled Config.isOtlpTracesExportEnabled() whether the resolved writer-type configuration selects OtlpWriter, directly or as a flat MultiWriter sub-writer
otlp_metrics_export_enabled Config.isOtlpMetricsExportEnabled() (isMetricsOtelEnabled() && isMetricsOtlpExporterEnabled()) || isOtelTracesSpanMetricsEnabled()
otlp_logs_export_enabled Config.isOtlpLogsExportEnabled() isLogsOtelEnabled() && isLogsOtlpExporterEnabled()

The three accessors live on Config, matching the other values that StatusLogger.toJson writes.

StatusLoggerTest adds 12 tests for the default and fully enabled cases, disabled OTel signals, both routes to metrics export, writer-type precedence, and seven direct or flat MultiWriter configurations.

Motivation

Part of a cross-tracer effort to report OTLP export status in each tracer's startup log. The JSON keys are identical across the dd-trace-* libraries so the fields can be read the same way regardless of language.

Additional Notes

The traces field cannot read dd.trace.otel.exporter alone because an explicit dd.writer.type takes precedence. isOtlpTracesExportEnabled follows that resolved setting and recognizes OtlpWriter in the supported flat MultiWriter:a,b form.

Metrics export has two triggers: the OTel metrics signal paired with the OTLP exporter, or dd.trace.otel.span.metrics.enabled, which routes span metrics over OTLP on its own.

Validated with the focused StatusLoggerTest, :internal-api:forbiddenApisMain, and Spotless checks for internal-api and dd-trace-core.

This is a diagnostic logging change and does not alter tracer runtime behavior.

Contributor Checklist

Jira ticket: N/A


Related PRs

Report whether the tracer exports each telemetry signal over OTLP in the
"DATADOG TRACER CONFIGURATION" startup log via three boolean fields:
otlp_traces_export_enabled, otlp_metrics_export_enabled, and
otlp_logs_export_enabled. Metrics and logs require both the OTel signal to
be enabled and the OTLP exporter to be selected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@datadog-official

datadog-official Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

🎯 Code Coverage (details)
Patch Coverage: 0.00%
Overall Coverage: 57.44% (-0.48%)

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

@dd-octo-sts

dd-octo-sts Bot commented Jul 24, 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.07 s 13.99 s [-0.2%; +1.4%] (no difference)
startup:insecure-bank:tracing:Agent 12.94 s 12.98 s [-1.1%; +0.4%] (no difference)
startup:petclinic:appsec:Agent 16.90 s 16.70 s [+0.2%; +2.1%] (maybe worse)
startup:petclinic:iast:Agent 16.92 s 16.90 s [-0.4%; +0.8%] (no difference)
startup:petclinic:profiling:Agent 16.76 s 16.87 s [-1.8%; +0.5%] (no difference)
startup:petclinic:sca:Agent 16.69 s 16.63 s [-0.6%; +1.3%] (no difference)
startup:petclinic:tracing:Agent 16.04 s 15.98 s [-0.9%; +1.6%] (no difference)

Commit: c884de54 · 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.

@bm1549
bm1549 marked this pull request as ready for review July 24, 2026 21:38
@bm1549
bm1549 requested a review from a team as a code owner July 24, 2026 21:38
@bm1549
bm1549 requested a review from mcculls July 24, 2026 21:38

@datadog-official datadog-official Bot 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.

Datadog Autotest: PASS

More details

The startup log fields match the runtime activation rules: traces follow OTLP exporter selection, while metrics and logs require both their OTel signal and OTLP exporter to be enabled. Alternate exporters, mixed signal states, and case variations are handled by the existing accessors; no diff-only behavioral regression was identified.

Was this helpful? React 👍 or 👎

Open Bits AI session

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

@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: a4287c54a9

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread dd-trace-core/src/main/java/datadog/trace/core/StatusLogger.java Outdated
Comment thread dd-trace-core/src/main/java/datadog/trace/core/StatusLogger.java Outdated
Report otlp_traces_export_enabled from the resolved writer type
(OtlpWriter) rather than the OTLP exporter selection, since an explicit
dd.writer.type override wins over dd.trace.otel.exporter=otlp in
WriterFactory. Also report otlp_metrics_export_enabled when client-side
span metrics are enabled, since those are exported over OTLP via
OtlpStatsMetricWriter independently of the OTel metrics signal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

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

Minor comments about style

Comment thread dd-trace-core/src/main/java/datadog/trace/core/StatusLogger.java Outdated
Comment thread dd-trace-core/src/test/java/datadog/trace/core/StatusLoggerTest.java Outdated
Comment thread dd-trace-core/src/test/java/datadog/trace/core/StatusLoggerTest.java Outdated
Move the three derived booleans out of StatusLogger.toJson and into Config
accessors: isOtlpTracesExportEnabled, isOtlpMetricsExportEnabled, and
isOtlpLogsExportEnabled. Every other field toJson emits forwards a Config
getter, so keeping the conjunctions inline made this method the only place in
the file that derives a value it writes.

Fix otlp_traces_export_enabled. It compared dd.writer.type to OtlpWriter for
equality, so MultiWriter:OtlpWriter,DDAgentWriter reported false even though
WriterFactory builds a real OtlpWriter for it. isOtlpTracesExportEnabled now
mirrors WriterFactory's dispatch: a writer type that does not start with
MultiWriter is compared to OtlpWriter directly, and one that does has every
literal MultiWriter: removed before the remainder is split on commas and each
sub-type compared. Removing every occurrence rather than a single leading
prefix matches what MultiWriter itself does, so a repeated prefix such as
MultiWriter:DDAgentWriter,MultiWriter:OtlpWriter resolves the same way in both
places.

Drop the two comment blocks in StatusLogger explaining writer precedence and
span-metrics routing, and the three in StatusLoggerTest. StatusLogger carries
no comments anywhere else, and the reasoning belongs in the commit message and
pull request, which both record it.

Expand StatusLoggerTest to 13 tests and assert with assertFalse and assertTrue
instead of assertEquals against boolean literals. The new cases pin the writer
type grammar: a MultiWriter list that includes OtlpWriter, one that excludes
it, a repeated MultiWriter prefix, a padded sub-type, a sub-type that only
prefixes OtlpWriter, a comma-separated list without the MultiWriter prefix, and
a TraceStructureWriter value that WriterFactory dispatches before it ever
reaches the MultiWriter branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
if (!writerType.startsWith(MULTI_WRITER_TYPE)) {
return OTLP_WRITER_TYPE.equals(writerType);
}
String multiWriterConfig = MULTI_WRITER_PREFIX.matcher(writerType).replaceAll("");

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.

Suggested change
String multiWriterConfig = MULTI_WRITER_PREFIX.matcher(writerType).replaceAll("");
String multiWriterConfig = writerType.substring(MULTI_WRITER_TYPE.length() + 1);

saves needing the extra regex, which almost all the time will never be used.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Dropped both regexes in 4db8aa4, but went with Strings.replace(writerType, MULTI_WRITER_TYPE + ":", "") rather than the substring. MultiWriter strips every MultiWriter: occurrence before splitting, not just the leading one, so MultiWriter:DDAgentWriter,MultiWriter:OtlpWriter really does build an OtlpWriter and the substring would miss it (tracesExportedWhenMultiWriterPrefixRepeats covers that). Substring also throws on a bare MultiWriter with no colon. Strings.replace is the same helper WriterFactory already uses for the TraceStructureWriter prefix, and nothing gets compiled at class-init now.

private static final Pattern COLON = Pattern.compile(":");
private static final Pattern COMMA = Pattern.compile(",");
private static final Pattern MULTI_WRITER_PREFIX =
Pattern.compile(MULTI_WRITER_TYPE + ":", Pattern.LITERAL);

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.

This will never be used for most deployments, and is the same as dropping the same number of characters as the matched string (+ 1) from the string.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Dropped in 4db8aa4.

return OTLP_WRITER_TYPE.equals(writerType);
}
String multiWriterConfig = MULTI_WRITER_PREFIX.matcher(writerType).replaceAll("");
for (String subWriterType : COMMA.split(multiWriterConfig)) {

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.

Given that almost all deployments will never reach this code, is it worth pre-compiling the regex and always taking that hit - rather than just using multiWriterConfig.split(","); and doing it lazily?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Dropped in 4db8aa4 - it's multiWriterConfig.split(",") now. A single non-metacharacter argument takes String.split's fast path, so no Pattern gets compiled there either.

Remove the COMMA and MULTI_WRITER_PREFIX Patterns. Both were compiled in
Config's static initializer, so every deployment paid for them even though only
a MultiWriter writer type reaches the branch that used them.

Strip the prefix with Strings.replace, the same helper WriterFactory already
uses to strip the TraceStructureWriter prefix, and split with String.split(","),
whose single non-metacharacter argument takes the fast path that compiles no
Pattern. Strings.replace deletes every occurrence rather than only the leading
one, so it stays output-identical to the Pattern it replaces and keeps mirroring
what MultiWriter does; a leading substring would report false for
MultiWriter:DDAgentWriter,MultiWriter:OtlpWriter, which does build an
OtlpWriter, and would throw on a bare MultiWriter with no colon.

Behavior is unchanged and the 13 StatusLoggerTest cases pass untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@bm1549
bm1549 requested review from PerfectSlayer and mcculls July 29, 2026 13:57
Comment thread internal-api/src/main/java/datadog/trace/api/Config.java Outdated

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

Looks reasonable

Comment thread internal-api/src/main/java/datadog/trace/api/Config.java
@bm1549
bm1549 enabled auto-merge July 31, 2026 21:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: core Tracer core tag: ai generated Largely based on code generated by an AI or LLM type: feature Enhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants