LinuxNotes

第 10 章:日志系统

zjc 于 2026-01-10 发布

这是《Linux 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 日志是排障和审计的证据。Linux 日志涉及内核 ring buffer、systemd journal、syslog、应用文件日志、容器 stdout、日志轮转和集中采集。治理日志要同时回答:写在哪里、能留多久、是否结构化、如何脱敏、如何报警。

10.1 日志全景

Kernel
  -> dmesg / journald

systemd service
  -> journald
  -> stdout / stderr

rsyslog / syslog-ng
  -> /var/log/messages
  -> /var/log/syslog
  -> remote syslog

Application
  -> file
  -> stdout
  -> collector

Container runtime
  -> stdout / stderr
  -> kubelet / container log driver

常见路径:

路径 内容
/var/log/messages RHEL 系常见通用日志
/var/log/syslog Debian 系常见通用日志
/var/log/auth.log Debian 系认证日志
/var/log/secure RHEL 系认证日志
/var/log/dmesg 启动时内核日志快照
/var/log/nginx/ Nginx 日志
/run/log/journal/ 运行时 journal
/var/log/journal/ 持久 journal

发行版差异明显,以实际配置为准。

10.2 内核日志

实时查看:

dmesg -w
dmesg -T
dmesg -T --level=err,warn

重点关键字:

dmesg -T | grep -Ei 'oom|out of memory|killed process'
dmesg -T | grep -Ei 'error|fail|timeout|i/o'
dmesg -T | grep -Ei 'conntrack|nf_conntrack'

常见信息:

关键字 方向
Out of memory 内存压力和 OOM
I/O error 磁盘或存储链路
EXT4-fs error 文件系统异常
XFS XFS 文件系统信息
blocked for more than 120 seconds IO 阻塞
conntrack: table full 连接跟踪表满
segfault 进程非法内存访问

10.3 journalctl

服务:

journalctl -u app
journalctl -u app -f
journalctl -u app -n 200 --no-pager
journalctl -u app --since '2026-08-25 10:00'
journalctl -u app --since '1 hour ago' -p warning

系统:

journalctl -b
journalctl -b -1
journalctl --since today
journalctl -p err
journalctl --disk-usage

JSON 输出:

journalctl -u app -o json-pretty -n 1

磁盘治理:

sudo journalctl --vacuum-size=2G
sudo journalctl --vacuum-time=14d

10.4 rsyslog

配置文件:

