Add OTEL_SEMCONV_EXCEPTION_SIGNAL_OPT_IN support to record_exception - #5323
Add OTEL_SEMCONV_EXCEPTION_SIGNAL_OPT_IN support to record_exception#5323RKest wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds opt-in support for recording exceptions as logs (and optionally duplicating to span events) in the SDK’s Span.record_exception, enabling migration away from span events per the exception-as-logs semantic conventions and the span-event deprecation plan.
Changes:
- Update
Span.record_exceptionto honorOTEL_SEMCONV_EXCEPTION_SIGNAL_OPT_INand emit an exceptionLogRecordcorrelated with the span when configured. - Add end-to-end unit tests covering unset/unrecognized/logs/logs-dup behaviors, correlation, scope usage, and attribute mapping.
- Add a changelog entry documenting the new opt-in behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| opentelemetry-sdk/src/opentelemetry/sdk/trace/init.py | Adds env-var gated branching in record_exception and a helper to emit correlated exception logs. |
| opentelemetry-sdk/tests/trace/test_record_exception_logs.py | New tests validating exception-as-logs behavior across all opt-in modes. |
| .changelog/5318.added | Notes the new env-var controlled behavior for Span.record_exception. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
828822d to
e039edd
Compare
e039edd to
01425f1
Compare
01425f1 to
086f5b5
Compare
|
This PR has been automatically marked as stale because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 days of this comment. |
2675e70 to
9867450
Compare
Pull request dashboard statusWaiting on maintainers · refreshed 2026-08-24 18:33 UTC Merge when ready. Status above doesn't look right?
|
| timestamp: int | None = None, | ||
| escaped: bool = False, | ||
| *, | ||
| event_name: str = "exception", |
There was a problem hiding this comment.
Don't we need to change the api to accept these new params as well?
There was a problem hiding this comment.
Yes, great point.
I added these, as default-None, to not pull in SeverityNumber (outside of if TYPE_CHECKING) from unstable _logs module, into the stable trace one. Meaningful defaults are set in the SDK only.
This does make current Span implementations incompatible according to some linters, but there have been prior similar changes, so I don't think this constitutes a breaking change.
I verified there was a similar change to this one, which was not in-fact marked as a breaking change: https://github.com/open-telemetry/opentelemetry-python/pull/4028/changes
| name="exception", attributes=_attributes, timestamp=timestamp | ||
| ) | ||
|
|
||
| def _record_exception_log( |
There was a problem hiding this comment.
I believe the old self.add_event() is a noop if the span has ended already. Should we do the same check here?
There was a problem hiding this comment.
I added a guard. However, unlike add_event, this one is not inside a lock, because a lock in this case would potentially block span.end() on synchronous log export (which I believe is not unacceptable?).
Only drawback here is a possible race condition, where log export can happen after the span has ended.
This should be okay, because AFAIU the guard should protect against egregious developer mistakes, where a log truly has no business being attached to a long ended span, in which case this race condition would be tolerable. Also unlike adding span events, logs export still functions even after the span ends (and is exported) so I think this minor lack of parity is okay.
`Span.record_exception` now honors the `OTEL_SEMCONV_EXCEPTION_SIGNAL_OPT_IN` environment variable, per the semantic conventions for exceptions in logs (https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-logs/): - unset: record exceptions as span events only (unchanged default) - `logs`: record exceptions as logs only - `logs/dup`: record exceptions as both logs and span events Exception logs are emitted at ERROR severity, correlated with the originating span's context, and use the span's instrumentation scope.
9c7aafc to
983420f
Compare
Description
Span.record_exceptioncurrently always records exceptions as spanevents. The semantic conventions for
exceptions in logs
and the span-event API deprecation plan
(OTEP 4430,
see also the
Deprecating Span Events
blog post) introduce the
OTEL_SEMCONV_EXCEPTION_SIGNAL_OPT_INenvironmentvariable so instrumentations can migrate exceptions from span events to logs.
This PR makes the SDK's
Span.record_exception(and therefore the__exit__/use_spanpaths that call it) honorOTEL_SEMCONV_EXCEPTION_SIGNAL_OPT_IN:logslogs/dupAny unrecognized value is treated as unset, preserving today's behavior.
Implementation notes:
LoggerProvider, correlatedwith the originating span's context (
trace_id/span_id), atERRORseverity, with
event_name="exception".exception.type,exception.messageandexception.stacktrace. The deprecatedexception.escapedattribute isintentionally omitted from the log representation; it is still set on the
span event when one is recorded (
logs/dupor default).OTEL_SEMCONV_EXCEPTION_SIGNAL_OPT_INis an experimental, transitionalopt-in, so it is kept private to
opentelemetry.sdk.tracerather thanexported from
opentelemetry.sdk.environment_variables.The default behavior is unchanged, so this is fully backwards compatible and
opt-in.
Type of change
How Has This Been Tested?
A new test module
opentelemetry-sdk/tests/trace/test_record_exception_logs.pycovers all modes end to end using an in-memory span exporter and a captured
logger:
logsrecords a log only (no span event)logs/duprecords both a log and a span event(
trace_id/span_id)exception.type/exception.message/exception.stacktracearepopulated and extra
attributesare forwardedexception.escapedattribute is not set on the logThe existing
record_exceptiontests inopentelemetry-sdk/tests/trace/test_trace.pycontinue to pass unchanged.Does This PR Require a Contrib Repo Change?
record_exceptionsignature is unchanged; the new behavior isgated behind an environment variable and defaults to today's behavior.
Checklist:
ruff check/ruff format).changelog/5318.added— rename to matchthe assigned PR number when opening the PR)
record_exceptiondocstring)