Contents

Backend Development › Backend Basics · also in Observability

Logging

Recording what the application does so you can debug it later.

Also known as: application logs, logs, log messages, logger

Logging is your application writing a record of what it’s doing, so that when something breaks (usually when you aren’t watching), you can work out what happened.

import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s %(message)s")
log = logging.getLogger(__name__)

def charge(order):
    log.info("charging order %s for %s cents", order.id, order.total_cents)
    try:
        gateway.charge(order)
    except GatewayError:
        log.exception("charge failed for order %s", order.id)   # includes the stack trace
        raise

Use a logging library, not print: you get levels, timestamps, names, formatting and control over where output goes.

What makes a log useful

  • Context: which order, user or request. “Payment failed” is almost useless; “Payment failed for order 917, reason: card declined” is actionable. Include a request or correlation ID so you can follow one request through the system (request context).
  • The right level, so you can filter.
  • A consistent format, ideally structured (JSON with fields) so tools can search it.
  • Errors with stack traces, and the original error preserved.
  • Enough, but not too much. Log decisions and failures, not every loop iteration. Excess costs money, hides the signal and slows things down.

What not to log

  • Passwords, tokens, API keys, full card numbers and other secrets.
  • Personal data you don’t need. Logs are copied around, kept for a long time and read by many people.
  • Whole request bodies by default.

Where logs go

In containers and cloud apps, write to standard output and let the platform collect them. Old-style files on a server need rotation so they don’t fill the disk. Logs are one pillar of observability, together with metrics and traces.

When reading them later, see reading production logs.