Skip to content

日志监控与告警

1. 这是什么

日志、监控和告警是系统上线后观测运行状态的核心手段。
它们共同构成了系统可观测性的基础。

一句话理解:

  • 日志负责记录发生了什么
  • 监控负责观察趋势和状态
  • 告警负责在超出预期时提醒人采取动作

2. 为什么重要

很多系统不是写挂的,而是:

  • 出问题时没人知道
  • 知道了也找不到原因

没有可观测性,再好的代码也很难长期稳定运行。
真正的工程能力不只是“系统能跑”,还包括:

  • 系统出问题时能不能快速定位

3. 先建立直觉:日志、监控、告警不是同一件事

最常见的误区之一是:

  • 以为打了很多日志就等于可观测性做好了

其实这三者解决的问题不同:

能力主要回答什么问题
日志当时具体发生了什么
监控系统整体趋势怎么样
告警是否已经超出预期,需要人介入

所以:

  • 日志很多,不代表监控完整
  • 监控很多,不代表告警有效

4. 核心内容

4.1 日志分级

日志分级的价值在于:

  • 让不同重要性的事件被区别对待

常见级别例如:

  • DEBUG
  • INFO
  • WARN
  • ERROR

学习阶段更重要的是建立习惯:

  • 不是所有日志都该打成错误
  • 也不是所有日志都值得长期保留

4.2 结构化日志

结构化日志的核心价值是:

  • 方便检索、聚合和分析

比起纯文本拼接,结构化日志更适合:

  • 按字段查询
  • 按 TraceId 聚合
  • 做告警和统计

4.3 TraceId / 请求链路

TraceId 的价值特别大,因为:

  • 一次请求可能会跨过很多层
  • 如果没有统一标识,排障会非常困难

有了 TraceId,你就能把:

  • 网关日志
  • 应用日志
  • 下游调用日志

串成一条请求链。

4.4 基础监控指标

监控不是只看机器 CPU 和内存。
至少要同时看两类指标:

系统指标

  • CPU
  • 内存
  • 磁盘
  • 网络

业务指标

  • QPS
  • RT
  • 错误率
  • 下单量
  • 支付成功率

如果只看系统指标,很容易漏掉业务故障。

4.5 告警阈值设计

告警的目标不是“尽量多报”,而是:

  • 报真正值得处理的问题

有效告警至少要考虑:

  • 阈值是否合理
  • 持续时间是否合理
  • 是否有恢复通知
  • 是否能定位到负责人

5. 学习重点

这一章最重要的是掌握:

  • 日志是证据,不是输出堆积
  • 监控和告警必须同时覆盖系统指标和业务指标
  • TraceId 是排障的关键基础设施
  • 告警质量比告警数量更重要

6. 常见问题

6.1 日志过多却没有重点

这样一出问题,检索成本会非常高。

6.2 监控只看机器指标不看业务指标

这会导致业务已经异常,但监控面板看起来仍然“机器正常”。

6.3 告警泛滥导致没人关注

告警太多、噪声太大,最后结果往往是:

  • 所有人都麻木

7. 动手验证

这一节我用一个纯 Java demo,把 TraceId、结构化日志、基础指标和告警阈值串起来。

7.1 准备一个可运行示例

新建文件 ObservabilityDemo.java,内容如下:

java
import java.util.UUID;

public class ObservabilityDemo {
    static class Metrics {
        int totalRequests;
        int totalErrors;
        long totalCostMs;

        void record(boolean success, long costMs) {
            totalRequests++;
            totalCostMs += costMs;
            if (!success) {
                totalErrors++;
            }
        }

        double errorRate() {
            return totalRequests == 0 ? 0 : (double) totalErrors / totalRequests;
        }

        long avgRt() {
            return totalRequests == 0 ? 0 : totalCostMs / totalRequests;
        }
    }

    public static void main(String[] args) {
        Metrics metrics = new Metrics();

        handleRequest(metrics, true, 80);
        handleRequest(metrics, true, 120);
        handleRequest(metrics, false, 300);

        System.out.println("metric-totalRequests=" + metrics.totalRequests);
        System.out.println("metric-totalErrors=" + metrics.totalErrors);
        System.out.println("metric-avgRtMs=" + metrics.avgRt());

        if (metrics.errorRate() > 0.2) {
            System.out.println("alert-errorRateHigh=true");
        }
        if (metrics.avgRt() > 150) {
            System.out.println("alert-rtHigh=true");
        }
    }

    private static void handleRequest(Metrics metrics, boolean success, long costMs) {
        String traceId = UUID.randomUUID().toString();
        System.out.println("{\"level\":\"INFO\",\"traceId\":\"" + traceId
                + "\",\"event\":\"request_start\"}");

        if (!success) {
            System.out.println("{\"level\":\"ERROR\",\"traceId\":\"" + traceId
                    + "\",\"event\":\"request_fail\",\"costMs\":" + costMs + "}");
        } else {
            System.out.println("{\"level\":\"INFO\",\"traceId\":\"" + traceId
                    + "\",\"event\":\"request_ok\",\"costMs\":" + costMs + "}");
        }

        metrics.record(success, costMs);
    }
}

7.2 编译并运行

bash
javac ObservabilityDemo.java
java ObservabilityDemo

7.3 你应该观察到什么

输出会有多行结构化日志和指标,但应重点包含这些关键信息:

text
{"level":"INFO","traceId":"...","event":"request_start"}
{"level":"ERROR","traceId":"...","event":"request_fail","costMs":300}
metric-totalRequests=3
metric-totalErrors=1
metric-avgRtMs=166
alert-errorRateHigh=true
alert-rtHigh=true

7.4 每一行在验证什么

  • 结构化日志里的 traceId:说明请求链路已具备可串联标识
  • request_start / request_ok / request_fail:说明日志事件应有明确语义
  • metric-totalRequestsmetric-totalErrorsmetric-avgRtMs:说明监控指标关注整体趋势,而不是单条日志
  • alert-errorRateHigh=truealert-rtHigh=true:说明告警是基于指标阈值触发,而不是单纯“有日志就报警”

8. 练习建议

下面这些练习做完,这一章会更扎实:

  • 给一个接口链路增加 TraceId
  • 设计一套基础监控指标清单
  • 复盘一次告警无效或过度告警的问题
  • 总结哪些日志该打结构化字段,哪些不值得打印

9. 自测问题

  • TraceId 为什么有助于排障?
  • 为什么日志、监控、告警必须一起设计?
  • 什么样的告警体系才算有效?
  • 为什么只看机器指标不够?

10. 自测核对要点

如果你的回答能覆盖下面这些点,说明这一章基本掌握到位了:

  • 日志、监控、告警分别解决不同层面的问题
  • TraceId 是跨层排障的重要连接线
  • 监控需要同时覆盖系统指标和业务指标
  • 告警应尽量减少噪声并指向可行动问题