日志管理
日志是排查问题、审计安全事件、分析系统行为的核心数据来源。本文介绍如何在 EL 系发行版上有效地管理和分析日志。
日志体系概览
Section titled “日志体系概览”在 CentOS/AlmaLinux/Rocky Linux 中,日志系统由两个核心组件构成:
- journald(systemd-journald):systemd 的日志守护进程,收集所有 systemd 单元、内核和启动日志,存储为二进制格式
- rsyslog:传统的 syslog 守护进程,接收 journald 转发的日志,写入文本文件,支持远程传输
两者协同工作:journald 负责收集,rsyslog 负责持久化存储和转发。
应用/服务 → journald(二进制日志)→ rsyslog → /var/log/下的文本日志 ↓ 远程日志服务器journald 配置与使用
Section titled “journald 配置与使用”# 查看所有日志journalctl
# 查看最新的日志(类似 tail -f)journalctl -f
# 只看最近 100 行journalctl -n 100
# 查看某个服务的日志journalctl -u nginxjournalctl -u sshd -f
# 查看内核日志journalctl -k
# 按时间范围查看journalctl --since "2026-03-20 00:00:00" --until "2026-03-20 23:59:59"journalctl --since "1 hour ago"journalctl --since today
# 按优先级过滤(0=emerg, 3=err, 4=warning, 6=info)journalctl -p err # 只看错误及以上journalctl -p warning -u nginx # nginx 的警告级别日志
# 输出为 JSON 格式journalctl -u nginx -o json-pretty -n 5
# 查看磁盘使用量journalctl --disk-usage默认情况下,journald 日志可能仅存储在内存中(/run/log/journal/),重启后丢失。开启持久化存储:
# 创建持久化目录sudo mkdir -p /var/log/journalsudo systemd-tmpfiles --create --prefix /var/log/journal
# 编辑配置sudo tee /etc/systemd/journald.conf.d/persistent.conf > /dev/null <<'EOF'[Journal]Storage=persistentSystemMaxUse=2GSystemMaxFileSize=256MMaxRetentionSec=3monthCompress=yesEOF
# 重启 journaldsudo systemctl restart systemd-journald关键参数说明:
| 参数 | 说明 |
|---|---|
Storage=persistent | 持久化存储到磁盘 |
SystemMaxUse=2G | 日志最多占用 2G 磁盘空间 |
SystemMaxFileSize=256M | 单个日志文件最大 256M |
MaxRetentionSec=3month | 最多保留 3 个月 |
Compress=yes | 启用压缩 |
rsyslog 配置
Section titled “rsyslog 配置”默认日志文件
Section titled “默认日志文件”# 查看 rsyslog 默认规则cat /etc/rsyslog.conf
# EL 系默认的日志分布:# /var/log/messages - 大多数系统日志# /var/log/secure - 认证与授权日志# /var/log/maillog - 邮件日志# /var/log/cron - cron 任务日志# /var/log/boot.log - 启动日志自定义日志规则
Section titled “自定义日志规则”# 为特定程序创建独立的日志文件sudo tee /etc/rsyslog.d/myapp.conf > /dev/null <<'EOF'# 将 myapp 标签的日志写入独立文件if $programname == 'myapp' then /var/log/myapp.log& stop
# 将所有 local6 设施的日志写入指定文件local6.* /var/log/custom-app.logEOF
sudo systemctl restart rsyslogrsyslog 支持自定义日志格式:
sudo tee /etc/rsyslog.d/custom-template.conf > /dev/null <<'EOF'# 自定义日志格式模板template(name="CustomFormat" type="string" string="%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag%%msg%\n")
# 对特定日志应用自定义格式local6.* /var/log/custom-app.log;CustomFormatEOF集中式日志(远程收集)
Section titled “集中式日志(远程收集)”在日志收集服务器上配置接收端:
sudo tee /etc/rsyslog.d/remote.conf > /dev/null <<'EOF'# 启用 TCP 接收(端口 514)module(load="imtcp")input(type="imtcp" port="514")
# 按主机名分目录存储远程日志template(name="RemoteHost" type="string" string="/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log")
# 远程日志使用自定义存储路径if $fromhost-ip != '127.0.0.1' then { action(type="omfile" dynaFile="RemoteHost") stop}EOF
sudo systemctl restart rsyslog
# 防火墙放行sudo firewall-cmd --permanent --add-port=514/tcpsudo firewall-cmd --reload在客户端上配置日志转发:
sudo tee /etc/rsyslog.d/forward.conf > /dev/null <<'EOF'# 将所有日志通过 TCP 转发到远程服务器*.* @@log-server.example.com:514
# @ 表示 UDP# @@ 表示 TCP(推荐,可靠性更高)
# 如果远程不可用,启用磁盘缓冲队列action( type="omfwd" target="log-server.example.com" port="514" protocol="tcp" queue.type="LinkedList" queue.filename="forward_queue" queue.maxdiskspace="1g" queue.saveonshutdown="on" action.resumeRetryCount="-1")EOF
sudo systemctl restart rsyslog使用 TLS 加密传输
Section titled “使用 TLS 加密传输”生产环境中,日志传输应当加密:
# 安装 TLS 模块sudo dnf install rsyslog-gnutls -y
# 日志服务器端 TLS 配置sudo tee /etc/rsyslog.d/tls-server.conf > /dev/null <<'EOF'global( defaultNetstreamDriver="gtls" defaultNetstreamDriverCAFile="/etc/pki/rsyslog/ca.pem" defaultNetstreamDriverCertFile="/etc/pki/rsyslog/server-cert.pem" defaultNetstreamDriverKeyFile="/etc/pki/rsyslog/server-key.pem")
module(load="imtcp" StreamDriver.Name="gtls" StreamDriver.Mode="1" StreamDriver.AuthMode="x509/name")
input(type="imtcp" port="6514")EOF
# 客户端 TLS 配置sudo tee /etc/rsyslog.d/tls-client.conf > /dev/null <<'EOF'global( defaultNetstreamDriver="gtls" defaultNetstreamDriverCAFile="/etc/pki/rsyslog/ca.pem" defaultNetstreamDriverCertFile="/etc/pki/rsyslog/client-cert.pem" defaultNetstreamDriverKeyFile="/etc/pki/rsyslog/client-key.pem")
action( type="omfwd" target="log-server.example.com" port="6514" protocol="tcp" StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name")EOFlogrotate 日志轮转
Section titled “logrotate 日志轮转”logrotate 防止日志文件无限增长,自动压缩和清理旧日志。
cat /etc/logrotate.conf
# 默认设置:# - 每周轮转# - 保留 4 周# - 创建新文件# - 包含 /etc/logrotate.d/ 目录下的配置为应用创建轮转规则
Section titled “为应用创建轮转规则”sudo tee /etc/logrotate.d/myapp > /dev/null <<'EOF'/var/log/myapp.log/var/log/myapp-error.log{ daily # 每天轮转 missingok # 文件不存在不报错 rotate 30 # 保留 30 份 compress # gzip 压缩 delaycompress # 延迟一次再压缩(便于程序继续写入) notifempty # 空文件不轮转 create 0640 myapp myapp # 创建新文件的权限和属主 dateext # 使用日期作为后缀(而非数字) dateformat -%Y%m%d # 日期格式 sharedscripts # 多个文件只执行一次脚本 postrotate # 轮转后通知应用重新打开日志文件 /bin/kill -USR1 $(cat /var/run/myapp.pid 2>/dev/null) 2>/dev/null || true endscript}EOFNginx 日志轮转示例
Section titled “Nginx 日志轮转示例”sudo tee /etc/logrotate.d/nginx > /dev/null <<'EOF'/var/log/nginx/*.log { daily missingok rotate 60 compress delaycompress notifempty create 0640 nginx adm dateext sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid) endscript}EOF手动测试轮转
Section titled “手动测试轮转”# 调试模式(不实际执行,只显示会做什么)sudo logrotate -d /etc/logrotate.d/myapp
# 强制执行轮转sudo logrotate -f /etc/logrotate.d/myapp
# 查看 logrotate 状态文件cat /var/lib/logrotate/logrotate.status日志分析技巧
Section titled “日志分析技巧”使用 grep 筛选
Section titled “使用 grep 筛选”# 搜索错误信息grep -i "error" /var/log/messagesgrep -i "failed" /var/log/secure
# 搜索特定时间段grep "Mar 20 1[0-5]:" /var/log/messages # 3月20日 10:00-15:59 的日志
# 排除干扰信息grep -i "error" /var/log/messages | grep -v "No error"
# 递归搜索目录grep -r "out of memory" /var/log/
# 显示匹配行前后的上下文grep -B 3 -A 5 "kernel panic" /var/log/messages
# 统计出现次数grep -c "Failed password" /var/log/secure使用 awk 分析
Section titled “使用 awk 分析”# 统计各 IP 的 SSH 失败登录次数awk '/Failed password/ {for(i=1;i<=NF;i++) if($i=="from") print $(i+1)}' /var/log/secure \ | sort | uniq -c | sort -rn | head -20
# 按小时统计 Nginx 请求数awk '{print $4}' /var/log/nginx/access.log \ | cut -d: -f1-2 | sort | uniq -c
# 统计 HTTP 状态码分布awk '{print $9}' /var/log/nginx/access.log \ | sort | uniq -c | sort -rn
# 找出请求最慢的 URL(假设响应时间在最后一列)awk '{print $NF, $7}' /var/log/nginx/access.log \ | sort -rn | head -20
# 统计每分钟请求量(找出流量高峰)awk '{print $4}' /var/log/nginx/access.log \ | cut -d: -f1-3 | sort | uniq -c | sort -rn | head -10使用 sed 和其他工具
Section titled “使用 sed 和其他工具”# 提取特定时间段的日志(journalctl 格式)sed -n '/^Mar 20 14:00/,/^Mar 20 15:00/p' /var/log/messages
# 实时监控并高亮关键字tail -f /var/log/messages | grep --color=auto -i "error\|warning\|fail"
# 使用 last 查看登录记录last -20 # 最近 20 条登录记录lastb -20 # 最近 20 条失败登录last reboot # 重启记录
# 使用 ausearch 搜索审计日志(需要 auditd)ausearch -m avc # SELinux 拒绝事件ausearch -k login_events # 按审计规则搜索实用日志分析脚本
Section titled “实用日志分析脚本”#!/bin/bash# 每日日志摘要报告
DATE=$(date -d yesterday '+%b %d')REPORT="/tmp/log_summary_$(date +%Y%m%d).txt"
{echo "=========================================="echo " 日志摘要报告 - ${DATE}"echo "=========================================="echo ""
echo "--- SSH 失败登录 TOP 10 ---"grep "${DATE}" /var/log/secure 2>/dev/null \ | grep "Failed password" \ | awk '{for(i=1;i<=NF;i++) if($i=="from") print $(i+1)}' \ | sort | uniq -c | sort -rn | head -10echo ""
echo "--- 错误日志统计 ---"echo "messages 中的 error: $(grep -ci "error" /var/log/messages 2>/dev/null || echo 0)"echo "secure 中的 failure: $(grep -ci "fail" /var/log/secure 2>/dev/null || echo 0)"echo ""
echo "--- 磁盘空间告警 ---"df -h | awk 'NR>1 {gsub(/%/,"",$5); if($5+0>80) print $0}'echo ""
echo "--- 最近重启记录 ---"last reboot | head -5echo ""
echo "--- OOM Killer 事件 ---"grep -c "Out of memory" /var/log/messages 2>/dev/null || echo "0 次"
} > "$REPORT"
cat "$REPORT"# 可选:邮件发送# mail -s "日志摘要 ${DATE}" admin@example.com < "$REPORT"进阶:集中式日志平台
Section titled “进阶:集中式日志平台”当服务器数量增多时,需要专门的日志平台进行统一收集、搜索和分析。
ELK Stack(Elasticsearch + Logstash + Kibana)
Section titled “ELK Stack(Elasticsearch + Logstash + Kibana)”ELK 是最流行的日志分析平台:
- Elasticsearch:日志存储和搜索引擎
- Logstash:日志收集和处理管道
- Kibana:Web 可视化界面
使用 Filebeat 作为轻量级日志采集器:
# 安装 Filebeatsudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
sudo tee /etc/yum.repos.d/elastic.repo > /dev/null <<'EOF'[elastic-8.x]name=Elastic repository for 8.x packagesbaseurl=https://artifacts.elastic.co/packages/8.x/yumgpgcheck=1gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearchenabled=1autorefresh=1type=rpm-mdEOF
sudo dnf install filebeat -y
# 配置 Filebeat 采集系统日志sudo tee /etc/filebeat/filebeat.yml > /dev/null <<'EOF'filebeat.inputs: - type: log enabled: true paths: - /var/log/messages - /var/log/secure fields: type: syslog
- type: log enabled: true paths: - /var/log/nginx/access.log fields: type: nginx-access
output.elasticsearch: hosts: ["https://elasticsearch:9200"] username: "elastic" password: "your_password"EOF
sudo systemctl enable --now filebeatGrafana Loki
Section titled “Grafana Loki”Loki 是 Grafana 推出的轻量级日志聚合系统,对标 ELK 但资源消耗更低:
# 安装 Promtail(Loki 的日志采集器)cd /tmpcurl -LO https://github.com/grafana/loki/releases/download/v3.0.0/promtail-linux-amd64.zipunzip promtail-linux-amd64.zipsudo cp promtail-linux-amd64 /usr/local/bin/promtailsudo chmod +x /usr/local/bin/promtail
# 基础配置sudo mkdir -p /etc/promtailsudo tee /etc/promtail/config.yml > /dev/null <<'EOF'server: http_listen_port: 9080
positions: filename: /var/lib/promtail/positions.yaml
clients: - url: http://loki-server:3100/loki/api/v1/push
scrape_configs: - job_name: syslog static_configs: - targets: - localhost labels: job: syslog host: __HOSTNAME__ __path__: /var/log/messages
- job_name: nginx static_configs: - targets: - localhost labels: job: nginx host: __HOSTNAME__ __path__: /var/log/nginx/*.logEOF
# 替换主机名sudo sed -i "s/__HOSTNAME__/$(hostname)/" /etc/promtail/config.ymlLoki 的优势在于它不索引日志全文,而是通过标签(labels)组织日志流,资源消耗远低于 Elasticsearch,非常适合中小规模部署。
| 任务 | 工具 |
|---|---|
| 查看服务日志 | journalctl -u 服务名 |
| 查看系统日志 | /var/log/messages 或 journalctl |
| 日志持久化 | journald Storage=persistent |
| 日志轮转 | logrotate |
| 远程集中收集 | rsyslog TCP/TLS 转发 |
| 日志搜索分析 | grep / awk / journalctl 过滤 |
| 大规模日志平台 | ELK Stack 或 Grafana Loki |
养成定期检查日志的习惯,并通过自动化脚本或日志平台及时发现异常,是保障服务器稳定运行的关键实践。