diff --git a/docs/grafana-dashboard-usage.md b/docs/grafana-dashboard-usage.md new file mode 100644 index 0000000..de88258 --- /dev/null +++ b/docs/grafana-dashboard-usage.md @@ -0,0 +1,182 @@ +# Grafana 日志仪表板使用说明 + +## Request ID 过滤功能 + +日志监控仪表板现在支持按 request_id 过滤日志,可以追踪单个请求的完整生命周期。 + +### 如何使用 + +1. **访问仪表板** + - 打开 Grafana: http://localhost:3000 + - 登录(admin/admin) + - 进入 "日志监控" 仪表板 + +2. **使用 Request ID 过滤** + - 在仪表板顶部找到 "Request ID" 输入框 + - 输入完整的 request_id(例如:`59017bdd-5963-40b1-a325-5088593382c0`) + - 所有面板会自动更新,只显示该 request_id 的日志 + +3. **查看所有日志** + - 清空 "Request ID" 输入框 + - 所有面板会显示所有日志 + +### 示例 + +#### 获取 Request ID + +从 API 响应中获取: + +```bash +curl -X POST http://localhost:8111/invoke \ + -H "Content-Type: application/json" \ + -d '{"number": 17}' | jq -r '.request_id' +``` + +输出示例: +``` +59017bdd-5963-40b1-a325-5088593382c0 +``` + +#### 在仪表板中过滤 + +1. 复制上面的 request_id +2. 在 Grafana 仪表板顶部的 "Request ID" 输入框中粘贴 +3. 按回车或点击刷新 + +#### 查看结果 + +过滤后,你会看到该请求的所有日志: + +- **日志流面板**:显示该请求的所有日志条目 +- **日志量趋势**:显示该请求的日志分布 +- **日志级别分布**:显示该请求的日志级别统计 +- **错误日志**:如果该请求有错误,会显示在这里 + +### 典型的请求日志流 + +一个成功的请求通常包含以下日志: + +``` +1. Request: POST /invoke +2. Processing request {request_id} with number=17 +3. Starting algorithm: PrimeChecker +4. Algorithm PrimeChecker completed successfully in 0.001s +5. Response: 200 +``` + +所有这些日志都有相同的 request_id,可以通过过滤功能一起查看。 + +### 高级用法 + +#### 在 Explore 中使用 + +1. 进入 Grafana Explore: http://localhost:3000/explore +2. 选择 Loki 数据源 +3. 使用以下查询: + +```logql +# 查询特定 request_id +{job="functional-scaffold-app"} |= "59017bdd-5963-40b1-a325-5088593382c0" + +# 使用 JSON 解析(更精确) +{job="functional-scaffold-app"} | json | request_id="59017bdd-5963-40b1-a325-5088593382c0" + +# 查询特定 request_id 的错误日志 +{job="functional-scaffold-app", level="ERROR"} |= "59017bdd-5963-40b1-a325-5088593382c0" +``` + +#### 组合过滤 + +可以结合其他过滤条件: + +```logql +# 特定 request_id 的 ERROR 日志 +{job="functional-scaffold-app", level="ERROR"} |= "59017bdd-5963-40b1-a325-5088593382c0" + +# 特定 request_id 的特定 logger +{job="functional-scaffold-app", logger="src.functional_scaffold.algorithms.base"} |= "59017bdd-5963-40b1-a325-5088593382c0" +``` + +### 故障排查 + +#### Request ID 过滤不生效 + +1. **检查 request_id 格式** + - 确保输入的是完整的 UUID 格式 + - 不要包含额外的空格或引号 + +2. **检查时间范围** + - 确保仪表板的时间范围包含该请求的时间 + - 可以调整为 "Last 15 minutes" 或更长 + +3. **刷新仪表板** + - 点击右上角的刷新按钮 + - 或者按 Ctrl+R (Cmd+R on Mac) + +4. **验证日志是否存在** + - 在 Explore 中手动查询: + ```logql + {job="functional-scaffold-app"} |= "your-request-id" + ``` + - 如果没有结果,说明日志还没有被收集 + +#### 日志延迟 + +- Promtail 每 5 秒刷新一次 +- Loki 可能有几秒的延迟 +- 建议等待 5-10 秒后再查询 + +### 最佳实践 + +1. **调试单个请求** + - 发送请求并记录 request_id + - 在仪表板中输入 request_id + - 查看完整的请求处理流程 + +2. **追踪错误** + - 当发现错误时,从错误日志中提取 request_id + - 使用 request_id 过滤查看完整的请求上下文 + - 分析错误发生前后的日志 + +3. **性能分析** + - 使用 request_id 过滤慢请求 + - 查看算法执行时间 + - 分析性能瓶颈 + +4. **用户问题排查** + - 从用户报告中获取 request_id(如果有) + - 使用 request_id 重现问题场景 + - 查看完整的请求处理过程 + +### 技术细节 + +#### 过滤实现 + +仪表板使用 LogQL 的文本匹配操作符 `|=`: + +```logql +{job="functional-scaffold-app"} |= "$request_id" +``` + +- 当 `$request_id` 为空时,`|= ""` 匹配所有日志 +- 当 `$request_id` 有值时,只匹配包含该字符串的日志 + +#### 性能考虑 + +- 文本匹配 (`|=`) 比 JSON 解析更快 +- 适合实时查询和仪表板 +- 对于精确匹配,可以在 Explore 中使用 JSON 解析 + +#### 变量配置 + +Request ID 变量配置: +- 类型:textbox(文本输入框) +- 名称:request_id +- 标签:Request ID +- 默认值:空字符串 + +## 相关文档 + +- [Loki 集成文档](loki-integration.md) +- [Loki 快速参考](loki-quick-reference.md) +- [LogQL 查询语言](https://grafana.com/docs/loki/latest/logql/) diff --git a/scripts/test_request_id_filter.sh b/scripts/test_request_id_filter.sh new file mode 100755 index 0000000..b2ac63f --- /dev/null +++ b/scripts/test_request_id_filter.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# Grafana Request ID 过滤功能测试脚本 + +set -e + +echo "=========================================" +echo "Grafana Request ID 过滤功能测试" +echo "=========================================" +echo "" + +# 颜色定义 +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +echo "1. 生成测试请求..." +echo "-------------------" +RESPONSE=$(curl -X POST http://localhost:8111/invoke \ + -H "Content-Type: application/json" \ + -d '{"number": 43}' \ + -s) + +REQUEST_ID=$(echo "$RESPONSE" | jq -r '.request_id') +echo -e "${GREEN}✓ 请求成功${NC}" +echo -e "${BLUE}Request ID: $REQUEST_ID${NC}" + +echo "" +echo "2. 等待日志收集 (5秒)..." +sleep 5 + +echo "" +echo "3. 测试 Loki 过滤..." +echo "-------------------" + +# 测试过滤特定 request_id +LOG_COUNT=$(curl -G -s "http://localhost:3100/loki/api/v1/query_range" \ + --data-urlencode "query={job=\"functional-scaffold-app\"} |= \"$REQUEST_ID\"" \ + | jq '.data.result[0].values | length') + +if [ "$LOG_COUNT" -gt 0 ]; then + echo -e "${GREEN}✓ 找到 $LOG_COUNT 条日志${NC}" +else + echo -e "${YELLOW}⚠ 没有找到日志,可能需要等待更长时间${NC}" +fi + +echo "" +echo "4. 显示日志内容..." +echo "-------------------" +curl -G -s "http://localhost:3100/loki/api/v1/query_range" \ + --data-urlencode "query={job=\"functional-scaffold-app\"} |= \"$REQUEST_ID\"" \ + | jq -r '.data.result[0].values[].[-1]' \ + | jq -r '.message' \ + | nl + +echo "" +echo "=========================================" +echo "测试完成!" +echo "=========================================" +echo "" +echo "在 Grafana 中测试:" +echo " 1. 访问: http://localhost:3000" +echo " 2. 进入 '日志监控' 仪表板" +echo " 3. 在顶部 'Request ID' 输入框中输入:" +echo -e " ${BLUE}$REQUEST_ID${NC}" +echo " 4. 按回车,查看过滤后的日志" +echo "" +echo "清空 Request ID 输入框可以查看所有日志" +echo ""