Linux 日志分析与管理

日志系统

日志记录简单来说就是记录系统何时由哪个程序做了什么行为,发生了什么事件等等。

常见日志文件有下面一些:

  • /var/log/boot.log:开机硬件检测产生的记录信息,在 CentOS 合并到了 dmesg 中。
  • /var/log/cron:记录 crontab 调度工作运行情况。
  • /var/log/dmesg:记录开机检测信息。
  • /var/log/lastlog:记录系统上所有账号最近一次登录的信息。
  • /var/log/maillog:记录邮件的往来信息。
  • /var/log/messages:记录所有错误与重要信息。
  • /var/log/secure:记录账号登录验证信息。
  • /var/log/wtmp/var/log/faillog:记录正确登录与错误登录时的账号信息。
  • /var/log/服务名:不同服务会使用各自的目录记录日志。

系统提供日志记录相关的服务有:

  • systemd-journald.service:由 systemd 提供的日志系统;
  • rsyslog.service:主要登录系统与网络等服务的信息;
  • logrotate:对日志文件进行轮替处理。

日志文件记录内容由四段组成:

  • 事件发生的时间与日期;
  • 发生此事件的主机名称;
  • 启动此事件的服务名称或命令与函数名;
  • 信息的实际内容。

日志规范

rsyslog 的配置文件位于 /etc/rsyslog.conf,可以配置服务、日志等级和日志存放位置:

