diff --git a/app/config.py b/app/config.py index 9471f7d..5df2265 100644 --- a/app/config.py +++ b/app/config.py @@ -54,14 +54,7 @@ class Settings(BaseSettings): log_date_format: str = "%Y-%m-%d %H:%M:%S" # API配置 - _api_authorization_token: str = "" # 内部存储API Authorization Token - - @property - def api_authorization_token(self) -> str: - """API Authorization Token - 只在生产环境下返回""" - if self.environment.lower() == "production": - return self._api_authorization_token - return "" + api_authorization_token: str = "" # API Authorization Token # 应用配置 app_name: str = "AI Talk Callback API" diff --git a/app/logger.py b/app/logger.py index c34d4dc..c6a64e5 100644 --- a/app/logger.py +++ b/app/logger.py @@ -2,10 +2,57 @@ import logging import logging.handlers from pathlib import Path from typing import Optional +import time +from datetime import datetime, timedelta from app.config import settings +class CustomTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler): + """自定义时间轮转文件处理器,支持指定轮转时间""" + + def __init__(self, filename, hour=17, minute=36, when='midnight', interval=1, backupCount=7, encoding='utf-8'): + self.target_hour = hour + self.target_minute = minute + self.target_when = when + self.target_interval = interval + + # 先调用父类初始化 + super().__init__(filename, when=when, interval=interval, backupCount=backupCount, encoding=encoding) + + # 重新计算轮转时间 + self.computeRollover() + + + def computeRollover(self, currentTime=None): + """计算下一次轮转时间,设置为每天的指定时间""" + if currentTime is None: + currentTime = time.time() + + # 获取当前时间 + current_time = datetime.fromtimestamp(currentTime) + + # 创建今天的目标时间 + target_time = current_time.replace(hour=self.target_hour, minute=self.target_minute, second=0, microsecond=0) + + # 如果今天的目标时间已过,设置为明天 + if current_time >= target_time: + target_time += timedelta(days=1) + + # 转换为时间戳 + self.rolloverAt = target_time.timestamp() + + + def doRollover(self): + # 调用父类轮转方法 + super().doRollover() + + # 重新计算下次轮转时间 + self.computeRollover() + + print(f"✅ 日志轮转完成,下次: {datetime.fromtimestamp(self.rolloverAt).strftime('%Y-%m-%d %H:%M:%S')}") + + class LoggerManager: """日志管理器""" @@ -40,10 +87,12 @@ class LoggerManager: ) console_handler.setFormatter(console_formatter) - # 创建文件处理器(按时间轮转) - file_handler = logging.handlers.TimedRotatingFileHandler( + # 创建文件处理器(按时间轮转,每天17:36) + file_handler = CustomTimedRotatingFileHandler( filename=settings.log_file, - when='midnight', # 每天午夜轮转 + hour=17, # 17点 + minute=36, # 36分 + when='midnight', # 每天轮转 interval=1, # 每天一次 backupCount=settings.log_backup_count, encoding='utf-8', @@ -117,7 +166,7 @@ redis_logger = get_logger("redis") # 通用文件日志器设置函数 def setup_celery_file_logger(logger_name: str, log_file: str, level: str = "INFO"): - """为Celery组件设置专用的文件日志器,同时保持控制台输出""" + """为Celery组件设置专用的文件日志器,同时输出到控制台和文件""" # 创建日志目录 log_dir = Path(log_file).parent log_dir.mkdir(parents=True, exist_ok=True) @@ -126,14 +175,25 @@ def setup_celery_file_logger(logger_name: str, log_file: str, level: str = "INFO logger = get_logger(logger_name) logger.setLevel(getattr(logging, level.upper())) - # 清除现有文件处理器(避免重复添加) - for handler in logger.handlers[:]: - if isinstance(handler, logging.handlers.TimedRotatingFileHandler): - logger.removeHandler(handler) + # 清除现有处理器(避免重复添加) + logger.handlers.clear() + + # 创建控制台处理器 + console_handler = logging.StreamHandler() + console_handler.setLevel(getattr(logging, level.upper())) + + # 控制台格式化器 + console_formatter = logging.Formatter( + fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + console_handler.setFormatter(console_formatter) # 创建文件处理器 - file_handler = logging.handlers.TimedRotatingFileHandler( + file_handler = CustomTimedRotatingFileHandler( filename=log_file, + hour=17, # 17点 + minute=36, # 36分 when='midnight', interval=1, backupCount=7, @@ -142,16 +202,17 @@ def setup_celery_file_logger(logger_name: str, log_file: str, level: str = "INFO file_handler.suffix = "%Y%m%d" file_handler.setLevel(getattr(logging, level.upper())) - # 格式化器 - formatter = logging.Formatter( + # 文件格式化器 + file_formatter = logging.Formatter( fmt='%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) - file_handler.setFormatter(formatter) + file_handler.setFormatter(file_formatter) - # 添加文件处理器 + # 添加处理器(先控制台,后文件) + logger.addHandler(console_handler) logger.addHandler(file_handler) - logger.propagate = True + logger.propagate = False # 防止重复输出到父日志器 return logger @@ -159,8 +220,8 @@ def setup_celery_file_logger(logger_name: str, log_file: str, level: str = "INFO CELERY_LOGGERS = { "celery_tasks": ("logs/celery_tasks.log", "INFO"), "celery": ("logs/celery_app.log", "INFO"), - "celery.beat": ("logs/celery_beat.log", "WARNING"), - "celery.worker": ("logs/celery_worker.log", "WARNING"), + "celery.beat": ("logs/celery_app.log", "INFO"), # Beat日志输出到celery_app.log + "celery.worker": ("logs/celery_app.log", "INFO"), # Worker日志输出到celery_app.log } # 初始化所有Celery文件日志器