编译与调试完全指南—第12章 日志分析

第12章 日志分析

完整 485 页的 《编译与调试完全指南》见: lengjingzju-notes发布页

日志是 Linux 系统调试和运维的第一手信息来源。无论是服务崩溃、内核异常、安全事件还是性能劣化,日志都能提供关键线索。本章系统介绍 Linux 日志体系的完整知识:从 systemd 日志查询(journalctl)、内核环形缓冲区(dmesg)、传统日志文件(/var/log),到底层内核消息接口(/proc/kmsg)、传统 syslog 体系(rsyslog/logger),再到日志生命周期管理(logrotate),构建从"日志产生→采集→存储→查询→管理"的完整工具链。
#mermaid-svg-cXTxePLj5FZCGFRX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cXTxePLj5FZCGFRX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cXTxePLj5FZCGFRX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cXTxePLj5FZCGFRX .error-icon{fill:#552222;}#mermaid-svg-cXTxePLj5FZCGFRX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cXTxePLj5FZCGFRX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cXTxePLj5FZCGFRX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cXTxePLj5FZCGFRX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cXTxePLj5FZCGFRX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cXTxePLj5FZCGFRX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cXTxePLj5FZCGFRX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cXTxePLj5FZCGFRX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cXTxePLj5FZCGFRX .marker.cross{stroke:#333333;}#mermaid-svg-cXTxePLj5FZCGFRX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cXTxePLj5FZCGFRX p{margin:0;}#mermaid-svg-cXTxePLj5FZCGFRX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cXTxePLj5FZCGFRX .cluster-label text{fill:#333;}#mermaid-svg-cXTxePLj5FZCGFRX .cluster-label span{color:#333;}#mermaid-svg-cXTxePLj5FZCGFRX .cluster-label span p{background-color:transparent;}#mermaid-svg-cXTxePLj5FZCGFRX .label text,#mermaid-svg-cXTxePLj5FZCGFRX span{fill:#333;color:#333;}#mermaid-svg-cXTxePLj5FZCGFRX .node rect,#mermaid-svg-cXTxePLj5FZCGFRX .node circle,#mermaid-svg-cXTxePLj5FZCGFRX .node ellipse,#mermaid-svg-cXTxePLj5FZCGFRX .node polygon,#mermaid-svg-cXTxePLj5FZCGFRX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cXTxePLj5FZCGFRX .rough-node .label text,#mermaid-svg-cXTxePLj5FZCGFRX .node .label text,#mermaid-svg-cXTxePLj5FZCGFRX .image-shape .label,#mermaid-svg-cXTxePLj5FZCGFRX .icon-shape .label{text-anchor:middle;}#mermaid-svg-cXTxePLj5FZCGFRX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cXTxePLj5FZCGFRX .rough-node .label,#mermaid-svg-cXTxePLj5FZCGFRX .node .label,#mermaid-svg-cXTxePLj5FZCGFRX .image-shape .label,#mermaid-svg-cXTxePLj5FZCGFRX .icon-shape .label{text-align:center;}#mermaid-svg-cXTxePLj5FZCGFRX .node.clickable{cursor:pointer;}#mermaid-svg-cXTxePLj5FZCGFRX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cXTxePLj5FZCGFRX .arrowheadPath{fill:#333333;}#mermaid-svg-cXTxePLj5FZCGFRX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cXTxePLj5FZCGFRX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cXTxePLj5FZCGFRX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cXTxePLj5FZCGFRX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cXTxePLj5FZCGFRX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cXTxePLj5FZCGFRX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cXTxePLj5FZCGFRX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cXTxePLj5FZCGFRX .cluster text{fill:#333;}#mermaid-svg-cXTxePLj5FZCGFRX .cluster span{color:#333;}#mermaid-svg-cXTxePLj5FZCGFRX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cXTxePLj5FZCGFRX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cXTxePLj5FZCGFRX rect.text{fill:none;stroke-width:0;}#mermaid-svg-cXTxePLj5FZCGFRX .icon-shape,#mermaid-svg-cXTxePLj5FZCGFRX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cXTxePLj5FZCGFRX .icon-shape p,#mermaid-svg-cXTxePLj5FZCGFRX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cXTxePLj5FZCGFRX .icon-shape .label rect,#mermaid-svg-cXTxePLj5FZCGFRX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cXTxePLj5FZCGFRX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cXTxePLj5FZCGFRX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cXTxePLj5FZCGFRX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 日志管理层
日志查询层
日志存储层
日志采集层
日志产生层
内核 printk
systemd 服务
用户应用
脚本 logger
systemd-journald
klogd
rsyslog
run-log-journal/

var-log-journal

二进制格式
var-log-*.log

文本格式
内核环形缓冲区
journalctl
dmesg
grep-tail-awk
logrotate

12.1 系统日志

本节介绍 Linux 系统中三类主要的日志查询途径:systemd 日志(journalctl)、内核环形缓冲区(dmesg)和传统日志文件(/var/log)。它们分别对应不同的日志来源和存储机制,适用于不同的排查场景。

12.1.1 journalctl(查询 systemd 日志)

journalctl 是 systemd 日志系统(systemd-journald)的查询工具,能够查询由 systemd-journald 服务收集的所有日志,包括内核日志、系统服务日志和用户会话日志。日志以二进制格式存储在 /run/log/journal/(易失性)或 /var/log/journal/(持久化)目录中。

基本用法

bash 复制代码
journalctl [OPTIONS...] [MATCHES...]

常用选项

