Spaces:
Running
Running
File size: 7,833 Bytes
83705b6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# 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() 中的日志架构
|