18 KiB
AstrBot 日志查看方式研究报告
概述
本文档详细说明了 AstrBot 的日志系统架构、查看方式、以及如何在代码中集成日志查看功能。
1. 日志文件默认位置
1.1 日志文件存储位置
根据配置,AstrBot 的日志文件存储在以下位置:
| 日志类型 | 默认位置 | 配置键 | 说明 |
|---|---|---|---|
| 普通日志 | data/logs/astrbot.log |
log_file_path |
主应用日志,记录应用运行信息 |
| Trace 日志 | data/logs/astrbot.trace.log |
trace_log_path |
链路追踪日志,记录请求跨度信息 |
1.2 日志文件配置参数
# 配置文件位置: 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 代码):
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):
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 对象结构:
{
"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
功能:
- ✅ 实时日志显示(通过 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
功能:
- ✅ 实时链路追踪显示
- ✅ Trace 启用/禁用开关
- ✅ Trace 事件详细信息展示
日志显示器组件
特性:
- 日志级别色彩标记
- ANSI 颜色代码转换为 HTML 样式
- 日志缓存最多保留 1000 条(configurable)
- 自动滚动到最新日志
3. LogBroker 架构(发布-订阅模式)
3.1 LogBroker 类设计
位置: astrbot/core/log.py
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 日志项结构
log_entry = {
"level": "INFO", # 日志级别
"time": 1697787296.123, # Unix 时间戳
"data": "Log message text", # 格式化的日志文本
}
3.4 在代码中集成 LogBroker
启动应用时初始化
# 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 中使用
# 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 启用配置
配置项:
"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
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:
{
"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 格式,每行一条):
[2024-01-01 12:34:56] {"type":"trace","span_id":"...","name":"group_analysis",...}
4.5 Trace 查询方式
-
Dashboard UI (
/trace路由)- 实时查看所有 Trace 事件
- 可启用/禁用 Trace 记录
-
日志文件查询
- 文件位置:
data/logs/astrbot.trace.log - 使用
jq或 Python 解析 NDJSON 格式
- 文件位置:
-
span_id 查询 - 用于追踪单个请求
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),可以这样集成日志追踪:
# 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 中:
- 打开
/console页面 - 输入日志过滤器(或查看所有日志)
- 搜索
GroupAnalysis或特定的 group_id
通过命令行:
# 查找特定群的日志
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 配置日志级别
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 日志
# 启用 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 - 编辑方式:
- 直接编辑 JSON 文件
- 通过 Dashboard 管理面板修改(未来功能)
8.2 配置更新
配置更改后,需要重启应用以生效(或通过 API 动态更新)。
8.3 环境变量支持
根目录自定义(可选):
export ASTRBOT_ROOT=/path/to/root
# 数据目录将为 /path/to/root/data
9. 代码示例汇总
9.1 获取日志记录器
from astrbot.core import logger
# 已配置的全局日志记录器
logger.info("Message")
logger.debug("Debug message")
logger.warning("Warning")
logger.error("Error")
logger.critical("Critical error")
9.2 创建自定义日志记录器
from astrbot.core import LogManager
# 获取命名日志记录器
plugin_logger = LogManager.GetLogger("my_plugin")
plugin_logger.info("Plugin message")
9.3 发起 Trace 追踪
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 订阅日志流(自定义)
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 启用文件日志的步骤
- 编辑
data/cmd_config.json:{ "log_file_enable": true, "log_file_path": "logs/astrbot.log", "log_file_max_mb": 50 } - 重启 AstrBot 应用
- 日志将写入
data/logs/astrbot.log
10.3 日志级别选择
- DEBUG: 开发调试,包含所有详细信息
- INFO: 生产环境推荐,记录重要事件
- WARNING: 只记录警告和错误
- ERROR: 仅记录错误
- CRITICAL: 仅记录严重错误
10.4 Trace ID 用于群分析追踪
对于"QQ 群日常分析"场景:
- 每个群的分析请求都有唯一的
span_id - 可通过此 ID 追踪整个分析流程
- 涉及多群并发时日志清晰分离
查询示例:
# 查找 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. 总结
日志查看的完整流程
-
应用启动
- LogBroker 初始化
- LogQueueHandler 连接到日志记录器
-
日志产生
- 应用或插件调用
logger.info()等方法 - LogQueueHandler 拦截日志记录
- 应用或插件调用
-
日志分发
- LogBroker.publish() 添加到缓存
- 分发给所有订阅者(Dashboard SSE、Trace 日志等)
-
用户查看
- Dashboard Console: 实时看到日志
- REST API: 获取历史日志或 SSE 流
- 文件: 直接查看
data/logs/astrbot.log
-
Trace 追踪
- 创建 TraceSpan 记录请求链路
- Dashboard
/trace实时查看 - 或通过 span_id 在文件中查询
推荐使用方式
- 开发调试: Dashboard
/console页面 - 生产监控: 启用文件日志 + 日志收集系统
- 问题诊断: 通过 span_id 追踪完整请求链路
- 群分析: 在日志中包含 group_id,便于后续查询
本文档基于 AstrBot v4.14.4 代码分析生成。