Skip to content

fix: emit context attributes regardless of active span#575

Closed
jbachorik wants to merge 3 commits into
mainfrom
jb/fix-writeCurrentContext-span-gate
Closed

fix: emit context attributes regardless of active span#575
jbachorik wants to merge 3 commits into
mainfrom
jb/fix-writeCurrentContext-span-gate

Conversation

@jbachorik

Copy link
Copy Markdown
Collaborator

What does this PR do?:
Context attributes (e.g. llm.agent.phase) were silently dropped from ExecutionSample events when no span was active. In Recording::writeCurrentContext, ProfiledThread was only fetched when hasContext was true — but hasContext only reflects whether a span is active, not whether thread-local context attributes exist.

Motivation:
ProfiledThread::currentSignalSafe() is a pure TLS lookup: signal-safe, never allocates, returns nullptr if the key is not yet initialized. It is safe to call unconditionally. The existing null-check in the attributes loop (thrd != nullptr ? thrd->getOtelTagEncoding(i) : 0) already handles the no-thread case correctly.

Span IDs continue to be written as zero when no span is active — ContextApi::get only fills them on success, which is unaffected by this change.

Additional Notes:
The old variable hasContext was renamed away (its return value is now discarded) because the name was misleading: LLM phase and other thread-local attributes ARE context, so hasContext = false while attributes are set is a contradiction.

How to test the change?:
AgentPhaseProfilingTest in ddprof-test covers the case: a worker thread sets llm.agent.phase without any active span and verifies that ExecutionSample events carry the value.

For Datadog employees:

  • If this PR touches code that signs or publishes builds or packages, or handles
    credentials of any kind, I've requested a review from @DataDog/security-design-and-guidance.
  • This PR doesn't touch any of that.
  • JIRA: [JIRA-XXXX]

Context attributes (e.g. llm.agent.phase) were silently dropped from
ExecutionSample events when no span was active, because ProfiledThread
was only fetched when hasContext was true.

ProfiledThread::currentSignalSafe() is a pure TLS lookup — signal-safe,
never allocates — and is safe to call unconditionally. Span IDs are
still zeroed when no span is active (ContextApi::get fills them only on
success).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jbachorik jbachorik added the AI label Jun 3, 2026
@dd-octo-sts

dd-octo-sts Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

CI Test Results

Run: #27125460476 | Commit: 73cf7b7 | Duration: 12m 20s (longest job)

All 32 test jobs passed

Status Overview

JDK glibc-aarch64/debug glibc-amd64/debug musl-aarch64/debug musl-amd64/debug
8 - - -
8-ibm - - -
8-j9 - -
8-librca - -
8-orcl - - -
11 - - -
11-j9 - -
11-librca - -
17 - -
17-graal - -
17-j9 - -
17-librca - -
21 - -
21-graal - -
21-librca - -
25 - -
25-graal - -
25-librca - -

Legend: ✅ passed | ❌ failed | ⚪ skipped | 🚫 cancelled

Summary: Total: 32 | Passed: 32 | Failed: 0


Updated: 2026-06-08 08:46:33 UTC

@jbachorik jbachorik marked this pull request as ready for review June 8, 2026 08:00
@jbachorik jbachorik requested a review from a team as a code owner June 8, 2026 08:00

@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: 2454eeb24f

ℹ️ 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 ddprof-lib/src/main/cpp/flightRecorder.cpp Outdated
@datadog-datadog-prod-us1

This comment has been minimized.

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.

Pull request overview

This PR updates the native JFR event writer to ensure thread-local context attributes are emitted for ExecutionSample events even when there is no active span, by decoupling attribute emission from span-context availability.

Changes:

  • Adjust Recording::writeCurrentContext to no longer conditionally fetch ProfiledThread based on ContextApi::get(...)’s boolean result.
  • Update the inline comment to describe the “no active span” case when ContextApi::get does not populate span IDs.

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

Comment on lines 1708 to 1712
size_t numAttrs = Profiler::instance()->numContextAttributes();
ProfiledThread* thrd = hasContext ? ProfiledThread::currentSignalSafe() : nullptr;
ProfiledThread* thrd = ProfiledThread::currentSignalSafe();
for (size_t i = 0; i < numAttrs; i++) {
buf->putVar32(thrd != nullptr ? thrd->getOtelTagEncoding(i) : 0);
}
Comment on lines +1702 to +1704
// spanId/rootSpanId are initialized to 0 above; ContextApi::get() only updates them
// on success, so 0s are always written when there is no valid context.
// on success, so 0s are always written when there is no active span.
ContextApi::get(spanId, rootSpanId);
@jbachorik

Copy link
Copy Markdown
Collaborator Author

Invalid

@jbachorik jbachorik closed this Jun 8, 2026
@jbachorik jbachorik deleted the jb/fix-writeCurrentContext-span-gate branch June 8, 2026 08:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants