1st_fix_login_issue

This commit is contained in:
beabigegg
2025-09-02 10:31:35 +08:00
commit a60d965317
103 changed files with 12402 additions and 0 deletions

211
app/models/log.py Normal file
View File

@@ -0,0 +1,211 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
系統日誌資料模型
Author: PANJIT IT Team
Created: 2024-01-28
Modified: 2024-01-28
"""
import json
from datetime import datetime, timedelta
from sqlalchemy.sql import func
from app import db
class SystemLog(db.Model):
"""系統日誌表 (dt_system_logs)"""
__tablename__ = 'dt_system_logs'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
level = db.Column(
db.Enum('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', name='log_level'),
nullable=False,
comment='日誌等級'
)
module = db.Column(db.String(100), nullable=False, comment='模組名稱')
user_id = db.Column(db.Integer, db.ForeignKey('dt_users.id'), comment='使用者ID')
job_id = db.Column(db.Integer, db.ForeignKey('dt_translation_jobs.id'), comment='任務ID')
message = db.Column(db.Text, nullable=False, comment='日誌訊息')
extra_data = db.Column(db.JSON, comment='額外資料')
created_at = db.Column(db.DateTime, default=func.now(), comment='建立時間')
def __repr__(self):
return f'<SystemLog {self.level} {self.module}>'
def to_dict(self):
"""轉換為字典格式"""
return {
'id': self.id,
'level': self.level,
'module': self.module,
'user_id': self.user_id,
'job_id': self.job_id,
'message': self.message,
'extra_data': self.extra_data,
'created_at': self.created_at.isoformat() if self.created_at else None
}
@classmethod
def log(cls, level, module, message, user_id=None, job_id=None, extra_data=None):
"""記錄日誌"""
log_entry = cls(
level=level.upper(),
module=module,
message=message,
user_id=user_id,
job_id=job_id,
extra_data=extra_data
)
db.session.add(log_entry)
db.session.commit()
return log_entry
@classmethod
def debug(cls, module, message, user_id=None, job_id=None, extra_data=None):
"""記錄除錯日誌"""
return cls.log('DEBUG', module, message, user_id, job_id, extra_data)
@classmethod
def info(cls, module, message, user_id=None, job_id=None, extra_data=None):
"""記錄資訊日誌"""
return cls.log('INFO', module, message, user_id, job_id, extra_data)
@classmethod
def warning(cls, module, message, user_id=None, job_id=None, extra_data=None):
"""記錄警告日誌"""
return cls.log('WARNING', module, message, user_id, job_id, extra_data)
@classmethod
def error(cls, module, message, user_id=None, job_id=None, extra_data=None):
"""記錄錯誤日誌"""
return cls.log('ERROR', module, message, user_id, job_id, extra_data)
@classmethod
def critical(cls, module, message, user_id=None, job_id=None, extra_data=None):
"""記錄嚴重錯誤日誌"""
return cls.log('CRITICAL', module, message, user_id, job_id, extra_data)
@classmethod
def get_logs(cls, level=None, module=None, user_id=None, start_date=None, end_date=None, limit=100, offset=0):
"""查詢日誌"""
query = cls.query
if level:
query = query.filter_by(level=level.upper())
if module:
query = query.filter(cls.module.like(f'%{module}%'))
if user_id:
query = query.filter_by(user_id=user_id)
if start_date:
query = query.filter(cls.created_at >= start_date)
if end_date:
query = query.filter(cls.created_at <= end_date)
# 按時間倒序排列
query = query.order_by(cls.created_at.desc())
if limit:
query = query.limit(limit)
if offset:
query = query.offset(offset)
return query.all()
@classmethod
def get_log_statistics(cls, days=7):
"""取得日誌統計資料"""
end_date = datetime.utcnow()
start_date = end_date - timedelta(days=days)
# 按等級統計
level_stats = db.session.query(
cls.level,
func.count(cls.id).label('count')
).filter(
cls.created_at >= start_date
).group_by(cls.level).all()
# 按模組統計
module_stats = db.session.query(
cls.module,
func.count(cls.id).label('count')
).filter(
cls.created_at >= start_date
).group_by(cls.module).order_by(
func.count(cls.id).desc()
).limit(10).all()
# 每日統計
daily_stats = db.session.query(
func.date(cls.created_at).label('date'),
cls.level,
func.count(cls.id).label('count')
).filter(
cls.created_at >= start_date
).group_by(
func.date(cls.created_at), cls.level
).order_by(
func.date(cls.created_at)
).all()
return {
'level_stats': [
{'level': stat.level, 'count': stat.count}
for stat in level_stats
],
'module_stats': [
{'module': stat.module, 'count': stat.count}
for stat in module_stats
],
'daily_stats': [
{
'date': stat.date.isoformat(),
'level': stat.level,
'count': stat.count
}
for stat in daily_stats
]
}
@classmethod
def cleanup_old_logs(cls, days_to_keep=30):
"""清理舊日誌"""
cutoff_date = datetime.utcnow() - timedelta(days=days_to_keep)
deleted_count = cls.query.filter(
cls.created_at < cutoff_date
).delete(synchronize_session=False)
db.session.commit()
return deleted_count
@classmethod
def get_error_summary(cls, days=1):
"""取得錯誤摘要"""
start_date = datetime.utcnow() - timedelta(days=days)
error_logs = cls.query.filter(
cls.level.in_(['ERROR', 'CRITICAL']),
cls.created_at >= start_date
).order_by(cls.created_at.desc()).limit(50).all()
# 按模組分組錯誤
error_by_module = {}
for log in error_logs:
module = log.module
if module not in error_by_module:
error_by_module[module] = []
error_by_module[module].append(log.to_dict())
return {
'total_errors': len(error_logs),
'error_by_module': error_by_module,
'recent_errors': [log.to_dict() for log in error_logs[:10]]
}