Spaces:
Running
Running
| # CLAUDE.md | |
| 此文件为 Claude Code (claude.ai/code) 在此存储库中工作时提供指导。 | |
| ## 项目概述 | |
| **LogDisplayer** 是一个基于 FastAPI 的日志聚合和显示系统,可以从多个端点/源收集日志,将其存储在本地,并同步到 Hugging Face 数据集。它提供了一个 Web UI,用于查看和管理带有 JWT 令牌用户认证的日志。 | |
| **技术栈:** | |
| - 后端:FastAPI + Uvicorn(Python 3.10+) | |
| - 数据存储:Hugging Face Datasets、Pandas | |
| - 云同步:Hugging Face Hub API | |
| - 后台任务:APScheduler | |
| - 前端:Jinja2 模板(HTML/CSS/JavaScript) | |
| - 部署:Docker | |
| ## 开发设置与命令 | |
| ### 前置要求 | |
| - Python 3.10+ | |
| - pip 包管理器 | |
| - 环境变量:`hf_token`(Hugging Face 令牌)、`SECRET_KEY`(用于 JWT 解析) | |
| ### 安装依赖 | |
| ```bash | |
| pip install -r requirements.txt | |
| ``` | |
| ### 运行应用程序 | |
| ```bash | |
| # 标准开发运行 | |
| uvicorn main:app --host 0.0.0.0 --port 7860 | |
| # 带自动重载的开发运行 | |
| uvicorn main:app --reload --host 0.0.0.0 --port 7860 | |
| ``` | |
| 应用将在 `http://localhost:7860` 可用 | |
| ### Docker 开发 | |
| ```bash | |
| # 构建 Docker 镜像 | |
| docker build -t log-displayer . | |
| # 运行 Docker 容器 | |
| docker run -p 7860:7860 \ | |
| -e hf_token="your_hf_token" \ | |
| -e SECRET_KEY="your_secret_key" \ | |
| log-displayer | |
| ``` | |
| ### 测试 | |
| 当前没有配置正式的测试框架。手动测试脚本位于 `scratch/`: | |
| - `scratch/test_dataset_to_dict.py` - 测试数据集转换 | |
| - `scratch/test_glob.py` - 测试文件搜索 | |
| 运行手动测试: | |
| ```bash | |
| python scratch/test_dataset_to_dict.py | |
| python scratch/test_glob.py | |
| ``` | |
| ## 架构概览 | |
| ### 核心组件 | |
| **1. main.py(FastAPI 应用)** | |
| - 初始化 FastAPI 应用,配置 CORS 中间件 | |
| - 定义 3 个主要端点: | |
| - `POST /{end}` - 接受日志,包含消息体、可选的令牌头和源头 | |
| - `GET /healthcheck` - 健康检查端点 | |
| - `GET /` 或 `GET ""` - 使用所有日志渲染 HTML 模板 | |
| - 实例化和管理 `LoggingHelper` 实例 | |
| **2. logging_helper.py(日志管理引擎)** | |
| - `LoggingHelper` 类处理所有日志持久化和同步 | |
| - **关键方法:** | |
| - `addlog(log)` - 将日志添加到内存缓冲区 | |
| - `pull()` - 从 Hugging Face 下载今天的日志 | |
| - `push()` - 将缓冲的日志上传到 Hugging Face 数据集(标记缓存需要刷新) | |
| - `push_yesterday()` - 归档昨天的日志 | |
| - `refresh()` - **[优化]** 返回所有日志作为排序的字典列表,使用 DataFrame 缓存机制避免重复加载 | |
| - `_load_all_logs()` - **[新增]** 从磁盘加载所有日志文件并合并成 DataFrame | |
| - **后台同步:** 使用 APScheduler 定期推送日志(默认:60 秒间隔) | |
| - **文件组织:** 日志在 HF 中组织为 `{year}/{month}/{day}/*.json` | |
| - **缓冲策略:** 内存中的 Hugging Face 数据集字典,按文件路径和需要推送状态跟踪 | |
| - **缓存策略:** DataFrame 缓存 + 智能失效。只在 push() 完成或首次加载时重新读取磁盘文件 | |
| **3. utils.py(辅助函数)** | |
| - `beijing()` - 返回 Asia/Shanghai 时区的当前时间 | |
| - `parse_token(token)` - 解码 JWT 令牌以提取 uid 和用户名 | |
| - `decode_jwt(token)` - 使用 SECRET_KEY 解码 JWT | |
| - `md5(text)` - 生成 MD5 哈希(用于日志文件名) | |
| - `json_to_str(obj)` - 将 JSON 转换为紧凑字符串格式 | |
| **4. static/index.html(前端模板)** | |
| - 带有中文 UI 的 Jinja2 模板 | |
| - 显示带有排序和过滤的日志表格 | |
| - 显示列:类型、来源、用户、时间戳、内容 | |
| ### 数据流 | |
| ``` | |
| 日志 POST 请求 | |
| → main.py add_log() | |
| → parse_token() 获取用户信息 | |
| → logging_helper.addlog()(添加到缓冲区) | |
| → APScheduler 每 60 秒触发 push() | |
| → logging_helper.push()(保存到本地 JSON,上传到 HF) | |
| → 设置 cache_needs_refresh = True | |
| 日志显示请求(带缓存优化) | |
| → GET / 或 GET "" | |
| → logging_helper.refresh() | |
| → 调用 push()(如无新日志,快速返回) | |
| → 检查缓存: | |
| - 如果 cache_needs_refresh == True 或缓存为空 → _load_all_logs()(从磁盘加载) | |
| - 否则 → 直接返回缓存的 DataFrame | |
| → 返回排序的字典列表 | |
| → Jinja2 渲染 HTML 模板 | |
| ``` | |
| ### 环境变量 | |
| 必需: | |
| - `hf_token` - Hugging Face API 令牌,用于认证 | |
| - `SECRET_KEY` - 用于 JWT 解码的密钥(用于解析用户令牌) | |
| ### 关键设计模式 | |
| 1. **两级缓冲:** 内存缓冲 + 磁盘存储。日志在 Python 对象中缓冲,定期写入 JSON,然后推送到 Hugging Face。 | |
| 2. **基于日期的组织:** 日志自动组织到年/月/日目录中,便于归档数据管理。 | |
| 3. **后台同步:** APScheduler 确保定期推送日志,而不会阻止主请求处理程序。 | |
| 4. **无状态端点:** 每个请求都是独立的;用户信息在每次调用时从 JWT 令牌中提取。 | |
| 5. **DataFrame 缓存(性能优化):** `refresh()` 方法缓存合并后的 DataFrame。只有在 `push()` 完成后才重新加载磁盘文件,避免每次刷新都重复读取和解析所有 JSON 文件。 | |
| ## 重要文件与职责 | |
| | 文件 | 行数 | 用途 | | |
| |------|------|------| | |
| | [main.py](main.py) | 74 | FastAPI 应用初始化、端点定义 | | |
| | [logging_helper.py](logging_helper.py) | 235 | 核心日志持久化、缓冲、HF 同步和缓存机制 | | |
| | [utils.py](utils.py) | 64 | 时区、JWT 解析、哈希工具函数 | | |
| | [static/index.html](static/index.html) | ~400 | Jinja2 Web UI 模板 | | |
| | [requirements.txt](requirements.txt) | 10 | Python 依赖 | | |
| | [Dockerfile](Dockerfile) | - | Docker 镜像定义 | | |
| | [data/logs/](data/logs/) | - | 本地日志文件存储 | | |
| ## 性能优化说明 | |
| ### 首页刷新优化(v1.1) | |
| **问题:** 之前每次刷新首页都需要从磁盘重新加载所有 JSON 日志文件,在日志数量较多时会导致加载时间过长。 | |
| **解决方案:** 实现了 DataFrame 缓存机制。 | |
| **具体改进:** | |
| 1. **DataFrame 内存缓存** - 在 LoggingHelper 中添加 `cached_df` 变量存储合并后的 DataFrame | |
| 2. **智能缓存失效** - 只有在调用 `push()` 方法写入新日志到磁盘后,才设置 `cache_needs_refresh = True` 标记 | |
| 3. **增量加载** - 新增 `_load_all_logs()` 私有方法,只在必要时(首次加载或 push 完成后)从磁盘重新加载数据 | |
| **性能改进:** | |
| - **首次刷新:** 需要加载所有 JSON 文件(不可避免) | |
| - **后续刷新(无新日志):** 直接返回缓存,避免磁盘 I/O,响应时间从秒级降低到毫秒级 | |
| - **后续刷新(有新日志):** push() 完成后重新加载,但由于 push() 已经处理完新日志,只需一次加载即可 | |
| **相关代码变更:** | |
| - [logging_helper.py:43-45](logging_helper.py#L43-L45) - 添加缓存变量初始化 | |
| - [logging_helper.py:172](logging_helper.py#L172) - push() 方法中标记缓存失效 | |
| - [logging_helper.py:199-216](logging_helper.py#L199-L216) - 新增 _load_all_logs() 方法 | |
| - [logging_helper.py:218-234](logging_helper.py#L218-L234) - 优化后的 refresh() 方法 | |
| ## 常见开发任务 | |
| ### 添加新的日志类型 | |
| 1. POST 到 `/{end}`,其中 `{end}` 是日志类型(例如 `/web`、`/mobile`、`/api`) | |
| 2. LoggingHelper 自动在缓冲区中创建新条目,按日期组织 | |
| ### 调试日志 | |
| - 查看 uvicorn 控制台输出,了解 add_log() 和 push() 中的打印语句 | |
| - 查看 `data/logs/{year}/{month}/{day}/` 中的本地 JSON 文件以获取存储的日志 | |
| - 检查 `data/logs/` 中下载的 HF 数据集 | |
| ### 修改同步间隔 | |
| 在 `logging_helper.py` 初始化(main.py 第 25-28 行)中调整 `synchronize_interval` 参数(以秒为单位) | |
| ### 扩展 JWT 有效负载 | |
| 修改 utils.py 中的 `parse_token()` 以从 JWT 有效负载中提取其他字段,然后更新 main.py 中 add_log() 中的日志架构 | |