diff --git a/doc/readme.md b/doc/readme.md index da760ff..6c7ac5c 100644 --- a/doc/readme.md +++ b/doc/readme.md @@ -3,28 +3,72 @@ ### 程序框架 ```angular2html intelligence_system/ -├── config/ # 配置管理 -│ ├── __init__.py -│ ├── settings.py # 全局参数 -│ └── logging.conf # 日志配置 -├── collectors/ # 数据采集 -│ ├── news_api.py -│ └── complaint_spider.py -├── processors/ # 数据处理 -│ ├── text_processor.py -│ └── image_processor.py -├── storage/ # 数据存储 -│ ├── database.py -│ └── cache_manager.py -├── applications/ # 应用层 -│ ├── reporter/ -│ │ ├── daily.py -│ │ └── monthly.py -│ └── alert.py -├── utils/ # 工具类 -│ ├── logger.py -│ └── network.py -└── main.py # 调度入口 +├── config/ # 系统配置中心 +│ ├── __init__.py # 配置包初始化 +│ ├── settings.py # 主配置文件(数据库连接、API密钥等) +│ └── scheduler_rules.yaml # 任务调度规则 + +├── data_collection/ # 数据采集层 +│ ├── spiders/ # 网络爬虫子系统 +│ │ ├── weibo_spider.py # 黑猫爬虫 +│ │ +│ ├── api_integration/ # API接口子系统 +│ │ ├── news_api.py # 新闻接口 +│ │ +│ └── internal/ # 内部数据收集 +│ ├── jian_dao_cloud.py # 简道云表单收集器 + +├── data_processing/ # 数据处理层 +│ ├── structured/ # 结构化数据处理 +│ │ ├── data_cleaner.py # 数据清洗(去重/标准化) +│ │ └── schema_mapper.py # 数据结构转换器 +│ │ +│ ├── unstructured/ # 非结构化数据处理 +│ │ ├── text_parser.py # 文本解析(PDF/HTML等) +│ │ ├── image_analyzer.py # 图像识别(OpenCV集成) +│ │ └── video_processor.py # 音视频分离分析 +│ │ +│ └── ai_engine/ # AI分析核心 +│ ├── nlp_processor.py # 自然语言处理引擎 +│ ├── sentiment_analyzer.py # 情感分析模型 +│ └── topic_modeler.py # LDA主题建模工具 + +├── storage/ # 数据存储层 +│ ├── mysql_agent.py # MySQL读写管理器 +│ └── query_builder.py # SQL动态构建器 + +├── services/ # 应用服务层 +│ ├── monitoring/ # 舆情监控 +│ │ ├── opinion_monitor.py # 实时舆情追踪 +│ │ └── brand_reputation.py # 品牌口碑分析 +│ │ +│ ├── analysis/ # 竞品分析 +│ │ ├── competitor_tracker.py # 竞品动态监控 +│ │ └── swot_generator.py # SWOT分析报告 +│ │ +│ ├── reporting/ # 报告服务 +│ │ ├── daily_reporter.py # 自动化日报生成 +│ │ └── weekly_digest.py # 周报汇编系统 +│ │ +│ └── alert/ # 预警服务 +│ ├── alert_trigger.py # 动态阈值告警 +│ └── notification_center.py # 邮件/短信通知 + +├── system_management/ # 系统管理层 +│ ├── scheduler/ # 任务调度 +│ │ ├── task_scheduler.py # 分布式任务调度器 +│ │ └── cron_manager.py # 定时规则配置 +│ │ +│ └── monitor/ # 系统监控 +│ ├── health_monitor.py # 服务健康检测 +│ └── performance_watcher.py # 资源占用监控 + +├── utils/ # 工具库 +│ ├── file_handler.py # 通用文件操作 +│ ├── logger.py # 日志系统 +│ └── datetime_parser.py # 时间格式处理 + +└── main.py # 系统入口(启动所有服务) ``` ### 程序设计原则 1. 所有程序尽可能在py文件中运行,尽量避免使用命令行执行 diff --git a/utils/logger.py b/utils/logger.py index 7b5c73e..e148554 100644 --- a/utils/logger.py +++ b/utils/logger.py @@ -1,129 +1,98 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -跨平台日志工具模块 -功能: -1. 自动适配不同操作系统的日志路径 -2. 支持中文等非ASCII字符 -3. 日志文件自动按日期分割 -4. 控制台与文件双输出 -""" - import os import sys -import logging -from logging.handlers import TimedRotatingFileHandler -from datetime import datetime +from pathlib import Path +from loguru import logger import platform +from datetime import datetime +import zipfile +class CrossPlatformLog: + """跨平台日志系统(支持Linux/Windows/Mac)""" -class CrossPlatformLogger: - def __init__(self, name="intelligence_system"): - """ - 初始化跨平台日志系统 + def __init__(self): + self.log_dir = self._get_log_dir() + self._setup_logger() - 参数: - name: 日志名称(用于创建日志文件夹) - """ - self.system = platform.system().lower() - self.logger = logging.getLogger(name) - self.logger.setLevel(logging.INFO) + def _get_log_dir(self): + """获取跨平台日志目录(相对路径)""" + base_dir = Path(__file__).parent.parent # 项目根目录 + log_dir = base_dir / "logs" - # 确保日志目录存在 - self.log_dir = self._get_log_dir(name) - os.makedirs(self.log_dir, exist_ok=True) + # 自动创建日志目录 + log_dir.mkdir(exist_ok=True) - # 配置日志格式 - formatter = logging.Formatter( - '%(asctime)s - %(name)s - %(levelname)s - %(message)s', - datefmt='%Y-%m-%d %H:%M:%S' - ) - - # 控制台处理器 - self._setup_console_handler(formatter) - - # 文件处理器(按天分割) - self._setup_file_handler(formatter) - - # 处理未捕获的异常 - sys.excepthook = self.handle_uncaught_exception - - def _get_log_dir(self, name: str) -> str: - """获取适合当前平台的日志目录路径""" - if self.system == 'windows': - base_dir = os.path.join(os.environ['APPDATA'], name) - elif self.system == 'darwin': # macOS - base_dir = os.path.expanduser(f"~/Library/Logs/{name}") - else: # Linux及其他Unix-like系统 - base_dir = f"/var/log/{name}" if os.access("/var/log", os.W_OK) \ - else os.path.expanduser(f"~/.local/share/{name}") - - return base_dir - - def _setup_console_handler(self, formatter: logging.Formatter): - """配置控制台输出(兼容不同终端的编码)""" - console = logging.StreamHandler() - - # Windows终端特殊处理 - if self.system == 'windows' and not sys.stdout.isatty(): - import colorama + # Windows特殊权限处理 + if platform.system() == "Windows": try: - colorama.init() - except ImportError: + os.chmod(log_dir, 0o777) # 确保写入权限 + except: pass - # 解决Windows控制台编码问题 - if sys.stdout.encoding != 'utf-8': - import io - sys.stdout = io.TextIOWrapper( - sys.stdout.buffer, - encoding='utf-8', - errors='replace' - ) + return log_dir - console.setFormatter(formatter) - self.logger.addHandler(console) + def _setup_logger(self): + """配置跨平台日志处理器""" + logger.remove() # 清除默认配置 - def _setup_file_handler(self, formatter: logging.Formatter): - """配置日志文件输出(UTF-8编码)""" - log_file = os.path.join( - self.log_dir, - f"{datetime.now().strftime('%Y%m%d')}.log" + # 统一控制台输出格式 + logger.add( + sys.stdout, + level="INFO", + format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {module} - {message}", + filter=lambda record: record["level"].no >= 20 # INFO及以上级别 ) - # 使用TimedRotatingFileHandler实现日志分割 - file_handler = TimedRotatingFileHandler( - filename=log_file, - when='midnight', # 每天午夜分割 - encoding='utf-8', - backupCount=30 # 保留30天日志 - ) - file_handler.setFormatter(formatter) - self.logger.addHandler(file_handler) + # 主日志文件(兼容所有平台路径) + self._add_main_log() - def handle_uncaught_exception(self, exc_type, exc_value, exc_traceback): - """全局异常捕获""" - self.logger.error( - "未捕获的异常:", - exc_info=(exc_type, exc_value, exc_traceback) + # 错误日志单独存储 + self._add_error_log() + + def _add_main_log(self): + """主日志文件配置""" + main_log = self.log_dir / "application.log" + logger.add( + str(main_log), + rotation="20 MB", + compression=self._compress_log, + encoding="utf-8", + level="DEBUG", + format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {module}:{line} - {message}", + retention="30 days", + enqueue=True # 线程安全 + ) + + def _add_error_log(self): + """错误日志专用配置""" + error_log = self.log_dir / "errors.log" + logger.add( + str(error_log), + level="ERROR", + format="{time:YYYY-MM-DD HH:mm:ss.SSS} | ERROR | {module}:{line} - {message}\n{exception}", + rotation="10 MB", + retention="90 days" ) @staticmethod - def get_logger(name: str = None) -> logging.Logger: - """获取配置好的日志实例""" - return CrossPlatformLogger(name).logger + def _compress_log(log_path): + """通用日志压缩方法(兼容所有平台)""" + if not os.path.exists(log_path): + return + try: + zip_path = f"{log_path}.{datetime.now().strftime('%Y%m%d')}.zip" + with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: + zipf.write(log_path, arcname=os.path.basename(log_path)) + os.remove(log_path) + return zip_path + except Exception as e: + print(f"日志压缩失败: {str(e)}") + return log_path # 返回原文件路径继续使用 -def setup_logging(name: str = "intelligence_system"): - """快速配置日志(兼容旧代码)""" - return CrossPlatformLogger(name).logger + @classmethod + def get_logger(cls, module_name=None): + """获取模块专属日志器""" + return logger.bind(module=module_name or "__main__") - -# 测试代码 -if __name__ == "__main__": - logger = CrossPlatformLogger().logger - logger.info("这是一条info日志(包含中文测试)") - try: - 1 / 0 - except Exception as e: - logger.error("除零错误示例", exc_info=True) +# 初始化全局日志器 +log = CrossPlatformLog().get_logger() \ No newline at end of file