14 - 日志系统
日志是系统管理的”黑匣子”。无论排查故障、安全审计还是性能分析,日志都是最重要的信息来源。本章覆盖 Linux 日志系统的完整知识体系,从传统 syslog 到 journald,从本地日志到集中化方案。
14.1 为什么日志如此重要
在系统管理中,日志扮演着不可替代的角色:
| 用途 | 说明 |
|---|---|
| 故障排查 | 服务挂掉、启动失败,日志是第一线索 |
| 安全审计 | 谁在什么时候从哪登录、执行了什么操作 |
| 性能分析 | 请求响应时间、资源消耗异常 |
| 合规要求 | 金融、医疗等行业需保留审计日志 |
| 容量规划 | 分析日志增长趋势,调整存储策略 |
| 入侵检测 | 异常登录模式、批量请求 |
系统管理的黄金法则:先看日志,再猜原因。
14.2 syslog 协议与传统实现
syslog 协议
syslog 是 Unix 系统最古老的日志协议(RFC 5424),定义了日志消息的传输格式和分类体系。每条 syslog 消息有两个关键属性:
设施(Facility)——标识消息来源:
| Facility | 代码 | 说明 |
|---|---|---|
kern | 0 | 内核消息 |
user | 1 | 用户级别 |
mail | 2 | 邮件系统 |
daemon | 3 | 系统守护进程 |
auth | 4 | 认证/授权 |
syslog | 5 | syslog 自身 |
lpr | 6 | 打印系统 |
news | 7 | 网络新闻 |
cron | 9 | 计划任务 |
authpriv | 10 | 安全认证(私密) |
local0-local7 | 16-23 | 本地自定义用途 |
优先级(Priority)——标识消息严重程度:
| 级别 | 数字 | 名称 | 含义 |
|---|---|---|---|
| emerg | 0 | EMERGENCY | 系统不可用 |
| alert | 1 | ALERT | 必须立即处理 |
| crit | 2 | CRITICAL | 严重错误 |
| err | 3 | ERROR | 一般错误 |
| warning | 4 | WARNING | 警告 |
| notice | 5 | NOTICE | 一般通知 |
| info | 6 | INFO | 信息 |
| debug | 7 | DEBUG | 调试 |
rsyslog
rsyslog 是大多数 Linux 发行版的默认 syslog 实现,功能强大且模块化。systemd 的 journald 可以接管日志,但 rsyslog 仍广泛用于 /var/log/ 传统文本日志。
# 安装(通常预装)
# Debian/Ubuntu
sudo apt install rsyslog
# Fedora/RHEL
sudo dnf install rsyslog
# Arch
sudo pacman -S rsyslog
# openSUSE
sudo zypper install rsyslog
# 启动
sudo systemctl enable --now rsyslog核心配置——/etc/rsyslog.conf:
# 模块加载
module(load="imuxsock") # 接受本地系统日志
module(load="imklog") # 接受内核日志
module(load="imjournal") # 从 journald 读取(配合 systemd)
# 规则:facility.priority action
# *.info;mail.none;authpriv.none /var/log/messages
# authpriv.* /var/log/secure
# mail.* -/var/log/maillog
# cron.* /var/log/cron
# *.emerg :omusrmsg:*
# local0.* /var/log/myapp.log
# 远程日志发送
# *.* @@central-log-server:514 # TCP
# *.* @central-log-server:514 # UDP
# 日志轮转调用(旧式)
# $IncludeConfig /etc/rsyslog.d/*.conf高级特性:
# 按属性过滤(RainerScript 语法)
if $programname == 'nginx' then /var/log/nginx/error.log
if $syslogseverity <= 3 then /var/log/critical.log
# 基于模板的输出格式
template(name="json-template" type="list") {
constant(value="{")
constant(value="\"timestamp\":\"") property(name="timereported" dateFormat="rfc3339")
constant(value="\",\"host\":\"") property(name="hostname")
constant(value="\",\"severity\":\"") property(name="syslogseverity-text")
constant(value="\",\"message\":\"") property(name="msg")
constant(value="\"}\n")
}
*.* action(type="omfile" file="/var/log/all.json" template="json-template")syslog-ng
syslog-ng 是 rsyslog 的主要替代方案,支持更丰富的传输协议和更灵活的消息处理管道。
# 安装
# Debian/Ubuntu: apt install syslog-ng
# Fedora/RHEL: dnf install syslog-ng
# Arch: pacman -S syslog-ng
# openSUSE: zypper install syslog-ngsyslog-ng 典型配置 (/etc/syslog-ng/syslog-ng.conf):
source s_sys {
system();
internal();
};
destination d_mesg { file("/var/log/messages"); };
destination d_auth { file("/var/log/secure"); };
destination d_cron { file("/var/log/cron"); };
filter f_mesg { level(info..emerg) and not facility(mail,authpriv,cron); };
filter f_auth { facility(authpriv); };
filter f_cron { facility(cron); };
log { source(s_sys); filter(f_mesg); destination(d_mesg); };
log { source(s_sys); filter(f_auth); destination(d_auth); };
log { source(s_sys); filter(f_cron); destination(d_cron); };14.3 journald——systemd 的二进制日志
systemd 自带的 journald 是一个现代化的二进制日志系统,与传统文本日志有根本性差异。
journald 的优势
| 特性 | journald | 传统 syslog |
|---|---|---|
| 存储格式 | 二进制(压缩、索引) | 纯文本 |
| 结构化字段 | 每条日志自动附加 UID、PID、unit、cmdline 等 | 仅时间+主机+消息 |
| 签名 | 支持 Seal=yes 防篡改 | 不支持 |
| 查询能力 | journalctl 字段级过滤 | grep 文本过滤 |
| 跨启动 | journalctl -b -1 查看历史启动 | 需手动保留 |
| 速率限制 | 内置防日志洪泛 | 依赖外部配置 |
journalctl 核心用法
# --- 基本查看 ---
journalctl # 所有日志(按时间排序)
journalctl -e # 跳到末尾
journalctl -n 100 # 最后 100 条
# --- 启动相关 ---
journalctl -b # 本次启动以来的日志
journalctl -b -1 # 上一次启动的日志
journalctl -b -2 # 倒数第二次启动
journalctl --list-boots # 列出所有启动记录
journalctl -k # 内核消息(等效 dmesg)
# --- 实时跟踪 ---
journalctl -f # 类似 tail -f
journalctl -f -u nginx
journalctl -f -u nginx -u php-fpm
# --- 时间过滤 ---
journalctl --since "2025-01-01 10:00:00"
journalctl --since "2025-01-01" --until "2025-01-02"
journalctl --since "1 hour ago"
journalctl --since "30 min ago"
journalctl --since yesterday
journalctl --since today
# --- 按 Unit 过滤 ---
journalctl -u nginx.service
journalctl -u sshd.service
journalctl --user -u myapp.service # 用户级服务
# --- 按优先级过滤 ---
journalctl -p err # 仅错误及以上
journalctl -p warning # 仅警告及以上
journalctl -p warning..err # 警告到错误范围
journalctl -b -p err # 本次启动的所有错误
# --- 按进程/用户过滤 ---
journalctl _PID=1234
journalctl _UID=1000
journalctl _COMM=sshd # 按可执行文件名
journalctl _SYSTEMD_UNIT=nginx.service
journalctl _TRANSPORT=kernel # 内核消息
# --- 输出格式 ---
journalctl -o short # 默认格式
journalctl -o short-full # 完整时间戳
journalctl -o short-iso # ISO 8601 时间
journalctl -o json # JSON(机器可读)
journalctl -o json-pretty # JSON 格式化
journalctl -o cat # 仅消息内容
journalctl -o verbose # 显示所有结构化字段
# --- JSON 配合 jq 分析 ---
journalctl -o json | jq 'select(._SYSTEMD_UNIT == "nginx.service") | .MESSAGE'
journalctl -o json | jq -r '.MESSAGE' | grep "ERROR" | wc -l
# --- 导出 ---
journalctl -b > /tmp/boot-log.txt # 文本导出
journalctl -o json > /tmp/full.json # JSON 导出
journalctl --output=export > journal.bin # 二进制导出(可导入另一系统)journald 配置
编辑 /etc/systemd/journald.conf:
[Journal]
# 存储模式
Storage=persistent # 持久化到 /var/log/journal
# persistent 磁盘持久化(重启保留)
# volatile 仅内存(重启丢失)
# auto 有 /var/log/journal 则持久化,否则仅内存
# none 不存储日志
# 压缩
Compress=yes # 启用 zstd 压缩
# 签名(防篡改)
Seal=yes # 对日志条目进行 FSS 签名
# 空间限制
SystemMaxUse=4G # 持久化日志总大小上限
SystemKeepFree=8G # 为其它文件保留空间
SystemMaxFileSize=128M # 单个日志文件最大尺寸
RuntimeMaxUse=256M # 内存中日志上限(volatile 模式)
RuntimeMaxFileSize=64M # 内存中单文件最大尺寸
# 时间限制
MaxRetentionSec=3month # 日志最长保留时间
MaxFileSec=1month # 单个日志文件覆盖前最长时间
# 转发
ForwardToSyslog=no # 是否转发到 syslog 守护进程
ForwardToConsole=no # 是否输出到控制台
ForwardToWall=yes # 紧急消息发送给所有登录用户
# 日志级别限制
MaxLevelStore=debug # 存储的最高级别
MaxLevelSyslog=debug # 转发到 syslog 的最高级别
MaxLevelConsole=info # 输出到控制台的最高级别
# 速率限制
RateLimitIntervalSec=30s
RateLimitBurst=10000
# 分割模式
SplitMode=uid # 按 UID 分割日志文件# 应用配置
sudo systemctl restart systemd-journald日志清理
# 查看磁盘占用
journalctl --disk-usage
# 按时间清理
sudo journalctl --vacuum-time=2weeks
sudo journalctl --vacuum-time=30d
# 按大小清理
sudo journalctl --vacuum-size=500M
sudo journalctl --vacuum-size=1G
# 按文件数量清理
sudo journalctl --vacuum-files=10
# 验证日志完整性
journalctl --verify创建持久化日志目录
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald14.4 /var/log/ 传统日志文件
即便使用了 journald,许多服务和工具仍将日志写入 /var/log/ 目录下的文本文件:
| 文件 | 内容 | 典型用途 |
|---|---|---|
/var/log/messages | 综合系统日志 | Debian/openSUSE 主要日志 |
/var/log/syslog | 综合系统日志 | Ubuntu 的主要日志 |
/var/log/auth.log | 认证相关日志 | Debian/Ubuntu |
/var/log/secure | 认证/授权日志 | Fedora/RHEL |
/var/log/kern.log | 内核消息 | Debian/Ubuntu |
/var/log/boot.log | 启动过程日志 | systemd 系统启动消息 |
/var/log/faillog | 登录失败记录 | faillog 命令读取 |
/var/log/lastlog | 最后一次登录 | lastlog 命令读取 |
/var/log/dmesg | 启动时内核环形缓冲区快照 | dmesg 命令输出 |
/var/log/httpd/ | Apache HTTPD 日志 | 访问日志和错误日志 |
/var/log/nginx/ | nginx 日志 | access.log + error.log |
/var/log/mysql/ | MySQL/MariaDB 日志 | 数据库错误、慢查询 |
/var/log/audit/ | 审计日志 | auditd 的安全审计 |
/var/log/cron | cron 任务执行记录 | 计划任务日志 |
实时查看日志
# 实时跟踪
tail -f /var/log/messages
tail -f /var/log/auth.log
tail -f /var/log/syslog
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
# 同时监控多个文件
tail -f /var/log/auth.log /var/log/nginx/error.log
# 使用 multitail(彩色、分栏)
# Debian/Ubuntu: apt install multitail
# Fedora: dnf install multitail
# Arch: pacman -S multitail
multitail /var/log/auth.log /var/log/nginx/error.log14.5 logrotate——日志轮转
不配置日志轮转,日志文件会无限增长,最终填满磁盘。logrotate 是管理日志轮转的标准工具。
核心配置
主配置文件 /etc/logrotate.conf:
# 每周轮转一次
weekly
# 保留 4 个历史版本
rotate 4
# 轮转后创建新的空日志文件
create
# 使用日期作为后缀(如 messages-20250101 而非 messages.1)
dateext
# 压缩轮转后的日志
compress
# 不轮转空文件
notifempty
# 包含子配置
include /etc/logrotate.d服务专属配置
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily # 每天轮转
missingok # 日志不存在不报错
rotate 14 # 保留 14 天
compress # 压缩旧日志
delaycompress # 延迟压缩一天(避免影响写入)
notifempty # 空文件不轮转
create 0640 nginx nginx # 新日志文件的权限和所有者
sharedscripts # 所有日志轮转后统一执行一次 postrotate
postrotate
# 轮转后通知 nginx 重新打开日志文件
if [ -f /var/run/nginx.pid ]; then
kill -USR1 $(cat /var/run/nginx.pid)
fi
endscript
}常用指令
| 指令 | 说明 |
|---|---|
daily / weekly / monthly / yearly | 轮转频率 |
rotate N | 保留多少个历史版本 |
size 100M | 达到指定大小触发轮转 |
maxsize 500M | 超过此大小强制轮转 |
compress | gzip 压缩旧日志 |
delaycompress | 延迟一个周期再压缩 |
missingok | 日志文件不存在时不报错 |
copytruncate | 复制后清空原文件(适用于无法发信号的服务) |
postrotate/endscript | 轮转后执行脚本 |
prerotate/endscript | 轮转前执行脚本 |
dateext / dateformat | 使用日期作为轮转后缀 |
olddir | 将旧日志移动到指定目录 |
sharedscripts | 匹配多个日志时只执行一次脚本 |
手动触 发与调试
# 强制轮转
sudo logrotate -f /etc/logrotate.conf
sudo logrotate -f /etc/logrotate.d/nginx
# 调试模式(dry-run,不实际执行)
sudo logrotate -d /etc/logrotate.conf
sudo logrotate -d /etc/logrotate.d/nginx
# 详细输出
sudo logrotate -v /etc/logrotate.conf14.6 dmesg——内核环形缓冲区
dmesg 读取内核的环形缓冲区,记录启动过程、硬件检测、驱动加载、内核错误等。
# 基本查看
dmesg
dmesg -H # 人类可读(颜色 + 时间)
dmesg -T # 显示可读时间戳
dmesg -w # 实时跟踪(类似 tail -f)
# 按级别过滤
dmesg -l err # 仅错误
dmesg -l err,warn # 错误 + 警告
dmesg -l emerg,alert,crit,err # 只显示严重消息
# 按设施过滤
dmesg -f kern
dmesg -f daemon
# 常见使用模式
dmesg | grep -i error
dmesg | grep -i fail
dmesg | grep -i "out of memory"
dmesg | grep -i firmware
dmesg | grep -iE "(sda|nvme|ata)" # 存储设备
dmesg | grep -iE "(drm|gpu|amdgpu)" # GPU 相关
dmesg | grep -iE "(usb|bluetooth)" # USB 和蓝牙
dmesg | grep -iE "(thermal|temperature)" # 温度相关
# 配合 journalctl
journalctl -k # 等效的 journalctl 命令14.7 日志分析技巧
基本分析命令
# 统计错误出现次数
journalctl -b -p err --no-pager | wc -l
dmesg | grep -i error | wc -l
# 找出最活跃的日志来源
journalctl -b | awk '{print $5}' | sort | uniq -c | sort -rn | head -10
# 分析 SSH 登录记录
grep "Accepted" /var/log/auth.log
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn
# 分析 nginx 请求量
cat /var/log/nginx/access.log | awk '{print $4}' | cut -d: -f1 | uniq -c
# 按时间段分析
journalctl --since "2025-01-01 08:00" --until "2025-01-01 12:00" -p err快速排查流程
1. 确定时间范围:问题何时开始?
2. journalctl --since "疑点时 间" -p err # 搜索错误
3. systemctl --failed # 检查失败的服务
4. dmesg -l err,warn # 检查内核问题
5. tail -f /var/log/messages # 实时监控
6. df -h && free -h # 排除资源耗尽
日志管理最佳实践
- 设置合理保留策略:日志自动清理,防止磁盘满载
- 使用时间同步:NTP 确保所有服务器日志时间戳一致
- 结构化日志:应用程序输出 JSON 格式便于自动化分析
- 分离日志存储:日志单独挂载分区,避免影响应用
- 定期审查:不应只在出问题时才看日志
14.8 集中化日志简介
当服务器数量增长到几十上百台时,逐一登录查看日志不再可行。集中式日志管理是生产环境的标准做法。
ELK / EFK 栈
- Elasticsearch:分布式搜索与存储引擎,存储索引后的日志
- Logstash:日志收集与处理管道(格式转换、过滤、增强)
- Filebeat(EFK 中替代 Logstash):轻量级日志采集代理
- Kibana:可视化面板,搜索、图表、告警
[服务器] → Filebeat → Elasticsearch → Kibana(网页界面)
[服务器] → Filebeat ↗
[服务器] → Filebeat ↗所有服务器安装 Filebeat 收集日志,统一发送到 Elasticsearch 集群,管理员在 Kibana 面板搜索分析。
集中化日志的详细部署配置将在 60-监控系统(Prometheus+Grafana) 中详细介绍,包括 Prometheus、Grafana、Loki 等替代方案。
journald 远程传输
journald 自身也支持日志远程传输:
# 在收集服务器上启用 systemd-journal-remote
# /etc/systemd/journal-remote.conf
[Remote]
Seal=true
SplitMode=host
# /etc/systemd/journal-upload.conf(发送端)
[Upload]
URL=https://log-collector.example.com:19532