Logging
Overview
SpeedPy uses django-structlog for structured logging. It provides consistent, machine-parseable log output with automatic request context binding.
Configuration
The logging setup in project/settings.py includes three formatters:
plain_console— human-readable console output (used by default)json_formatter— JSON output for log aggregation serviceskey_value— key=value format
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"json_formatter": {
"()": structlog.stdlib.ProcessorFormatter,
"processor": structlog.processors.JSONRenderer(),
},
"plain_console": {
"()": structlog.stdlib.ProcessorFormatter,
"processor": structlog.dev.ConsoleRenderer(),
},
},
"handlers": {
"console": {"class": "logging.StreamHandler", "formatter": "plain_console"}
},
"loggers": {"": {"handlers": ["console"], "level": "DEBUG"}},
}
Middleware
The structlog request middleware is included to automatically bind request data (user, IP, request ID) to log entries:
MIDDLEWARE = [
...
"django_structlog.middlewares.RequestMiddleware",
]
DJANGO_STRUCTLOG_CELERY_ENABLED = True
DJANGO_STRUCTLOG_COMMAND_LOGGING_ENABLED = True
Usage
import structlog
logger = structlog.get_logger(__name__)
def my_view(request):
logger.info("processing_request", user_id=request.user.id)
try:
result = do_something()
logger.info("processing_complete", result=result)
except Exception:
logger.exception("processing_failed")
Key practices:
- Use
structlog.get_logger(__name__)at module level - Pass context as keyword arguments, not in the message string
- Use
snake_casefor event names - Use
logger.exception()for errors (automatically includes traceback)
Celery Integration
Structlog is also configured for Celery workers in project/celeryapp.py via DjangoStructLogInitStep. This ensures Celery tasks get the same structured logging format.
from django_structlog.celery.steps import DjangoStructLogInitStep
app.steps["worker"].add(DjangoStructLogInitStep)
Switching to JSON in Production
To output JSON logs (for services like Datadog, Elastic, etc.), change the handler formatter:
"handlers": {
"console": {"class": "logging.StreamHandler", "formatter": "json_formatter"}
},