Files
thrillwiki_django_no_react/docs/architecture/adr-007-logging-standardization.md
pacnpal ca770d76ff Enhance documentation and management commands for ThrillWiki
- Updated backend README.md to include detailed management commands for configuration, database operations, cache management, data management, user authentication, content/media handling, trending/discovery, testing/development, and security/auditing.
- Added a new MANAGEMENT_COMMANDS.md file for comprehensive command reference.
- Included logging standardization details in architecture documentation (ADR-007).
- Improved production checklist with configuration validation and cache verification steps.
- Expanded API documentation to include error logging details.
- Created a documentation review checklist to ensure completeness and accuracy.
2025-12-23 21:28:14 -05:00

6.5 KiB

ADR-007: Logging Standardization Pattern

Status

Accepted

Context

As the ThrillWiki application grew, logging patterns became inconsistent across different modules. Some files had no logging, others used print statements, and logging levels were applied inconsistently. This made debugging production issues difficult and prevented effective monitoring.

The team needed:

  • Consistent logging patterns across all modules
  • Structured logging with contextual information
  • Security event tracking for compliance
  • Performance monitoring capabilities
  • Integration with centralized logging systems (Sentry, CloudWatch)

Decision

We implemented a standardized logging pattern with centralized utilities for structured logging.

Core Pattern

Every module initializes a logger using Python's standard logging:

import logging

logger = logging.getLogger(__name__)

Centralized Logging Utilities

Created apps.core.logging module with specialized logging functions:

  1. log_exception(logger, exception, context, request)

    • Logs exceptions with full stack trace
    • Includes request context (user, IP, path)
    • Automatically sends to Sentry in production
  2. log_business_event(logger, event_type, message, context, request)

    • Logs significant business operations
    • Used for FSM transitions, user actions, data changes
    • Structured format for analytics
  3. log_security_event(logger, event_type, message, severity, context, request)

    • Logs authentication and authorization events
    • Tracks security-relevant actions
    • Supports compliance auditing

Log Levels

Standardized log level usage:

Level Usage
DEBUG Detailed diagnostic information (disabled in production)
INFO General operational events (user actions, searches)
WARNING Unexpected conditions that don't prevent operation
ERROR Error conditions requiring attention
CRITICAL System failures requiring immediate action

Logging Configuration

Modular logging configuration in config/settings/logging.py:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'json': {
            '()': 'pythonjsonlogger.jsonlogger.JsonFormatter',
            'format': '%(asctime)s %(name)s %(levelname)s %(message)s',
        },
        'verbose': {
            'format': '{levelname} {asctime} {name} {message}',
            'style': '{',
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
        },
        'file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': 'logs/django.log',
            'maxBytes': 10485760,  # 10MB
            'backupCount': 5,
            'formatter': 'json',
        },
        'sentry': {
            'class': 'sentry_sdk.integrations.logging.EventHandler',
            'level': 'ERROR',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'file'],
            'level': 'INFO',
        },
        'apps': {
            'handlers': ['console', 'file', 'sentry'],
            'level': 'INFO',
            'propagate': False,
        },
    },
}

Consequences

Benefits

  1. Consistent Debugging: All modules log in the same format
  2. Structured Logs: JSON format enables log aggregation and analysis
  3. Security Auditing: Dedicated security event logging for compliance
  4. Performance Monitoring: Cache and query performance tracking
  5. Production Monitoring: Integration with Sentry for error tracking
  6. Contextual Information: All logs include user, request, and operation context

Trade-offs

  1. Verbosity: More logging code in each module
  2. Performance: Logging has minimal overhead (~1-2ms per log)
  3. Storage: JSON logs consume more disk space than plain text
  4. Learning Curve: Developers must learn when to use each logging function

Implementation Guidelines

  1. Logger Initialization: Every view, service, and middleware file must initialize a logger
  2. Exception Handling: Always use log_exception() in exception handlers
  3. Business Events: Use log_business_event() for FSM transitions and significant actions
  4. Security Events: Use log_security_event() for authentication and authorization
  5. Sensitive Data: Never log passwords, tokens, session IDs, or PII

Example Usage

import logging
from apps.core.logging import log_exception, log_business_event, log_security_event

logger = logging.getLogger(__name__)

class ParkDetailView(DetailView):
    def get_object(self):
        try:
            park = super().get_object()
            logger.info(f"Park viewed: {park.name}", extra={
                'park_id': park.id,
                'user_id': self.request.user.id if self.request.user.is_authenticated else None,
            })
            return park
        except Park.DoesNotExist as e:
            log_exception(
                logger,
                e,
                context={'slug': self.kwargs.get('slug')},
                request=self.request,
            )
            raise

    def post(self, request, *args, **kwargs):
        park = self.get_object()
        old_status = park.status
        park.approve()
        park.save()

        log_business_event(
            logger,
            event_type='fsm_transition',
            message=f'Park approved: {park.name}',
            context={
                'model': 'Park',
                'object_id': park.id,
                'old_state': old_status,
                'new_state': park.status,
            },
            request=request,
        )

        return redirect('park_detail', slug=park.slug)

Alternatives Considered

Django Debug Toolbar Only

Rejected because:

  • Only works in development
  • No production monitoring
  • No structured logging
  • No security event tracking

Third-Party Logging Service (Datadog, New Relic)

Rejected because:

  • High cost for small team
  • Vendor lock-in
  • Sentry + CloudWatch sufficient for current needs

Print Statements

Rejected because:

  • Not configurable
  • No log levels
  • No structured format
  • Not production-ready

References