Instrument LangGraph execution state changes - #507
Conversation
|
Building the suspend/resume half alongside this: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 12713073f5
ℹ️ 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".
| if state_version is not None: | ||
| attributes["gen_ai.execution.state.version"] = state_version | ||
| workflow.emit_event( | ||
| "gen_ai.execution.state.changed", |
There was a problem hiding this comment.
Land the semantic convention before emitting this event
The commit describes these names as candidate conventions pending the companion proposal, so emitting them now exposes users and collectors to an unstandardized schema that may change. Land the convention and consume its generated constants first instead of hardcoding the proposed event and attribute names.
AGENTS.md reference: AGENTS.md:L286-L291
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
🟡 Changes recommended
It introduces hard-coded candidate semconv event/attribute names that are not yet part of the generated semconv constants, which conflicts with the repo’s semconv-first expectations and makes the emitted telemetry unstable.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR adds a correlated “invocation event” emission API to opentelemetry-util-genai, then uses it in the LangChain/LangGraph instrumentation to emit execution state-change events (as logs) that are correlated to the active workflow span.
Changes:
- Add
GenAIInvocation.emit_event(...)to emit a log record with the invocation’s active span context. - Extend LangChain instrumentation to detect LangGraph node runs and emit a correlated state-change event with a changed-key count and optional step/version.
- Add/extend unit tests and document the new state-change event behavior; include Towncrier fragments for both packages.
File summaries
| File | Description |
|---|---|
| util/opentelemetry-util-genai/src/opentelemetry/util/genai/_invocation.py | Adds emit_event(...) to correlate emitted log records with the active invocation span context. |
| util/opentelemetry-util-genai/tests/test_workflow_invocation.py | Adds log-provider plumbing and tests verifying correlation + post-stop no-op behavior for emit_event. |
| util/opentelemetry-util-genai/.changelog/507.added | Towncrier fragment for the new invocation event API. |
| instrumentation/opentelemetry-instrumentation-genai-langchain/src/opentelemetry/instrumentation/genai/langchain/invocation_manager.py | Tracks LangGraph-node markers and normalized step/version extracted from metadata (without retaining full metadata). |
| instrumentation/opentelemetry-instrumentation-genai-langchain/src/opentelemetry/instrumentation/genai/langchain/callback_handler.py | Emits a correlated state-change event for non-empty LangGraph node outputs, associated with the nearest workflow invocation. |
| instrumentation/opentelemetry-instrumentation-genai-langchain/tests/test_langgraph_state_events.py | Adds an integration-style test validating correlated state-change event emission and privacy expectations. |
| instrumentation/opentelemetry-instrumentation-genai-langchain/tests/test_invocation_manager.py | Adds unit tests for LangGraph metadata normalization and non-LangGraph lookalike metadata handling. |
| instrumentation/opentelemetry-instrumentation-genai-langchain/tests/test_callback_handler.py | Adds unit tests validating the callback-driven state-change event emission/omission logic. |
| instrumentation/opentelemetry-instrumentation-genai-langchain/README.rst | Documents emitted state-change events and their privacy properties. |
| instrumentation/opentelemetry-instrumentation-genai-langchain/.changelog/507.added | Towncrier fragment for emitting LangGraph state-change events. |
Review details
- Files reviewed: 10/10 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| attributes: dict[str, int | str] = { | ||
| "gen_ai.execution.state.changed_key.count": len(outputs) | ||
| } | ||
| state_version = self._invocation_manager.get_langgraph_state_version( | ||
| run_id | ||
| ) | ||
| if state_version is not None: | ||
| attributes["gen_ai.execution.state.version"] = state_version | ||
| workflow.emit_event( | ||
| "gen_ai.execution.state.changed", | ||
| attributes, | ||
| body="Execution state changed", | ||
| ) |
Pull request dashboard statusWaiting on the author · refreshed 2026-09-02 06:30 UTC Respond to 1 review item (e.g. link a commit, explain why not, ask a follow-up):
Status above doesn't look right?
|
The design note, its generating script, and the captured telemetry lived under a new top-level docs/design-notes directory. They now live where the package's other runnable material does. The script becomes examples/langgraph-lifecycle/main.py alongside a requirements.txt and a README.rst, matching the shape of the sibling examples. The design note is now the README's design note section in reStructuredText, unchanged in substance, and the captured telemetry is sample-output.json referenced from it. The PR open-telemetry#507 reference source moves to util/opentelemetry-util-genai/tests/fixtures, next to the test that checks it, which now resolves the path from the test file rather than the repository root. The top-level docs/design-notes directory is gone and nothing else under docs/ changed. Claude-Session: https://claude.ai/code/session_01FAnWkWBL3mJ81AMv7KA6br
Adds a LangGraph producer for execution state-change telemetry using the schema proposed in open-telemetry/semantic-conventions-genai#483.
Behavior:
gen_ai.execution.state.changedin the active workflow span contextgen_ai.execution.state.changed_key.countValidation:
Merge dependency: