14 - 日志系统

日志是系统管理的”黑匣子”。无论排查故障、安全审计还是性能分析,日志都是最重要的信息来源。本章覆盖 Linux 日志系统的完整知识体系,从传统 syslog 到 journald,从本地日志到集中化方案。


14.1 为什么日志如此重要

在系统管理中,日志扮演着不可替代的角色:

用途说明
故障排查服务挂掉、启动失败,日志是第一线索
安全审计谁在什么时候从哪登录、执行了什么操作
性能分析请求响应时间、资源消耗异常
合规要求金融、医疗等行业需保留审计日志
容量规划分析日志增长趋势,调整存储策略
入侵检测异常登录模式、批量请求

系统管理的黄金法则:先看日志,再猜原因。


14.2 syslog 协议与传统实现

syslog 协议

syslog 是 Unix 系统最古老的日志协议(RFC 5424),定义了日志消息的传输格式和分类体系。每条 syslog 消息有两个关键属性:

设施(Facility)——标识消息来源:

Facility代码说明
kern0内核消息
user1用户级别
mail2邮件系统
daemon3系统守护进程
auth4认证/授权
syslog5syslog 自身
lpr6打印系统
news7网络新闻
cron9计划任务
authpriv10安全认证(私密)
local0-local716-23本地自定义用途

优先级(Priority)——标识消息严重程度:

级别数字名称含义
emerg0EMERGENCY系统不可用
alert1ALERT必须立即处理
crit2CRITICAL严重错误
err3ERROR一般错误
warning4WARNING警告
notice5NOTICE一般通知
info6INFO信息
debug7DEBUG调试

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-ng

syslog-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-journald

14.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/croncron 任务执行记录计划任务日志

实时查看日志

# 实时跟踪
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.log

14.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超过此大小强制轮转
compressgzip 压缩旧日志
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.conf

14.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 # 排除资源耗尽

日志管理最佳实践

  1. 设置合理保留策略:日志自动清理,防止磁盘满载
  2. 使用时间同步:NTP 确保所有服务器日志时间戳一致
  3. 结构化日志:应用程序输出 JSON 格式便于自动化分析
  4. 分离日志存储:日志单独挂载分区,避免影响应用
  5. 定期审查:不应只在出问题时才看日志

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