xfvsdf/qqbot
0
1"""2日志模块 - 使用环境变量配置3"""4import os5import sys6import threading7from datetime import datetime8 9# 日志级别定义10LOG_LEVELS = {11 'debug': 0,12 'info': 1,13 'warning': 2,14 'error': 3,15 'critical': 416}17 18# 线程锁,用于文件写入同步19_file_lock = threading.Lock()20 21# 文件写入状态标志22_file_writing_disabled = False23_disable_reason = None24 25def _get_current_log_level():26 """获取当前日志级别"""27 level = os.getenv('LOG_LEVEL', 'info').lower()28 return LOG_LEVELS.get(level, LOG_LEVELS['info'])29 30def _get_log_file_path():31 """获取日志文件路径"""32 return os.getenv('LOG_FILE', 'log.txt')33 34def _write_to_file(message: str):35 """线程安全地写入日志文件"""36 global _file_writing_disabled, _disable_reason37 38 # 如果文件写入已被禁用,直接返回39 if _file_writing_disabled:40 return41 42 try:43 log_file = _get_log_file_path()44 with _file_lock:45 with open(log_file, 'a', encoding='utf-8') as f:46 f.write(message + '\n')47 f.flush() # 强制刷新到磁盘,确保实时写入48 except (PermissionError, OSError, IOError) as e:49 # 检测只读文件系统或权限问题,禁用文件写入50 _file_writing_disabled = True51 _disable_reason = str(e)52 print(f"Warning: File system appears to be read-only or permission denied. Disabling log file writing: {e}", file=sys.stderr)53 print(f"Log messages will continue to display in console only.", file=sys.stderr)54 except Exception as e:55 # 其他异常仍然输出警告但不禁用写入(可能是临时问题)56 print(f"Warning: Failed to write to log file: {e}", file=sys.stderr)57 58def _log(level: str, message: str):59 """60 内部日志函数61 """62 level = level.lower()63 if level not in LOG_LEVELS:64 print(f"Warning: Unknown log level '{level}'", file=sys.stderr)65 return66 67 # 检查日志级别68 current_level = _get_current_log_level()69 if LOG_LEVELS[level] < current_level:70 return71 72 # 格式化日志消息73 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")74 entry = f"[{timestamp}] [{level.upper()}] {message}"75 76 # 输出到控制台77 if level in ('error', 'critical'):78 print(entry, file=sys.stderr)79 else:80 print(entry)81 82 # 实时写入文件83 _write_to_file(entry)84 85def set_log_level(level: str):86 """设置日志级别提示"""87 level = level.lower()88 if level not in LOG_LEVELS:89 print(f"Warning: Unknown log level '{level}'. Valid levels: {', '.join(LOG_LEVELS.keys())}")90 return False91 92 print(f"Note: To set log level '{level}', please set LOG_LEVEL environment variable")93 return True94 95class Logger:96 """支持 log('info', 'msg') 和 log.info('msg') 两种调用方式"""97 98 def __call__(self, level: str, message: str):99 """支持 log('info', 'message') 调用方式"""100 _log(level, message)101 102 def debug(self, message: str):103 """记录调试信息"""104 _log('debug', message)105 106 def info(self, message: str):107 """记录一般信息"""108 _log('info', message)109 110 def warning(self, message: str):111 """记录警告信息"""112 _log('warning', message)113 114 def error(self, message: str):115 """记录错误信息"""116 _log('error', message)117 118 def critical(self, message: str):119 """记录严重错误信息"""120 _log('critical', message)121 122 def get_current_level(self) -> str:123 """获取当前日志级别名称"""124 current_level = _get_current_log_level()125 for name, value in LOG_LEVELS.items():126 if value == current_level:127 return name128 return 'info'129 130 def get_log_file(self) -> str:131 """获取当前日志文件路径"""132 return _get_log_file_path()133 134 135# 导出全局日志实例136log = Logger()137 138# 导出的公共接口139__all__ = ['log', 'set_log_level', 'LOG_LEVELS']140 141# 使用说明:142# 1. 设置日志级别: export LOG_LEVEL=debug (或在.env文件中设置)143# 2. 设置日志文件: export LOG_FILE=log.txt (或在.env文件中设置)