From e73fd99e26e33ffa891f09142d62da4c8d3de5eb Mon Sep 17 00:00:00 2001 From: SXP-Simon Date: Sun, 8 Feb 2026 23:28:56 +0800 Subject: [PATCH] feat(logger) --- scripts/mock_pdf_gen.py | 13 +++-- src/analysis/analyzers/base_analyzer.py | 2 +- .../analyzers/golden_quote_analyzer.py | 2 +- src/analysis/analyzers/topic_analyzer.py | 2 +- src/analysis/analyzers/user_title_analyzer.py | 2 +- src/analysis/llm_analyzer.py | 2 +- src/analysis/utils/json_utils.py | 2 +- src/analysis/utils/llm_utils.py | 2 +- src/application/analysis_orchestrator.py | 52 +++++++++---------- src/application/reporting_service.py | 6 ++- src/application/scheduling_service.py | 8 ++- src/core/bot_manager.py | 2 +- src/core/history_manager.py | 2 +- src/core/message_handler.py | 2 +- src/core/message_sender.py | 2 +- src/infrastructure/config/config_manager.py | 2 +- src/infrastructure/llm/llm_client.py | 6 ++- .../persistence/history_repository.py | 6 +-- src/infrastructure/platform/factory.py | 19 ++++--- .../resilience/circuit_breaker.py | 2 +- src/infrastructure/resilience/rate_limiter.py | 2 +- src/infrastructure/resilience/retry.py | 2 +- src/reports/dispatcher.py | 2 +- src/reports/generators.py | 2 +- src/reports/templates.py | 2 +- src/scheduler/auto_scheduler.py | 2 +- src/scheduler/retry.py | 2 +- src/utils/helpers.py | 2 +- src/utils/logger.py | 16 ++++++ src/utils/pdf_utils.py | 2 +- src/utils/resilience.py | 2 +- 31 files changed, 100 insertions(+), 72 deletions(-) create mode 100644 src/utils/logger.py diff --git a/scripts/mock_pdf_gen.py b/scripts/mock_pdf_gen.py index 1b017d2..b3a456f 100644 --- a/scripts/mock_pdf_gen.py +++ b/scripts/mock_pdf_gen.py @@ -17,11 +17,16 @@ sys.path.insert(0, project_root) print(f"Project Root: {project_root}") # Mock logger before importing anything that uses it -from astrbot.api import logger # noqa: E402 +# Mock logger +from data.plugins.astrbot_plugin_qq_group_daily_analysis.src.utils import ( + logger as plugin_logger_module, +) -logger.info = lambda msg, *args, **kwargs: print(f"[INFO] {msg}") -logger.error = lambda msg, *args, **kwargs: print(f"[ERROR] {msg}") -logger.warning = lambda msg, *args, **kwargs: print(f"[WARN] {msg}") +plugin_logger_module.logger.info = lambda msg, *args, **kwargs: print(f"[INFO] {msg}") +plugin_logger_module.logger.error = lambda msg, *args, **kwargs: print(f"[ERROR] {msg}") +plugin_logger_module.logger.warning = lambda msg, *args, **kwargs: print( + f"[WARN] {msg}" +) # Now import plugin modules try: diff --git a/src/analysis/analyzers/base_analyzer.py b/src/analysis/analyzers/base_analyzer.py index cbef1e5..0d259a5 100644 --- a/src/analysis/analyzers/base_analyzer.py +++ b/src/analysis/analyzers/base_analyzer.py @@ -6,7 +6,7 @@ from abc import ABC, abstractmethod from typing import Any -from astrbot.api import logger +from ...utils.logger import logger from ...models.data_models import TokenUsage from ..utils.json_utils import parse_json_response diff --git a/src/analysis/analyzers/golden_quote_analyzer.py b/src/analysis/analyzers/golden_quote_analyzer.py index a493297..c0aed9a 100644 --- a/src/analysis/analyzers/golden_quote_analyzer.py +++ b/src/analysis/analyzers/golden_quote_analyzer.py @@ -5,7 +5,7 @@ from datetime import datetime -from astrbot.api import logger +from ...utils.logger import logger from ...models.data_models import GoldenQuote, TokenUsage from ..utils import InfoUtils diff --git a/src/analysis/analyzers/topic_analyzer.py b/src/analysis/analyzers/topic_analyzer.py index aa866ad..83417ed 100644 --- a/src/analysis/analyzers/topic_analyzer.py +++ b/src/analysis/analyzers/topic_analyzer.py @@ -6,7 +6,7 @@ import re from datetime import datetime -from astrbot.api import logger +from ...utils.logger import logger from ...models.data_models import SummaryTopic, TokenUsage from ..utils import InfoUtils diff --git a/src/analysis/analyzers/user_title_analyzer.py b/src/analysis/analyzers/user_title_analyzer.py index 217dbab..a2fa073 100644 --- a/src/analysis/analyzers/user_title_analyzer.py +++ b/src/analysis/analyzers/user_title_analyzer.py @@ -3,7 +3,7 @@ 专门处理用户称号和MBTI类型分析 """ -from astrbot.api import logger +from ...utils.logger import logger from ...models.data_models import TokenUsage, UserTitle from ..utils.json_utils import extract_user_titles_with_regex diff --git a/src/analysis/llm_analyzer.py b/src/analysis/llm_analyzer.py index d3d8e0a..0c28390 100644 --- a/src/analysis/llm_analyzer.py +++ b/src/analysis/llm_analyzer.py @@ -5,7 +5,7 @@ LLM分析器模块 import asyncio -from astrbot.api import logger +from ..utils.logger import logger from ..models.data_models import GoldenQuote, SummaryTopic, TokenUsage, UserTitle from .analyzers.golden_quote_analyzer import GoldenQuoteAnalyzer diff --git a/src/analysis/utils/json_utils.py b/src/analysis/utils/json_utils.py index f96ac9b..fe420c1 100644 --- a/src/analysis/utils/json_utils.py +++ b/src/analysis/utils/json_utils.py @@ -6,7 +6,7 @@ JSON处理工具模块 import json import re -from astrbot.api import logger +from ...utils.logger import logger def fix_json(text: str) -> str: diff --git a/src/analysis/utils/llm_utils.py b/src/analysis/utils/llm_utils.py index 5f402c0..4dad48f 100644 --- a/src/analysis/utils/llm_utils.py +++ b/src/analysis/utils/llm_utils.py @@ -6,7 +6,7 @@ LLM API请求处理工具模块 import asyncio from typing import Any -from astrbot.api import logger +from ...utils.logger import logger from ...utils.resilience import CircuitBreaker, global_llm_rate_limiter diff --git a/src/application/analysis_orchestrator.py b/src/application/analysis_orchestrator.py index 8ad3e64..eb91f0d 100644 --- a/src/application/analysis_orchestrator.py +++ b/src/application/analysis_orchestrator.py @@ -12,7 +12,7 @@ from typing import Optional, List, Dict, Any from dataclasses import dataclass -from astrbot.api import logger +from ..utils.logger import logger from ..domain.value_objects.unified_message import UnifiedMessage from ..domain.value_objects.platform_capabilities import PlatformCapabilities @@ -23,6 +23,7 @@ from .message_converter import MessageConverter @dataclass class AnalysisConfig: """分析操作配置""" + days: int = 1 max_messages: int = 1000 min_messages_threshold: int = 10 @@ -32,13 +33,13 @@ class AnalysisConfig: class AnalysisOrchestrator: """ 分析编排器 - 协调分析工作流。 - + 职责: 1. 使用 PlatformAdapter 获取消息(DDD 方式) 2. 转换消息以兼容现有分析器 3. 协调分析流程 4. 提供平台能力检查 - + 此类作为以下组件之间的桥梁: - 新的 DDD 基础设施(PlatformAdapter, UnifiedMessage) - 现有分析逻辑(MessageHandler, LLMAnalyzer 等) @@ -51,7 +52,7 @@ class AnalysisOrchestrator: ): """ 初始化编排器。 - + 参数: adapter: 用于消息操作的平台适配器 config: 分析配置 @@ -69,13 +70,13 @@ class AnalysisOrchestrator: ) -> Optional["AnalysisOrchestrator"]: """ 工厂方法 - 为特定平台创建编排器。 - + 参数: platform_name: 平台名称(如 "aiocqhttp", "telegram") bot_instance: 来自 AstrBot 的 bot 实例 config: 平台特定配置 analysis_config: 分析配置 - + 返回: AnalysisOrchestrator 或 None(如果平台不支持) """ @@ -83,7 +84,7 @@ class AnalysisOrchestrator: if adapter is None: logger.warning(f"平台 '{platform_name}' 不支持分析功能") return None - + return cls(adapter, analysis_config) def get_capabilities(self) -> PlatformCapabilities: @@ -106,29 +107,26 @@ class AnalysisOrchestrator: ) -> List[UnifiedMessage]: """ 使用平台适配器获取消息。 - + 参数: group_id: 要获取消息的群组 ID days: 天数(默认使用配置值) max_count: 最大消息数量(默认使用配置值) - + 返回: UnifiedMessage 列表 """ days = days or self.config.days max_count = max_count or self.config.max_messages - + # 应用平台能力限制 caps = self.adapter.get_capabilities() effective_days = caps.get_effective_days(days) effective_count = caps.get_effective_count(max_count) - + if effective_days < days: - logger.info( - f"平台限制:请求 {days} 天," - f"实际使用 {effective_days} 天" - ) - + logger.info(f"平台限制:请求 {days} 天,实际使用 {effective_days} 天") + return await self.adapter.fetch_messages( group_id=group_id, days=effective_days, @@ -143,15 +141,15 @@ class AnalysisOrchestrator: ) -> List[dict]: """ 获取消息并转换为原始字典格式。 - + 此方法提供与现有分析器的向后兼容性, 这些分析器期望原始字典格式的消息。 - + 参数: group_id: 要获取消息的群组 ID days: 天数 max_count: 最大消息数量 - + 返回: 原始消息字典列表(通用格式,由适配器决定具体格式) """ @@ -178,11 +176,11 @@ class AnalysisOrchestrator: # } # for msg in unified_messages # ] - + # 暂时直接使用适配器获取 raw 格式,如果适配器支持 # 这是为了确保现有逻辑完全兼容,因为 convert_to_raw_format 可能有损 # 但我们希望尽可能使用新的 fetch_messages - + unified_messages = await self.fetch_messages(group_id, days, max_count) return self.adapter.convert_to_raw_format(unified_messages) @@ -197,11 +195,11 @@ class AnalysisOrchestrator: ) -> Dict[str, Optional[str]]: """ 批量获取用户头像 URL。 - + 参数: user_ids: 用户 ID 列表 size: 头像尺寸 - + 返回: 用户 ID 到头像 URL 的映射字典(URL 可能为 None) """ @@ -232,10 +230,10 @@ class AnalysisOrchestrator: def validate_message_count(self, messages: List[UnifiedMessage]) -> bool: """ 检查消息数量是否达到最小阈值。 - + 参数: messages: 消息列表 - + 返回: 如果数量足够返回 True """ @@ -244,10 +242,10 @@ class AnalysisOrchestrator: def get_analysis_text(self, messages: List[UnifiedMessage]) -> str: """ 将消息转换为 LLM 分析文本格式。 - + 参数: messages: UnifiedMessage 列表 - + 返回: 格式化的 LLM 分析文本 """ diff --git a/src/application/reporting_service.py b/src/application/reporting_service.py index 44f9567..463e7a6 100644 --- a/src/application/reporting_service.py +++ b/src/application/reporting_service.py @@ -7,7 +7,7 @@ from datetime import datetime from typing import Any, Dict, List, Optional -from astrbot.api import logger +from ..utils.logger import logger from ..domain.services import ReportGenerator from ..domain.value_objects.topic import Topic @@ -78,7 +78,9 @@ class ReportingService: statistics=statistics, topics=topics if self.config.get_include_topics() else [], user_titles=user_titles if self.config.get_include_user_titles() else [], - golden_quotes=golden_quotes if self.config.get_include_golden_quotes() else [], + golden_quotes=golden_quotes + if self.config.get_include_golden_quotes() + else [], include_header=True, include_footer=True, ) diff --git a/src/application/scheduling_service.py b/src/application/scheduling_service.py index 72ad309..71e479d 100644 --- a/src/application/scheduling_service.py +++ b/src/application/scheduling_service.py @@ -9,10 +9,14 @@ import asyncio from datetime import datetime, timedelta from typing import Any, Callable, Dict, List, Optional, Set -from astrbot.api import logger +from ..utils.logger import logger from ..infrastructure.config import ConfigManager -from ..shared.constants import TASK_STATE_PENDING, TASK_STATE_RUNNING, TASK_STATE_COMPLETED +from ..shared.constants import ( + TASK_STATE_PENDING, + TASK_STATE_RUNNING, + TASK_STATE_COMPLETED, +) class ScheduledTask: diff --git a/src/core/bot_manager.py b/src/core/bot_manager.py index b5b4bd0..5670ca6 100644 --- a/src/core/bot_manager.py +++ b/src/core/bot_manager.py @@ -7,7 +7,7 @@ Bot实例管理模块 from typing import Any, Optional -from astrbot.api import logger +from ..utils.logger import logger from ..infrastructure.platform import PlatformAdapter, PlatformAdapterFactory diff --git a/src/core/history_manager.py b/src/core/history_manager.py index 922616b..598615b 100644 --- a/src/core/history_manager.py +++ b/src/core/history_manager.py @@ -7,7 +7,7 @@ import datetime from typing import Any -from astrbot.api import logger +from ..utils.logger import logger class HistoryManager: diff --git a/src/core/message_handler.py b/src/core/message_handler.py index 9f75ec4..82e7f82 100644 --- a/src/core/message_handler.py +++ b/src/core/message_handler.py @@ -6,7 +6,7 @@ from collections import defaultdict from datetime import datetime, timedelta -from astrbot.api import logger +from ..utils.logger import logger from ..models.data_models import EmojiStatistics, GroupStatistics, TokenUsage from ..visualization.activity_charts import ActivityVisualizer diff --git a/src/core/message_sender.py b/src/core/message_sender.py index 90a2a33..d6c2ede 100644 --- a/src/core/message_sender.py +++ b/src/core/message_sender.py @@ -2,7 +2,7 @@ import base64 import aiohttp -from astrbot.api import logger +from ..utils.logger import logger from ..utils.trace_context import TraceContext diff --git a/src/infrastructure/config/config_manager.py b/src/infrastructure/config/config_manager.py index 7347ef4..99547a5 100644 --- a/src/infrastructure/config/config_manager.py +++ b/src/infrastructure/config/config_manager.py @@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional -from astrbot.api import logger +from ...utils.logger import logger class ConfigManager: diff --git a/src/infrastructure/llm/llm_client.py b/src/infrastructure/llm/llm_client.py index b76c1fb..519150a 100644 --- a/src/infrastructure/llm/llm_client.py +++ b/src/infrastructure/llm/llm_client.py @@ -7,7 +7,7 @@ LLM 客户端 - 包装 AstrBot 的 LLM 提供商系统 from typing import Any, Dict, List, Optional, Tuple -from astrbot.api import logger +from ...utils.logger import logger from ...domain.value_objects.statistics import TokenUsage from ...domain.exceptions import LLMException, LLMRateLimitException @@ -110,7 +110,9 @@ class LLMClient: if hasattr(response, "completion_text"): response_text = response.completion_text elif isinstance(response, dict): - response_text = response.get("completion_text", response.get("text", "")) + response_text = response.get( + "completion_text", response.get("text", "") + ) else: response_text = str(response) diff --git a/src/infrastructure/persistence/history_repository.py b/src/infrastructure/persistence/history_repository.py index 13a9ecc..7616899 100644 --- a/src/infrastructure/persistence/history_repository.py +++ b/src/infrastructure/persistence/history_repository.py @@ -11,7 +11,7 @@ from datetime import datetime from pathlib import Path from typing import Any, Dict, List, Optional -from astrbot.api import logger +from ...utils.logger import logger class HistoryRepository: @@ -121,9 +121,7 @@ class HistoryRepository: history = self.load_group_history(group_id) return history.get("daily", {}).get(date_str) - def get_recent_results( - self, group_id: str, limit: int = 7 - ) -> List[Dict[str, Any]]: + def get_recent_results(self, group_id: str, limit: int = 7) -> List[Dict[str, Any]]: """ 获取最近的分析结果。 diff --git a/src/infrastructure/platform/factory.py b/src/infrastructure/platform/factory.py index 6e825f9..87805d9 100644 --- a/src/infrastructure/platform/factory.py +++ b/src/infrastructure/platform/factory.py @@ -2,7 +2,9 @@ 平台适配器工厂 """ -from typing import Optional, Any, Dict, Type +from typing import Any, Dict, List, Optional, Type + +from ...utils.logger import logger from .base import PlatformAdapter @@ -10,7 +12,7 @@ from .base import PlatformAdapter class PlatformAdapterFactory: """ 平台适配器工厂 - + 根据平台名称创建适配器实例。 使用注册表模式便于扩展。 """ @@ -31,12 +33,12 @@ class PlatformAdapterFactory: ) -> Optional[PlatformAdapter]: """ 创建平台适配器 - + 参数: platform_name: 平台名称(如 "aiocqhttp"、"telegram") bot_instance: AstrBot 机器人实例 config: 配置字典 - + 返回: 平台适配器实例,如果不支持则返回 None """ @@ -49,8 +51,7 @@ class PlatformAdapterFactory: return adapter_class(bot_instance, config) except Exception: # 记录异常,但不崩溃 - import logging - logging.getLogger(__name__).error(f"为 {platform_name} 创建适配器时出错", exc_info=True) + logger.error(f"为 {platform_name} 创建适配器时出错", exc_info=True) return None @classmethod @@ -68,15 +69,17 @@ class PlatformAdapterFactory: def _register_adapters(): try: from .adapters.onebot_adapter import OneBotAdapter + PlatformAdapterFactory.register("aiocqhttp", OneBotAdapter) PlatformAdapterFactory.register("onebot", OneBotAdapter) except ImportError: pass - + try: from .adapters.discord_adapter import DiscordAdapter + PlatformAdapterFactory.register("discord", DiscordAdapter) - PlatformAdapterFactory.register("discord_bot", DiscordAdapter) # 添加别名 + PlatformAdapterFactory.register("discord_bot", DiscordAdapter) # 添加别名 except ImportError: pass diff --git a/src/infrastructure/resilience/circuit_breaker.py b/src/infrastructure/resilience/circuit_breaker.py index 5266ae8..21e7a01 100644 --- a/src/infrastructure/resilience/circuit_breaker.py +++ b/src/infrastructure/resilience/circuit_breaker.py @@ -9,7 +9,7 @@ from dataclasses import dataclass, field from enum import Enum from typing import Callable, Optional -from astrbot.api import logger +from ...utils.logger import logger class CircuitState(Enum): diff --git a/src/infrastructure/resilience/rate_limiter.py b/src/infrastructure/resilience/rate_limiter.py index abdb619..0f8f26f 100644 --- a/src/infrastructure/resilience/rate_limiter.py +++ b/src/infrastructure/resilience/rate_limiter.py @@ -9,7 +9,7 @@ import time from dataclasses import dataclass, field from typing import Optional -from astrbot.api import logger +from ...utils.logger import logger @dataclass diff --git a/src/infrastructure/resilience/retry.py b/src/infrastructure/resilience/retry.py index 5cd5536..f50910e 100644 --- a/src/infrastructure/resilience/retry.py +++ b/src/infrastructure/resilience/retry.py @@ -10,7 +10,7 @@ from dataclasses import dataclass from functools import wraps from typing import Callable, Optional, Tuple, Type, Union -from astrbot.api import logger +from ...utils.logger import logger @dataclass diff --git a/src/reports/dispatcher.py b/src/reports/dispatcher.py index e0ad8eb..7a20d9a 100644 --- a/src/reports/dispatcher.py +++ b/src/reports/dispatcher.py @@ -1,7 +1,7 @@ from collections.abc import Callable from typing import Any -from astrbot.api import logger +from ..utils.logger import logger from ..utils.trace_context import TraceContext diff --git a/src/reports/generators.py b/src/reports/generators.py index 8ad589f..2a9fd8b 100644 --- a/src/reports/generators.py +++ b/src/reports/generators.py @@ -10,7 +10,7 @@ from pathlib import Path import aiohttp -from astrbot.api import logger +from ..utils.logger import logger from ..visualization.activity_charts import ActivityVisualizer from .templates import HTMLTemplates diff --git a/src/reports/templates.py b/src/reports/templates.py index d422919..e6ba93e 100644 --- a/src/reports/templates.py +++ b/src/reports/templates.py @@ -9,7 +9,7 @@ import threading from jinja2 import Environment, FileSystemLoader, select_autoescape -from astrbot.api import logger +from ..utils.logger import logger class HTMLTemplates: diff --git a/src/scheduler/auto_scheduler.py b/src/scheduler/auto_scheduler.py index cd697ae..5eeda4f 100644 --- a/src/scheduler/auto_scheduler.py +++ b/src/scheduler/auto_scheduler.py @@ -8,7 +8,7 @@ import weakref from apscheduler.triggers.cron import CronTrigger -from astrbot.api import logger +from ..utils.logger import logger from ..core.message_sender import MessageSender from ..reports.dispatcher import ReportDispatcher diff --git a/src/scheduler/retry.py b/src/scheduler/retry.py index 36ed410..e27b77c 100644 --- a/src/scheduler/retry.py +++ b/src/scheduler/retry.py @@ -6,7 +6,7 @@ import aiohttp from collections.abc import Callable from dataclasses import dataclass -from astrbot.api import logger +from ..utils.logger import logger @dataclass diff --git a/src/utils/helpers.py b/src/utils/helpers.py index 0bc5918..81098eb 100644 --- a/src/utils/helpers.py +++ b/src/utils/helpers.py @@ -5,7 +5,7 @@ import asyncio -from astrbot.api import logger +from .logger import logger from ..analysis.llm_analyzer import LLMAnalyzer from ..analysis.statistics import UserAnalyzer diff --git a/src/utils/logger.py b/src/utils/logger.py new file mode 100644 index 0000000..8d84b94 --- /dev/null +++ b/src/utils/logger.py @@ -0,0 +1,16 @@ +import logging +from astrbot.api import logger as astrbot_logger + + +class PluginLoggerAdapter(logging.LoggerAdapter): + """ + 插件日志适配器 + 自动为日志添加 [QQ群分析] 前缀,方便区分 + """ + + def process(self, msg, kwargs): + return f"[QQ群分析] {msg}", kwargs + + +# 导出带前缀的 logger +logger = PluginLoggerAdapter(astrbot_logger, {}) diff --git a/src/utils/pdf_utils.py b/src/utils/pdf_utils.py index 3030b2b..70c464e 100644 --- a/src/utils/pdf_utils.py +++ b/src/utils/pdf_utils.py @@ -7,7 +7,7 @@ import asyncio import sys from concurrent.futures import ThreadPoolExecutor -from astrbot.api import logger +from .logger import logger class PDFInstaller: diff --git a/src/utils/resilience.py b/src/utils/resilience.py index 5ced582..1abbb3c 100644 --- a/src/utils/resilience.py +++ b/src/utils/resilience.py @@ -1,7 +1,7 @@ import asyncio import time -from astrbot.api import logger +from .logger import logger class CircuitBreaker: