Django 项目日志系统配置指南

Django项目日志系统配置指南

一、基础配置框架

1. 最小化配置模板

# settings.py
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
            'style': '{',
        },
        'simple': {
            'format': '{levelname} {message}',
            'style': '{',
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            'level': 'WARNING',
            'class': 'logging.handlers.TimedRotatingFileHandler',
            'filename': 'logs/app.log',
            'when': 'midnight',
            'backupCount': 7,
            'formatter': 'verbose'
        },
    },
    'root': {
        'handlers': ['console', 'file'],
        'level': 'WARNING',
    },
}

2. 目录结构规范

project_root/
├── logs/               # 日志目录
│   ├── app.log         # 当前日志
│   ├── app.log.2023-08-01  # 历史日志
│   └── errors/         # 错误日志分离
├── manage.py
└── myproject/

3. 视图层日志实践

# myapp/views.py
import logging
from django.http import JsonResponse

# 获取模块级logger(推荐方式)
logger = logging.getLogger(__name__)

def user_profile(request):
    try:
        user_id = request.GET.get('id')
        logger.debug(
            "用户详情请求参数: user_id=%s",
            user_id,
            extra={'user': request.user.username}
        )
        
        # 模拟业务操作
        if not user_id.isdigit():
            logger.warning("非法ID格式", exc_info=True)
            return JsonResponse({"error": "invalid id"})
            
        # 记录业务日志
        logger.info(
            "获取用户资料成功",
            extra={
                'type': 'business',
                'operation': 'get_profile',
                'ip': request.META.get('REMOTE_ADDR')
            }
        )
        return JsonResponse({"data": "..."})
        
    except Exception as e:
        logger.error(
            "用户资料获取异常",
            exc_info=True,
            stack_info=True,
            extra={'request_data': request.GET.dict()}
        )
        return JsonResponse({"error": "server error"}, status=500)

二、进阶配置方案

1. 环境差异化配置

# settings/__init__.py
from .base import *

if DEBUG:
    LOGGING['handlers']['console']['level'] = 'DEBUG'
    LOGGING['root']['level'] = 'DEBUG'
else:
    LOGGING['handlers']['file']['filename'] = '/var/log/django/app.log'
    LOGGING['handlers']['file']['class'] = 'logging.handlers.WatchedFileHandler'

2. 模块级日志控制

LOGGING['loggers'] = {
    'django': {
        'handlers': ['console'],
        'level': 'INFO',
        'propagate': False,
    },
    'myapp': {
        'handlers': ['file'],
        'level': 'DEBUG' if DEBUG else 'INFO',
        'propagate': True,
    }
}

3. 错误邮件通知

'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'class': 'django.utils.log.AdminEmailHandler',
        'include_html': True,
        'email_backend': 'django.core.mail.backends.smtp.EmailBackend'
    }
},
'loggers': {
    'django.request': {
        'handlers': ['mail_admins'],
        'level': 'ERROR',
        'propagate': False,
    },
}

三、实用功能扩展

1. JSON格式日志(ELK集成)

'formatters': {
    'json': {
        '()': 'pythonjsonlogger.jsonlogger.JsonFormatter',
        'format': '''
            %(asctime)s %(levelname)s %(name)s 
            %(message)s %(pathname)s %(exc_info)s
        '''
    }
}

2. 请求上下文增强

# myproject/middleware/log_middleware.py(新建文件)
import logging
from uuid import uuid4

class RequestLogMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.logger = logging.getLogger('django.request')

    def __call__(self, request):
        # 生成唯一请求ID
        request.request_id = uuid4().hex
        
        # 请求前日志
        self.logger.info(
            "Request started",
            extra={
                'request_id': request.request_id,
                'method': request.method,
                'path': request.path
            }
        )
        
        response = self.get_response(request)
        
        # 请求后日志
        self.logger.info(
            "Request completed",
            extra={
                'request_id': request.request_id,
                'status': response.status_code,
                'duration': time.time() - start_time
            }
        )
        return response

# settings.py(激活中间件)
MIDDLEWARE = [
    'myproject.middleware.log_middleware.RequestLogMiddleware',
    # ...
]

3. 性能日志记录

# myproject/decorators/log_decorators.py(新建文件)
import time
from functools import wraps
import logging
from django.db import connection

logger = logging.getLogger('performance')

