-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat: log management #3188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: log management #3188
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # coding=utf-8 | ||
| """ | ||
| @project: MaxKB | ||
| @Author:虎虎 | ||
| @file: log.py | ||
| @date:2025/6/4 14:13 | ||
| @desc: | ||
| """ | ||
|
|
||
| from system_manage.models.log_management import Log | ||
|
|
||
|
|
||
| def _get_ip_address(request): | ||
| """ | ||
| 获取ip地址 | ||
| @param request: | ||
| @return: | ||
| """ | ||
| x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') | ||
| if x_forwarded_for: | ||
| ip = x_forwarded_for.split(',')[0] | ||
| else: | ||
| ip = request.META.get('REMOTE_ADDR') | ||
| return ip | ||
|
|
||
|
|
||
| def _get_user(request): | ||
| """ | ||
| 获取用户 | ||
| @param request: | ||
| @return: | ||
| """ | ||
| user = request.user | ||
| if user is None: | ||
| return { | ||
|
|
||
| } | ||
| return { | ||
| "id": str(user.id), | ||
| "email": user.email, | ||
| "phone": user.phone, | ||
| "nick_name": user.nick_name, | ||
| "username": user.username, | ||
| "role": user.role, | ||
| } | ||
|
|
||
|
|
||
| def _get_details(request): | ||
| path = request.path | ||
| body = request.data | ||
| query = request.query_params | ||
| return { | ||
| 'path': path, | ||
| 'body': body, | ||
| 'query': query | ||
| } | ||
|
|
||
|
|
||
| def log(menu: str, operate, get_user=_get_user, get_ip_address=_get_ip_address, get_details=_get_details, | ||
| get_operation_object=None): | ||
| """ | ||
| 记录审计日志 | ||
| @param menu: 操作菜单 str | ||
| @param operate: 操作 str|func 如果是一个函数 入参将是一个request 响应为str def operate(request): return "操作菜单" | ||
| @param get_user: 获取用户 | ||
| @param get_ip_address:获取IP地址 | ||
| @param get_details: 获取执行详情 | ||
| @param get_operation_object: 获取操作对象 | ||
| @return: | ||
| """ | ||
|
|
||
| def inner(func): | ||
| def run(view, request, **kwargs): | ||
| status = 200 | ||
| operation_object = {} | ||
| try: | ||
| if get_operation_object is not None: | ||
| operation_object = get_operation_object(request, kwargs) | ||
| except Exception as e: | ||
| pass | ||
| try: | ||
| return func(view, request, **kwargs) | ||
| except Exception as e: | ||
| status = 500 | ||
| raise e | ||
| finally: | ||
| ip = get_ip_address(request) | ||
| user = get_user(request) | ||
| details = get_details(request) | ||
| _operate = operate | ||
| if callable(operate): | ||
| _operate = operate(request) | ||
| # 插入审计日志 | ||
| Log(menu=menu, operate=_operate, user=user, status=status, ip_address=ip, details=details, | ||
| operation_object=operation_object).save() | ||
|
|
||
| return run | ||
|
|
||
| return inner | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # Generated by Django 5.2 on 2025-06-04 06:17 | ||
|
|
||
| import common.encoder.encoder | ||
| import uuid | ||
| from django.db import migrations, models | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ('system_manage', '0003_workspaceuserresourcepermission_and_more'), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.CreateModel( | ||
| name='Log', | ||
| fields=[ | ||
| ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), | ||
| ('update_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')), | ||
| ('id', models.UUIDField(default=uuid.uuid1, editable=False, primary_key=True, serialize=False, verbose_name='主键id')), | ||
| ('menu', models.CharField(max_length=128, verbose_name='操作菜单')), | ||
| ('operate', models.CharField(max_length=128, verbose_name='操作')), | ||
| ('operation_object', models.JSONField(default=dict, encoder=common.encoder.encoder.SystemEncoder, verbose_name='操作对象')), | ||
| ('user', models.JSONField(default=dict, verbose_name='用户信息')), | ||
| ('status', models.IntegerField(verbose_name='状态')), | ||
| ('ip_address', models.CharField(max_length=128, verbose_name='ip地址')), | ||
| ('details', models.JSONField(default=dict, encoder=common.encoder.encoder.SystemEncoder, verbose_name='详情')), | ||
| ], | ||
| options={ | ||
| 'db_table': 'log', | ||
| }, | ||
| ), | ||
| ] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code appears to be correctly structured for creating a new model called However, there are a few suggestions for improvement:
Here’s an updated version of the code incorporating these improvements: # Generated by django-migrate on 2025-06-04 06:17 UTC
import common.encoder.encoder
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('system_manage', '0003_workspaceuserresourcepermission_and_more'),
]
operations = [
migrations.CreateModel(
name='Log',
fields=[
(
'create_time',
models.DateTimeField(auto_now_add=True,
verbose_name='创建时间'
)
),
(
'update_time',
models.DateTimeField(auto_now=True,
verbose_name='修改时间')
),
(
'id',
models.UUIDField(default=uuid.uuid1,
editable=False,
primary_key=True,
serialize=False,
verbose_name='主键id')
),
(
'menu',
models.CharField(max_length=128,
verbose_name='操作菜单')
),
(
'operate',
models.CharField(max_length=128,
verbose_name='操作')
),
(
'operation_object',
models.JSONField(default=dict,
encoder=common.encoder.encoder.SystemEncoder,
verbose_name='操作对象')
),
(
'user',
models.JSONField(default=dict,
verbose_name='用户信息')
),
(
'status',
models.IntegerField(verbose_name='状态')
),
(
'ip_address',
models.CharField(max_length=128,
verbose_name='IP地址')
),
(
'details',
models.JSONField(default=dict,
encoder=common.encoder.encoder.SystemEncoder,
verbose_name='详情')
),
],
options={
'db_table': 'log',
},
),
]These changes help ensure clarity and correctness in the database schema definition. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,3 +8,4 @@ | |
| """ | ||
| from .workspace_user_permission import * | ||
| from .system_setting import * | ||
| from .log_management import * | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # coding=utf-8 | ||
| """ | ||
| @project: MaxKB | ||
| @Author:虎虎 | ||
| @file: log_management.py | ||
| @date:2025/6/4 14:15 | ||
| @desc: | ||
| """ | ||
| import uuid | ||
|
|
||
| from django.db import models | ||
|
|
||
| from common.encoder.encoder import SystemEncoder | ||
| from common.mixins.app_model_mixin import AppModelMixin | ||
|
|
||
|
|
||
| class Log(AppModelMixin): | ||
| """ | ||
| 审计日志 | ||
| """ | ||
| id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id") | ||
|
|
||
| menu = models.CharField(max_length=128, verbose_name="操作菜单") | ||
|
|
||
| operate = models.CharField(max_length=128, verbose_name="操作") | ||
|
|
||
| operation_object = models.JSONField(verbose_name="操作对象", default=dict, encoder=SystemEncoder) | ||
|
|
||
| user = models.JSONField(verbose_name="用户信息", default=dict) | ||
|
|
||
| status = models.IntegerField(verbose_name="状态") | ||
|
|
||
| ip_address = models.CharField(max_length=128, verbose_name="ip地址") | ||
|
|
||
| details = models.JSONField(verbose_name="详情", default=dict, encoder=SystemEncoder) | ||
|
|
||
| class Meta: | ||
| db_table = "log" | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are no apparent irregularities or potential issues with the code provided. However, I can suggest a few minor improvements:
Here's a revised version of the code without unnecessary changes but still follows good practices: # coding=utf-8
"""
@project: MaxKB
@Author:虎虎
@file: log_management.py
@date:2025/6/4 14:15
@desc:
"""
import uuid
from django.db import models
from common.encoder.encoder import SystemEncoder
from common.mixins.app_model_mixin import AppModelMixin
class Log(AppModelMixin):
"""
审计日志
"""
id = models.UUIDField(
primary_key=True,
max_length=128,
default=uuid.uuid1,
editable=False,
verbose_name="主键id"
)
menu = models.CharField(max_length=128, verbose_name="操作菜单")
operate = models.CharField(max_length=128, verbose_name="操作")
operation_object = models.JSONField(
verbose_name="操作对象",
default=dict,
encoder=SystemEncoder
)
user = models.JSONField(verbose_name="用户信息", default=dict)
status = models.IntegerField(verbose_name="状态")
ip_address = models.CharField(max_length=128, verbose_name="ip地址")
details = models.JSONField(
verbose_name="详情",
default=dict,
encoder=SystemEncoder
)
class Meta:
db_table = "log"This slight formatting change enhances readability while adhering to typical coding standards. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The provided Python code defines several helper functions and a decorator to record audit logs. Here's an analysis of its content:
Helper Functions:
_get_ip_address(request)HTTP_X_FORWARDED_FORif available._get_user(request)request.user. If no user is found, it returns an empty dictionary._get_details(request)Decorator Function (
log):Parameters:
menu: The menu item under which this action was performed.operate: A string representation or function that describes what was done by the operator. The function can acceptrequestas input and should return a string indicating the operation or error message.Optional arguments like
_get_user,_get_ip_address,_get_details, and_get_operation_object.Inner Function
run(view, request, **kwargs):Logmodel defined in the imported module.Potential Issues:
Lack of Input Validation:
menu,operate, etc. This could lead to bugs where invalid inputs might result in unexpected behavior or security vulnerabilities.Error Handling:
Code Reusability:
Security Concerns:
Performance Considerations:
Optimization Suggestions:
Input Validation and Error Handling:
Decomposition of Code:
Logging Best Practices:
Database Efficiency:
By addressing these considerations, you can enhance both functional stability and performance while ensuring adherence to best practices for production applications.