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 | 与邮件收发者有关的日志 | |
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
中排除掉 news
和 mail
的日志,可以设置为:
*,*;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
可以看到非常详细的系统报告。