Skip to content

Logging

The drf_corekit.logging module provides structured request / response logging for Django and DRF projects.

Middleware

CoreLoggingMiddleware

from drf_corekit.logging.middleware import CoreLoggingMiddleware

Django middleware that automatically:

  • Assigns a transaction ID to every incoming request (from header or auto generated)
  • Attaches the transaction ID to the response header
  • Logs structured request / response metadata on every response

Setup

Add it to your MIDDLEWARE in settings.py:

MIDDLEWARE = [
    ...
    "drf_corekit.logging.middleware.CoreLoggingMiddleware",
]

Logging Configuration

get_logging_config()

from drf_corekit.logging.config import get_logging_config

Builds and returns a fully valid Django LOGGING dict with pre configured formatters, handlers, and loggers. Use this in settings.py.

Signature

get_logging_config(
    *,
    console_level: str = "INFO",
    file_level: str = "INFO",
    error_level: str = "ERROR",
    disable_existing_loggers: bool = False,
    extra_formatters: dict | None = None,
    extra_handlers: dict | None = None,
    extra_loggers: dict | None = None,
) -> dict

Example — basic usage

from drf_corekit.logging.config import get_logging_config

LOGGING = get_logging_config()

Example — with overrides

LOGGING = get_logging_config(
    console_level="DEBUG",
    extra_loggers={
        "myapp": {
            "level": "DEBUG",
            "handlers": ["core.console"],
            "propagate": False,
        }
    },
)

get_drf_logging_config()

from drf_corekit.logging.config import get_drf_logging_config

Shorthand for get_logging_config() with all defaults. Suitable for most cases.

LOGGING = get_drf_logging_config()

Logger Access

get_logger()

from drf_corekit.logging.loggers import get_logger

Returns a cached logging.Logger instance scoped to a context. Accepts a LoggerContext enum or a plain string.

Signature

get_logger(context: LoggerContext | str | None = None) -> logging.Logger

Example

from drf_corekit.logging.loggers import get_logger
from drf_corekit.logging.contexts import LoggerContext

logger = get_logger(LoggerContext.AUDIT)
logger.info("User updated profile", extra={"user_id": user.id})

LoggerContext

from drf_corekit.logging.contexts import LoggerContext

A StrEnum used to categorize log entries by their purpose.

Member Value Use for
REQUEST "request" Incoming HTTP requests and responses
AUDIT "audit" State changes, approvals, business events
SECURITY "security" Auth, authorization, security events
INTEGRATION "integration" External service or third party calls
TASK "task" Background jobs, scheduled work
SYSTEM "system" Internal system or infrastructure logs

Example

from drf_corekit.logging.loggers import get_logger
from drf_corekit.logging.contexts import LoggerContext

logger = get_logger(LoggerContext.SECURITY)
logger.warning("Failed login attempt", extra={"username": username})

Operation Context

OperationContext

from drf_corekit.logging.contexts import OperationContext

Thread-safe, request-scoped key/value store backed by contextvars. Used internally by CoreLoggingMiddleware to propagate the transaction ID, but also accessible in application code.

Method Description
OperationContext.set(key, value) Store a value for the current request
OperationContext.get(key, default=None) Retrieve a stored value
OperationContext.clear() Clear all context (called automatically at end of request)
OperationContext.set_transaction_id(txn_id) Store the transaction ID
OperationContext.get_transaction_id(default=None) Retrieve the current transaction ID

Example — reading the transaction ID in a view

from drf_corekit.logging.contexts import OperationContext

def my_view(request):
    txn_id = OperationContext.get_transaction_id()
    ...

Example — storing custom request-scoped data

OperationContext.set("tenant_id", request.tenant.id)

# later in the same request
tenant_id = OperationContext.get("tenant_id")

Advanced

LoggerFactory

from drf_corekit.logging.factory import LoggerFactory

Creates a logging.Logger using a pluggable resolver. Useful when you need custom logger naming beyond what get_logger() provides.

from drf_corekit.logging.factory import LoggerFactory

logger = LoggerFactory(context="payments").get_logger()

LoggerNameResolver

from drf_corekit.logging.factory import LoggerNameResolver

Base class for custom logger naming strategies. Subclass this and pass it to LoggerFactory to override the default core.<context> naming.

from drf_corekit.logging.factory import LoggerFactory, LoggerNameResolver

class MyResolver(LoggerNameResolver):
    def resolve(self, context: str | None, file_path: str | None) -> str:
        return f"myapp.{context}" if context else "myapp"

logger = LoggerFactory(context="payments", resolver=MyResolver()).get_logger()