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"
)
六、安全注意事项
- 敏感信息过滤
# 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'],
# ...
}
}
}
- 访问控制策略
# Nginx日志访问控制示例
location /logs/ {
internal;
alias /var/log/django/;
access_log off;
}
- 审计日志规范
# 关键操作审计
logger.info(
"Security event: user=%s action=%s",
request.user.username,
'password_change',
extra={'type': 'audit'}
)
配套检查清单
- 确认日志目录自动创建(使用
logging.handlers.WatchedFileHandler
) - 测试不同级别日志的输出路径
- 验证日志轮转策略是否生效
- 检查敏感字段过滤功能
- 配置日志监控警报阈值
- 设置定期日志分析任务(如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
标志自动切换日志级别,构建完整的调试监控体系。