logger.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. """
  2. 日志配置模块
  3. 提供统一的日志配置和管理
  4. """
  5. import logging
  6. import sys
  7. from pathlib import Path
  8. from typing import Optional, Union
  9. def _get_log_level(level: Union[str, int]) -> int:
  10. """
  11. 将字符串形式的日志级别转换为logging常量
  12. Args:
  13. level: 日志级别(字符串或int)
  14. Returns:
  15. logging级别常量
  16. """
  17. if isinstance(level, int):
  18. return level
  19. level_map = {
  20. "DEBUG": logging.DEBUG,
  21. "INFO": logging.INFO,
  22. "WARNING": logging.WARNING,
  23. "ERROR": logging.ERROR,
  24. "CRITICAL": logging.CRITICAL,
  25. }
  26. return level_map.get(level.upper(), logging.INFO)
  27. def _load_logging_config_from_config():
  28. """
  29. 从配置中加载日志设置
  30. Returns:
  31. 包含日志配置的字典,如果配置不可用则返回None
  32. """
  33. try:
  34. from .config import get_config
  35. config = get_config()
  36. logging_config = config.get_section("logging")
  37. if logging_config:
  38. return logging_config
  39. except Exception:
  40. # 如果配置模块不可用或加载失败,返回None
  41. pass
  42. return None
  43. def setup_logger(
  44. name: str = "taskflow",
  45. level: Union[str, int] = logging.INFO,
  46. log_file: Optional[str] = None,
  47. format_string: Optional[str] = None,
  48. console_output: Optional[bool] = None,
  49. use_config: bool = True
  50. ) -> logging.Logger:
  51. """
  52. 设置并返回配置好的日志记录器
  53. Args:
  54. name: 日志记录器名称
  55. level: 日志级别(logging.DEBUG, INFO, WARNING, ERROR, CRITICAL 或字符串形式)
  56. log_file: 日志文件路径(如果为None,则尝试从配置中读取)
  57. format_string: 日志格式字符串(如果为None,则尝试从配置中读取或使用默认格式)
  58. console_output: 是否输出到控制台(如果为None,则尝试从配置中读取)
  59. use_config: 是否从配置中读取日志设置(默认True)
  60. Returns:
  61. 配置好的日志记录器
  62. 使用示例:
  63. >>> logger = setup_logger(name="my_project", level=logging.DEBUG)
  64. >>> logger.info("这是一条信息")
  65. >>> logger.error("这是一条错误")
  66. """
  67. logger = logging.getLogger(name)
  68. # 避免重复添加处理器
  69. if logger.handlers:
  70. return logger
  71. # 从配置中加载日志设置
  72. config_logging = None
  73. if use_config:
  74. config_logging = _load_logging_config_from_config()
  75. # 确定日志级别
  76. if isinstance(level, str):
  77. level = _get_log_level(level)
  78. elif config_logging and level == logging.INFO:
  79. # 如果使用默认值且配置可用,尝试从配置读取
  80. config_level = config_logging.get("level")
  81. if config_level:
  82. level = _get_log_level(config_level)
  83. logger.setLevel(level)
  84. # 确定格式字符串
  85. if format_string is None:
  86. if config_logging:
  87. format_string = config_logging.get("format")
  88. if format_string is None:
  89. format_string = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
  90. # 确定日期格式
  91. if config_logging:
  92. date_format = config_logging.get("date_format", "%Y-%m-%d %H:%M:%S")
  93. else:
  94. date_format = '%Y-%m-%d %H:%M:%S'
  95. formatter = logging.Formatter(format_string, datefmt=date_format)
  96. # 确定是否输出到控制台
  97. if console_output is None:
  98. if config_logging:
  99. console_output = config_logging.get("console_output", True)
  100. else:
  101. console_output = True
  102. # 控制台处理器
  103. if console_output:
  104. console_handler = logging.StreamHandler(sys.stdout)
  105. console_handler.setLevel(level)
  106. console_handler.setFormatter(formatter)
  107. logger.addHandler(console_handler)
  108. # 确定日志文件路径
  109. if log_file is None and config_logging:
  110. file_output = config_logging.get("file_output", False)
  111. if file_output:
  112. log_file = config_logging.get("log_file")
  113. # 文件处理器
  114. if log_file:
  115. log_path = Path(log_file)
  116. log_path.parent.mkdir(parents=True, exist_ok=True)
  117. file_handler = logging.FileHandler(log_file, encoding='utf-8')
  118. file_handler.setLevel(level)
  119. file_handler.setFormatter(formatter)
  120. logger.addHandler(file_handler)
  121. return logger
  122. def get_logger(name: Optional[str] = None) -> logging.Logger:
  123. """
  124. 获取日志记录器
  125. 如果指定名称的记录器不存在,会创建一个默认配置的记录器。
  126. 会自动从配置中读取日志设置。
  127. Args:
  128. name: 日志记录器名称(如果为None,使用 "taskflow")
  129. Returns:
  130. 日志记录器实例
  131. """
  132. if name is None:
  133. name = "taskflow"
  134. logger = logging.getLogger(name)
  135. # 如果记录器还没有配置,从配置中读取设置并创建
  136. if not logger.handlers:
  137. logger = setup_logger(name=name, use_config=True)
  138. return logger
  139. # 创建默认的 taskflow 日志记录器
  140. default_logger = setup_logger(name="taskflow", level=logging.INFO)