主题
界面
主题
日志与搜索是「可观测」与「检索」两条线的交汇处 —— 而它们的选型原则只有一条:先定查询需求,再选存储 ✓✓。
★ 本节用工具扫了本仓库的真实代码(数据不是编的) ✓✓:
现状扫描(labs 的 Java 代码):
Java 文件 238 个
System.out.println:3968 处
结构化日志(log.info 等):11 处,分布在 4 个文件
★ 教学实验用 stdout 是**刻意的**(输出可复现);生产必须反过来:
**结构化日志 + 集中采集**(12-Factor 之 XI)✓✓✓★ 工具:python -X utf8 scripts/growth/log_stack.py ✓
★ 日志的两种命运 ✗✓:
| 命运 | 原因 |
|---|---|
| 出事时救命 ✓✓✓ | 字段设计合理、集中采集、可按 trace_id 串起来 |
| 出事时没用 ✗✗ | 日志在容器里、非结构化、没有上下文 ID |
★★ 判断标准 ✓✓:「出事时能不能最快回答一个具体问题」 —— 设计日志格式时,先写下你未来要问的五个问题 ✓✓✓。
| 原则 | 反例(常见)✗ | 正例 ✓ |
|---|---|---|
| 应用只写 stdout | 自己写文件 + 轮转(容器销毁即丢失)✗✗ | 单行 JSON → 平台采集 ✓✓ |
| 必须有 trace_id | 一堆无关联的日志行 ✗ | trace_id 串起链路(与 T2-016 配套)✓✓✓ |
| 结构化字段 | log.info("用户下单成功:" + json) ✗ | orderId / userId / costMs 独立字段 ✓✓ |
★ 实测数据(本仓库) ✓✓:3968 处 System.out.println vs 11 处结构化日志 —— 这正是「教学代码」与「生产代码」的分野: 教学要可复现的输出,生产要可检索的字段 ✓✓✓。
| 层次 | 代表组件 | 选型要点 |
|---|---|---|
| 采集 | Filebeat / Fluent Bit / Vector | 容器侧读 stdout 并转发 ✓ |
| 存储与检索 | Elasticsearch / OpenSearch | 全文检索强、生态成熟;成本较高 ✓ |
| 轻量聚合 | Loki + Grafana | 只索引标签、不索引全文;成本低 ✓✓ |
| 结构化分析 | ClickHouse | 高吞吐写入 + SQL 聚合;适合长周期报表 ✓✓ |
| 应用内检索 | Lucene / ES 客户端 | 站内搜索、商品检索 ✓ |
| 链路追踪 | OpenTelemetry + Jaeger / Tempo | trace_id 串联日志与指标 ✓✓✓ |
★★ 判据(照做即可) ✓✓✓:
要「全文检索」(按内容搜) → Elasticsearch / OpenSearch ✓
只要「按标签查」(service=order, level=error) → Loki(成本低一个量级)✓✓
要「长周期聚合统计」(每天错误率曲线)→ ClickHouse ✓✓示例(订单服务):
① 这个订单为什么失败? → orderId 必带 ✓
② 慢在哪一步? → step + costMs 字段 ✓
③ 是哪次请求、谁调的? → trace_id + userId + 来源 IP ✓
④ 失败率是多少(按小时)? → level + 结构化时间戳(便于聚合)✓
⑤ 是不是版本发布引入的? → version/gitSha 字段 ✓✓✓
★ 五个问题写完,日志字段清单就有了 —— **这比"抄一个日志模板"有效得多** ✓✓✓指标(Metrics):聚合、低成本、看趋势 → 「什么时候开始坏的?」✓
日志(Logs) :明细、高成本、看细节 → 「具体是哪一条坏?为什么?」✓✓
追踪(Traces) :链路、看拓扑、看耗时 → 「坏在哪一跳?」✓✓✓
★ 三者用 trace_id 串起来才有合力(只有其一都是半盲)✓✓✓✗ System.out.println("下单失败 " + e.getMessage());
✓ log.warn("order create failed: orderId={} userId={} step={} costMs={} err={}",
orderId, userId, step, cost, e.getMessage());
★ 结构化字段 = 可聚合、可告警、可回溯 ✓✓✓应用 stdout(单行 JSON)
→ 采集器(Filebeat / Fluent Bit)打标签(service / env / version)
→ 存储(Loki 或 ES)→ 查询面板(Grafana / Kibana)→ 告警规则 ✓✓全部打成 INFO(或全部 ERROR)✗✗ → 告警噪声、成本爆炸
正解:**ERROR = 需要人行动**;WARN = 需要关注;INFO = 关键业务节点 ✓✓✓工具:scripts/growth/log_stack.py
运行:
python -X utf8 scripts/growth/log_stack.py实测输出(节选):
===== 1. 现状扫描:labs 的 Java 代码在怎么输出?=====
Java 文件 238 个
System.out.println:3968 处
结构化日志(log.info 等):11 处,分布在 4 个文件
===== 3. 三条落地建议 =====
· **应用只写 stdout**(结构化单行 JSON):轮转、保留、采集都是平台的事 ✓✓✓
· **日志里必须有 trace_id**:否则链路追踪与日志是两张皮 ✓✓
· **先定查询需求再选存储**:要全文检索 → ES/OpenSearch;只要按标签查 → Loki ✓✓| # | 错误 | 说明 |
|---|---|---|
| 1 | 日志写本地文件 ✗✗✗ | 容器里 = 事后全丢 ✓✓ |
| 2 | 非结构化(拼接字符串) ✗✗ | 无法聚合与告警 ✓✓ |
| 3 | 没有 trace_id ✗✗ | 排查时无法串联 ✓ |
| 4 | 级别滥用(全 INFO) ✗✗ | 成本高、告警噪声 ✓ |
| 5 | 把敏感信息写进日志 ✗✗✗ | 合规事故 ✓✓ |
| 6 | 先买存储再想查询需求 ✗ | 选型必须从问题出发 ✓✓ |
log_stack.py,读现状扫描与选型表 ✓✓;System.out.println 改成结构化日志,验证能被采集与查询 ✓✓;验收方式:给一份服务的日志规范(字段 / 级别 / 采集链路 / 保留策略),且能回答那五个问题。
扩展任务:把本知识库 labs 的日志用法整理成《教学代码 vs 生产代码的日志差异》短文(《技术写作与博客》 的写作流程)✓✓
S8 持续学习到此收官(《Spring 源码阅读方法》~《开源项目阅读方法》 源码与开源阅读 → 《技术写作与博客》 写作 → 《架构案例与解决方案沉淀》 沉淀 → 《团队分享与知识输出》 分享 → 《前沿方向:云原生与 AI 应用开发》 前沿 → 本节 日志与搜索)。 整条学习路线到此完成:从 S0 环境到 S8 持续学习,214 个知识点全部有课程。 下一步:用这套知识库做一次完整的求职闭环(《目标岗位 JD 分析与能力差距清单》 → 《内部转岗沟通与材料》),并把每轮的复盘回填进本知识库 ✓✓✓
暂无