Logging Configuration Basics

Set up Django logging with dictConfig. Configure handlers, formatters, and log levels per module. Tips for local development vs production logging.

1. Introduction

Logging is how your Django project records what is happening at runtime — errors, warnings, database queries, and custom messages you write yourself. Without logging, debugging production issues is guesswork.

Django uses Python's built-in logging module. You configure it in settings.py using a dictionary called LOGGING. This guide covers the key concepts and gives you a working setup for both development and production.

  • You should already have myproject set up with split settings files.
  • Your .venv must be active and Django 5.2 installed.

2. Key concepts

Before writing any configuration, understand these four building blocks:

  • Loggers — the entry point. Your code sends messages to a logger by name, for example django or pages.views. Each logger has a minimum level — messages below that level are ignored.
  • Handlers — decide where the log message goes. Common handlers send messages to the console, a file, or an external service.
  • Formatters — control what the log message looks like. You define the timestamp format, log level, module name, and message.
  • Log levels — how serious the message is. From lowest to highest: DEBUG, INFO, WARNING, ERROR, CRITICAL.

3. Log levels

Each log level has a specific meaning:

  • DEBUG — detailed information for diagnosing problems. Only use during development.
  • INFO — confirmation that things are working as expected. For example, a user logged in or a task completed.
  • WARNING — something unexpected happened but the application is still running. For example, a deprecated function was called.
  • ERROR — a serious problem that prevented something from working. For example, a database query failed.
  • CRITICAL — a very serious error that may cause the application to stop working entirely.

4. Basic logging configuration

Add this to mysite/settings/base.py. It sets up a clean console logger that works well in both development and production:

# mysite/settings/base.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {message}',
            'style': '{',
        },
        'simple': {
            'format': '{levelname} {message}',
            'style': '{',
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
        },
    },
    'root': {
        'handlers': ['console'],
        'level': 'WARNING',
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': 'INFO',
            'propagate': False,
        },
    },
}

Here is what each part does:

  • version: 1 — required by Python's logging configuration. Always set this to 1.
  • disable_existing_loggers: False — keeps Django's built-in loggers active. Always set this to False.
  • formatters — defines how messages look. verbose includes the level, timestamp, module, and message. simple is just level and message.
  • handlersconsole sends messages to the terminal using the verbose formatter.
  • root — the fallback logger for anything not matched by a specific logger. Set to WARNING so only serious messages appear by default.
  • loggers.django — captures all messages from Django itself at INFO level and above. propagate: False stops the message from also being handled by the root logger.

5. Logging to a file in production

In production, you want errors saved to a file so you can review them later. Add a file handler to your prod.py settings:

# mysite/settings/prod.py

from .base import *

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {message}',
            'style': '{',
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
        },
        'file': {
            'class': 'logging.FileHandler',
            'filename': BASE_DIR / 'logs' / 'django.log',
            'formatter': 'verbose',
        },
    },
    'root': {
        'handlers': ['console', 'file'],
        'level': 'WARNING',
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'file'],
            'level': 'ERROR',
            'propagate': False,
        },
    },
}

Create the logs/ folder at the root of myproject before deploying:

mkdir logs
touch logs/.gitkeep

6. Writing log messages in your code

To write log messages from your views or any other part of your code, import the logging module and create a logger named after the current module:

# pages/views.py

import logging
from django.http import HttpResponse

logger = logging.getLogger(__name__)


def hello_world(request):
    logger.info('hello_world view was called')
    logger.debug('request path: %s', request.path)
    return HttpResponse('Hello, World!')

Using __name__ as the logger name means the logger is named pages.views — matching the module path. This makes it easy to target specific parts of your app in the logging config if needed.

7. Development vs production logging

A simple rule for choosing log levels:

  • Development — set Django logger to DEBUG or INFO. You want to see as much as possible while building.
  • Production — set Django logger to ERROR or WARNING. You only want to know when something goes wrong, not routine activity.
  • Never log sensitive data — passwords, tokens, personal user data, and payment details should never appear in log files regardless of environment.

8. Next steps

That completes the Core and Project Structure section. You now have a solid foundation — a well-configured Django project with split settings, environment variables, clean structure, and logging in place. The next section covers Models and Database — where you define your data structure and let Django manage the database for you.


Never miss a story on Django.wiki

Subscribe for fresh tutorials, snippets, and updates.

By subscribing you agree to our Privacy Policy.