Logging From Python
This documentation outlines how to configure logging with the AppSignal for Python integration.
Configure Logging
You do not need to create a log source to send logs from the AppSignal for Python integration. An "application" log source will be created automatically.
When using collector mode, AppSignal automatically instruments Python's built-in logging module via OpenTelemetry, attaching a handler to the root logger.
Disabling logging instrumentation
Instrumentation for Python's logging module can be disabled using the disable_default_instrumentations configuration option:
# __appsignal__.py appsignal = Appsignal( # ... disable_default_instrumentations=["logging"], )
This disables the automatic instrumentation of the logging module by attaching a handler to the root logger, meaning that logs sent to Python's logging module will no longer be captured by AppSignal.
You can still send logs directly using the OpenTelemetry logs API, as described in the Sending Logs with OpenTelemetry section below.
Attaching handlers manually
When automatic instrumentation is disabled, you can attach the OpenTelemetry LoggingHandler to specific loggers yourself, rather than relying on AppSignal adding it to the root logger:
import logging from opentelemetry.sdk._logs import LoggingHandler handler = LoggingHandler(level=logging.NOTSET) logging.getLogger("myapp").addHandler(handler)
This gives you control over which loggers send their output to AppSignal.
Log level
Python's logging module defaults to WARNING, meaning INFO and DEBUG messages are not captured by default. To capture lower-severity messages, set the root logger level explicitly:
import logging logging.root.setLevel(logging.INFO)
Which logs are captured
AppSignal captures logs sent to the root logger and any logger that propagates to it. Propagation is controlled by the propagate attribute on each logger, which defaults to True in Python.
Loggers with propagate=False will not have their messages captured by AppSignal.
Framework Setup
Django
Django configures some loggers with propagate=False by default, which prevents them from reaching AppSignal. Override these in settings.py to re-enable propagation:
# settings.py LOGGING = { "version": 1, "disable_existing_loggers": False, "handlers": { "console": {"class": "logging.StreamHandler"}, }, "loggers": { "django.server": { "handlers": ["console"], "level": "INFO", "propagate": True, }, "myapp": { "handlers": ["console"], "level": "INFO", "propagate": True, }, }, }
Setting "propagate": True ensures that the logger's messages reach the root logger, where AppSignal's handler is attached.
Attaching handlers manually
Alternatively, you can attach the LoggingHandler directly to Django's loggers instead of relying on propagation to the root logger:
# settings.py import logging from opentelemetry.sdk._logs import LoggingHandler LOGGING = { "version": 1, "handlers": { "console": {"class": "logging.StreamHandler"}, "appsignal": {"()": LoggingHandler, "level": logging.NOTSET}, }, "loggers": { "django.server": { "handlers": ["console", "appsignal"], "level": "INFO", }, "myapp": { "handlers": ["console", "appsignal"], "level": "INFO", }, }, }
Celery
Celery forks worker processes, so AppSignal must be started for each fork. Use the worker_process_init signal to reinitialise AppSignal and configure logging in each worker process. See the Celery instrumentation page for more details on instrumenting Celery tasks.
# tasks.py import logging import appsignal from celery.signals import worker_process_init @worker_process_init.connect(weak=False) def init_worker_logging(*args, **kwargs): appsignal.start() logging.root.setLevel(logging.INFO) logging.getLogger("celery").propagate = True
Sending Logs with OpenTelemetry
You can also send logs directly using the OpenTelemetry logs API, without going through Python's logging module:
from opentelemetry._logs import get_logger_provider from opentelemetry.sdk._logs import SeverityNumber logger_provider = get_logger_provider() logger = logger_provider.get_logger("my-app") logger.emit( logger_provider.get_logger("my-app").create_log_record( body="Log message line", severity_number=SeverityNumber.INFO, ) )
Need Help?
After configuring your Python application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always reach out for assistance. We'll help get you back on track!