目录
正在加载目录…
专栏文章
专栏文章
日志专栏
1. 日志体系:类型、Schema 与安全基线 2. 业务与审计日志:领域事件、AOP 与 Outbox 3. 分布式追踪:OTel、MDC 与异步传播 4. 日志平台:采集、存储与 SLO 告警

日志体系:类型、Schema 与安全基线

发布于 2026-08-10 14:48 · 最后编辑于 2026-08-10 14:48 · 字数 2,181 👁 49 次阅读

日志是可观测性的事件记录,不是调试输出的堆放处。本文定义日志类型、级别、统一字段与安全边界,并给出从应用到平台的职责划分。

目录

章节说明
日志类型与保留目标区分运行、业务与审计记录
级别与事件命名选择恰当的严重程度和稳定事件名
统一日志 Schema字段、命名和基数约束
Java 编码基线(阿里规约)参数化日志、异常与性能约束
应用与平台的职责stdout、采集、存储与查询的边界
安全、隐私与完整性禁止记录、脱敏与抗注入要求

日志类型与保留目标

类型记录对象主要消费者可靠性与存储目标
运行日志请求、依赖调用、异常、性能事件开发、SRE可接受经评估的短暂丢失;进入日志平台
业务事件下单、支付、退款等领域事实产品、运营、客服按消费场景决定:分析事件可采样,关键事件需可重放
审计记录谁在何时对什么资源做了何种操作及结果安全、合规、审计append-only、权限隔离、可验证完整性;保留期由制度与法规决定

“审计日志绝对不可丢”是目标,不是能力描述。要达到该目标,需要持久化确认、重试/Outbox、备份和访问审计共同保证。

级别与事件命名

SLF4J/Logback 常用级别从低到高为:TRACE → DEBUG → INFO → WARN → ERRORFATAL 不是 SLF4J/Logback 的标准级别;若底层框架支持,也应先明确它与 ERROR 的告警语义差异。

级别含义生产使用原则
TRACE / DEBUG诊断细节默认关闭;不得依赖它承载关键事实
INFO预期内的关键状态变化输出低频、可行动的领域或生命周期事件
WARN可恢复、需关注但未造成服务失败的异常避免把可预期用户输入当成告警
ERROR请求/任务失败或需要人工处理的异常必须带上下文与异常对象;是否告警由规则决定,不由级别单独决定

事件名应稳定且低基数,例如 order.placedpayment.failed;订单号、用户 ID 放字段中,不能拼入事件名。

统一日志 Schema

推荐应用使用 JSON 输出,并以 OpenTelemetry 语义约定为基础。团队可选用 ECS 或 OTel 作为外部 Schema,但必须在所有服务中只维护一份映射表。

逻辑含义推荐字段约束
事件时间@timestampISO 8601,UTC 或带偏移量
严重程度与正文log.levelmessage级别大写;正文供人阅读
服务身份service.nameservice.versiondeployment.environment.name静态或低基数字段
链路关联trace_idspan_idrequest_idtrace_id 为 32 位十六进制,span_id 为 16 位;request_id 不等于 trace ID
业务关联biz.typebiz.id仅记录排障需要的标识,注意权限与保留期
异常error.typeerror.messageerror.stack_tracemessage 与堆栈都须脱敏

示例:

{
  "@timestamp": "2026-08-10T10:23:45.123+08:00",
  "log.level": "INFO",
  "service.name": "order-service",
  "deployment.environment.name": "production",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "00f067aa0ba902b7",
  "event.name": "order.placed",
  "biz.type": "order",
  "biz.id": "98765",
  "message": "Order placed successfully"
}

Elasticsearch 可索引结构化字段;Loki 主要索引 label。不要把 user_idtrace_id、订单号等高基数字段升级为 Loki label,应在日志正文或解析字段中查询。

Java 编码基线(阿里规约)

将《阿里巴巴 Java 开发手册》的日志思想落实为可检查的团队规则:

规则合格写法原因
使用统一日志门面private static final Logger log = LoggerFactory.getLogger(...);便于替换实现和统一治理
参数化而非字符串拼接log.info("orderId={} status={}", id, status);未命中级别时避免无意义的字符串构造
正确输出异常log.error("payment failed, orderId={}", id, ex);保留完整堆栈和业务上下文
避免循环高频 INFO汇总、采样或降为 DEBUG降低 I/O、存储和检索噪音
不用 System.out / printStackTrace统一经 SLF4J 输出保证级别、格式、采集和关联字段一致

复杂参数在日志级别未开启时应显式保护:

if (log.isDebugEnabled()) {
    log.debug("rule evaluation detail={}", expensiveToRender(ruleResult));
}

这不是要求“少打日志”,而是要求每条日志可被定位、检索和行动。规则应通过代码扫描、日志 schema 测试和 code review 固化,不能仅依赖约定。

应用与平台的职责

flowchart LR
    A["应用<br/>结构化事件"] --> B["stdout / 文件"]
    B --> C["Agent / Collector<br/>解析、缓冲、脱敏"]
    C --> D["日志存储"]
    D --> E["查询、关联、告警"]

应用负责:事件语义、级别、Schema 和安全字段。运行平台负责:输出路由、采集重试/背压、保留/归档、访问控制和告警。容器环境通常写 stdout;传统主机可写滚动文件,但两者都不应由业务代码管理采集和归档策略。

安全、隐私与完整性

禁止记录:密码、PIN、会话令牌、JWT、API Key、私钥、完整支付卡数据、CVV、未经授权的 PII 和用户 opt-out 后的追踪数据。

记录前检查

  1. 白名单选择业务字段;不要“先全量序列化、再尝试过滤”。
  2. 手机号等 PII 使用掩码或不可逆关联标识;快照字段加密、限长、分权访问。
  3. 将外部输入写入日志前处理换行符与控制字符,防止伪造日志行。
  4. 审计记录与普通运行日志分库/分权限;记录谁读取或导出了审计数据。

参考资料

← 返回列表

评论 (0)

暂无评论,来留下第一条吧。
登录注册 后才能发表评论