logger.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. """
  2. 结构化日志系统
  3. 支持生态状态、智能体决策、风险事件分级记录
  4. """
  5. import json
  6. import logging
  7. import sys
  8. from datetime import datetime
  9. from enum import Enum
  10. from pathlib import Path
  11. from typing import Any, Dict, Optional
  12. import structlog
  13. class LogLevel(Enum):
  14. """日志级别"""
  15. DEBUG = "debug"
  16. INFO = "info"
  17. WARNING = "warning"
  18. ERROR = "error"
  19. CRITICAL = "critical"
  20. class EventType(Enum):
  21. """事件类型"""
  22. # 生态事件
  23. ECOSYSTEM_CHANGE = "ecosystem_change"
  24. REGIME_TRANSITION = "regime_transition"
  25. # 智能体事件
  26. AGENT_SIGNAL = "agent_signal"
  27. AGENT_ROUTING = "agent_routing"
  28. AGENT_HEALTH = "agent_health"
  29. # 风险事件
  30. RISK_BUDGET = "risk_budget"
  31. RISK_HEDGE = "risk_hedge"
  32. RISK_ALERT = "risk_alert"
  33. RISK_WARNING = "risk_warning"
  34. RISK_STOP = "risk_stop"
  35. # 执行事件
  36. EXECUTION_ORDER = "execution_order"
  37. EXECUTION_FILL = "execution_fill"
  38. EXECUTION_COST = "execution_cost"
  39. # 系统事件
  40. SYSTEM_START = "system_start"
  41. SYSTEM_STOP = "system_stop"
  42. SYSTEM_ERROR = "system_error"
  43. class CYB50Logger:
  44. """CYB50-Pro 结构化日志器"""
  45. def __init__(self, log_dir: str = "logs", log_level: str = "INFO"):
  46. self.log_dir = Path(log_dir)
  47. self.log_dir.mkdir(exist_ok=True)
  48. self.log_level = getattr(logging, log_level.upper())
  49. self._configure_structlog()
  50. self._configure_standard_logging()
  51. self.logger = structlog.get_logger()
  52. def _configure_structlog(self):
  53. """配置 structlog"""
  54. structlog.configure(
  55. processors=[
  56. structlog.stdlib.filter_by_level,
  57. structlog.stdlib.add_logger_name,
  58. structlog.stdlib.add_log_level,
  59. structlog.stdlib.PositionalArgumentsFormatter(),
  60. structlog.processors.TimeStamper(fmt="iso"),
  61. structlog.processors.StackInfoRenderer(),
  62. structlog.processors.format_exc_info,
  63. structlog.processors.UnicodeDecoder(),
  64. structlog.processors.JSONRenderer()
  65. ],
  66. context_class=dict,
  67. logger_factory=structlog.stdlib.LoggerFactory(),
  68. wrapper_class=structlog.stdlib.BoundLogger,
  69. cache_logger_on_first_use=True,
  70. )
  71. def _configure_standard_logging(self):
  72. """配置标准日志"""
  73. # 文件处理器 - 详细日志
  74. detailed_handler = logging.FileHandler(
  75. self.log_dir / f"cyb50_pro_{datetime.now():%Y%m%d}.log"
  76. )
  77. detailed_handler.setLevel(self.log_level)
  78. # 文件处理器 - 仅错误
  79. error_handler = logging.FileHandler(
  80. self.log_dir / f"cyb50_pro_error_{datetime.now():%Y%m%d}.log"
  81. )
  82. error_handler.setLevel(logging.ERROR)
  83. # 控制台处理器
  84. console_handler = logging.StreamHandler(sys.stdout)
  85. console_handler.setLevel(self.log_level)
  86. # 格式化器
  87. formatter = logging.Formatter(
  88. "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
  89. )
  90. detailed_handler.setFormatter(formatter)
  91. error_handler.setFormatter(formatter)
  92. console_handler.setFormatter(formatter)
  93. # 根日志配置
  94. logging.basicConfig(
  95. level=self.log_level,
  96. handlers=[detailed_handler, error_handler, console_handler]
  97. )
  98. def log_ecosystem(
  99. self,
  100. event_type: EventType,
  101. macro_regime: str,
  102. meso_health: float,
  103. micro_state: str,
  104. confidence: float,
  105. details: Optional[Dict[str, Any]] = None
  106. ):
  107. """记录生态状态"""
  108. self.logger.info(
  109. event_type=event_type.value,
  110. category="ecosystem",
  111. macro_regime=macro_regime,
  112. meso_health=meso_health,
  113. micro_state=micro_state,
  114. confidence=confidence,
  115. details=details or {}
  116. )
  117. def log_agent(
  118. self,
  119. event_type: EventType,
  120. agent_name: str,
  121. signal: Optional[str] = None,
  122. weight: Optional[float] = None,
  123. health_score: Optional[float] = None,
  124. expected_return: Optional[float] = None,
  125. details: Optional[Dict[str, Any]] = None
  126. ):
  127. """记录智能体决策"""
  128. self.logger.info(
  129. event_type=event_type.value,
  130. category="agent",
  131. agent_name=agent_name,
  132. signal=signal,
  133. weight=weight,
  134. health_score=health_score,
  135. expected_return=expected_return,
  136. details=details or {}
  137. )
  138. def log_risk(
  139. self,
  140. event_type: EventType,
  141. level: str, # "info", "warning", "critical"
  142. metric_name: Optional[str] = None,
  143. metric_value: Optional[float] = None,
  144. threshold: Optional[float] = None,
  145. action: Optional[str] = None,
  146. details: Optional[Dict[str, Any]] = None
  147. ):
  148. """记录风险事件"""
  149. log_method = getattr(self.logger, level)
  150. log_method(
  151. event_type=event_type.value,
  152. category="risk",
  153. metric_name=metric_name,
  154. metric_value=metric_value,
  155. threshold=threshold,
  156. action=action,
  157. details=details or {}
  158. )
  159. def log_execution(
  160. self,
  161. event_type: EventType,
  162. order_id: str,
  163. symbol: str,
  164. side: str,
  165. quantity: int,
  166. price: Optional[float] = None,
  167. cost: Optional[float] = None,
  168. strategy: Optional[str] = None,
  169. details: Optional[Dict[str, Any]] = None
  170. ):
  171. """记录执行事件"""
  172. self.logger.info(
  173. event_type=event_type.value,
  174. category="execution",
  175. order_id=order_id,
  176. symbol=symbol,
  177. side=side,
  178. quantity=quantity,
  179. price=price,
  180. cost=cost,
  181. strategy=strategy,
  182. details=details or {}
  183. )
  184. def log_system(
  185. self,
  186. event_type: EventType,
  187. message: str,
  188. level: str = "info",
  189. details: Optional[Dict[str, Any]] = None
  190. ):
  191. """记录系统事件"""
  192. log_method = getattr(self.logger, level)
  193. log_method(
  194. event_type=event_type.value,
  195. category="system",
  196. message=message,
  197. details=details or {}
  198. )
  199. # 全局日志实例
  200. _logger: Optional[CYB50Logger] = None
  201. def get_logger(log_dir: str = "logs", log_level: str = "INFO") -> CYB50Logger:
  202. """获取全局日志实例"""
  203. global _logger
  204. if _logger is None:
  205. _logger = CYB50Logger(log_dir, log_level)
  206. return _logger
  207. def configure_logging(log_dir: str = "logs", log_level: str = "INFO"):
  208. """配置日志系统"""
  209. global _logger
  210. _logger = CYB50Logger(log_dir, log_level)