def log_slow_operations(threshold=1000):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            duration = (time.time() - start_time) * 1000
            
            if duration > threshold:
                logger.warning(
                    "Slow operation: %s took %.2fms",
                    func.__name__, 
                    duration,
                    extra={
                        'type': 'performance',
                        'duration': duration,
                        'query_count': len(connection.queries)
                    }
                )
            return result
        return wrapper
    return decorator

四、生产环境最佳实践

1. 日志轮转策略

'handlers': {
    'applog': {
        'class': 'logging.handlers.RotatingFileHandler',
        'filename': '/var/log/django/app.log',
        'maxBytes': 1024 * 1024 * 50,  # 50MB
        'backupCount': 10,
        'formatter': 'json',
        'delay': True  # 延迟文件创建
    }
}

2. 权限与维护方案

# 日志目录初始化脚本
mkdir -p /var/log/django
touch /var/log/django/app.log
chown -R django:django /var/log/django
chmod 755 /var/log/django
find /var/log/django -type f -exec chmod 644 {} \;

3. 监控警报集成

# Sentry配置示例
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration

sentry_sdk.init(
    dsn="your_sentry_dsn",
    integrations=[DjangoIntegration()],
    traces_sample_rate=1.0,
    send_default_pii=True
)

五、调试技巧与工具

1. 动态日志级别切换

# 通过Django Admin动态调整
from django.contrib import admin
from django.http import HttpResponse
import logging

@admin.action(description='Set DEBUG level')
def set_debug_level(modeladmin, request, queryset):
    logger = logging.getLogger('myapp')
    logger.setLevel(logging.DEBUG)
    return HttpResponse("日志级别已切换为DEBUG")

2. 日志可视化方案

# 使用Loguru增强功能
from loguru import logger
import sys

logger.add(
    sys.stderr,
    format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
    level="DEBUG" if DEBUG else "INFO"
)

# 自动压缩旧日志
logger.add(
    "logs/app_{time:YYYY-MM-DD}.log",
    rotation="00:00",
    compression="zip",
    retention="30 days"
)

六、安全注意事项

  1. 敏感信息过滤
# myproject/utils/log_filters.py(新建文件)
import logging

class SensitiveDataFilter(logging.Filter):
    sensitive_fields = ['password', 'token', 'credit_card']
    
    def filter(self, record):
        if record.msg:
            for field in self.sensitive_fields:
                if f'{field}=' in record.msg:
                    record.msg = record.msg.replace(
                        f'{field}=', 
                        f'{field}=******'
                    )
        return super().filter(record)

# settings.py(更新配置)
LOGGING = {
    # ...
    'filters': {
        'sensitive': {
            '()': 'myproject.utils.log_filters.SensitiveDataFilter',
        }
    },
    'handlers': {
        'console': {
            'filters': ['sensitive'],
            # ...
        }
    }
}
  1. 访问控制策略
# Nginx日志访问控制示例
location /logs/ {
    internal;
    alias /var/log/django/;
    access_log off;
}
  1. 审计日志规范
# 关键操作审计
logger.info(
    "Security event: user=%s action=%s",
    request.user.username,
    'password_change',
    extra={'type': 'audit'}
)

配套检查清单

  1. 确认日志目录自动创建(使用logging.handlers.WatchedFileHandler
  2. 测试不同级别日志的输出路径
  3. 验证日志轮转策略是否生效
  4. 检查敏感字段过滤功能
  5. 配置日志监控警报阈值
  6. 设置定期日志分析任务(如ELK定时报表)

常见问题解决方案

Q:日志文件没有自动创建?

  • 检查目录权限:sudo -u django touch /var/log/django/test.log
  • 确认handler配置delay=True时首次需要手动触发

Q:生产环境日志量过大?

  • 使用logging.handlers.QueueHandler实现异步写入
  • 配置django-prometheus进行采样监控

Q:如何关联请求日志?

# 在中间件中注入request_id
import uuid

class RequestIDMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        request.id = uuid.uuid4().hex
        response = self.get_response(request)
        response['X-Request-ID'] = request.id
        return response

# 日志格式添加{request_id}
format = '%(asctime)s [%(request_id)s] %(message)s'

建议将本配置与之前学习的Django Debug Toolbar结合使用,通过settings.DEBUG标志自动切换日志级别,构建完整的调试监控体系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yant224

点滴鼓励,汇成前行星光🌟

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值