# 中央日志接入与查询手册 教学反馈服务通过容器标签接入宿主机中央观测栈。本项目不包含也不启停 Loki、Alloy 或 Grafana;中央栈位于 `/home/shay/data/docker-service/observability`,Grafana 地址为 `http://192.168.193.237:39300`。 ## 登录 Grafana 1. 在可信局域网或已接入该主机网络的浏览器中打开 `http://192.168.193.237:39300`。 2. 用户名使用 `admin`。 3. 初始密码读取中央栈的 `/home/shay/data/docker-service/observability/.env` 中的 `GRAFANA_ADMIN_PASSWORD`。 需要在目标机终端确认初始密码时使用: ```bash sed -n 's/^GRAFANA_ADMIN_PASSWORD=//p' /home/shay/data/docker-service/observability/.env ``` 不要把密码粘贴到 issue、提交信息、聊天记录或截图中。如果已经在 Grafana 页面修改过密码, 应使用修改后的密码;`.env` 只保证记录首次创建管理员时使用的值。 ## 发布与接入检查 业务镜像构建时注入版本信息: ```bash export APP_VERSION="$(git describe --tags --always)" export GIT_SHA="$(git rev-parse --short HEAD)" docker compose -f compose.deploy.yml config -q docker compose -f compose.deploy.yml up -d --build --force-recreate docker compose -f compose.deploy.yml ps ``` 仅修改采集标签或日志轮转时不需要构建镜像: ```bash docker compose -f compose.deploy.yml up -d --force-recreate --no-build api funasr ``` 确认运行容器配置: ```bash docker inspect teaching-feedback-api-1 --format '{{json .HostConfig.LogConfig}}' docker inspect teaching-feedback-api-1 --format '{{json .Config.Labels}}' docker inspect teaching-feedback-funasr-1 --format '{{json .HostConfig.LogConfig}}' docker inspect teaching-feedback-funasr-1 --format '{{json .Config.Labels}}' curl -fsS http://127.0.0.1:39180/health ``` 预期日志驱动为 `local`,`max-size=20m`、`max-file=5`;两个服务都应包含 `observability.logs=true`、`observability.application=teaching-feedback` 和 `observability.environment=lan`。 ## 使用预置仪表盘 登录后打开 `Dashboards`,进入 `Host Observability / Host Service Logs`,然后设置: - `Application`:`teaching-feedback` - `Environment`:`lan` - `Service`:按需选择 `api`、`funasr` 或 `All` - 右上角时间范围:复现问题时优先选择最近 5 至 30 分钟 仪表盘适合浏览和筛选;需要精确关联请求或比较版本时,打开 `Explore`,数据源选择 `Loki`。 仪表盘包含两个日志面板: - `HTTP Errors`:只显示能够解析出 HTTP `status >= 400` 的结构化日志。 - `Service Logs (health excluded)`:显示所选服务的普通日志,并默认排除例行 `/health` 请求。 API 不记录成功 `/health` 请求的开始和结束事件,以避免 Docker 日志与 Loki 被固定频率的探针日志占满。 如果 `/health` 返回非 2xx 或请求在中间件中失败,错误日志仍会保留。需要查看改造前的历史健康检查日志时, 在 `Explore` 中使用明确包含 `/health` 的查询,并把时间范围设置到对应部署时间之前。 ## 常用 LogQL 查看教学反馈的全部日志: ```logql {application="teaching-feedback"} ``` 排除改造前已采集的健康检查日志: ```logql {application="teaching-feedback", service="api"} != "\"path\":\"/health\"" ``` 按服务、级别和文本筛选: ```logql {application="teaching-feedback", service="api"} | json {application="teaching-feedback", service="funasr"} | json {application="teaching-feedback", level=~"WARN|ERROR"} {application="teaching-feedback"} |= "database" ``` 按 HTTP 状态和耗时寻找优化目标: ```logql {application="teaching-feedback", service="api"} | json | status >= 500 {application="teaching-feedback", service="api"} | json | latency_ms >= 1000 {application="teaching-feedback", service="api"} | json | event="http_request_finished" ``` 按关联 ID 追踪一次请求或转录任务: ```logql {application="teaching-feedback", service="api"} | json | request_id="" {application="teaching-feedback", service="api"} | json | feedback_session_id="" {application="teaching-feedback", service="api"} | json | lesson_id="" {application="teaching-feedback", service="api"} | json | segment_id="" {application="teaching-feedback", service="funasr"} | json | segment_id="" ``` 按部署版本确认问题发生在哪份代码: ```logql {application="teaching-feedback"} | json | app_version="0.2.0" {application="teaching-feedback"} | json | git_sha="" ``` `request_id`、`segment_id`、`git_sha` 等字段位于 JSON 正文,不能直接放进流选择器的 `{...}`, 也不能新增为 Loki 标签。查询无结果时先扩大时间范围,再从只包含 `application` 的查询逐步增加条件。 ## 用日志定位代码 优化或修复代码时采用以下流程: 1. 复现问题,记录发生时间和小程序错误界面显示的 `request_id`。 2. 用 `request_id` 查询 API 的完整事件序列,确认状态码、`event`、`latency_ms` 和 `error_class`。 3. 涉及录音时,从 API 日志取得 `segment_id`,分别查询 API worker 和 FunASR,判断耗时发生在 排队、上传、推理还是结果写回阶段。 4. 用 `app_version` 和 `git_sha` 确认运行代码版本,避免根据旧镜像日志修改新代码。 5. 修改后使用相同路径复现并比较事件数量、失败分类和耗时,不以“没有 ERROR”代替性能验收。 日志事件主要对应以下代码: - HTTP 请求开始、结束、请求 ID:`server/src/main.rs` - API 错误分类和响应:`server/src/error.rs`、`server/src/recording_routes.rs` - 转录队列、租约、重试和状态写回:`server/src/transcription_worker.rs` - API 到本地 ASR 的请求关联:`server/src/speech.rs` - FunASR 请求和推理耗时:`asr-service/app.py` - 小程序请求 ID 展示与复制:`utils/api.ts` 及各页面的错误处理代码 ## 历史范围 中央栈首次接入时回采了当时仍存在的 Docker 容器日志。2026-07-22 验收时可查询到的最早记录为: - API:2026-07-22 11:48:42(北京时间) - FunASR:2026-07-22 11:53:42(北京时间) 已删除容器中更早的日志无法恢复。Loki 当前保留期为 14 天,Docker 本地日志还受到 `20m x 5` 轮转限制,因此长期比较应记录 `git_sha`、问题时间和关键查询结果,而不能假设日志永久存在。 ## 故障定位 应用健康但 Grafana 无日志: 1. 检查业务容器是否具有采集标签。 2. 检查业务容器是否持续向 stdout/stderr 输出日志。 3. 检查中央栈运行状态;命令见中央目录 `README.md`。 4. 使用 `{application="teaching-feedback"}` 查询,避免一开始叠加过多过滤条件。 Grafana/Loki 不可用时,不要重启或回滚业务容器来尝试修复中央栈。先确认: ```bash curl -fsS http://127.0.0.1:39180/health docker compose -f compose.deploy.yml ps docker compose -f compose.deploy.yml logs --since 10m api funasr ``` 如果本地 Docker 日志仍正常,则问题属于中央观测栈。中央栈的启停、数据卷、备份、恢复和升级 统一由 `/home/shay/data/docker-service/observability/README.md` 管理。 Grafana 不可用时,可以先用 Docker 本地日志继续定位: ```bash docker compose -f compose.deploy.yml logs --since 30m api funasr ``` 不要为了临时查询而把 Loki `3100` 或 Alloy `12345` 发布到宿主机。 ## 应用侧回滚 结构化日志代码出现回归时,回滚对应代码并重建业务镜像。仅日志驱动不兼容时,修改 `compose.deploy.yml` 后必须 `--force-recreate`;普通 restart 不会更新容器日志驱动。任何应用侧 回滚都不得删除中央 Loki 或 Grafana 数据卷。