/etc/rsyslog.conf
/etc/rsyslog.d/*.conf

传统规则:

facility.priority    action
auth.*               /var/log/auth.log
*.info;mail.none     /var/log/messages

示例:把应用 local1 日志写入独立文件:

# /etc/rsyslog.d/30-app.conf
local1.*    /var/log/app/syslog.log
& stop

重启:

sudo systemctl restart rsyslog

发送远端:

*.* @@log.example.internal:6514

一个 @ 常见为 UDP,两个 @ 常见为 TCP;TLS 需要额外模块和证书配置。

10.5 应用日志设计

日志级别:

级别 用途
TRACE 细粒度跟踪,默认关闭
DEBUG 开发诊断,生产谨慎开启
INFO 关键业务动作和状态
WARN 可恢复异常、降级、重试
ERROR 影响请求或功能的错误
FATAL 进程即将退出

推荐字段:

{
  "ts": "2026-08-25T10:00:00.123+08:00",
  "level": "ERROR",
  "service": "order",
  "trace_id": "7f3a",
  "span_id": "01",
  "user_id": "10001",
  "method": "POST",
  "path": "/api/orders",
  "status": 500,
  "latency_ms": 120,
  "error_type": "DbTimeout",
  "message": "create order failed"
}

原则:

  1. 时间带时区;
  2. 输出结构化 JSON;
  3. 每个请求有 trace_id;
  4. 异常带类型和堆栈;
  5. 不记录明文密码、密钥、身份证号;
  6. ERROR 对应可行动事件;
  7. 避免 ERROR 洪水。

10.6 日志轮转

logrotate 配置目录:

/etc/logrotate.conf
/etc/logrotate.d/*

Nginx 示例:

/var/log/nginx/*.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    dateext
    create 0640 www-data adm
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
    endscript
}

测试:

sudo logrotate -d /etc/logrotate.d/nginx
sudo logrotate -f /etc/logrotate.d/nginx

-d 是 dry run,-f 是强制轮转。

应用自身有轮转能力时,避免和应用内轮转、logrotate 重复治理。

10.7 容器日志

查看:

docker logs <container>
docker logs -f --tail 100 <container>
kubectl logs <pod>
kubectl logs -f <pod> -c <container>
kubectl logs --previous <pod>

推荐容器应用输出到 stdout / stderr,由容器运行时和采集器统一处理。

不推荐:

  1. 容器内写无限增长文件;
  2. 依赖手工 docker exec 看日志;
  3. 把敏感信息打印到 stdout;
  4. 单行日志超过过大尺寸;
  5. 无日志上限的本地 JSON 文件驱动。

10.8 集中采集

常见链路:

App / journald / file
  -> Fluent Bit / Filebeat / Vector
     -> Kafka
        -> Loki / Elasticsearch / OpenSearch
           -> Grafana / Kibana

采集关注:

项目 说明
位置 file offset、journal cursor
解析 JSON、多行堆栈
脱敏 密码、token、手机号
路由 按服务和环境
缓冲 本地缓冲和背压
丢失策略 崩溃、磁盘满、远端不可用
时区 统一时区

多行日志示例:

ERROR order create failed
java.lang.NullPointerException
    at com.example.order.Service.create(Service.java:20)

必须把堆栈归并到同一事件,否则搜索和统计都会失真。

10.9 日志检索技巧

错误:

grep -E 'ERROR|FATAL' app.log
journalctl -u app -p err --since '1 hour ago'

时间范围:

sed -n '/2026-08-25 10:00/,/2026-08-25 10:10/p' app.log

按 trace:

grep 'trace_id=7f3a' app.log
jq 'select(.trace_id == "7f3a")' events.json

压缩日志:

zgrep ERROR app.log.2.gz

注意日志时间可能来自不同机器,需要确认 NTP 或 chronyd 状态。

10.10 日志告警

告警类型:

类型 示例
错误率 5 分钟 ERROR / 总请求
关键字 OOM、certificate expired
缺失 心跳日志超过阈值未出现
延迟 日志时间与采集时间差距大
容量 采集器队列积压
审计 root 登录、sudo 失败

告警要能行动:

告警名称
  -> 影响什么
  -> 可能原因
  -> 排查入口
  -> 处理手册链接

不要把所有 ERROR 都设为电话告警,先按业务影响分级。

10.11 生产案例

案例一:磁盘被日志占满

df -hT
du -sh /var/log/*
ls -lh /var/log/app
cat /etc/logrotate.d/app

处理:

  1. 紧急清理已轮转压缩文件;
  2. 修复轮转配置;
  3. 降低 DEBUG 输出;
  4. 增加容量告警;
  5. 接入集中日志后缩短本地留存。

案例二:看不到服务日志

systemctl status app
journalctl -u app -n 100
systemctl cat app
ls -l /proc/$(systemctl show -p MainPID --value app)/fd

可能原因:

  1. StandardOutput 被丢弃;
  2. 应用写到文件;
  3. 日志级别配置错误;
  4. 服务实际没有起来;
  5. journald 限制或采集器失败。

案例三:多行堆栈被拆散

检查采集器 multiline 配置:

以非 ERROR/WARN//INFO 开头的行
  -> 归并到上一条日志

同时设置最大归并时长和最大行数,防止异常日志无限合并。

本章小结

Linux 日志由内核、journal、syslog、应用和容器多个来源组成。生产日志要结构化、带链路 ID、可轮转、可采集、可脱敏、可告警。排障时先按时间和服务缩小范围,再从系统日志进入应用日志,最终形成完整证据链。

思考题

  1. dmesgjournalctl 分别适合看什么?
  2. 日志轮转后为什么需要通知应用或 Nginx?
  3. 容器应用为什么推荐输出 stdout?
  4. 如何设计敏感信息脱敏?
  5. 设计一个服务错误率告警,包含排查入口和处理手册。