选项 说明 典型用途
-b / -b 0 仅显示本次启动的日志 排查当前启动问题
-b -1 显示上次启动的日志 排查重启前的问题
-b -2 显示上上次启动的日志 追溯历史问题
-u <unit> 过滤指定服务/单元的日志 排查特定服务问题
-p <priority> 按优先级过滤(0-7 或名称) 只看错误/警告
-f 实时跟踪新日志(类似 tail -f 实时监控
-n <num> 显示最后 N 条日志 快速查看最近日志
--since <time> 起始时间过滤 按时间段查询
--until <time> 截止时间过滤 按时间段查询
-o <format> 输出格式(short/json/verbose/cat 等) 脚本解析/详细查看
-k 仅显示内核日志 等价于 dmesg 的 journal 版本
-g <pattern> 使用正则表达式过滤消息内容 关键词搜索
--no-pager 不使用分页器 脚本中使用
--no-hostname 不显示主机名 简化输出
-x 显示目录(catalog)中的解释信息 获取错误的详细说明
--list-boots 列出所有启动记录 查看启动历史
--disk-usage 显示日志占用的磁盘空间 磁盘空间管理
--vacuum-size=<size> 清理日志至指定大小 释放磁盘空间
--vacuum-time=<time> 清理指定时间之前的日志 释放磁盘空间

匹配字段(MATCHES)

journalctl 支持通过 FIELD=VALUE 形式的匹配字段进行精确过滤。这些字段对应日志条目中的元数据,比 -u-p 等选项提供更细粒度的过滤能力:

匹配字段 说明 示例
_PID=<pid> 按产生日志的进程 ID 过滤 journalctl _PID=1234
_UID=<uid> 按产生日志的用户 ID 过滤 journalctl _UID=1000
_GID=<gid> 按产生日志的组 ID 过滤 journalctl _GID=1000
_COMM=<name> 按进程命令名过滤(不含路径) journalctl _COMM=nginx
_EXE=<path> 按可执行文件完整路径过滤 journalctl _EXE=/usr/sbin/nginx
_SYSTEMD_UNIT=<unit> 按 systemd 单元名过滤 journalctl _SYSTEMD_UNIT=sshd.service
_SYSTEMD_SLICE=<slice> 按 systemd slice 过滤 journalctl _SYSTEMD_SLICE=user.slice
_BOOT_ID=<id> 按启动 ID 过滤 journalctl _BOOT_ID=xxx
_TRANSPORT=<type> 按日志传输方式过滤(stdout/syslog/journal 等) journalctl _TRANSPORT=stdout
SYSLOG_FACILITY=<num> 按 syslog facility 编号过滤(0-23) journalctl SYSLOG_FACILITY=3
SYSLOG_IDENTIFIER=<name> 按 syslog 标识符过滤 journalctl SYSLOG_IDENTIFIER=sshd
PRIORITY=<num> 按优先级过滤(等价于 -p journalctl PRIORITY=3
MESSAGE=<text> 按消息内容精确匹配 journalctl MESSAGE="Started"

提示 :使用 journalctl -o verbose 可以查看日志条目的所有可用字段,从而发现更多可过滤的字段。多个匹配字段同时指定时,默认为 AND 关系;同一字段的多个值之间为 OR 关系。

优先级(Priority)级别

数值 名称 缩写 说明
0 emerg emerg 系统不可用
1 alert alert 必须立即处理
2 crit crit 严重情况
3 err err 错误
4 warning warning 警告
5 notice notice 正常但值得注意
6 info info 信息性消息
7 debug debug 调试信息

实战示例

bash 复制代码
# 查看所有日志
journalctl

# 查看本次启动的所有日志
journalctl -b

# 查看上次启动的日志(排查崩溃原因)
journalctl -b -1

# 查看指定服务的日志
journalctl -u nginx
journalctl -u sshd.service

# 实时跟踪日志(类似 tail -f)
journalctl -f

# 实时跟踪特定服务的日志
journalctl -u nginx -f

# 按时间范围过滤
journalctl --since "2024-01-01" --until "2024-01-02"
journalctl --since "1 hour ago"
journalctl --since today

# 按优先级过滤(只看错误及以上)
journalctl -p err
journalctl -p 3

# 只看内核日志
journalctl -k

# 显示最后 50 条日志
journalctl -n 50

# 按进程 ID 过滤
journalctl _PID=1234

# 按用户过滤
journalctl _UID=1000

# 按命令名过滤
journalctl _COMM=nginx

# 按可执行文件路径过滤
journalctl /usr/sbin/nginx

# 按 syslog facility 过滤(3 = daemon)
journalctl SYSLOG_FACILITY=3

# 使用正则表达式搜索
journalctl -g "segfault|OOM|error"

# JSON 格式输出(便于脚本解析)
journalctl -o json --no-pager

# 显示详细字段信息(查看所有可用匹配字段)
journalctl -o verbose -n 5

# 查看日志占用的磁盘空间
journalctl --disk-usage

# 清理日志:只保留最近 7 天
journalctl --vacuum-time=7d

# 清理日志:只保留 500M
journalctl --vacuum-size=500M

# 列出所有启动记录
journalctl --list-boots

# 组合过滤:查看 nginx 服务今天的错误日志
journalctl -u nginx -p err --since today

输出解读

复制代码
Jan 15 10:30:01 hostname sshd[1234]: Failed password for root from 192.168.1.100 port 52341 ssh2
字段 含义
Jan 15 10:30:01 时间戳
hostname 主机名
sshd 产生日志的程序名
[1234] 进程 PID
后续内容 日志消息

journalctl 持久化配置

默认情况下,systemd-journald 的日志可能仅存储在 /run/log/journal/(内存中,重启丢失)。要启用持久化存储:

bash 复制代码
# 创建持久化目录
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal

# 重启 journald 服务
sudo systemctl restart systemd-journald

配置文件位于 /etc/systemd/journald.conf,关键参数:

参数 说明 默认值 建议值
Storage 存储方式(auto/persistent/volatile/none) auto persistent
SystemMaxUse 日志最大占用空间 4G 或磁盘的 10% 根据磁盘调整
SystemMaxFileSize 单个日志文件最大大小 1/8 的 SystemMaxUse 默认即可
MaxRetentionSec 日志最大保留时间 0(不限) 1month
Compress 是否压缩 yes yes
ForwardToSyslog 是否转发给 syslog no 按需

易错点

  • -b 选项不带参数时等同于 -b 0(本次启动),-b -1 才是上次启动
  • --since--until 的时间格式灵活,支持 "2024-01-01""today""1 hour ago""yesterday"
  • 如果 journal 未持久化,重启后历史日志会丢失
  • journalctl -u 中的服务名可以省略 .service 后缀
  • 匹配字段区分大小写,_COMM=nginx_COMM=Nginx 是不同的过滤条件
  • 同一字段指定多个值时为 OR 关系:journalctl _COMM=nginx _COMM=sshd 表示 nginx 或 sshd

12.1.2 dmesg(查看内核环形缓冲区)

dmesg(diagnostic message)用于显示和控制内核环形缓冲区(kernel ring buffer)中的消息。内核通过 printk() 函数输出的所有消息都存储在这个环形缓冲区中,包括硬件检测、驱动加载、系统错误、OOM 事件等。

基本用法

bash 复制代码
dmesg [OPTIONS...]

常用选项

选项 说明 典型用途
-T 显示人类可读的时间戳(而非秒数) 日常查看
-w 实时跟踪新消息(类似 tail -f 实时监控内核事件
-c 读取并清除内核环形缓冲区 获取增量日志
-C 清除内核环形缓冲区(不显示) 重置缓冲区
-n <level> 设置内核日志输出到控制台的级别 控制控制台输出
-l <level> 按级别过滤显示 只看特定级别
-f <facility> 按 facility 过滤(如 kern, user) 按来源过滤
-t 不显示时间戳 简化输出
-x 显示 facility 和 level 的十六进制编码 详细分类
--color[=when] 彩色输出(auto/always/never) 终端查看
-S 强制使用 syslog(2) 系统调用 兼容旧内核
-s <size> 设置读取缓冲区大小 读取大量日志

内核日志级别

级别 名称 说明
0 KERN_EMERG 系统不可用(如内核崩溃)
1 KERN_ALERT 必须立即采取行动
2 KERN_CRIT 严重情况(如硬件故障)
3 KERN_ERR 错误(如驱动报错)
4 KERN_WARNING 警告
5 KERN_NOTICE 正常但重要
6 KERN_INFO 信息性消息
7 KERN_DEBUG 调试信息

实战示例

bash 复制代码
# 查看所有内核消息(带时间戳)
dmesg -T

# 实时跟踪内核消息
dmesg -w

# 查看最后 20 条内核消息
dmesg -T | tail -20

# 只看错误级别及以上
dmesg -l err,crit,alert,emerg

# 只看警告及以上
dmesg -l warn

# 按 facility 过滤(只看内核消息)
dmesg -f kern

# 搜索特定关键词
dmesg -T | grep -i "error"
dmesg -T | grep -i "usb"
dmesg -T | grep -i "oom"

# 查看段错误信息(定位崩溃程序)
dmesg | grep segfault
# 输出示例:
# [83208.450712] a.out[13275]: segfault at 491f44 ip 0000000000400b80 sp 00007ffecb47fd50 error 7 in a.out[400000+b6000]

# 查看 OOM killer 事件
dmesg -T | grep -i "out of memory"

# 查看硬件相关信息
dmesg -T | grep -i "sda"
dmesg -T | grep -i "eth0"

# 清除内核环形缓冲区
dmesg -C

# 读取并清除(用于脚本获取增量日志)
dmesg -c > /tmp/new_kernel_msgs.txt

# 设置控制台日志级别(只显示 emerg~err)
dmesg -n 3

输出解读

复制代码
[83208.450712] a.out[13275]: segfault at 491f44 ip 0000000000400b80 sp 00007ffecb47fd50 error 7 in a.out[400000+b6000]
字段 含义
[83208.450712] 系统启动后的秒数(加 -T 显示为日期时间)
a.out 进程名
[13275] 进程 PID
segfault at 491f44 段错误发生的地址
ip 0000000000400b80 指令指针(出错指令的地址,可用 addr2line 定位源码行)
sp 00007ffecb47fd50 栈指针
error 7 页表错误码
in a.out[400000+b6000] 出错指令所在的内存映射区域

dmesg 与 journalctl -k 的区别

对比项 dmesg journalctl -k
数据来源 直接读取内核环形缓冲区 从 journald 数据库中读取
历史保留 环形缓冲区,会被覆盖 持久化存储(如果配置了)
重启后 缓冲区被清空 可查看历史启动的内核日志
权限 通常需要 root(或 dmesg_restrict=0 通常需要 adm 组或 root
适用场景 实时调试、嵌入式系统 历史日志分析

易错点

  • 内核环形缓冲区大小有限(默认 128KB~1MB),高日志量时旧消息会被覆盖
  • 可通过内核启动参数 log_buf_len=4M 增大缓冲区
  • /proc/sys/kernel/dmesg_restrict 控制非 root 用户是否可以读取 dmesg(1 = 限制)
  • 使用 dmesg -c 会清除缓冲区,慎用

12.1.3 /var/log 目录结构(传统日志文件)

/var/log/ 是 Linux 系统中存放各类日志文件的标准目录。不同的服务和系统组件将日志写入不同的文件中。

常见日志文件

文件/目录 说明 写入者
/var/log/syslog 系统综合日志(Debian/Ubuntu) rsyslog
/var/log/messages 系统综合日志(RHEL/CentOS) rsyslog
/var/log/kern.log 内核日志 rsyslog
/var/log/auth.log 认证和授权日志(Debian/Ubuntu) rsyslog
/var/log/secure 认证和授权日志(RHEL/CentOS) rsyslog
/var/log/dmesg 启动时的内核日志 系统初始化脚本
/var/log/dpkg.log 软件包安装/卸载日志(Debian/Ubuntu) dpkg
/var/log/apt/history.log APT 操作历史(Debian/Ubuntu) apt
/var/log/yum.log YUM 操作日志(RHEL/CentOS) yum
/var/log/boot.log 系统启动日志 系统初始化
/var/log/cron 定时任务日志 crond
/var/log/lastlog 用户最后登录信息(二进制) login
/var/log/wtmp 登录/登出记录(二进制) login
/var/log/btmp 失败登录记录(二进制) login
/var/log/journal/ systemd-journald 持久化日志 systemd-journald
/var/log/nginx/ Nginx 日志 nginx
/var/log/apache2/ Apache 日志 apache2
/var/log/mysql/ MySQL 日志 mysql
/var/log/sssd/ SSSD 日志 sssd

查看命令

bash 复制代码
# 查看系统日志最后 50 行
tail -50 /var/log/syslog

# 实时跟踪认证日志
tail -f /var/log/auth.log

# 搜索失败的 SSH 登录
grep "Failed password" /var/log/auth.log

# 查看最后登录记录
lastlog

# 查看登录/登出历史
last

# 查看失败登录尝试
lastb

# 查看内核日志文件
cat /var/log/kern.log | tail -20

Debian/Ubuntu 与 RHEL/CentOS 日志文件对比

功能 Debian/Ubuntu RHEL/CentOS
系统综合日志 /var/log/syslog /var/log/messages
认证日志 /var/log/auth.log /var/log/secure
内核日志 /var/log/kern.log /var/log/messages(含内核)
包管理日志 /var/log/dpkg.log /var/log/yum.log

12.2 内核日志

本节介绍内核日志的底层接口和传统守护进程。理解这些机制有助于掌握内核消息从产生到用户空间可见的完整链路,在嵌入式系统和旧系统中尤为重要。

12.2.1 /proc/kmsg(内核消息原始接口)

/proc/kmsg 是内核消息的接口文件,提供了对用户空间读取内核日志的原始访问方式。它是一个只读的伪文件,读取时会阻塞直到有新消息到达。

特性说明

特性 说明
文件类型 只读伪文件(proc 文件系统)
读取行为 阻塞式读取,每次读取返回一批新消息
消息格式 <级别>时间戳 消息内容
权限 需要 root 权限
互斥性 同一时间只能有一个进程读取

实战示例

bash 复制代码
# 直接读取(需要 root,会持续输出直到 Ctrl+C)
sudo cat /proc/kmsg

# 输出示例:
# <6>[ 123.456789] usb 1-1: new high-speed USB device number 5 using xhci_hcd
# <3>[ 124.567890] EXT4-fs error (device sda1): ...

输出解读

<N> 中的 N 表示日志级别(0-7),对应关系与 dmesg 的级别一致。

/proc/kmsg 与 dmesg 的关系

/proc/kmsg 是内核消息的原始接口 ,而 dmesg 是对该接口的用户空间封装。两者的关系如下图所示:
#mermaid-svg-wUHZDcLkfpxMSZFr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wUHZDcLkfpxMSZFr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wUHZDcLkfpxMSZFr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wUHZDcLkfpxMSZFr .error-icon{fill:#552222;}#mermaid-svg-wUHZDcLkfpxMSZFr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wUHZDcLkfpxMSZFr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wUHZDcLkfpxMSZFr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wUHZDcLkfpxMSZFr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wUHZDcLkfpxMSZFr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wUHZDcLkfpxMSZFr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wUHZDcLkfpxMSZFr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wUHZDcLkfpxMSZFr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wUHZDcLkfpxMSZFr .marker.cross{stroke:#333333;}#mermaid-svg-wUHZDcLkfpxMSZFr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wUHZDcLkfpxMSZFr p{margin:0;}#mermaid-svg-wUHZDcLkfpxMSZFr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wUHZDcLkfpxMSZFr .cluster-label text{fill:#333;}#mermaid-svg-wUHZDcLkfpxMSZFr .cluster-label span{color:#333;}#mermaid-svg-wUHZDcLkfpxMSZFr .cluster-label span p{background-color:transparent;}#mermaid-svg-wUHZDcLkfpxMSZFr .label text,#mermaid-svg-wUHZDcLkfpxMSZFr span{fill:#333;color:#333;}#mermaid-svg-wUHZDcLkfpxMSZFr .node rect,#mermaid-svg-wUHZDcLkfpxMSZFr .node circle,#mermaid-svg-wUHZDcLkfpxMSZFr .node ellipse,#mermaid-svg-wUHZDcLkfpxMSZFr .node polygon,#mermaid-svg-wUHZDcLkfpxMSZFr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wUHZDcLkfpxMSZFr .rough-node .label text,#mermaid-svg-wUHZDcLkfpxMSZFr .node .label text,#mermaid-svg-wUHZDcLkfpxMSZFr .image-shape .label,#mermaid-svg-wUHZDcLkfpxMSZFr .icon-shape .label{text-anchor:middle;}#mermaid-svg-wUHZDcLkfpxMSZFr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wUHZDcLkfpxMSZFr .rough-node .label,#mermaid-svg-wUHZDcLkfpxMSZFr .node .label,#mermaid-svg-wUHZDcLkfpxMSZFr .image-shape .label,#mermaid-svg-wUHZDcLkfpxMSZFr .icon-shape .label{text-align:center;}#mermaid-svg-wUHZDcLkfpxMSZFr .node.clickable{cursor:pointer;}#mermaid-svg-wUHZDcLkfpxMSZFr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wUHZDcLkfpxMSZFr .arrowheadPath{fill:#333333;}#mermaid-svg-wUHZDcLkfpxMSZFr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wUHZDcLkfpxMSZFr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wUHZDcLkfpxMSZFr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wUHZDcLkfpxMSZFr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wUHZDcLkfpxMSZFr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wUHZDcLkfpxMSZFr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wUHZDcLkfpxMSZFr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wUHZDcLkfpxMSZFr .cluster text{fill:#333;}#mermaid-svg-wUHZDcLkfpxMSZFr .cluster span{color:#333;}#mermaid-svg-wUHZDcLkfpxMSZFr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-wUHZDcLkfpxMSZFr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wUHZDcLkfpxMSZFr rect.text{fill:none;stroke-width:0;}#mermaid-svg-wUHZDcLkfpxMSZFr .icon-shape,#mermaid-svg-wUHZDcLkfpxMSZFr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wUHZDcLkfpxMSZFr .icon-shape p,#mermaid-svg-wUHZDcLkfpxMSZFr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wUHZDcLkfpxMSZFr .icon-shape .label rect,#mermaid-svg-wUHZDcLkfpxMSZFr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wUHZDcLkfpxMSZFr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wUHZDcLkfpxMSZFr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wUHZDcLkfpxMSZFr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} printk()

内核打印函数
内核环形缓冲区

(kernel ring buffer)
/proc/kmsg

原始接口(阻塞读取)
dmesg 命令

(syslog(2) 系统调用)
klogd 守护进程

(传统系统)
systemd-journald

(现代系统)
rsyslog
journalctl
/var/log/kern.log

关键关系总结

对比项 /proc/kmsg dmesg
本质 内核提供的原始文件接口 用户空间命令工具
访问方式 read() 系统调用(阻塞) syslog(2) 系统调用(非阻塞快照)
读取行为 每次读取返回新消息(消费式) 每次读取返回全部缓冲区内容(快照式)
互斥性 同一时间只能有一个读者 多个进程可同时读取
典型使用者 klogd、systemd-journald 用户手动查看
适用场景 守护进程持续消费内核消息 人工排查、脚本获取快照

核心区别/proc/kmsg 是"消费式"读取------读过的消息不会再返回给下一个读者;dmesg 是"快照式"读取------每次都能看到缓冲区中的全部内容。因此,如果 systemd-journald 已经在读取 /proc/kmsg,用户再执行 cat /proc/kmsg 将无法获取任何消息(被 journald 消费了),但 dmesg 仍然可以正常显示。

易错点

  • /proc/kmsg 只能被一个进程同时读取,如果 systemd-journaldklogd 已经在读取,其他进程将无法获取消息
  • 在现代 systemd 系统中,通常由 systemd-journald 负责读取 /proc/kmsg
  • 不建议直接使用 cat /proc/kmsg,应优先使用 dmesgjournalctl -k

12.2.2 klogd(内核日志守护进程)

klogd(kernel log daemon)是传统的内核日志守护进程,负责从内核环形缓冲区(通过 /proc/kmsgsyslog(2) 系统调用)读取内核消息,并将其转发给 syslogd(如 rsyslog)进行持久化存储。

工作方式

特性 说明
数据来源 /proc/kmsgsyslog(2) 系统调用
输出目标 转发给 syslog 守护进程(rsyslog/syslog-ng)
运行模式 作为守护进程在后台运行
现代替代 systemd 系统中由 systemd-journald 取代

基本用法

bash 复制代码
# 启动 klogd(通常由系统自动管理)
klogd

# 指定日志级别(只转发此级别及以上的消息)
klogd -c 4

# 从 syslog(2) 读取而非 /proc/kmsg
klogd -s

常用选项

选项 说明
-c <level> 设置控制台日志级别(1-8)
-s 使用 syslog(2) 系统调用读取内核消息
-k <file> 指定内核符号表文件(用于解析 oops 消息)
-p 兼容模式(与 syslogd 的 -p 配合)
-n 前台运行(不 fork 为守护进程)

在现代系统中的地位

在使用 systemd 的现代 Linux 发行版中,klogd 通常不再需要,因为 systemd-journald 已经承担了读取内核日志的职责。但在以下场景中仍可能遇到 klogd

  • 使用 SysVinit 或 OpenRC 的旧系统
  • 嵌入式 Linux 系统(如 BusyBox 环境)
  • 使用传统 syslog 配置且未启用 systemd-journald 的系统

12.3 传统 Syslog 体系

本节介绍传统的 syslog 日志体系,包括日志守护进程 rsyslog 和日志发送工具 logger。虽然现代系统已广泛使用 systemd-journald,但 syslog 体系仍然是许多应用程序和旧系统的日志基础设施,理解它对于日志路由配置和跨系统日志管理至关重要。

12.3.1 rsyslog(日志守护进程)

rsyslog 是 Linux 上最广泛使用的 syslog 守护进程实现,负责接收、过滤、路由和存储来自各种来源的日志消息。它是传统 syslogd 的增强替代品。

核心概念

rsyslog 使用 facility(设施)priority(优先级) 两个维度对日志进行分类和路由。

Facility(设施)分类

数值 名称 说明
0 kern 内核消息
1 user 用户级消息
2 mail 邮件系统
3 daemon 系统守护进程
4 auth 认证/授权消息
5 syslog syslog 内部消息
6 lpr 打印系统
7 news 网络新闻
8 uucp UUCP 子系统
9 cron 时钟/定时任务
10 authpriv 敏感认证消息
11 ftp FTP 守护进程
16-23 local0-local7 本地自定义(应用程序可用)

local0~local7 自定义 facility 详解

local0local7 是 syslog 标准预留的 8 个自定义 facility,供用户自定义应用程序使用。它们没有预定义的语义,开发者可以自由分配用途。

典型使用场景:

使用场景 推荐 facility 说明
自研业务应用 local0 最常用,作为默认自定义 facility
数据库服务 local1 如 MySQL、PostgreSQL 自定义日志
Web 服务器 local2 如 Nginx 自定义格式日志
监控系统 local3 如 Zabbix Agent 日志
部署/CI 脚本 local4 部署流程记录
安全审计 local5 自定义安全事件
预留扩展 local6-local7 多应用共存时分配

配置示例------将自定义应用的日志路由到独立文件:

bash 复制代码
# /etc/rsyslog.d/myapp.conf

# 将 local0 的所有消息写入 /var/log/myapp.log
local0.*                        /var/log/myapp.log

# 将 local1 的错误及以上级别写入 /var/log/db-error.log
local1.err                      /var/log/db-error.log

# 将 local2 的 info 及以上写入 /var/log/webapp.log,排除 debug
local2.info;local2.!debug       /var/log/webapp.log

# 将 local3 的消息同时写入文件和转发到远程服务器
local3.*                        /var/log/monitor.log
local3.*                        @192.168.1.100:514

配合 logger 命令测试:

bash 复制代码
# 发送测试消息到 local0
logger -p local0.info "MyApp started successfully"

# 验证消息已写入
tail -1 /var/log/myapp.log
# 输出: Jan 15 10:30:01 hostname myapp: MyApp started successfully

配合应用程序使用(C 语言示例):

c 复制代码
#include <syslog.h>

int main(void) {
    // 打开 syslog,标识为 "myapp",使用 local0 facility
    openlog("myapp", LOG_PID | LOG_NDELAY, LOG_LOCAL0);

    syslog(LOG_INFO, "Service started, listening on port %d", 8080);
    syslog(LOG_ERR, "Failed to connect to database: %s", strerror(errno));

    closelog();
    return 0;
}

注意 :使用 local0~local7 时,需要确保 rsyslog 配置中有对应的规则将消息路由到目标文件,否则消息会被丢弃或写入默认的 /var/log/syslog

配置文件与规则格式

配置文件:/etc/rsyslog.conf/etc/rsyslog.d/*.conf

配置规则格式:

复制代码
facility.priority   action

配置示例

bash 复制代码
# 所有 kern 级别的消息写入 /var/log/kern.log
kern.*                          /var/log/kern.log

# auth 和 authpriv 的所有消息写入 /var/log/auth.log
auth,authpriv.*                 /var/log/auth.log

# 所有 mail 消息写入 /var/log/mail.log(- 前缀表示异步写入,提升性能)
mail.*                          -/var/log/mail.log

# 所有 info 及以上级别(排除 mail、authpriv、cron)写入 /var/log/syslog
*.*;auth,authpriv.none;cron.none    -/var/log/syslog

# 所有 emerg 级别的消息发送给所有登录用户
*.emerg                         :omusrmsg:*

# 将 local0 的所有消息写入自定义文件
local0.*                        /var/log/myapp.log

常用管理命令

bash 复制代码
# 查看 rsyslog 服务状态
systemctl status rsyslog

# 重启 rsyslog
systemctl restart rsyslog

# 检查配置文件语法
rsyslogd -N1

# 以调试模式运行
rsyslogd -d

12.3.2 logger(手动发送日志消息)

logger 命令用于从命令行或脚本手动向 syslog 发送日志消息,是测试日志系统和在脚本中记录事件的实用工具。

基本用法

bash 复制代码
logger [OPTIONS] MESSAGE

常用选项

选项 说明 示例
-p <facility.priority> 指定 facility 和 priority logger -p local0.info "msg"
-t <tag> 指定日志标签(标识来源) logger -t myscript "msg"
-i 记录发送进程的 PID logger -i "msg"
-f <file> 从文件读取消息内容 logger -f /tmp/msg.txt
-s 同时输出到 stderr logger -s "msg"
-n <server> 发送到远程 syslog 服务器 logger -n 192.168.1.1 "msg"
-P <port> 指定远程端口(默认 514) logger -n server -P 1514 "msg"
-d 使用 TCP 而非 UDP logger -d -n server "msg"

实战示例

bash 复制代码
# 发送简单的日志消息(默认 user.notice)
logger "This is a test message"

# 指定 facility 和 priority
logger -p local0.err "Application error occurred"

# 带标签的消息(便于在日志中识别来源)
logger -t backup_script "Backup completed successfully"

# 在脚本中记录事件
#!/bin/bash
logger -t myapp -p local0.info "Service started at $(date)"
# ... 业务逻辑 ...
logger -t myapp -p local0.err "Failed to connect to database"

# 验证消息已写入
grep "backup_script" /var/log/syslog

12.4 日志轮转与管理

本节介绍日志轮转工具 logrotate,它是防止日志文件无限增长占满磁盘的关键管理工具。通过合理的轮转策略,可以在保留历史日志的同时控制磁盘使用。

12.4.1 logrotate(日志轮转工具)

logrotate 是 Linux 系统的日志轮转工具,用于自动管理日志文件的大小、数量和生命周期,防止日志文件无限增长占满磁盘。

工作原理
#mermaid-svg-Moyd0IXgk0a76tVK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Moyd0IXgk0a76tVK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Moyd0IXgk0a76tVK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Moyd0IXgk0a76tVK .error-icon{fill:#552222;}#mermaid-svg-Moyd0IXgk0a76tVK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Moyd0IXgk0a76tVK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Moyd0IXgk0a76tVK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Moyd0IXgk0a76tVK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Moyd0IXgk0a76tVK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Moyd0IXgk0a76tVK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Moyd0IXgk0a76tVK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Moyd0IXgk0a76tVK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Moyd0IXgk0a76tVK .marker.cross{stroke:#333333;}#mermaid-svg-Moyd0IXgk0a76tVK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Moyd0IXgk0a76tVK p{margin:0;}#mermaid-svg-Moyd0IXgk0a76tVK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Moyd0IXgk0a76tVK .cluster-label text{fill:#333;}#mermaid-svg-Moyd0IXgk0a76tVK .cluster-label span{color:#333;}#mermaid-svg-Moyd0IXgk0a76tVK .cluster-label span p{background-color:transparent;}#mermaid-svg-Moyd0IXgk0a76tVK .label text,#mermaid-svg-Moyd0IXgk0a76tVK span{fill:#333;color:#333;}#mermaid-svg-Moyd0IXgk0a76tVK .node rect,#mermaid-svg-Moyd0IXgk0a76tVK .node circle,#mermaid-svg-Moyd0IXgk0a76tVK .node ellipse,#mermaid-svg-Moyd0IXgk0a76tVK .node polygon,#mermaid-svg-Moyd0IXgk0a76tVK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Moyd0IXgk0a76tVK .rough-node .label text,#mermaid-svg-Moyd0IXgk0a76tVK .node .label text,#mermaid-svg-Moyd0IXgk0a76tVK .image-shape .label,#mermaid-svg-Moyd0IXgk0a76tVK .icon-shape .label{text-anchor:middle;}#mermaid-svg-Moyd0IXgk0a76tVK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Moyd0IXgk0a76tVK .rough-node .label,#mermaid-svg-Moyd0IXgk0a76tVK .node .label,#mermaid-svg-Moyd0IXgk0a76tVK .image-shape .label,#mermaid-svg-Moyd0IXgk0a76tVK .icon-shape .label{text-align:center;}#mermaid-svg-Moyd0IXgk0a76tVK .node.clickable{cursor:pointer;}#mermaid-svg-Moyd0IXgk0a76tVK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Moyd0IXgk0a76tVK .arrowheadPath{fill:#333333;}#mermaid-svg-Moyd0IXgk0a76tVK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Moyd0IXgk0a76tVK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Moyd0IXgk0a76tVK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Moyd0IXgk0a76tVK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Moyd0IXgk0a76tVK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Moyd0IXgk0a76tVK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Moyd0IXgk0a76tVK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Moyd0IXgk0a76tVK .cluster text{fill:#333;}#mermaid-svg-Moyd0IXgk0a76tVK .cluster span{color:#333;}#mermaid-svg-Moyd0IXgk0a76tVK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Moyd0IXgk0a76tVK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Moyd0IXgk0a76tVK rect.text{fill:none;stroke-width:0;}#mermaid-svg-Moyd0IXgk0a76tVK .icon-shape,#mermaid-svg-Moyd0IXgk0a76tVK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Moyd0IXgk0a76tVK .icon-shape p,#mermaid-svg-Moyd0IXgk0a76tVK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Moyd0IXgk0a76tVK .icon-shape .label rect,#mermaid-svg-Moyd0IXgk0a76tVK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Moyd0IXgk0a76tVK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Moyd0IXgk0a76tVK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Moyd0IXgk0a76tVK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

日志文件增长
达到轮转条件?
重命名当前日志

app.log → app.log.1
压缩旧日志

app.log.1 → app.log.2.gz
删除超出保留数量的日志
创建新的空日志文件
通知服务重新打开日志

发送 SIGHUP 或执行 postrotate
继续写入

配置文件位置

路径 说明
/etc/logrotate.conf 主配置文件(全局默认设置)
/etc/logrotate.d/ 各服务的独立配置目录
/etc/cron.daily/logrotate 每日自动执行的 cron 任务

配置语法

复制代码
/path/to/logfile {
    directive1
    directive2
    ...
}

常用指令

指令 说明 示例
daily 每天轮转 daily
weekly 每周轮转 weekly
monthly 每月轮转 monthly
rotate <N> 保留 N 个旧日志文件 rotate 4
compress 压缩旧日志(gzip) compress
delaycompress 延迟一个周期再压缩 delaycompress
missingok 日志文件不存在时不报错 missingok
notifempty 空文件不轮转 notifempty
copytruncate 复制后截断原文件(无需重启服务) copytruncate
create <mode> <owner> <group> 创建新日志文件的权限和属主 create 0640 root adm
size <size> 按大小轮转(如 100M) size 100M
minsize <size> 最小大小(配合时间轮转) minsize 10M
postrotate/endscript 轮转后执行的脚本 发送信号给服务
prerotate/endscript 轮转前执行的脚本 预处理
sharedscripts 所有日志轮转完成后只执行一次 postrotate sharedscripts
dateext 使用日期作为后缀而非数字 dateext
dateformat 自定义日期格式 dateformat -%Y%m%d

dateext 与 dateformat 详解

默认情况下,logrotate 使用数字后缀命名轮转后的日志文件(如 app.log.1app.log.2)。启用 dateext 后,改用日期作为后缀,便于直观识别日志的时间范围。

指令 作用 示例效果
dateext 启用日期后缀(替代数字后缀) app.log-20240115
dateformat 自定义日期格式字符串 配合 dateext 使用

dateformat 支持的格式说明符:

说明符 含义 示例输出
%Y 四位年份 2024
%m 两位月份 01
%d 两位日期 15
%H 两位小时 10
%M 两位分钟 30
%s Unix 时间戳 1705312200

配置示例对比:

bash 复制代码
# 默认数字后缀
/var/log/myapp/*.log {
    daily
    rotate 7
    compress
}
# 轮转结果: myapp.log.1.gz, myapp.log.2.gz, ...

# 使用 dateext(日期后缀)
/var/log/myapp/*.log {
    daily
    rotate 7
    compress
    dateext
}
# 轮转结果: myapp.log-20240115.gz, myapp.log-20240114.gz, ...

# 使用 dateext + dateformat(自定义格式)
/var/log/myapp/*.log {
    daily
    rotate 30
    compress
    dateext
    dateformat -%Y%m%d-%H%M%S
}
# 轮转结果: myapp.log-20240115-030001.gz

注意dateextrotate 配合使用时,如果同一天内多次强制执行轮转(logrotate -f),由于日期后缀相同,旧文件会被覆盖。可通过 dateformat 加入时分秒来避免。

实战示例

bash 复制代码
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
    endscript
}

# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
    weekly
    rotate 8
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
    size 50M
}

copytruncate 与信号方式的区别

对比项 copytruncate postrotate + 信号
原理 复制文件后截断原文件 重命名文件,通知服务重新打开
是否需要服务支持 不需要 需要服务支持重新打开日志
数据丢失风险 复制和截断之间可能丢失少量数据
适用场景 不支持重新打开日志的程序 nginx、rsyslog 等支持的服务

管理命令

bash 复制代码
# 手动执行轮转(测试配置是否正确)
sudo logrotate -d /etc/logrotate.conf    # -d 调试模式,不实际执行
sudo logrotate -f /etc/logrotate.conf    # -f 强制执行

# 只轮转特定配置
sudo logrotate -f /etc/logrotate.d/nginx

# 查看轮转状态(上次轮转时间)
cat /var/lib/logrotate/status

# 查看详细输出
sudo logrotate -v /etc/logrotate.conf

易错点

  • logrotate 默认由 cron 每天执行一次,如果系统长时间运行不重启,注意检查 cron 是否正常
  • 使用 copytruncate 时,在复制和截断之间的极短时间内写入的数据会丢失
  • postrotate 脚本中的命令必须正确处理 PID 文件不存在的情况
  • 修改配置后可用 logrotate -d 进行干跑测试
  • dateext 模式下同一天多次强制轮转会覆盖同名文件,建议配合 dateformat 加入时间

12.5 日志分析工具对比总结

本章介绍了 Linux 日志分析从产生、采集、存储到查询、管理的完整工具链。以下从多个维度进行总结对比。

工具功能对比总表

工具/接口 类别 主要用途 典型命令
journalctl systemd 日志 查询 systemd-journald 日志 journalctl -u nginx -p err
dmesg 内核日志 查看内核环形缓冲区 dmesg -T -w
/proc/kmsg 内核日志接口 原始内核消息读取 cat /proc/kmsg
klogd 内核日志守护进程 转发内核消息到 syslog klogd -c 4
rsyslog 日志守护进程 接收、路由、存储日志 systemctl status rsyslog
logger 日志发送 手动/脚本发送日志消息 logger -p local0.info "msg"
logrotate 日志管理 自动轮转、压缩、清理日志 logrotate -f /etc/logrotate.conf
/var/log/* 日志文件 各类服务的文本日志 tail -f /var/log/syslog
last/lastb/lastlog 登录日志 查看登录/登出/失败记录 last -20

工具适用场景对比

工具 适用场景 数据格式 查询能力 是否需要额外安装 持久化
journalctl systemd 系统的全量日志查询 二进制 强(时间/服务/级别/正则) 系统自带(systemd) 可配置
dmesg 内核消息实时查看 文本 中(级别/facility 过滤) 系统自带 否(环形缓冲区)
rsyslog 日志路由和持久化存储 文本 弱(需配合 grep 等) 系统自带
logger 脚本/应用发送日志 --- --- 系统自带 ---
logrotate 日志文件生命周期管理 --- --- 系统自带 ---
/var/log 文件 直接查看文本日志 文本 依赖 grep/tail/awk 系统自带

日志查询工具选择决策图
#mermaid-svg-eB1YXWCpJ5ioeh7J{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eB1YXWCpJ5ioeh7J .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eB1YXWCpJ5ioeh7J .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eB1YXWCpJ5ioeh7J .error-icon{fill:#552222;}#mermaid-svg-eB1YXWCpJ5ioeh7J .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eB1YXWCpJ5ioeh7J .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eB1YXWCpJ5ioeh7J .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eB1YXWCpJ5ioeh7J .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eB1YXWCpJ5ioeh7J .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eB1YXWCpJ5ioeh7J .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eB1YXWCpJ5ioeh7J .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eB1YXWCpJ5ioeh7J .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eB1YXWCpJ5ioeh7J .marker.cross{stroke:#333333;}#mermaid-svg-eB1YXWCpJ5ioeh7J svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eB1YXWCpJ5ioeh7J p{margin:0;}#mermaid-svg-eB1YXWCpJ5ioeh7J .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eB1YXWCpJ5ioeh7J .cluster-label text{fill:#333;}#mermaid-svg-eB1YXWCpJ5ioeh7J .cluster-label span{color:#333;}#mermaid-svg-eB1YXWCpJ5ioeh7J .cluster-label span p{background-color:transparent;}#mermaid-svg-eB1YXWCpJ5ioeh7J .label text,#mermaid-svg-eB1YXWCpJ5ioeh7J span{fill:#333;color:#333;}#mermaid-svg-eB1YXWCpJ5ioeh7J .node rect,#mermaid-svg-eB1YXWCpJ5ioeh7J .node circle,#mermaid-svg-eB1YXWCpJ5ioeh7J .node ellipse,#mermaid-svg-eB1YXWCpJ5ioeh7J .node polygon,#mermaid-svg-eB1YXWCpJ5ioeh7J .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eB1YXWCpJ5ioeh7J .rough-node .label text,#mermaid-svg-eB1YXWCpJ5ioeh7J .node .label text,#mermaid-svg-eB1YXWCpJ5ioeh7J .image-shape .label,#mermaid-svg-eB1YXWCpJ5ioeh7J .icon-shape .label{text-anchor:middle;}#mermaid-svg-eB1YXWCpJ5ioeh7J .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eB1YXWCpJ5ioeh7J .rough-node .label,#mermaid-svg-eB1YXWCpJ5ioeh7J .node .label,#mermaid-svg-eB1YXWCpJ5ioeh7J .image-shape .label,#mermaid-svg-eB1YXWCpJ5ioeh7J .icon-shape .label{text-align:center;}#mermaid-svg-eB1YXWCpJ5ioeh7J .node.clickable{cursor:pointer;}#mermaid-svg-eB1YXWCpJ5ioeh7J .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eB1YXWCpJ5ioeh7J .arrowheadPath{fill:#333333;}#mermaid-svg-eB1YXWCpJ5ioeh7J .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eB1YXWCpJ5ioeh7J .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eB1YXWCpJ5ioeh7J .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eB1YXWCpJ5ioeh7J .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eB1YXWCpJ5ioeh7J .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eB1YXWCpJ5ioeh7J .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eB1YXWCpJ5ioeh7J .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eB1YXWCpJ5ioeh7J .cluster text{fill:#333;}#mermaid-svg-eB1YXWCpJ5ioeh7J .cluster span{color:#333;}#mermaid-svg-eB1YXWCpJ5ioeh7J div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eB1YXWCpJ5ioeh7J .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eB1YXWCpJ5ioeh7J rect.text{fill:none;stroke-width:0;}#mermaid-svg-eB1YXWCpJ5ioeh7J .icon-shape,#mermaid-svg-eB1YXWCpJ5ioeh7J .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eB1YXWCpJ5ioeh7J .icon-shape p,#mermaid-svg-eB1YXWCpJ5ioeh7J .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eB1YXWCpJ5ioeh7J .icon-shape .label rect,#mermaid-svg-eB1YXWCpJ5ioeh7J .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eB1YXWCpJ5ioeh7J .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eB1YXWCpJ5ioeh7J .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eB1YXWCpJ5ioeh7J :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 内核消息


systemd 服务
传统应用日志
安全/认证
脚本记录事件
按时间
按级别
实时跟踪
需要查看日志
日志来源?
需要历史数据?
journalctl -k -b -1
dmesg -T
journalctl -u 服务名
cat/grep /var/log/xxx
cat /var/log/auth.log
logger -t tag -p facility.level
需要过滤?
journalctl -u svc --since today
journalctl -u svc -p err
journalctl -u svc -f

12.6 日志分析实战决策图

以下决策图和示例展示了面对不同类型问题时的日志排查路径。
#mermaid-svg-e8RhU0wkR3ROfJSK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-e8RhU0wkR3ROfJSK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-e8RhU0wkR3ROfJSK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-e8RhU0wkR3ROfJSK .error-icon{fill:#552222;}#mermaid-svg-e8RhU0wkR3ROfJSK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-e8RhU0wkR3ROfJSK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-e8RhU0wkR3ROfJSK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-e8RhU0wkR3ROfJSK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-e8RhU0wkR3ROfJSK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-e8RhU0wkR3ROfJSK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-e8RhU0wkR3ROfJSK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-e8RhU0wkR3ROfJSK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-e8RhU0wkR3ROfJSK .marker.cross{stroke:#333333;}#mermaid-svg-e8RhU0wkR3ROfJSK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-e8RhU0wkR3ROfJSK p{margin:0;}#mermaid-svg-e8RhU0wkR3ROfJSK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-e8RhU0wkR3ROfJSK .cluster-label text{fill:#333;}#mermaid-svg-e8RhU0wkR3ROfJSK .cluster-label span{color:#333;}#mermaid-svg-e8RhU0wkR3ROfJSK .cluster-label span p{background-color:transparent;}#mermaid-svg-e8RhU0wkR3ROfJSK .label text,#mermaid-svg-e8RhU0wkR3ROfJSK span{fill:#333;color:#333;}#mermaid-svg-e8RhU0wkR3ROfJSK .node rect,#mermaid-svg-e8RhU0wkR3ROfJSK .node circle,#mermaid-svg-e8RhU0wkR3ROfJSK .node ellipse,#mermaid-svg-e8RhU0wkR3ROfJSK .node polygon,#mermaid-svg-e8RhU0wkR3ROfJSK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-e8RhU0wkR3ROfJSK .rough-node .label text,#mermaid-svg-e8RhU0wkR3ROfJSK .node .label text,#mermaid-svg-e8RhU0wkR3ROfJSK .image-shape .label,#mermaid-svg-e8RhU0wkR3ROfJSK .icon-shape .label{text-anchor:middle;}#mermaid-svg-e8RhU0wkR3ROfJSK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-e8RhU0wkR3ROfJSK .rough-node .label,#mermaid-svg-e8RhU0wkR3ROfJSK .node .label,#mermaid-svg-e8RhU0wkR3ROfJSK .image-shape .label,#mermaid-svg-e8RhU0wkR3ROfJSK .icon-shape .label{text-align:center;}#mermaid-svg-e8RhU0wkR3ROfJSK .node.clickable{cursor:pointer;}#mermaid-svg-e8RhU0wkR3ROfJSK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-e8RhU0wkR3ROfJSK .arrowheadPath{fill:#333333;}#mermaid-svg-e8RhU0wkR3ROfJSK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-e8RhU0wkR3ROfJSK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-e8RhU0wkR3ROfJSK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e8RhU0wkR3ROfJSK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-e8RhU0wkR3ROfJSK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e8RhU0wkR3ROfJSK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-e8RhU0wkR3ROfJSK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-e8RhU0wkR3ROfJSK .cluster text{fill:#333;}#mermaid-svg-e8RhU0wkR3ROfJSK .cluster span{color:#333;}#mermaid-svg-e8RhU0wkR3ROfJSK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-e8RhU0wkR3ROfJSK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-e8RhU0wkR3ROfJSK rect.text{fill:none;stroke-width:0;}#mermaid-svg-e8RhU0wkR3ROfJSK .icon-shape,#mermaid-svg-e8RhU0wkR3ROfJSK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e8RhU0wkR3ROfJSK .icon-shape p,#mermaid-svg-e8RhU0wkR3ROfJSK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-e8RhU0wkR3ROfJSK .icon-shape .label rect,#mermaid-svg-e8RhU0wkR3ROfJSK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e8RhU0wkR3ROfJSK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-e8RhU0wkR3ROfJSK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-e8RhU0wkR3ROfJSK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 内核/硬件问题


服务异常
按时间
按级别
实时跟踪
安全/认证
启动问题
磁盘空间
遇到系统问题
问题类型?
dmesg -T
需要历史日志?
journalctl -k -b -1
dmesg -T 当前缓冲区
journalctl -u 服务名
需要过滤?
journalctl -u svc --since today
journalctl -u svc -p err
journalctl -u svc -f
cat /var/log/auth.log
grep 'Failed password' /var/log/auth.log
journalctl -b
journalctl -b -1 -p err
journalctl --disk-usage
journalctl --vacuum-size=500M

典型排查流程示例

bash 复制代码
# 场景1:服务突然崩溃,排查原因
journalctl -u myservice -b -p err --no-pager

# 场景2:系统重启后排查上次崩溃原因
journalctl -b -1 -p err
dmesg -T | grep -i "oom\|panic\|bug"

# 场景3:SSH 暴力破解排查
grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn

# 场景4:磁盘空间被日志占满
journalctl --disk-usage
du -sh /var/log/*
journalctl --vacuum-size=200M
sudo logrotate -f /etc/logrotate.conf

# 场景5:在脚本中记录关键事件
#!/bin/bash
logger -t deploy -p local0.info "Deployment started: version=$VERSION"
# ... 部署逻辑 ...
if [ $? -ne 0 ]; then
    logger -t deploy -p local0.err "Deployment failed!"
    exit 1
fi
logger -t deploy -p local0.info "Deployment completed successfully"

12.7 本章小结

本章从日志产生、采集、存储、查询到管理的完整生命周期,系统介绍了 Linux 日志分析的工具链和排查方法。以下是日志排查速查总表:

日志排查速查总表

排查场景 首选命令 辅助命令 关键关注点
服务崩溃 journalctl -u svc -p err -b systemctl status svc 错误消息和退出码
内核崩溃/panic `dmesg -T grep -i panic` journalctl -k -b -1
OOM 事件 `dmesg -T grep -i oom` `journalctl -k
段错误 `dmesg grep segfault` addr2line -e prog <ip>
硬件故障 `dmesg -T grep -i error` journalctl -k -p err
SSH 入侵 grep "Failed" /var/log/auth.log lastb 来源 IP 和频率
启动失败 journalctl -b -p err journalctl -b -1 失败的 unit 和原因
磁盘满 journalctl --disk-usage du -sh /var/log/* 占用最大的日志
驱动加载 `dmesg -T grep ` lsmod
网络问题 `dmesg -T grep eth0` journalctl -u NetworkManager

选项速查总表

工具 最常用选项 说明
journalctl -u <unit> -p err -b 按服务+级别+启动过滤
journalctl -f 实时跟踪
journalctl --since "1 hour ago" 时间过滤
journalctl _PID=<pid> / _COMM=<name> 匹配字段过滤
journalctl --vacuum-size=500M 清理磁盘空间
journalctl -o json JSON 输出(脚本解析)
dmesg -T 人类可读时间戳
dmesg -w 实时跟踪
dmesg -l err 按级别过滤
dmesg -c 读取并清除
rsyslog rsyslogd -N1 检查配置语法
logger -t tag -p facility.level 指定标签和级别
logrotate -d 干跑测试
logrotate -f 强制执行
logrotate dateext + dateformat 日期后缀命名

本章从 systemd 日志查询(journalctl)、内核环形缓冲区(dmesg)、传统日志文件(/var/log)、内核消息底层接口(/proc/kmsg、klogd)、syslog 体系(rsyslog、logger)到日志生命周期管理(logrotate),构建了完整的日志分析知识体系。日常排查中,journalctl 是 systemd 系统的首选日志查询工具,dmesg 用于快速查看内核消息,/var/log 下的文本日志配合 grep/tail 适用于传统应用,logrotate 则是保障磁盘空间不被日志耗尽的关键管理手段。

相关推荐
-今昭-1 小时前
MooseFS分布式文件系统
linux·服务器·网络
byte轻骑兵1 小时前
【BlueZ 】蓝牙 HCI 协议基础:与 BlueZ 源码的层面对应关系
linux·hci·电脑蓝牙·嵌入式蓝牙·buez
Brilliantwxx2 小时前
【Linux】 进程(1) 从冯诺依曼体系到进程核心概念
linux·运维·服务器
城管不管2 小时前
重生——第十次面试之开源中国一面挂
java·linux·开发语言·算法·面试·职场和发展·开源
蜀道山老天师2 小时前
Zabbix监控Apache与Nginx应用实践完整指南
linux·运维·nginx·apache·zabbix
暖核2 小时前
Linux实战入门:从零编写第一个Bash Shell脚本
linux·运维·bash
March.s3 小时前
深入理解 Linux 系统启动原理
linux·运维·服务器
zbyyd3 小时前
Linux 基础与 Shell 命令
linux·运维·arm开发
起名真的太难了3 小时前
Linux系统运维与远程管理核心命令速查指南
linux·运维·服务器