-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat: log management #3189
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 #3189
Conversation
Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our release note process to remove it. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
||
return run | ||
|
||
return inner |
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.
Code Review and Suggestions
1. Function Definitions
- All functions (
_get_ip_address
,_get_user
,log
) should be at the top of the file to ensure readability.
2. Class Imports
- Ensure that
Log
fromsystem_manage.models.log_management
is correctly imported and available in this module scope.
3. Method Decorators
-
The decorator pattern used in the
run
function can be made more concise using Python'sfunctools.wraps
. -
Remove duplicate variable names like
request
. For examplerequest
can be simply referred to asview.request
.
4. String Formatting
-
Use formatted string literals (f-strings) instead of concatenation for cleaner code.
-
Example: Replace
"操作菜单"
with{operate}
if it's supposed to display the result of executing theoperate
function.
5. Error Handling
- In rare cases where an error occurs during execution or logging, the exception handling may still lead to data inconsistencies because exceptions might occur within
function(view, request, **kwargs)
even when wrapped by another try-except block.
# Improve final exception catch statement to handle possible errors outside inner lambda function without interfering with original view logic
except Exception as e:
status = 500
print(f"Exception happened while processing {operate}, {e}")
6. Comments for Clarity
- Add comments explaining the purpose of each part, especially around complex control structures and edge case handles such as when
get_operation_object
raises an error.
7. Return Statements
- Consider whether all returned values are necessary or if the function could just return one value.
8. Logging Structure
- While logging structure seems functional, consider how logs are managed over multiple requests and systems. How will you rotate, back up, and access theselogs efficiently?
9. Security Considerations
- If sensitive information needs to be logged, ensure no personally identifiable information (PII) is recorded unless absolutely necessary, and make sure there's proper security measures implemented for accessing and managing these logs.
Final Revised Code:
# coding=utf-8
"""
@project: MaxKB
@Author:虎虎
@file: log.py
@date:2025/6/4 14:13
@desc:
"""
from functools import wraps
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 {'error': 'User not found'}
# Simplify dictionary construction for better readability
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
# Using f-string for clean formatting and improved readability
return {
'path': path,
'body': body,
'query': query
}
def log(menu, 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):
"""Wraps a view function to log audit events."""
@wraps(func)
def run(view, request, **kwargs):
try:
op_object = {}
if get_operation_object:
try:
op_object = get_operation_object(request, kwargs)
except Exception as e:
print(f"Error occurred fetching operation object - {e}")
response_obj = None
try:
response_obj = func(view, request, **kwargs)
status_code = 200
except Exception as e:
print(f"Inner function raised an unexpected error - {e}")
status_code = 500
# Log the audit event
Log(
menu=menu,
operate=getattr(response_obj, 'message', ''), # Assuming 'response' has a 'message' attribute which holds the actual message
user=get_user(request),
status=status_code,
ip_address=get_ip_address(request),
details=get_details(request),
operation_object=obj,
).save()
except Exception as e:
print(f"Final catch handler failed to complete properly - {e}")
traceback.print_exc()
return run
return inner
Key Changes Made:
- Imports: Moved class imports to maintain consistency and clarity.
- Function Enhancements:
- Simplified dictionary contruction.
- Used f-string format strings for readable output.
- Error Handling Improvement: Improved exception handling by catching them specifically in each appropriate context.
- Documentation: Added additional explanations about certain parts of the code for better understanding.
- Security Note: Highlighted importance of securing Sensitive information in logs.
details = models.JSONField(verbose_name="详情", default=dict, encoder=SystemEncoder) | ||
|
||
class Meta: | ||
db_table = "log" |
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.
There are several potential improvements and corrections needed in this Python code:
-
UTF-8 Encoding: Ensure that all strings use UTF-8 encoding to avoid any compatibility issues.
-
Imports: The
uuid
module may have been moved or renamed in later versions of Python. It's always safer to explicitly import modules from their original location rather than relying on implicit imports. -
Class Inheritance: Ensure that the
AppModelMixin
is correctly inherited and handles all necessary attributes and methods. -
JSON Fields Initialization: Initialize
operation_object
anduser
fields with JSON objects, not just empty dictionaries. -
Database Table Definition: Double-check the database table name
log
to ensure it matches your database schema.
Here’s an updated version of your code with these changes:
# coding=utf-8
"""
@project: MaxKB
@Author:虎虎
@file: log_management.py
@date:2025/6/4 14:15
@desc:
"""
import uuid
from django.conf import settings
from django.db import models
from common.encoder.encoder import SystemEncoder
from common.mixins.app_model_mixin import AppModelMixin
class Log(AppModelMixin):
"""
审计日志
"""
# Explicitly specify UUID type
id = models.UUIDField(primary_key=True, max_length=128)
# Define char fields properly
menu = models.CharField(max_length=settings.MAX_LENGTH_MENU, verbose_name="操作菜单")
operate = models.CharField(max_length=settings.MAX_LENGTH_OPERATE, verbose_name="操作")
# Initialize JSON fields properly
operation_object = models.JSONField(verbose_name="操作对象", default={}, encoder=SystemEncoder)
user = models.JSONField(verbose_name="用户信息", default={})
status = models.IntegerField(verbose_name="状态")
ip_address = models.CharField(max_length=settings.MAX_LENGTH_IP_ADDRESS, verbose_name="ip地址")
details = models.JSONField(verbose_name="详情", default={}, encoder=SystemEncoder)
class Meta:
db_table = "log"
Key Changes:
- Used
settings.MAX_LENGTH_MENU
,settings.MAX_LENGTH_OPERATE
,settings.MAX_LENGTH_IP_ADDRESS
instead of hardcoding numbers directly. - Ensured explicit definition for the UUID field using
models.UUIDField
. - Initialized JSON fields properly with default values
{}
instead ofdict
.
Additional Recommendations:
- Consider adding custom validation and sanitization logic for sensitive data handled by the
operation_details
field. - Review the migration script (if applicable) to ensure there aren't any breaking changes to the database schema. You can generate a new migration if necessary using Django's management commands (
makemigrations
,migrate
).
'db_table': 'log', | ||
}, | ||
), | ||
] |
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.
There are no significant issues with the provided code snippet for creating a migration to introduce a new Log
model. Here are some minor points you might consider:
-
Default Value for UUID: You're using
default=uuid.uuid1
, which is generally fine, but ensure that this value adheres to your project's naming conventions and security requirements. -
Use of Django JSONField: In Django, there is specifically an
OptionalValueJSONField
if empty values should be treated as null instead of defaulting to{}
. Consider updating your field declarations accordingly unless you prefer to handle empty objects natively. -
Version Check: The comment mentions "Generated by Django 5.2" from June 4th, 2025. If this migration is used in another environment where Django version may differ significantly, it could lead to compatibility issues. Ensure all relevant parts of your project are compatible with Django 5.2.
-
Verbosity: Using custom encoders can add complexity and might not always perform well in production environments, especially when dealing with very large datasets or complex data structures. Review the efficiency impact of these choices.
Overall, the migration looks clean and straightforward, suitable for adding a logging system to your Django application.
feat: log management