Logs are how you learn what a production Django app is doing. This lesson builds a practical setup: a LOGGING dict, request logs with an id, structured JSON and a different configuration per environment.
From print to logging
print has no level, time, source or traceback. The standard logging module gives levels, named loggers, several destinations and formats. Django itself logs through it (django.request, django.db.backends).
| Block | Role |
|---|---|
| Logger | The object you call; named with getLogger(__name__) |
| Handler | Where a record goes: console, file, email, collector |
| Formatter | What it looks like: text or JSON |
| Filter | Drops records or adds fields such as request_id |
Logging in your code
import logging
import sys
logging.basicConfig(
stream=sys.stdout,
level=logging.INFO,
format='%(levelname)s %(name)s %(message)s',
)
log = logging.getLogger('shop.orders')
log.debug('hidden')
log.info('order %s created', 42)
log.warning('stock low: %d left', 3)It prints:
INFO shop.orders order 42 created
WARNING shop.orders stock low: 3 leftThe DEBUG line is dropped because the threshold is INFO. Pass values as arguments (%s), not through an f-string.
| Level | When |
|---|---|
| DEBUG | Details, development only |
| INFO | Normal events: order created |
| WARNING | Unexpected, still working |
| ERROR | An operation failed |
| CRITICAL | The system is down |
# shop/services.py
import logging
logger = logging.getLogger(__name__) # -> 'shop.services'
def pay(order_id):
logger.info('paying order %s', order_id)
try:
charge(order_id)
except TimeoutError:
logger.exception('payment gateway timeout, order %s', order_id)
raise