opentelemetry-python-contrib
opentelemetry-python-contrib copied to clipboard
Fix emitting logs when Logger propagation is disabled for a logger
Description
The logs are emited via LoggingHandler as a handler of the root logger. Unfortunatelly when there is a Logger instance with disabled propagation with logger.propagate=False, the root logger handler does not get called. Fix this by instrumenting Logger.propagate as a property attribute, so when the value changes to False, install the LoggingHandler to the logger automatically, and when the value changes to True, uninstall it.
Type of change
Please delete options that are not relevant.
- [x] Bug fix (non-breaking change which fixes an issue)
How Has This Been Tested?
Tested with unit tests. Tested with real project using gunicorn with uvicorn workers (uvicorn.workers.UvicornWorker) and celery task executor. Previously there were logs missing (i.e. not forwarded) from gunicorn, uvicorn and celery task loggers, now they are forwarded to OpenTelemetry collector.
Does This PR Require a Core Repo Change?
- [x] No.
Checklist:
See contributing.md for styleguide, changelog guidelines, and more.
- [x] Followed the style guidelines of this project
- [x] Changelogs have been updated
- [x] Unit tests have been added
The committers listed above are authorized under a signed CLA.
- :white_check_mark: login: oldium / name: Oldřich Jedlička (8a86358008c95ae86777c34979029a4d0ed85a55, 033284b90a36dba7c60c79ea2d66be03d242ac9c)
Added few more tests for user-added LoggingHandler - they are not touched by instrumentation.
Updated changelog to refer to this pull request.
I have added a Proof-of-Concept commit to prove that LoggingHandler can be moved out of SDK:
- Root logger instrumentation is done in the logging instrumentation, not in the SDK. Previously it was done in SDK, which I think is conceptually wrong.
- Logger instrumentation uses only
opentelemetry-apipackage, nothing from the SDK.
There are several things that need to be checked/finished:
- Ensure that
resourceattribute is added toLogRecordby SDK, when we are not able to do so inLoggingHandler/OpenTelemetry API. This attribute is missing inLogRecordAPI, but present in SDK. - If there is any other
LogRecordmodification in SDK, ensure it is applied. - Fix SDK startup with
OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLEDenabled for compatibility - run instrumentation manually (as the env var name suggests)?
Please suggest how to handle the logging instrumentation situation. I will be happy to do some implementation if necessary or to finish the POC.
@oldium
A couple of questions as I seem to be confused about the issue and the proposed solution.
- Can you provide sample code in the description to show a logger that is configured in such a way that this bug is prevalent?
- Why do we have to move the
LoggingHandlerout of the SDK? How does this address the original problem? - What does this issue have to do with the logging instrumentation? I though we were discussing the
LoggingHandler?
@lzchen
A couple of questions as I seem to be confused about the issue and the proposed solution.
- Can you provide sample code in the description to show a logger that is configured in such a way that this bug is prevalent?
Try my example repo: https://github.com/oldium/gunicorn-opentelemetry-test
The Dockerfile there simulates exactly the same instrumentation steps that are done via K8s Operator for Python auto-instrumentation, i.e. puts /opentelemetry/opentelemetry/instrumentation/auto_instrumentation on the PYTHONPATH and lets the auto-instrumentation hook itself.
Steps to reproduce:
docker build . -t gunicorn-testdocker run -it --rm -e OTEL_TRACES_EXPORTER=none -e OTEL_METRICS_EXPORTER=none -p 8080:8080 gunicorn-testcurl localhost:8080(run from different console)
Now observe that the docker console contains only OTEL log from app.py read_root(), but nothing from gunicorn.
- Why do we have to move the
LoggingHandlerout of the SDK? How does this address the original problem?- What does this issue have to do with the logging instrumentation? I though we were discussing the
LoggingHandler?
From the repro steps it can be seen that the opentelemetry-instrumentation-logging library actually does not do the auto-instrumentation of the logging subsystem in the way that all the logs would be automatically sent via OTEL. By further investigating this I have found out that it is the SDK (!), who is actually auto-instrumenting the root logger to send the logs via OTEL by adding LoggingHandler to the root logger. With hypothetical different Python OTEL SDK you would not see any logs in OTEL.
So my goal is to fix the opentelemetry-instrumentation-logging to actually auto-instrument the logging subsystem in a way that all the logs, which are sent via the standard Python logging subsystem, are also sent via OTEL.
Here are the key-points for the final implementation:
- Implementing logging auto-instrumentation in
opentelemetry-instrumentation-loggingin a SDK-independent way requires similar approach, which is implemented in the SDK actually. That means to create something likeLoggingHandlerand install it into a root logger. - Instrumenting a root logger is not enough, because there might be other loggers with
logger.propagate=False, which means that the log record is not propagated upwards in the logger hierarchy. This is exactly why the logs from gunicorn, uvicorn and celery are not forwarded via OTEL, they are settinglogger.propagate=Falsefor their loggers, so the log records are simply not forwarded to the root logger and its handlers, so the installedLoggingHandlerdoes not see them and cannot forward them further to OTEL collector. - The
LoggingHandleris actually a good start to implement logging instrumentation in a SDK-independent way, but it resides in SDK. Having it both in SDK and inopentelemetry-instrumentation-loggingdoes not make much sense to me, so I chose to move it from SDK.
So it is not strictly necessary to remove LoggingHandler from SDK, but in order to implement logging subsystem instrumentation inside opentelemetry-instrumentation-logging, something like a LoggingHandler is necessary.
Any update, please? I can finish the PoC - just let me know if that is acceptable, I can prepare it. 😊