日志管理
youlai-django 提供 API 操作日志记录功能,日志存储在 sys_log 表中。
日志表结构
数据库表:sys_log
| 字段 | 类型 | 说明 |
|---|---|---|
| id | bigint | 主键 |
| module | varchar | 模块标识 |
| content | varchar | 日志内容 |
| request_method | varchar | 请求方式 |
| request_uri | varchar | 请求路径 |
| request_params | text | 请求参数 |
| response_data | text | 响应内容 |
| ip | varchar | 客户端 IP |
| browser | varchar | 浏览器信息 |
| os | varchar | 操作系统 |
| duration | int | 耗时(毫秒) |
| create_by | bigint | 操作人 |
| create_time | datetime | 操作时间 |
日志接口
分页查询
GET /api/v1/logs/page参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| pageNum | int | 页码 |
| pageSize | int | 每页数量 |
| keywords | string | 关键字 |
| createTime | string | 时间范围(起止时间,逗号分隔) |
访问趋势
GET /api/v1/logs/visit-trend参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| startDate | string | 开始日期(yyyy-MM-dd) |
| endDate | string | 结束日期(yyyy-MM-dd) |
返回:
json
{
"code": "00000",
"msg": "操作成功",
"data": {
"dates": ["2024-01-15", "2024-01-16"],
"pvList": [1000, 1200],
"ipList": [500, 600]
}
}访问统计
GET /api/v1/logs/visit-stats返回:
json
{
"code": "00000",
"data": {
"todayUv": 500,
"todayPv": 1000,
"totalUv": 10000,
"totalPv": 50000
}
}日志记录方式
中间件方式
在 Django 中间件中记录请求日志:
python
# infra/middleware/log_middleware.py
import time
import json
from django.utils.deprecation import MiddlewareMixin
class LogMiddleware(MiddlewareMixin):
def process_request(self, request):
request.start_time = time.time()
def process_response(self, request, response):
duration = int((time.time() - request.start_time) * 1000)
# 记录日志
Log.objects.create(
module='API',
content=f"{request.method} {request.path}",
request_method=request.method,
request_uri=request.path,
request_params=json.dumps(request.GET.dict()),
response_data=response.content.decode()[:500],
ip=self.get_client_ip(request),
duration=duration,
)
return response
def get_client_ip(self, request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
return x_forwarded_for.split(',')[0]
return request.META.get('REMOTE_ADDR')装饰器方式
python
from functools import wraps
import time
def log_operation(module='SYSTEM'):
def decorator(func):
@wraps(func)
def wrapper(self, request, *args, **kwargs):
start_time = time.time()
try:
response = func(self, request, *args, **kwargs)
duration = int((time.time() - start_time) * 1000)
# 记录成功日志
Log.objects.create(
module=module,
content=f"{request.method} {request.path}",
request_method=request.method,
request_uri=request.path,
duration=duration,
)
return response
except Exception as e:
# 记录失败日志
Log.objects.create(
module=module,
content=f"操作失败: {str(e)}",
request_method=request.method,
request_uri=request.path,
)
raise
return wrapper
return decoratorDjango Logging 配置
python
# config/settings/base.py
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.handlers.RotatingFileHandler',
'filename': 'logs/django.log',
'maxBytes': 10 * 1024 * 1024, # 10MB
'backupCount': 10,
'formatter': 'verbose',
},
},
'loggers': {
'django': {
'handlers': ['console'],
'level': 'INFO',
},
'youlai': {
'handlers': ['console', 'file'],
'level': 'DEBUG',
},
},
}日志查看
命令行查看
bash
# 查看日志文件
tail -f logs/django.log
# 搜索错误
grep "ERROR" logs/django.logDjango Admin 查看
配置 ModelAdmin 后可在后台查看:
python
# system/logs/admin.py
from django.contrib import admin
from .models import Log
@admin.register(Log)
class LogAdmin(admin.ModelAdmin):
list_display = ['id', 'module', 'content', 'ip', 'create_time']
list_filter = ['module', 'request_method']
search_fields = ['content', 'ip']
readonly_fields = [f.name for f in Log._meta.fields]相关文件
| 文件 | 说明 |
|---|---|
system/logs/models.py | 日志模型 |
system/logs/views.py | 日志接口 |
infra/middleware/log_middleware.py | 日志中间件 |
