126 lines
3.7 KiB
Python
126 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
日誌管理模組
|
|
|
|
Author: PANJIT IT Team
|
|
Created: 2024-01-28
|
|
Modified: 2024-01-28
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
from pathlib import Path
|
|
from logging.handlers import RotatingFileHandler
|
|
from flask import current_app, has_request_context, request, g
|
|
|
|
|
|
def get_logger(name):
|
|
"""取得指定名稱的日誌器"""
|
|
logger = logging.getLogger(name)
|
|
|
|
# 避免重複設定 handler
|
|
if not logger.handlers:
|
|
setup_logger(logger)
|
|
|
|
return logger
|
|
|
|
|
|
def setup_logger(logger):
|
|
"""設定日誌器"""
|
|
if has_request_context() and current_app:
|
|
log_level = current_app.config.get('LOG_LEVEL', 'INFO')
|
|
log_file = current_app.config.get('LOG_FILE', 'logs/app.log')
|
|
else:
|
|
log_level = os.environ.get('LOG_LEVEL', 'INFO')
|
|
log_file = os.environ.get('LOG_FILE', 'logs/app.log')
|
|
|
|
# 確保日誌目錄存在
|
|
log_path = Path(log_file)
|
|
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
# 設定日誌等級
|
|
logger.setLevel(getattr(logging, log_level.upper()))
|
|
|
|
# 建立格式化器
|
|
formatter = logging.Formatter(
|
|
'%(asctime)s [%(levelname)s] %(name)s: %(message)s',
|
|
datefmt='%Y-%m-%d %H:%M:%S'
|
|
)
|
|
|
|
# 檔案處理器(使用輪轉)
|
|
file_handler = RotatingFileHandler(
|
|
log_file,
|
|
maxBytes=10*1024*1024, # 10MB
|
|
backupCount=5,
|
|
encoding='utf-8'
|
|
)
|
|
file_handler.setLevel(getattr(logging, log_level.upper()))
|
|
file_handler.setFormatter(formatter)
|
|
logger.addHandler(file_handler)
|
|
|
|
# 控制台處理器
|
|
console_handler = logging.StreamHandler()
|
|
console_handler.setLevel(logging.INFO)
|
|
console_handler.setFormatter(formatter)
|
|
logger.addHandler(console_handler)
|
|
|
|
|
|
class DatabaseLogHandler(logging.Handler):
|
|
"""資料庫日誌處理器"""
|
|
|
|
def emit(self, record):
|
|
"""發送日誌記錄到資料庫"""
|
|
try:
|
|
from app.models.log import SystemLog
|
|
|
|
# 取得使用者和任務資訊(如果有的話)
|
|
user_id = None
|
|
job_id = None
|
|
extra_data = {}
|
|
|
|
if has_request_context():
|
|
user_id = g.get('current_user_id')
|
|
extra_data.update({
|
|
'method': request.method,
|
|
'endpoint': request.endpoint,
|
|
'url': request.url,
|
|
'ip_address': request.remote_addr,
|
|
'user_agent': request.headers.get('User-Agent')
|
|
})
|
|
|
|
# 儲存到資料庫
|
|
SystemLog.log(
|
|
level=record.levelname,
|
|
module=record.name,
|
|
message=record.getMessage(),
|
|
user_id=user_id,
|
|
job_id=job_id,
|
|
extra_data=extra_data if extra_data else None
|
|
)
|
|
|
|
except Exception:
|
|
# 避免日誌記錄失敗影響主程序
|
|
pass
|
|
|
|
|
|
def init_logging(app):
|
|
"""初始化應用程式日誌"""
|
|
# 設定根日誌器
|
|
root_logger = logging.getLogger()
|
|
root_logger.setLevel(logging.INFO)
|
|
|
|
# 添加資料庫日誌處理器(僅對重要日誌)
|
|
if app.config.get('SQLALCHEMY_DATABASE_URI'):
|
|
db_handler = DatabaseLogHandler()
|
|
db_handler.setLevel(logging.WARNING) # 只記錄警告以上等級到資料庫
|
|
root_logger.addHandler(db_handler)
|
|
|
|
# 設定 Flask 應用日誌
|
|
if not app.logger.handlers:
|
|
setup_logger(app.logger)
|
|
|
|
# 設定第三方庫日誌等級
|
|
logging.getLogger('werkzeug').setLevel(logging.WARNING)
|
|
logging.getLogger('urllib3').setLevel(logging.WARNING)
|
|
logging.getLogger('requests').setLevel(logging.WARNING) |