[root@101c7 ~]$ cat /etc/rsyslog.conf 
$ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
$ModLoad imjournal # provides access to the systemd journal
$WorkDirectory /var/lib/rsyslog
$IncludeConfig /etc/rsyslog.d/*.conf
mail.*                                                  -/var/log/maillog
uucp,news.crit                                          /var/log/spooler

Linux 的 syslog 有规范服务类型如下:

编号 类别 说明
0 kernel 内核产生日志,比如硬件检测和内核功能启用
1 user 使用者层级产生的日志
2 mail 与邮件收发者有关的日志
3 daemon 系统服务产生的日志
4 auth 与认证/授权有关的日志
5 syslog rsyslogd 程序产生的日志
6 lpr 与打印相关的日志
7 news 与新闻组服务有关日志
8 uucp Unix to Unix Copy Protocol,早期 Unix 系统间程序数据交换日志
9 cron 与工作调度有关日志
10 authpriv 与 auth 类似,但记录较多私人信息,包括 pam 模块的运行等
11 ftp 与 FTP 通讯协议有关的日志
16~23 local0~7 保留给本机用户使用的一些日志文件信息,较常与终端机互动

日志等级有八级,根据 syslog.h 的定义如下:

等级数值 等级名称 说明
7 debug Debug 时产生的日志
6 info 一些基本运行记录
5 notice 正常提示信息
4 warning (warn) 警示信息,可能有问题,但还不至于影响服务运行
3 err (error) 重大错误信息,例如配置文件错误导致的服务不能启动
2 crit 致命错误信息
1 alert 告警信息
0 emerg (panic) 紧急级别,意味着出现了硬件问题导致系统无法运行

在服务名和日志等级之间使用符号进行设置:

  • . :代表比后面等级更严重的日志都会被记录下来;
  • .= :代表只记录后面等级的日志;
  • .! :代表除该等级以外的其他等级日志都被记录。

如果是 *.emerg 的写法,则代表所有程序的 emerg 等级的日志。

在日志文件记录位置前的减号 - 代表日志会先放到内存中缓存,直到达到一定大小才会写入到硬盘。

例如,要在 /var/log/messages 中排除掉 newsmail 的日志,可以设置为:

*,*;news,mail.none /var/log/messages

或者:

*.*;news.none;mail.none /var/log/messages

设置好记录规则后,需要重启 rsyslog 服务才能生效。

注意,如果在记录中的日志文件被其他程序打开并修改,rsyslog 将不会再向这个日志文件中写入新内容,此时也需要重启 rsyslog 服务才能恢复。

如果实在要向日志文件中插入数据,可以使用 logger 命令,用法为:logger [-p 服务名称.日志等级] "内容"

[root@101c7 ~]$ logger -p user.info "msg from logger"
[root@101c7 ~]$ journalctl -f
Sep 19 06:34:57 101c7 root[10003]: msg from logger

这通常写在脚本中用来记录时间戳。

日志收集

rsyslogd 具有日志收集功能,也就是用一台主机做服务端,收集客户端发送的日志。

日志收集功能需要手动启用,可以在 /etc/rsyslog.conf 中修改相关配置。例如,在服务端:

[root@101c7 ~]$ vi /etc/rsyslog.conf
# Provides UDP syslog reception
#$ModLoad imudp
#$UDPServerRun 514

# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514

如上所示,开启了通过 TCP 传输日志,监听端口 514。重启服务以使设置生效。

对于客户端,只需在 /etc/rsyslog.conf 文件中设置一条记录,将日志文件发送到服务端。例如,如果服务端 IP 地址为 192.168.2.234,则可以这样设置:*.* @@192.168.2.234

重启后生效,服务端接收的日志内容中的第二段会标明日志发送的来源主机。

日志轮替

执行日志轮替操作的程序 logrotate 会定期将旧有日志文件重命名,再建立一个空的新文件来写入新日志。

由于是定期执行,所以可以到 /etc/cron.daily 中查看定时任务内容:

[root@101c7 ~]$ cat /etc/cron.daily/logrotate 
#!/bin/sh

/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0

在执行脚本中调用了配置文件 /etc/logrotate.conf,它用来在没有指定参数的情况下作为默认值使用:

[root@101c7 ~]$ cat /etc/logrotate.conf 
# see "man logrotate" for details
# rotate log files weekly
weekly

# keep 4 weeks worth of backlogs
rotate 4

# create new (empty) log files after rotating old ones
create

# use date as a suffix of the rotated file
dateext

# uncomment this if you want your log files compressed
#compress

# RPM packages drop log rotation information into this directory
include /etc/logrotate.d

# no packages own wtmp and btmp -- we'll rotate them here
/var/log/wtmp {
    monthly
    create 0664 root utmp
        minsize 1M
    rotate 1
}

/var/log/btmp {
    missingok
    monthly
    create 0600 root utmp
    rotate 1
}

由配置文件注释可以得知目前的设置为:每周进行一次轮替工作,保留最多四个记录,轮替后创建新的空文件作日志记录,被轮替文件名上加日期,不压缩日志,读取 /etc/logrotate.d 目录内的配置文件。

下面以 {} 括起来的段落是针对不同文件的单独配置,例如针对 wtmp,轮替周期为月而不是周,指定新建文件的权限与所属,文件大小超过 1M 才进行轮替(比时间条件优先),最后是只保留一个记录。

再看看保存在 /etc/logrotate.d 中针对个别程序的独立设置:

[root@101c7 ~]$ cat /etc/logrotate.d/syslog 
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
{
    missingok
    sharedscripts
    postrotate
        /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
    endscript
}

logrotate 配置文件基本写法如下:

  • 文件名:以绝对路径写在最前面,可以每行一个表示处理多个日志文件。
  • 参数:用 {} 括起来。
  • 执行脚本:可调用外部命令,需要写入 sharedscripts...endscript 里面。可以用 prerotate/postrotate 表示执行命令的时机在启动 logrotate 之前/之后。这个特性可以用于处理加上特殊属性的文件。例如处理 messages 文件上的追加属性。
[root@101c7 ~]$ vi /etc/logrotate.d/syslog 
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
{
    missingok
    sharedscripts
    prerotate
        /usr/bin/chattr -a /var/log/messages
    endscript
    sharedscripts
    postrotate
        /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
        /usr/bin/chattr +a /var/log/messages
    endscript
}

配置修改完毕后可以使用 systemctl reload 来让配置生效,或者手动强制执行一次:

[root@101c7 ~]$ logrotate -vf /etc/logrotate.conf
reading config file /etc/logrotate.conf
including /etc/logrotate.d
reading config file bootlog
reading config file chrony

日志查询

systemd 使用 systemd-journald.service 服务来记录日志,会记录所有经由 systemd 所管理服务产生的日志。

由于 systemd-journald 把日志存在内存中,因此重启后上次登录时产生的日志文件都不存在了。可以搭配 rsyslogd 来记录需要的日志。

journalctl 命令使用语法为:journalctl [-nrpf] [--since TIME] [--until TIME] 选项

主要参数和选项为:

参数或选项 说明
-n 打印最近的 n 条日志
-r 反向输出,最新的记录在前
-p 只查询指定等级日志
-f 类似 tail -f 来持续输出
--since --until 设置开始与结束时间来筛选日志
_SYSTEMD_UNIT=unit.service 只输出 unit.service 的日志
_COMM=bash 只输出与 bash 有关的日志
_PID=pid 只输出指定 pid 进程的日志
_UID=uid 只输出指定 uid 用户的日志
SYSLOG_FACILITY=[0-23] 使用 syslog.h 规范的服务类型编号来调用数据

如只查看 9.1 到 9.3 号之间的日志:

[root@101c7 ~]$ journalctl --since "2020-09-01 00:00:00" --until "2020-09-04 00:00:00"
-- Logs begin at Sat 2021-09-18 23:12:47 EDT, end at Sun 2021-09-19 06:01:01 EDT. --

查询搜索错误 err 等级日志:

[root@101c7 ~]$ journalctl -p err
-- Logs begin at Sat 2021-09-18 23:12:47 EDT, end at Sun 2021-09-19 06:01:01 EDT. --
Sep 18 23:12:47 101c7 kernel: Detected CPU family 17h model 8

只查询和 sshd 服务有关的最近 3 条普通日志:

[root@101c7 ~]$ journalctl _SYSTEMD_UNIT=sshd.service -n 3 -p info
-- Logs begin at Sat 2021-09-18 23:12:47 EDT, end at Sun 2021-09-19 06:01:01 EDT. --
Sep 18 23:12:54 101c7 sshd[2610]: Accepted password for root from 192.168.2.101 port 62528 ssh2
Sep 18 23:12:55 101c7 sshd[2923]: Accepted password for root from 192.168.2.101 port 59039 ssh2
Sep 18 23:12:55 101c7 sshd[2956]: Accepted password for root from 192.168.2.101 port 59040 ssh2

如果想要保存 journalctl 的日志文件,不需要修改 /etc/systemd/journald.conf 文件,只需要在 /var/log/ 下面新建一个 journal 的目录并处理一下权限就可以了:

[root@101c7 ~]$ mkdir /var/log/journal
[root@101c7 ~]$ chown root:systemd-journal /var/log/journal
[root@101c7 ~]$ chmod 2775 /var/log/journal
[root@101c7 ~]$ systemctl restart systemd-journald
[root@101c7 ~]$ ll /var/log/journal

这样设置以后在 /run/log 下面就不会有相关 journal 日志存在了。

日志分析

logwatch是 CentOS 7 默认提供的日志文件分析工具,功能为每天定时发送一份邮件给 root 报告昨天系统状态。

安装完毕后可以直接运行一下计划任务:

[root@101c7 ~]$ /etc/cron.daily/0logwatch 
[root@101c7 ~]$ mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
"/var/spool/mail/root": 24 messages 15 unread
 U 24 logwatch@101c7.local  Sun Sep 19 06:46 183/10954 "Logwatch for 101c7 (Linux)"
 & 24
Message 24:
From root@101c7.localdomain  Sun Sep 19 06:46:51 2021
Return-Path: <root@101c7.localdomain>
X-Original-To: root
Delivered-To: root@101c7.localdomain
To: root@101c7.localdomain
From: logwatch@101c7.localdomain
Subject: Logwatch for 101c7 (Linux)
Auto-Submitted: auto-generated
Precedence: bulk
Content-Type: text/plain; charset="iso-8859-1"
Date: Sun, 19 Sep 2021 06:46:50 -0400 (EDT)
Status: RO

 
 ################### Logwatch 7.4.0 (03/01/11) #################### 
        Processing Initiated: Sun Sep 19 06:46:50 2021
        Date Range Processed: yesterday
                              ( 2021-Sep-18 )
                              Period is day.
        Detail Level of Output: 0
        Type of Output/Format: mail / text
        Logfiles for Host: 101c7

可以看到非常详细的系统报告。