mirror of
https://github.com/Nezumi-2711/astrbot_plugin_qq_group_daily_analysis.git
synced 2026-09-22 05:31:52 +00:00
feat: Add documentation for log quick reference and viewing research.
This commit is contained in:
@@ -0,0 +1,457 @@
|
||||
# TraceID 日志增强指南 + AstrBot 日志查看
|
||||
|
||||
> **核心观点**:`contextvars + logging.Filter` 方案是对 AstrBot logger 的增强,不是替换。日志仍通过 AstrBot 输出,只是自动注入 trace_id。
|
||||
|
||||
---
|
||||
|
||||
## 🔍 日志查看入口(三种方式)
|
||||
|
||||
### 1️⃣ 控制台输出(最简单,开发环境推荐)
|
||||
|
||||
**启动 AstrBot 后,直接在终端看日志**
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
|
||||
# 输出示例:
|
||||
[10:30:45] [Plug] [INFO ] [group_daily:45]: [123456789-1707292800] 开始分析群
|
||||
[10:30:46] [Plug] [INFO ] [group_daily:46]: [123456789-1707292800] 获取 256 条消息
|
||||
[10:30:47] [Plug] [INFO ] [group_daily:47]: [123456789-1707292800] 话题分析完成
|
||||
[10:30:48] [Plug] [ERROR] [group_daily:50]: [123456789-1707292800] LLM 超时
|
||||
↑
|
||||
TraceID(自动注入)
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- ✅ 零配置,启动即可看
|
||||
- ✅ 实时显示,彩色输出
|
||||
- ✅ 容易识别错误
|
||||
|
||||
### 2️⃣ 日志文件(生产环境标配)
|
||||
|
||||
**在 `astrbot_config.yml` 中启用文件日志**
|
||||
|
||||
```yaml
|
||||
log_file_enable: true
|
||||
log_file_path: "logs/astrbot.log" # 日志文件路径
|
||||
log_file_max_mb: 20 # 文件大小限制(轮转)
|
||||
```
|
||||
|
||||
**查看方式**
|
||||
|
||||
```bash
|
||||
# Linux/Mac 实时查看
|
||||
tail -f logs/astrbot.log
|
||||
|
||||
# Windows PowerShell 实时查看
|
||||
Get-Content -Path logs/astrbot.log -Wait
|
||||
|
||||
# 搜索特定群的所有日志
|
||||
grep "123456789" logs/astrbot.log
|
||||
|
||||
# 查看最后 100 行
|
||||
tail -100 logs/astrbot.log
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- ✅ 永久保存
|
||||
- ✅ 支持搜索和分析
|
||||
- ✅ 生产环境必须
|
||||
|
||||
### 3️⃣ AstrBot Dashboard(最舒服,Web 界面)
|
||||
|
||||
**方式 A:AstrBot 内置 Dashboard(如果启用了)**
|
||||
|
||||
```
|
||||
访问:http://localhost:8000
|
||||
→ 日志 / Logs 菜单
|
||||
→ 可看实时日志流
|
||||
```
|
||||
|
||||
**方式 B:Astrbot-dashboard 独立工具**
|
||||
|
||||
```bash
|
||||
# 安装独立的 dashboard 包
|
||||
pip install astrbot-dashboard
|
||||
|
||||
# 启动(连接本地 AstrBot)
|
||||
astrbot-dashboard
|
||||
|
||||
# 浏览器打开
|
||||
# http://localhost:6185/#/console
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- ✅ Web 界面直观
|
||||
- ✅ 实时流式显示
|
||||
- ✅ 支持过滤和搜索
|
||||
|
||||
---
|
||||
|
||||
## ✅ 为什么使用 contextvars + logging.Filter?
|
||||
|
||||
### 核心原因:**自动 TraceID 注入**
|
||||
|
||||
```
|
||||
现状问题: 使用 contextvars 后:
|
||||
────────────────────────────────────────────────────
|
||||
logger.info("开始") logger.info("开始")
|
||||
logger.info("获取消息") → logger.info("获取消息")
|
||||
logger.error("超时") logger.error("超时")
|
||||
|
||||
输出: 输出:
|
||||
[INFO] 开始 [trace_id:123] [INFO] 开始
|
||||
[INFO] 获取消息 [trace_id:123] [INFO] 获取消息
|
||||
[ERROR] 超时 [trace_id:123] [ERROR] 超时
|
||||
|
||||
❌ 100 个群并发时看不出 ✅ 清晰看出所有日志属于
|
||||
谁的日志在哪里 同一个分析任务!
|
||||
```
|
||||
|
||||
### 有没有利用 AstrBot 现有日志?
|
||||
|
||||
**完全利用了!** 这是在 AstrBot logger 上添加一层装饰器:
|
||||
|
||||
```
|
||||
你的代码: logger.info("message")
|
||||
↓
|
||||
[TraceIDFilter](新增)← 自动注入 trace_id
|
||||
↓
|
||||
[AstrBot Logger](已有)
|
||||
├─ ColoredFormatter
|
||||
├─ StreamHandler(控制台)
|
||||
└─ RotatingFileHandler(文件)
|
||||
```
|
||||
|
||||
### 代码实现(简化版)
|
||||
|
||||
```python
|
||||
# src/utils/trace.py
|
||||
import contextvars
|
||||
import logging
|
||||
from astrbot.api import logger
|
||||
|
||||
# 全局 ContextVar
|
||||
_trace_id: contextvars.ContextVar[str] = contextvars.ContextVar('trace_id', default='')
|
||||
|
||||
# 自定义 Filter
|
||||
class TraceIDFilter(logging.Filter):
|
||||
def filter(self, record):
|
||||
record.trace_id = _trace_id.get('') or 'no-trace'
|
||||
return True
|
||||
|
||||
# 注册到 AstrBot logger(在插件初始化时)
|
||||
logger.addFilter(TraceIDFilter())
|
||||
|
||||
# 使用(在分析开始处)
|
||||
async def analyze_group(group_id: str):
|
||||
import time
|
||||
|
||||
# 设置 trace_id
|
||||
_trace_id.set(f"{group_id}-{int(time.time())}")
|
||||
|
||||
try:
|
||||
logger.info("开始分析") # 自动包含 trace_id
|
||||
# ... 分析逻辑
|
||||
finally:
|
||||
_trace_id.set('') # 清理
|
||||
```
|
||||
|
||||
### 输出效果
|
||||
|
||||
```bash
|
||||
$ tail -f logs/astrbot.log | grep trace_id
|
||||
|
||||
[123456789-1707292800] [10:30:45] [Plug] [INFO ] [group_daily:45]: 开始分析群
|
||||
[123456789-1707292800] [10:30:46] [Plug] [INFO ] [group_daily:46]: 获取 256 条消息
|
||||
[123456789-1707292800] [10:30:47] [Plug] [INFO ] [group_daily:47]: 话题分析完成
|
||||
[123456789-1707292800] [10:30:48] [Plug] [ERROR] [group_daily:50]: LLM 超时
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 架构流程图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ AstrBot 应用 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 核心组件/插件 │
|
||||
│ │ │
|
||||
│ ├─→ logger.info("message") │
|
||||
│ └─→ logger.error("error") │
|
||||
│ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────────────────────────────┐ │
|
||||
│ │ LogQueueHandler (日志处理器) │ │
|
||||
│ │ 接收 logging.LogRecord │ │
|
||||
│ └──────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────────────────────────────────────────────┐ │
|
||||
│ │ LogBroker (日志代理) │ │
|
||||
│ │ - log_cache: deque(maxlen=500) [环形缓冲区] │ │
|
||||
│ │ - subscribers: List[Queue] [订阅者队列] │ │
|
||||
│ │ │ │
|
||||
│ │ publish(log_entry): │ │
|
||||
│ │ 1. 添加到 log_cache │ │
|
||||
│ │ 2. 分发给所有 subscribers │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ├──────────────────┬─────────────────────────────┐ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌─────────────┐ ┌───────────────┐ ┌──────────────┐ │
|
||||
│ │ Dashboard │ │ Trace Logger │ │ 其他订阅者 │ │
|
||||
│ │ SSE 连接 │ │ (可选) │ │ (可选) │ │
|
||||
│ │ (实时推送) │ │ (文件/内存) │ │ │ │
|
||||
│ └─────────────┘ └───────────────┘ └──────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 数据输出 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 1. Dashboard UI (/:console) │
|
||||
│ - 实时日志显示 │
|
||||
│ - 级别过滤 │
|
||||
│ │
|
||||
│ 2. 日志文件 (可选) │
|
||||
│ - data/logs/astrbot.log │
|
||||
│ - data/logs/astrbot.trace.log │
|
||||
│ │
|
||||
│ 3. 浏览器 Memory │
|
||||
│ - SSE 缓存 (断网重连补发) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 文件位置速查
|
||||
|
||||
| 类型 | 位置 | 启用方式 |
|
||||
|------|------|--------|
|
||||
| **普通日志** | `data/logs/astrbot.log` | `log_file_enable: true` |
|
||||
| **Trace 日志** | `data/logs/astrbot.trace.log` | `trace_log_enable: true` |
|
||||
| **配置文件** | `data/cmd_config.json` | 直接编辑 |
|
||||
| **数据目录** | `data/` | 环境变量 `ASTRBOT_ROOT` |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 配置项清单
|
||||
|
||||
### 日志配置(最常用)
|
||||
|
||||
```json
|
||||
{
|
||||
"log_level": "INFO", // DEBUG|INFO|WARNING|ERROR|CRITICAL
|
||||
"log_file_enable": false, // 启用文件日志
|
||||
"log_file_path": "logs/astrbot.log", // 相对于 data/ 目录
|
||||
"log_file_max_mb": 20, // 单个文件最大大小
|
||||
|
||||
"trace_enable": false, // 启用 Trace 记录
|
||||
"trace_log_enable": false, // 启用 Trace 文件日志
|
||||
"trace_log_path": "logs/astrbot.trace.log", // Trace 文件位置
|
||||
"trace_log_max_mb": 20
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💻 代码使用速查
|
||||
|
||||
### 记录日志(最常用)
|
||||
|
||||
```python
|
||||
from astrbot.core import logger
|
||||
|
||||
logger.debug("Debug message")
|
||||
logger.info("Info message")
|
||||
logger.warning("Warning message")
|
||||
logger.error("Error message")
|
||||
logger.critical("Critical error")
|
||||
```
|
||||
|
||||
### Trace 追踪(链路追踪)
|
||||
|
||||
```python
|
||||
from astrbot.core.utils.trace import TraceSpan
|
||||
|
||||
span = TraceSpan(
|
||||
name="operation_name",
|
||||
sender_name="ComponentA",
|
||||
message_outline="Brief description"
|
||||
)
|
||||
|
||||
span.record("stage1", key1="value1")
|
||||
span.record("stage2", key2="value2")
|
||||
```
|
||||
|
||||
### 订阅日志流(高级)
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
async def listen_logs(log_broker):
|
||||
queue = log_broker.register()
|
||||
try:
|
||||
while True:
|
||||
log_entry = await queue.get()
|
||||
print(f"{log_entry['level']}: {log_entry['data']}")
|
||||
finally:
|
||||
log_broker.unregister(queue)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 常见操作
|
||||
|
||||
### ❓ 如何启用文件日志?
|
||||
|
||||
1. 打开 `data/cmd_config.json`
|
||||
2. 修改:
|
||||
```json
|
||||
"log_file_enable": true,
|
||||
"log_file_path": "logs/astrbot.log"
|
||||
```
|
||||
3. 重启应用
|
||||
|
||||
### ❓ 如何查看特定群的日志?
|
||||
|
||||
```bash
|
||||
# 方式 1: Dashboard 中搜索 group_id
|
||||
http://localhost:6185/#/console
|
||||
|
||||
# 方式 2: 命令行查询
|
||||
grep "QQGroup:123456789" data/logs/astrbot.log
|
||||
```
|
||||
|
||||
### ❓ 如何用 span_id 追踪完整请求?
|
||||
|
||||
```bash
|
||||
# Trace 日志包含 span_id,可追踪单个请求的全生命周期
|
||||
grep "span_id.*abc-123-def" data/logs/astrbot.trace.log
|
||||
|
||||
# 或在 Dashboard 的 /trace 页面实时查看
|
||||
```
|
||||
|
||||
### ❓ 日志缓存大小是多少?
|
||||
|
||||
- **内存缓存**: 最近 500 条日志(deque with maxlen=500)
|
||||
- **Dashboard 前端缓存**: 最近 1000 条日志
|
||||
- **文件日志**: 单个文件 20MB,自动轮转(3 个备份)
|
||||
|
||||
### ❓ 日志是否会自动删除?
|
||||
|
||||
- **内存缓存**: 自动淘汰(先进先出,保持最近 500 条)
|
||||
- **文件日志**: 不自动删除,需手动管理或配置轮转
|
||||
- **Dashboard 前端**: 页面关闭后清空
|
||||
|
||||
---
|
||||
|
||||
## 📊 日志格式示例
|
||||
|
||||
### Console 日志输出
|
||||
|
||||
```
|
||||
[12:34:56] [Core] [INFO] [astrbot.py:123]: Application started successfully
|
||||
[12:34:57] [Plug] [WARN] [plugin.py:45]: Missing dependency: requests
|
||||
[12:35:00] [Core] [ERRO] [error.py:78]: Connection timeout to server [v4.14.4]
|
||||
```
|
||||
|
||||
格式:`[时间] [来源] [级别] [文件:行号]: 消息`
|
||||
|
||||
### Trace JSON 日志
|
||||
|
||||
```json
|
||||
[2024-01-01 12:34:56] {"type":"trace","span_id":"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx","name":"group_analysis","sender_name":"QQGroup:123456789","action":"start","fields":{"group_id":"123456789","step":"initialization"}}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 日志级别和颜色
|
||||
|
||||
| 级别 | 缩写 | 颜色 | 含义 |
|
||||
|------|------|------|------|
|
||||
| DEBUG | DBUG | 🟢 绿色 | 调试信息 |
|
||||
| INFO | INFO | 🔵 青色 | 一般信息 |
|
||||
| WARNING | WARN | 🟡 黄色 | 警告信息 |
|
||||
| ERROR | ERRO | 🔴 红色 | 错误信息 |
|
||||
| CRITICAL | CRIT | 🟣 紫色 | 严重错误 |
|
||||
|
||||
---
|
||||
|
||||
## 📈 性能指标
|
||||
|
||||
| 项目 | 值 | 说明 |
|
||||
|------|-----|------|
|
||||
| 日志缓存大小 | 500 条 | 环形缓冲区 |
|
||||
| Dashboard 前端缓存 | 1000 条 | 浏览器内存 |
|
||||
| SSE 队列大小 | 510 条 | maxsize = CACHED_SIZE + 10 |
|
||||
| 日志文件大小 | 20MB | 单个文件,可配置 |
|
||||
| 备份文件数 | 3 个 | 自动轮转 |
|
||||
| SSE 连接超时 | None | 永不超时 |
|
||||
|
||||
---
|
||||
|
||||
## 🔐 安全相关
|
||||
|
||||
### 日志中的敏感信息
|
||||
|
||||
```python
|
||||
# ❌ 不要直接记录密钥
|
||||
logger.info(f"API key: {api_key}")
|
||||
|
||||
# ✅ 使用脱敏
|
||||
logger.info(f"API key: {api_key[:8]}...")
|
||||
|
||||
# ✅ 或使用占位符
|
||||
logger.info(f"Using API key: ***")
|
||||
```
|
||||
|
||||
### Dashboard 访问认证
|
||||
|
||||
- 默认用户名:`astrbot`
|
||||
- 默认密码:(MD5 哈希,需在配置中修改)
|
||||
- JWT Token:用于 API 认证
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关链接
|
||||
|
||||
| 资源 | 位置 |
|
||||
|------|------|
|
||||
| 完整文档 | `LOG_VIEWING_RESEARCH.md` |
|
||||
| 日志实现 | `astrbot/core/log.py` |
|
||||
| Trace 系统 | `astrbot/core/utils/trace.py` |
|
||||
| Dashboard API | `astrbot/dashboard/routes/log.py` |
|
||||
| 前端组件 | `dashboard/src/components/shared/ConsoleDisplayer.vue` |
|
||||
| 默认配置 | `astrbot/core/config/default.py` |
|
||||
|
||||
---
|
||||
|
||||
## ✅ 检查清单
|
||||
|
||||
### 开发调试
|
||||
|
||||
- [ ] Dashboard 可以实时看到日志
|
||||
- [ ] 日志级别设置为 DEBUG
|
||||
- [ ] Trace 追踪已启用(if needed)
|
||||
|
||||
### 生产部署
|
||||
|
||||
- [ ] 日志级别设置为 INFO
|
||||
- [ ] 文件日志已启用(for persistence)
|
||||
- [ ] 日志轮转已配置
|
||||
- [ ] 监控系统已连接
|
||||
|
||||
### 问题诊断
|
||||
|
||||
- [ ] 日志中包含 span_id(for tracing)
|
||||
- [ ] 时间戳正确(for correlation)
|
||||
- [ ] 日志级别适当(not too verbose)
|
||||
|
||||
---
|
||||
|
||||
*最后更新:2024年 | AstrBot v4.14.4*
|
||||
@@ -0,0 +1,677 @@
|
||||
# AstrBot 日志查看方式研究报告
|
||||
|
||||
## 概述
|
||||
|
||||
本文档详细说明了 AstrBot 的日志系统架构、查看方式、以及如何在代码中集成日志查看功能。
|
||||
|
||||
---
|
||||
|
||||
## 1. 日志文件默认位置
|
||||
|
||||
### 1.1 日志文件存储位置
|
||||
|
||||
根据配置,AstrBot 的日志文件存储在以下位置:
|
||||
|
||||
| 日志类型 | 默认位置 | 配置键 | 说明 |
|
||||
|---------|--------|-------|------|
|
||||
| **普通日志** | `data/logs/astrbot.log` | `log_file_path` | 主应用日志,记录应用运行信息 |
|
||||
| **Trace 日志** | `data/logs/astrbot.trace.log` | `trace_log_path` | 链路追踪日志,记录请求跨度信息 |
|
||||
|
||||
### 1.2 日志文件配置参数
|
||||
|
||||
```python
|
||||
# 配置文件位置: astrbot/core/config/default.py
|
||||
DEFAULT_CONFIG = {
|
||||
"log_level": "INFO", # 日志级别(DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||
"log_file_enable": False, # 是否启用文件日志(默认禁用)
|
||||
"log_file_path": "logs/astrbot.log", # 日志文件相对路径(相对于 data/ 目录)
|
||||
"log_file_max_mb": 20, # 单个日志文件最大大小(MB)
|
||||
"trace_enable": False, # 是否启用 Trace 记录
|
||||
"trace_log_enable": False, # 是否启用 Trace 文件日志
|
||||
"trace_log_path": "logs/astrbot.trace.log", # Trace 日志文件路径
|
||||
"trace_log_max_mb": 20, # Trace 日志文件最大大小
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 日志目录基路径
|
||||
|
||||
- **根数据目录**: `data/`
|
||||
- **日志目录**: `data/logs/`
|
||||
- **获取方法**(Python 代码):
|
||||
```python
|
||||
from astrbot.core.utils.astrbot_path import get_astrbot_data_path
|
||||
log_dir = os.path.join(get_astrbot_data_path(), "logs")
|
||||
```
|
||||
|
||||
### 1.4 日志文件轮转配置
|
||||
|
||||
当启用文件日志时,AstrBot 使用 `RotatingFileHandler`:
|
||||
- 最大单个文件大小:`log_file_max_mb`(默认 20MB)
|
||||
- 备份文件数量:3 个
|
||||
- 超过大小后自动轮转:`astrbot.log.1`, `astrbot.log.2`, `astrbot.log.3`
|
||||
|
||||
---
|
||||
|
||||
## 2. Dashboard 中的日志查看功能
|
||||
|
||||
### 2.1 Dashboard 路由和 API
|
||||
|
||||
AstrBot Dashboard 提供以下日志相关的 REST API(代码位置:`astrbot/dashboard/routes/log.py`):
|
||||
|
||||
| API 端点 | 方法 | 功能 | 说明 |
|
||||
|---------|------|------|------|
|
||||
| `/api/live-log` | GET | 实时日志流 | Server-Sent Events (SSE) 连接,推送实时日志 |
|
||||
| `/api/log-history` | GET | 日志历史 | 获取缓存的日志历史(JSON 格式) |
|
||||
| `/api/trace/settings` | GET | Trace 设置查询 | 获取当前 Trace 启用状态 |
|
||||
| `/api/trace/settings` | POST | Trace 设置更新 | 更新 Trace 启用/禁用状态 |
|
||||
|
||||
### 2.2 实时日志流(SSE)
|
||||
|
||||
#### 连接方式
|
||||
|
||||
**前端代码**(Vue.js,位置:`dashboard/src/stores/common.js`):
|
||||
|
||||
```javascript
|
||||
fetch('/api/live-log', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
'Authorization': 'Bearer ' + localStorage.getItem('token')
|
||||
},
|
||||
cache: 'no-cache',
|
||||
}).then(response => {
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
// 处理流式数据...
|
||||
})
|
||||
```
|
||||
|
||||
#### SSE 消息格式
|
||||
|
||||
后端返回的 SSE 消息格式(`astrbot/dashboard/routes/log.py`):
|
||||
|
||||
```
|
||||
id: {timestamp}
|
||||
data: {json_object}
|
||||
|
||||
```
|
||||
|
||||
JSON 对象结构:
|
||||
```json
|
||||
{
|
||||
"type": "log",
|
||||
"level": "INFO",
|
||||
"data": "[12:34:56] [Core] [INFO] [file.py:123]: Log message",
|
||||
"time": 1697787296.123456,
|
||||
"uuid": "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
```
|
||||
|
||||
#### 日志缓存和重放
|
||||
|
||||
- **缓存大小**: 最多 500 条日志(常量 `CACHED_SIZE = 500`)
|
||||
- **缓存数据结构**: `deque(maxlen=500)`(环形缓冲区)
|
||||
- **浏览器断网重连**: 发送 `Last-Event-ID` 请求头,服务端根据时间戳重放缺失的日志
|
||||
|
||||
### 2.3 Dashboard 前端界面
|
||||
|
||||
#### 控制台页面(Console)
|
||||
|
||||
**路由**: `/console`
|
||||
**组件**: [ConsolePage.vue](dashboard/src/views/ConsolePage.vue)
|
||||
|
||||
功能:
|
||||
- ✅ 实时日志显示(通过 SSE 连接)
|
||||
- ✅ 日志级别过滤(DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||
- ✅ 自动滚动开关
|
||||
- ✅ pip 包安装界面
|
||||
|
||||
日志样式:
|
||||
```
|
||||
[12:34:56] [Core] [INFO] [astrbot.py:123]: AstrBot started successfully
|
||||
[12:34:57] [Plug] [WARN] [plugin.py:45]: Missing dependency
|
||||
[12:35:00] [Core] [ERRO] [error.py:78]: Connection timeout [v4.14.4]
|
||||
```
|
||||
|
||||
#### 链路追踪页面(Trace)
|
||||
|
||||
**路由**: `/trace`
|
||||
**组件**: [TracePage.vue](dashboard/src/views/TracePage.vue)
|
||||
|
||||
功能:
|
||||
- ✅ 实时链路追踪显示
|
||||
- ✅ Trace 启用/禁用开关
|
||||
- ✅ Trace 事件详细信息展示
|
||||
|
||||
#### 日志显示器组件
|
||||
|
||||
**组件**: [ConsoleDisplayer.vue](dashboard/src/components/shared/ConsoleDisplayer.vue)
|
||||
|
||||
特性:
|
||||
- 日志级别色彩标记
|
||||
- ANSI 颜色代码转换为 HTML 样式
|
||||
- 日志缓存最多保留 1000 条(configurable)
|
||||
- 自动滚动到最新日志
|
||||
|
||||
---
|
||||
|
||||
## 3. LogBroker 架构(发布-订阅模式)
|
||||
|
||||
### 3.1 LogBroker 类设计
|
||||
|
||||
**位置**: `astrbot/core/log.py`
|
||||
|
||||
```python
|
||||
class LogBroker:
|
||||
"""日志代理类, 用于缓存和分发日志消息"""
|
||||
|
||||
def __init__(self):
|
||||
self.log_cache = deque(maxlen=CACHED_SIZE) # 环形缓冲区
|
||||
self.subscribers: list[Queue] = [] # 订阅者列表
|
||||
|
||||
def register(self) -> Queue:
|
||||
"""注册新的订阅者,返回一个队列用于接收日志"""
|
||||
q = Queue(maxsize=CACHED_SIZE + 10)
|
||||
self.subscribers.append(q)
|
||||
return q
|
||||
|
||||
def unregister(self, q: Queue):
|
||||
"""取消订阅"""
|
||||
self.subscribers.remove(q)
|
||||
|
||||
def publish(self, log_entry: dict):
|
||||
"""发布日志到所有订阅者(非阻塞方式)"""
|
||||
self.log_cache.append(log_entry)
|
||||
for q in self.subscribers:
|
||||
try:
|
||||
q.put_nowait(log_entry)
|
||||
except asyncio.QueueFull:
|
||||
pass # 订阅者队列满,丢弃该日志
|
||||
```
|
||||
|
||||
### 3.2 工作流程图
|
||||
|
||||
```
|
||||
日志记录器 (logger)
|
||||
↓
|
||||
LogQueueHandler (日志处理器)
|
||||
↓
|
||||
LogBroker.publish(log_entry)
|
||||
├→ 添加到 log_cache(环形缓冲区)
|
||||
└→ 分发给所有订阅者的队列
|
||||
├→ Dashboard SSE 连接
|
||||
├→ Trace 日志记录器
|
||||
└→ 其他订阅者
|
||||
```
|
||||
|
||||
### 3.3 日志项结构
|
||||
|
||||
```python
|
||||
log_entry = {
|
||||
"level": "INFO", # 日志级别
|
||||
"time": 1697787296.123, # Unix 时间戳
|
||||
"data": "Log message text", # 格式化的日志文本
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 在代码中集成 LogBroker
|
||||
|
||||
#### 启动应用时初始化
|
||||
|
||||
```python
|
||||
# main.py 或 cmd_run.py
|
||||
from astrbot.core import LogBroker, LogManager, logger
|
||||
|
||||
# 创建日志代理
|
||||
log_broker = LogBroker()
|
||||
|
||||
# 将日志处理器连接到 LogBroker
|
||||
LogManager.set_queue_handler(logger, log_broker)
|
||||
|
||||
# 传递给应用初始化器
|
||||
core_lifecycle = InitialLoader(db, log_broker)
|
||||
```
|
||||
|
||||
#### 在 Dashboard 中使用
|
||||
|
||||
```python
|
||||
# dashboard/routes/log.py
|
||||
class LogRoute(Route):
|
||||
def __init__(self, context: RouteContext, log_broker: LogBroker) -> None:
|
||||
self.log_broker = log_broker
|
||||
# 注册 API 路由...
|
||||
|
||||
async def log(self) -> QuartResponse:
|
||||
"""SSE 日志流"""
|
||||
queue = self.log_broker.register() # 注册订阅者
|
||||
try:
|
||||
while True:
|
||||
message = await queue.get() # 等待日志
|
||||
yield _format_log_sse(message, current_ts)
|
||||
finally:
|
||||
self.log_broker.unregister(queue) # 取消订阅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Trace 日志系统
|
||||
|
||||
### 4.1 Trace 概念
|
||||
|
||||
Trace 日志用于记录**请求的整个链路**,包括:
|
||||
- 跨度信息(span_id)
|
||||
- 请求发起者(sender_name)
|
||||
- 操作阶段(action)
|
||||
- 自定义字段(fields)
|
||||
|
||||
### 4.2 Trace 启用配置
|
||||
|
||||
**配置项**:
|
||||
```python
|
||||
"trace_enable": False, # 启用 Trace 记录
|
||||
"trace_log_enable": False, # 启用 Trace 文件日志
|
||||
"trace_log_path": "logs/astrbot.trace.log", # Trace 日志文件路径
|
||||
```
|
||||
|
||||
**Dashboard 设置**: `/api/trace/settings` 端点可动态启用/禁用 Trace
|
||||
|
||||
### 4.3 使用 TraceSpan 记录链路
|
||||
|
||||
**代码位置**: `astrbot/core/utils/trace.py`
|
||||
|
||||
```python
|
||||
from astrbot.core.utils.trace import TraceSpan
|
||||
|
||||
# 创建 Trace 跨度
|
||||
span = TraceSpan(
|
||||
name="group_analysis",
|
||||
umo="qq_group",
|
||||
sender_name="QQGroup:123456789",
|
||||
message_outline="Daily analysis request"
|
||||
)
|
||||
|
||||
# 记录不同阶段的操作
|
||||
span.record("start", step="initialization")
|
||||
span.record("process", data_count=1000)
|
||||
span.record("end", result_code=200)
|
||||
```
|
||||
|
||||
### 4.4 Trace 日志格式
|
||||
|
||||
**发布到 LogBroker**:
|
||||
```json
|
||||
{
|
||||
"type": "trace",
|
||||
"level": "TRACE",
|
||||
"time": 1697787296.123,
|
||||
"span_id": "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx",
|
||||
"name": "group_analysis",
|
||||
"umo": "qq_group",
|
||||
"sender_name": "QQGroup:123456789",
|
||||
"message_outline": "Daily analysis request",
|
||||
"action": "start",
|
||||
"fields": {"step": "initialization"}
|
||||
}
|
||||
```
|
||||
|
||||
**写入文件**(JSON 格式,每行一条):
|
||||
```json
|
||||
[2024-01-01 12:34:56] {"type":"trace","span_id":"...","name":"group_analysis",...}
|
||||
```
|
||||
|
||||
### 4.5 Trace 查询方式
|
||||
|
||||
1. **Dashboard UI** (`/trace` 路由)
|
||||
- 实时查看所有 Trace 事件
|
||||
- 可启用/禁用 Trace 记录
|
||||
|
||||
2. **日志文件查询**
|
||||
- 文件位置:`data/logs/astrbot.trace.log`
|
||||
- 使用 `jq` 或 Python 解析 NDJSON 格式
|
||||
|
||||
3. **span_id 查询** - 用于追踪单个请求
|
||||
```bash
|
||||
grep "span_id.*abc123" data/logs/astrbot.trace.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 日志访问方式总结
|
||||
|
||||
### 5.1 实时日志查看
|
||||
|
||||
| 方式 | 说明 | 适用场景 |
|
||||
|------|------|---------|
|
||||
| **Dashboard Console** | 浏览器访问 `http://localhost:6185/#/console` | 实时监控、界面友好 |
|
||||
| **REST API SSE** | `GET /api/live-log`(Server-Sent Events) | 集成第三方系统 |
|
||||
| **文件直接查看** | `tail -f data/logs/astrbot.log` | 服务器终端查看 |
|
||||
|
||||
### 5.2 历史日志查看
|
||||
|
||||
| 方式 | 说明 | 命令/代码 |
|
||||
|------|------|---------|
|
||||
| **Dashboard History** | `GET /api/log-history` 返回缓存的日志 | 返回最近 500 条 |
|
||||
| **文件查询** | 日志文件存储在 `data/logs/astrbot.log` | `grep` 或编辑器打开 |
|
||||
| **日志分析** | Python/shell 脚本处理日志文件 | 自定义分析 |
|
||||
|
||||
### 5.3 Trace 日志查看
|
||||
|
||||
| 方式 | 说明 | 对应 API |
|
||||
|------|------|---------|
|
||||
| **Dashboard Trace** | 实时追踪链路,浏览器访问 `/trace` | SSE 推送 |
|
||||
| **Trace 文件** | `data/logs/astrbot.trace.log`(NDJSON 格式) | 离线分析 |
|
||||
| **span_id 查询** | 按 span_id 追踪单个请求 | `grep` 搜索 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 插件/群分析日志集成示例
|
||||
|
||||
### 6.1 为群分析日志添加 Trace ID
|
||||
|
||||
对于"QQ 群日常分析插件"(`astrbot_plugin_qq_group_daily_analysis`),可以这样集成日志追踪:
|
||||
|
||||
```python
|
||||
# main.py 或分析模块
|
||||
from astrbot import logger
|
||||
from astrbot.core.utils.trace import TraceSpan
|
||||
|
||||
class GroupAnalyzer:
|
||||
def analyze_group(self, group_id: str):
|
||||
# 创建追踪跨度
|
||||
span = TraceSpan(
|
||||
name="group_daily_analysis",
|
||||
umo="qq_group",
|
||||
sender_name=f"QQGroup:{group_id}",
|
||||
message_outline=f"Daily analysis for group {group_id}"
|
||||
)
|
||||
|
||||
try:
|
||||
span.record("start", group_id=group_id)
|
||||
logger.info(f"[GroupAnalysis] Starting analysis for group: {group_id}")
|
||||
|
||||
# 分析逻辑...
|
||||
data = self._fetch_messages(group_id)
|
||||
span.record("fetch_complete", message_count=len(data))
|
||||
|
||||
# 处理数据...
|
||||
result = self._process_data(data)
|
||||
span.record("process_complete", result_code=200)
|
||||
|
||||
logger.info(f"[GroupAnalysis] Analysis complete for {group_id}")
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
span.record("error", error_type=type(e).__name__, error_msg=str(e))
|
||||
logger.error(f"[GroupAnalysis] Error analyzing group {group_id}: {e}")
|
||||
raise
|
||||
```
|
||||
|
||||
### 6.2 查询特定群的日志
|
||||
|
||||
**在 Dashboard 中**:
|
||||
1. 打开 `/console` 页面
|
||||
2. 输入日志过滤器(或查看所有日志)
|
||||
3. 搜索 `GroupAnalysis` 或特定的 group_id
|
||||
|
||||
**通过命令行**:
|
||||
```bash
|
||||
# 查找特定群的日志
|
||||
grep "QQGroup:123456789" data/logs/astrbot.log
|
||||
|
||||
# 或查找 Trace 日志
|
||||
grep "group_id.*123456789" data/logs/astrbot.trace.log
|
||||
```
|
||||
|
||||
### 6.3 日志格式确保
|
||||
|
||||
在日志中需要包含:
|
||||
- **时间戳**: 自动添加(格式 `HH:MM:SS`)
|
||||
- **日志级别**: DEBUG, INFO, WARNING, ERROR, CRITICAL
|
||||
- **来源标记**: [Core] 或 [Plug]
|
||||
- **文件和行号**: 自动添加
|
||||
- **消息内容**: 手动添加
|
||||
|
||||
**示例日志行**:
|
||||
```
|
||||
[12:34:56] [Plug] [INFO] [group_analyzer.py:145]: [GroupAnalysis] Analysis complete for QQGroup:123456789
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. LogManager 高级配置
|
||||
|
||||
### 7.1 配置日志级别
|
||||
|
||||
```python
|
||||
from astrbot.core import LogManager, logger
|
||||
|
||||
# 根据配置设置日志级别
|
||||
config = {
|
||||
"log_level": "DEBUG",
|
||||
"log_file_enable": True,
|
||||
"log_file_path": "logs/astrbot.log",
|
||||
"log_file_max_mb": 50,
|
||||
}
|
||||
|
||||
LogManager.configure_logger(logger, config)
|
||||
```
|
||||
|
||||
### 7.2 配置 Trace 日志
|
||||
|
||||
```python
|
||||
# 启用 Trace 日志文件
|
||||
config = {
|
||||
"trace_enable": True,
|
||||
"trace_log_enable": True,
|
||||
"trace_log_path": "logs/astrbot.trace.log",
|
||||
"trace_log_max_mb": 30,
|
||||
}
|
||||
|
||||
LogManager.configure_trace_logger(config)
|
||||
```
|
||||
|
||||
### 7.3 日志过滤器
|
||||
|
||||
LogManager 自动添加以下过滤器:
|
||||
|
||||
| 过滤器 | 功能 | 输出示例 |
|
||||
|-------|------|--------|
|
||||
| **PluginFilter** | 标记日志来源(Core/Plug) | `[Core]` 或 `[Plug]` |
|
||||
| **FileNameFilter** | 修改文件名格式 | `folder.filename` |
|
||||
| **LevelNameFilter** | 4 字母缩写 | `DBUG`, `INFO`, `WARN`, `ERRO`, `CRIT` |
|
||||
| **AstrBotVersionTagFilter** | 在 WARNING 及以上追加版本 | `[v4.14.4]` |
|
||||
|
||||
---
|
||||
|
||||
## 8. 日志配置管理
|
||||
|
||||
### 8.1 配置文件路径
|
||||
|
||||
- **配置文件**: `data/cmd_config.json`
|
||||
- **默认配置**: `astrbot/core/config/default.py`
|
||||
- **编辑方式**:
|
||||
1. 直接编辑 JSON 文件
|
||||
2. 通过 Dashboard 管理面板修改(未来功能)
|
||||
|
||||
### 8.2 配置更新
|
||||
|
||||
配置更改后,需要重启应用以生效(或通过 API 动态更新)。
|
||||
|
||||
### 8.3 环境变量支持
|
||||
|
||||
**根目录自定义**(可选):
|
||||
```bash
|
||||
export ASTRBOT_ROOT=/path/to/root
|
||||
# 数据目录将为 /path/to/root/data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 代码示例汇总
|
||||
|
||||
### 9.1 获取日志记录器
|
||||
|
||||
```python
|
||||
from astrbot.core import logger
|
||||
|
||||
# 已配置的全局日志记录器
|
||||
logger.info("Message")
|
||||
logger.debug("Debug message")
|
||||
logger.warning("Warning")
|
||||
logger.error("Error")
|
||||
logger.critical("Critical error")
|
||||
```
|
||||
|
||||
### 9.2 创建自定义日志记录器
|
||||
|
||||
```python
|
||||
from astrbot.core import LogManager
|
||||
|
||||
# 获取命名日志记录器
|
||||
plugin_logger = LogManager.GetLogger("my_plugin")
|
||||
plugin_logger.info("Plugin message")
|
||||
```
|
||||
|
||||
### 9.3 发起 Trace 追踪
|
||||
|
||||
```python
|
||||
from astrbot.core.utils.trace import TraceSpan
|
||||
|
||||
span = TraceSpan(
|
||||
name="custom_operation",
|
||||
umo="custom_type",
|
||||
sender_name="CustomOperator",
|
||||
message_outline="Operation description"
|
||||
)
|
||||
|
||||
span.record("stage1", param1="value1")
|
||||
span.record("stage2", param2="value2", status="success")
|
||||
```
|
||||
|
||||
### 9.4 订阅日志流(自定义)
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from astrbot.core import LogBroker
|
||||
|
||||
# 从 LogBroker 获取日志队列
|
||||
log_broker = app.log_broker # 从应用上下文获取
|
||||
|
||||
async def listen_logs():
|
||||
queue = log_broker.register()
|
||||
try:
|
||||
while True:
|
||||
log_entry = await queue.get()
|
||||
print(f"[{log_entry['level']}] {log_entry['data']}")
|
||||
finally:
|
||||
log_broker.unregister(queue)
|
||||
|
||||
# 运行监听器
|
||||
asyncio.run(listen_logs())
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 常见问题和最佳实践
|
||||
|
||||
### 10.1 为什么文件日志默认禁用?
|
||||
|
||||
- 性能考虑(避免磁盘 I/O 开销)
|
||||
- 容器环境中不需要持久化
|
||||
- 大多数用户通过 Dashboard 查看日志
|
||||
|
||||
### 10.2 启用文件日志的步骤
|
||||
|
||||
1. 编辑 `data/cmd_config.json`:
|
||||
```json
|
||||
{
|
||||
"log_file_enable": true,
|
||||
"log_file_path": "logs/astrbot.log",
|
||||
"log_file_max_mb": 50
|
||||
}
|
||||
```
|
||||
2. 重启 AstrBot 应用
|
||||
3. 日志将写入 `data/logs/astrbot.log`
|
||||
|
||||
### 10.3 日志级别选择
|
||||
|
||||
- **DEBUG**: 开发调试,包含所有详细信息
|
||||
- **INFO**: 生产环境推荐,记录重要事件
|
||||
- **WARNING**: 只记录警告和错误
|
||||
- **ERROR**: 仅记录错误
|
||||
- **CRITICAL**: 仅记录严重错误
|
||||
|
||||
### 10.4 Trace ID 用于群分析追踪
|
||||
|
||||
对于"QQ 群日常分析"场景:
|
||||
- 每个群的分析请求都有唯一的 `span_id`
|
||||
- 可通过此 ID 追踪整个分析流程
|
||||
- 涉及多群并发时日志清晰分离
|
||||
|
||||
**查询示例**:
|
||||
```bash
|
||||
# 查找 span_id 相关的所有日志
|
||||
grep "span_id: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" data/logs/astrbot.trace.log
|
||||
```
|
||||
|
||||
### 10.5 性能考虑
|
||||
|
||||
- **日志缓存**: 最多 500 条,超出自动淘汰(先进先出)
|
||||
- **SSE 连接**: 断网自动重连,支持日志补发
|
||||
- **文件轮转**: 单个文件超过 20MB(可配置)自动轮转
|
||||
|
||||
---
|
||||
|
||||
## 11. 相关文件速查表
|
||||
|
||||
| 功能 | 文件路径 |
|
||||
|------|--------|
|
||||
| 日志核心逻辑 | `astrbot/core/log.py` |
|
||||
| 日志管理器 | `astrbot/core/log.py` (LogManager 类) |
|
||||
| Trace 系统 | `astrbot/core/utils/trace.py` |
|
||||
| Dashboard API | `astrbot/dashboard/routes/log.py` |
|
||||
| 默认配置 | `astrbot/core/config/default.py` |
|
||||
| 路径工具 | `astrbot/core/utils/astrbot_path.py` |
|
||||
| Dashboard Console UI | `dashboard/src/views/ConsolePage.vue` |
|
||||
| 日志显示器组件 | `dashboard/src/components/shared/ConsoleDisplayer.vue` |
|
||||
| Trace UI | `dashboard/src/views/TracePage.vue` |
|
||||
| 公共 Store | `dashboard/src/stores/common.js` |
|
||||
|
||||
---
|
||||
|
||||
## 12. 总结
|
||||
|
||||
### 日志查看的完整流程
|
||||
|
||||
1. **应用启动**
|
||||
- LogBroker 初始化
|
||||
- LogQueueHandler 连接到日志记录器
|
||||
|
||||
2. **日志产生**
|
||||
- 应用或插件调用 `logger.info()` 等方法
|
||||
- LogQueueHandler 拦截日志记录
|
||||
|
||||
3. **日志分发**
|
||||
- LogBroker.publish() 添加到缓存
|
||||
- 分发给所有订阅者(Dashboard SSE、Trace 日志等)
|
||||
|
||||
4. **用户查看**
|
||||
- **Dashboard Console**: 实时看到日志
|
||||
- **REST API**: 获取历史日志或 SSE 流
|
||||
- **文件**: 直接查看 `data/logs/astrbot.log`
|
||||
|
||||
5. **Trace 追踪**
|
||||
- 创建 TraceSpan 记录请求链路
|
||||
- Dashboard `/trace` 实时查看
|
||||
- 或通过 span_id 在文件中查询
|
||||
|
||||
### 推荐使用方式
|
||||
|
||||
- **开发调试**: Dashboard `/console` 页面
|
||||
- **生产监控**: 启用文件日志 + 日志收集系统
|
||||
- **问题诊断**: 通过 span_id 追踪完整请求链路
|
||||
- **群分析**: 在日志中包含 group_id,便于后续查询
|
||||
|
||||
---
|
||||
|
||||
*本文档基于 AstrBot v4.14.4 代码分析生成。*
|
||||
Reference in New Issue
Block a user