AI 助手 07:不用 Kibana,如何把 Elasticsearch 日志检索接入业务管理后台
基于 ai-study V1.6 已实现基线,记录 Java、Python、Filebeat、Elasticsearch 与管理员日志页面如何通过 requestId 形成可控的排查链路。
所属项目:AI-assistant做 AI 应用时,模型调用记录和运行日志不能混为一谈。前者适合进入 PostgreSQL,用于统计 token、成本、请求和审计;后者适合进入可检索的日志系统,用来定位一次请求在哪个服务、哪个时间点失败。ai-study 的 V1.6 选择 Elasticsearch + Filebeat,但没有把 Kibana 当作项目运行必需品,而是直接把受限检索能力接到管理后台。
为什么不让浏览器直连 Elasticsearch
Elasticsearch DSL 非常强,但也意味着浏览器一旦直连就能绕过查询范围、字段脱敏和分页限制。当前系统只提供管理员接口:
GET /api/admin/runtime-logs
GET /api/admin/runtime-logs/status
服务端先验证 ADMIN 角色,再将时间、服务名、日志级别、requestId、关键词、页码和条数转换为受限查询。单页最多 100 条,默认查询最近 24 小时;返回给前端的只有安全字段,例如时间、级别、服务、事件、requestId、脱敏后的消息和错误摘要。
这使前端得到的是“排查任务需要的信息”,而不是整个 Elasticsearch 索引、节点元数据或任意 DSL 的执行权。
一次请求如何串到两个服务
认证过滤器会把 requestId、tenantId、userId 同时写入 Java 的 RequestContext 与 SLF4J MDC。Java 调 Python 时继续透传 requestId 和已认证的上下文;Python 也以结构化方式记录关键事件。Filebeat 只采集带 ai-study.logs=true 标签的 Java 和 Python 容器日志,避免把 Postgres、Redis、Milvus 等基础设施噪声一并塞进业务日志索引。
因此,发生一次失败 Chat 请求后,管理员先从响应或调用记录拿到 requestId,再在运行日志页按该 ID 查询,就可以看到 Java 接收请求、下游 Python 调用和错误事件的关联信息。这比用时间猜日志、在多个容器里手工搜索更稳定。
普通 log.info 也会带上 MDC 尾部上下文;结构化运行事件还额外使用 serviceName 和 eventName,避免与 Elasticsearch ECS 的对象字段发生冲突。异步任务、定时任务或启动日志没有请求上下文时,这些字段为空是预期行为,不应伪造一个用户身份。
日志里最重要的不是“尽可能多”
运行日志禁止记录密码、JWT、refresh token、Cookie、API Key、Authorization Header、完整 prompt 和完整模型回答。这既是安全要求,也能控制索引成本与敏感数据扩散范围。模型调用参数、用量和审计需要保留时,应进入职责明确的业务表,并按权限查询,而不是把所有原始内容打到 stdout。
本地环境的索引保留策略为 7 天,Elasticsearch 仅绑定 127.0.0.1:9200。Filebeat 状态写入 Docker 卷,避免重启后从头重复采集。单节点数据流出现 YELLOW 也属正常:副本没有第二个节点可分配,并不阻止本地读写。
失败时如何降级
Elasticsearch 是排查能力,不是 Chat 主流程的强依赖。日志服务未启用或不可访问时,管理 API 返回 503,页面明确提示不可用;登录、聊天和 PostgreSQL 中的业务审计仍应继续工作。把可观测性系统做成核心路径依赖,只会把“无法查看日志”放大为“业务也无法使用”。
当前版本还没有日志 TLS、Elasticsearch 用户认证、租户级日志可见范围、独立链路时间线和告警指标。它解决的是本地/开发环境中“无需 Kibana、可在项目内按 requestId 排查”的基线;生产部署前仍需补充更严格的权限、留存和安全设计。