123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- import logging
- import os
- import sys
- from datetime import datetime
- from typing import Optional
- def setup_logging(verbose: bool = False, log_file: Optional[str] = None, log_dir: Optional[str] = None):
- """
- 设置日志系统
-
- Args:
- verbose: 是否启用详细日志
- log_file: 日志文件名
- log_dir: 日志目录
- """
- # 确定日志级别
- log_level = logging.DEBUG if verbose else logging.INFO
-
- # 创建根logger
- root_logger = logging.getLogger()
- root_logger.setLevel(log_level)
-
- # 清除已有的处理器
- root_logger.handlers.clear()
-
- # 设置日志格式
- console_format = "%(asctime)s [%(levelname)s] %(message)s"
- file_format = "%(asctime)s [%(levelname)s] [%(name)s] %(message)s"
- date_format = "%Y-%m-%d %H:%M:%S"
-
- # 控制台处理器
- console_handler = logging.StreamHandler(sys.stdout)
- console_handler.setLevel(log_level)
- console_formatter = logging.Formatter(console_format, datefmt=date_format)
- console_handler.setFormatter(console_formatter)
- root_logger.addHandler(console_handler)
-
- # 文件处理器(如果指定)
- if log_file:
- # 确定日志文件路径
- if log_dir:
- os.makedirs(log_dir, exist_ok=True)
- log_path = os.path.join(log_dir, log_file)
- else:
- log_path = log_file
-
- # 添加时间戳到日志文件名
- base_name, ext = os.path.splitext(log_path)
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
- log_path = f"{base_name}_{timestamp}{ext}"
-
- file_handler = logging.FileHandler(log_path, encoding='utf-8')
- file_handler.setLevel(log_level)
- file_formatter = logging.Formatter(file_format, datefmt=date_format)
- file_handler.setFormatter(file_formatter)
- root_logger.addHandler(file_handler)
-
- # 记录日志文件位置
- root_logger.info(f"日志文件: {os.path.abspath(log_path)}")
-
- # 设置schema_tools模块的日志级别
- schema_tools_logger = logging.getLogger("schema_tools")
- schema_tools_logger.setLevel(log_level)
-
- # 设置第三方库的日志级别(避免过多输出)
- logging.getLogger("asyncio").setLevel(logging.WARNING)
- logging.getLogger("asyncpg").setLevel(logging.WARNING)
- logging.getLogger("openai").setLevel(logging.WARNING)
- logging.getLogger("httpx").setLevel(logging.WARNING)
- logging.getLogger("urllib3").setLevel(logging.WARNING)
-
- # 返回schema_tools的logger
- return schema_tools_logger
- class ColoredFormatter(logging.Formatter):
- """带颜色的日志格式化器(用于控制台)"""
-
- # ANSI颜色代码
- COLORS = {
- 'DEBUG': '\033[36m', # 青色
- 'INFO': '\033[32m', # 绿色
- 'WARNING': '\033[33m', # 黄色
- 'ERROR': '\033[31m', # 红色
- 'CRITICAL': '\033[35m', # 紫色
- }
- RESET = '\033[0m'
-
- def format(self, record):
- # 保存原始级别名
- levelname = record.levelname
-
- # 添加颜色
- if levelname in self.COLORS:
- record.levelname = f"{self.COLORS[levelname]}{levelname}{self.RESET}"
-
- # 格式化消息
- formatted = super().format(record)
-
- # 恢复原始级别名
- record.levelname = levelname
-
- return formatted
- def get_colored_console_handler(level=logging.INFO):
- """获取带颜色的控制台处理器"""
- handler = logging.StreamHandler(sys.stdout)
- handler.setLevel(level)
-
- # 检查是否支持颜色(Windows需要特殊处理)
- if sys.platform == "win32":
- try:
- import colorama
- colorama.init()
- use_color = True
- except ImportError:
- use_color = False
- else:
- # Unix/Linux/Mac通常支持ANSI颜色
- use_color = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
-
- if use_color:
- formatter = ColoredFormatter(
- "%(asctime)s [%(levelname)s] %(message)s",
- datefmt="%Y-%m-%d %H:%M:%S"
- )
- else:
- formatter = logging.Formatter(
- "%(asctime)s [%(levelname)s] %(message)s",
- datefmt="%Y-%m-%d %H:%M:%S"
- )
-
- handler.setFormatter(formatter)
- return handler
- class TableProcessingLogger:
- """表处理专用日志器"""
-
- def __init__(self, logger_name: str = "schema_tools.TableProcessor"):
- self.logger = logging.getLogger(logger_name)
- self.current_table = None
- self.start_time = None
-
- def start_table(self, table_name: str):
- """开始处理表"""
- self.current_table = table_name
- self.start_time = datetime.now()
- self.logger.info(f"{'='*60}")
- self.logger.info(f"开始处理表: {table_name}")
- self.logger.info(f"开始时间: {self.start_time.strftime('%Y-%m-%d %H:%M:%S')}")
-
- def end_table(self, success: bool = True):
- """结束处理表"""
- if self.start_time:
- duration = (datetime.now() - self.start_time).total_seconds()
- status = "成功" if success else "失败"
- self.logger.info(f"处理{status},耗时: {duration:.2f}秒")
- self.logger.info(f"{'='*60}\n")
- self.current_table = None
- self.start_time = None
-
- def log_step(self, step_name: str, message: str = None):
- """记录处理步骤"""
- if message:
- self.logger.info(f" [{step_name}] {message}")
- else:
- self.logger.info(f" [{step_name}]")
-
- def log_warning(self, message: str):
- """记录警告"""
- self.logger.warning(f" ⚠ {message}")
-
- def log_error(self, message: str):
- """记录错误"""
- self.logger.error(f" ✗ {message}")
|