Skip to content

Attach the OpenTelemetry logging handler - #295

Merged
unflxw merged 4 commits into
mainfrom
contrib-logging-handler
Oct 2, 2026
Merged

unflxw merged 4 commits into
mainfrom
contrib-logging-handler

Conversation

@unflxw

@unflxw unflxw commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Require Python 3.10

The opentelemetry-instrumentation-logging package requires Python 3.9,
and its last release supporting 3.9 pins the OpenTelemetry stack to
versions that no longer move. Requiring 3.10 puts every supported Python
version on the same OpenTelemetry release.

Python 3.13 and 3.14 join the test matrix and the classifiers. Ruff
reads requires-python to decide which rewrites apply, so raising the
floor turns on the pyupgrade rules that account for the rest of this
change.

Attach the OpenTelemetry logging handler

The log handler attached to the root logger comes from
opentelemetry.sdk._logs, which is deprecated, and configuring the
logging module removes it, so a Django application's LOGGING setting
stops logs being sent. The handler in
opentelemetry-instrumentation-logging wraps dictConfig, fileConfig
and basicConfig so that it survives them. It records the file,
function and line a log line came from only when asked, so
log_code_attributes is passed to keep those attributes.

Wrapping basicConfig means the level it is given now applies, because
Python skips that call when the root logger already has a handler. An
application that calls it with a level below WARNING starts sending
those log lines.

Warn about log handlers the application attached

An application that attached an OpenTelemetry log handler of its own now
has two handlers sending to the same place, so every log line reaching
both is sent twice. Our documentation told Django applications to attach
one. Only a handler sending to the logger provider started here is
warned about, and only when the records it handles reach the root
logger, where the handler attached here receives them too.

A handler from opentelemetry.sdk._logs is warned about separately,
whether or not it duplicates anything, because it is deprecated and is
removed in a future release. It raises a DeprecationWarning about
itself, which Python hides unless it comes from __main__, so an
application that attaches it from its settings never sees it.

Keep internal logs out of an application's logs

The appsignal and opentelemetry loggers are stopped from propagating
to the root logger when the log handler is attached here, so an
application that attaches the handler itself, through the
disable_default_instrumentations option, sends what AppSignal and the
OpenTelemetry SDK log about themselves as its own logs. Stopping the two
loggers when logging starts covers a handler attached either way.


Documented in appsignal/appsignal-docs#342. The /logs/ route in
appsignal/test-setups#389 exercises the structured log line; the
python-logs-handler-warnings
branch adds routes that trigger each warning, and is not for merging.

The `opentelemetry-instrumentation-logging` package requires Python 3.9,
and its last release supporting 3.9 pins the OpenTelemetry stack to
versions that no longer move. Requiring 3.10 puts every supported Python
version on the same OpenTelemetry release.

Python 3.13 and 3.14 join the test matrix and the classifiers. Ruff
reads `requires-python` to decide which rewrites apply, so raising the
floor turns on the pyupgrade rules that account for the rest of this
change.
@backlog-helper

backlog-helper Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

鉁旓笍 All good!

New issue guide | Backlog management | Rules | Feedback

@unflxw unflxw added the enhancement An improvement to an existing feature. label Sep 30, 2026
@unflxw
unflxw marked this pull request as ready for review September 30, 2026 15:10
@unflxw
unflxw force-pushed the contrib-logging-handler branch from d5b62c9 to e4e36b8 Compare September 30, 2026 15:13
The log handler attached to the root logger comes from
`opentelemetry.sdk._logs`, which is deprecated, and configuring the
logging module removes it, so a Django application's `LOGGING` setting
stops logs being sent. The handler in
`opentelemetry-instrumentation-logging` wraps `dictConfig`, `fileConfig`
and `basicConfig` so that it survives them. It records the file,
function and line a log line came from only when asked, so
`log_code_attributes` is passed to keep those attributes.

Wrapping `basicConfig` means the level it is given now applies, because
Python skips that call when the root logger already has a handler. An
application that calls it with a level below `WARNING` starts sending
those log lines.
An application that attached an OpenTelemetry log handler of its own now
has two handlers sending to the same place, so every log line reaching
both is sent twice. Our documentation told Django applications to attach
one. Only a handler sending to the logger provider started here is
warned about, and only when the records it handles reach the root
logger, where the handler attached here receives them too.

A handler from `opentelemetry.sdk._logs` is warned about separately,
whether or not it duplicates anything, because it is deprecated and is
removed in a future release. It raises a `DeprecationWarning` about
itself, which Python hides unless it comes from `__main__`, so an
application that attaches it from its settings never sees it.
The `appsignal` and `opentelemetry` loggers are stopped from propagating
to the root logger when the log handler is attached here, so an
application that attaches the handler itself, through the
`disable_default_instrumentations` option, sends what AppSignal and the
OpenTelemetry SDK log about themselves as its own logs. Stopping the two
loggers when logging starts covers a handler attached either way.
@unflxw
unflxw force-pushed the contrib-logging-handler branch from e4e36b8 to 3ca65d0 Compare September 30, 2026 15:20
@unflxw
unflxw merged commit e99c15c into main Oct 2, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement An improvement to an existing feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants