Linux 日志系统、auditd用户审计、kdump故障定位

一、Linux系统日志 

1、系统常见日志文件

在Linux系统中,系统日志一般都保存在/var/log/目录下。

如下所示:

[root@localhost ~]# ls /var/log/
anaconda.ifcfg.log    btmp           maillog            secure
anaconda.log          ConsoleKit     maillog-20200705   secure-20200705
anaconda.program.log  cron           mcelog             spooler
anaconda.storage.log  cron-20200705  messages           spooler-20200705
anaconda.syslog       cups           messages-20200705  sssd
anaconda.xlog         dmesg          ntpstats           tallylog
anaconda.yum.log      dmesg.old      prelink            wtmp
audit                 dracut.log     sa                 yum.log
boot.log              lastlog        samba

 具体介绍一下这上面的主要日志文件:

日志文件 说明
/var/log/cron 记录了系统定时任务相关的日志。
/var/log/cups/ 记录打印信息的日志。(前提你要有打印机或者打印服务器,一般不用)
/var/log/dmesg 记录了系统在开机时内核自检的信息。也可以使用dmesg命令直接查看内核自检信息。
/var/log/btmp 记录错误登录的日志。这个文件是二进制文件,不能直接vim查看,而要使用lastb命令查看。
/var/log/lastlog 记录系统中所有用户最后一次的登录时间的日志。这个文件也是二进制文件,不能直接vim,而要使用lastlog命令查看。
/var/log/mailog 记录邮件信息。
/var/log/message 记录系统重要信息的日志。这个日志文件中会记录Linux系统的绝大多数重要信息,系统启动后的信息和错误日志,如果系统出现问题时,首先要检查的就应该是这个日志文件。
/var/log/secure 记录验证和授权方面的信息,只要涉及账户和密码的程序都会记录。比如说系统的登录,ssh的登录,su切换用户,sudo授权,甚至添加用户和修改用户密码都会记录在这个日志文件中。
/var/log/wtmp 永久记录所有用户的登录、注销信息,同时记录系统的启动、重启、关机事件。同样这个文件也是一个二进制文件,不能直接vim,而需要使用last命令来查看。

/var/run/utmp

记录当前已经登录的用户的信息。这个文件会随着用户的登录和注销而不断变化,只记录当前登录用户的信息。同样这个文件不能直接vim,而要使用wwhousers等命令来查询。
/var/log/spooler 与UUCP和news设备相关的日志信息
/var/log/boot.log 守护进程启动和停止相关的日志消息

说明:不能用vim编辑器查看的日志文件示例: 

# 有人在6月4日22:38使用root用户,在本地终端1登录错误
[root@localhost log]# lastb
root  tty1        Tue Jun 4 22:38 - 22:38 (00:00)

为什么有些日志文件不能使用vim编辑器查看?

是因为这些日志文件中的内容,记录的是重要系统资源的日志,与系统安全有关,不能让你修改,要确保数据的准确性,只能通关相关命令来查看。

除了系统默认的日志之外,采用RPM方式安装的系统服务也会默认把日志记录在/var/log/目录中。

例如:

日志文件 说明
/var/log/httpd/ RPM包安装的apache服务的默认日志目录。
/var/log/mail/ RPM包安装的邮件服务的额外日志目录。
/var/log/samba/ RPM包安装的samba服务的日志目录。
/var/log/sssd/ 守护进程安全服务目录。

而源码包安装的服务日志是在源码包指定目录中。

不过这些日志不是由rsyslogd服务来记录和管理的,而是各个服务使用自己的日志管理文档来记录自身日志。

二、日志服务

1、syslogd日志服务

syslog是一种工业标准的协议,可用来记录设备的日志。在UNIX系统,路由器、交换机等网络设备中,系统日志(System Log)记录系统中任何时间发生的大小事件。管理者可以通过查看系统记录,随时掌握系统状况。UNIX的系统日志是通过syslogd这个进程记录系统有关事件记录,也可以记录应用程序运作事件。通过适当的配置,我们还可以实现运行syslog协议的机器间通信,通过分析这些网络行为日志,藉以追踪掌握与设备和网络有关的状况。

syslogd是Linux下的一个记录日志文件服务。从结构来说,可以理解为这个服务下面有一系列的子服务,例如mail、auth、cron、kern等等,这些子服务对外提供日志记录的功能,而当其它的程序或服务需要记录日志的时候,就可以直接调用这些子服务将日志记录到设定的地方。而配置这整个守护进程以及其子服务的地方就是/etc/syslog.conf这个文件。

在用户空间有专门用于记录系统日志的程序,统称为“日志守护进程syslog”。位于 /etc/syslog 或 /etc/syslogd,默认配置文件为 /etc/syslog.conf。

 查看日志守护进程:

命令: ps aux | grep syslog
root 921 0.0 0.1 35976 928 ? Sl Jan22 0:00 /sbin/rsyslogd -i /var/run/syslogd.pid -c 5
• 注:系统centos6,rsyslogd r带有网络的性质。
• 注:centos5服务名为syslogd。本地的性质。
• 注:日志会根据大小或者日期 切换到另外一个文件,新日志还叫原名

syslog不仅表示一个系统日志协议,同时程序名称也叫syslog,其配置文件为”/etc/syslog.conf“,信息如下介绍:

# 表示将所有facility的info级别,但不包括mail,authpriv,cron相关的信息,记录到 /var/log/messages文件
*.info;mail.none;authpriv.none;cron.none       /var/log/messages
 
# 表示将权限,授权相关的所有基本的信息,记录到/var/log/secure文件中.这个文件的权限是600 
authpriv.*    /var/log/secure
 
# 表示将mail相关的所有基本的信息记录到/var/log/maillog文件中,可以看到路径前面有一个"-"而"-" 表示异步写入磁盘
mail.*        -/var/log/maillog 
 
# 表示将任务计划相关的所有级别的信息记录到/var/log/cron文件中
cron.*        /var/log/cron
 
# 表示将所有facility的emerg级别的信息,发送给登录到系统上的所有用户
*.emerg       *
 
# 表示将uucp及news的crit级别的信息记录到/var/log/spooler文件中
uucp,news.crit   /var/log/spooler
 
# 表示将local7的所有级别的信息记录到/var/log/boot.log文件中上面说过local0 到local7这8个是用户自定义使用的,这里的local7记录的是系统启动相关的信息
local7.*         /var/log/boot.log

2、rsyslogd日志服务

而目前不少的Linux发行版已经用rsyslogd将syslogd代替了,它所做的事就是统一记录系统的各个子系统产生的日志。rsyslogd是syslogd的升级版,其配置语法与syslogd的配置文件一致。CentOS6.x、CentOS7.x和ubuntu-gnome-16.04使用的是rsyslogd。

rsyslogd服务相比syslogd服务具有一些新的特点:

1)基于TCP网络协议传输日志信息。

2)更安全的网络传输方式。

3)有日志消息的及时分析框架。

4)后台数据库。配置文件中可以写简单的逻辑判断。

5)与syslog配置文件相兼容。

日志配置文件:

/etc/rsyslog.conf      # 系统日志配置文件
/etc/logrotate.conf     # 定义日志切割归档
/etc/logrotate.d/syslog  # 定义日志格式文件
/etc/logrotate.d/*      # 是一些日志自定义的服务
/etc/rsyslog.d/*.conf    # 自定义日志添加路径,记录日志格式

默认配置文件为 /etc/rsyslog.conf 或 /etc/rsyslog.d/50-default.conf (日志文件的记录规则和路径),任何希望生成日志的程序都可以向 syslog 发送信息, 大多数日志文件都位于 /var/log/ 目录中。

主配置文件/etc/rsyslog.conf:

#### 加载模块 ####
$ModLoad imuxsock   # provides support for local system logging (e.g. via logger command)
$ModLoad imklog     # provides kernel logging support (previously done by rklogd)
 
#### 定义日志格式默认模板 ####
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
 
#### 包含其他配置文件 ####
$IncludeConfig /etc/rsyslog.d/*.conf
 
#### 规则 ####
# 关于内核的所有日志都放到/dev/console(控制台)
#kern.*                                                 /dev/console
 
# 记录所有日志类型的info级别以及大于info级别的信息到/var/log/messages,但是mail邮件信息,authpriv验证方面的信息和cron时间任务相关的信息除外
*.info;mail.none;authpriv.none;cron.none                /var/log/messages
 
# authpriv验证相关的所有信息存放在/var/log/secure
authpriv.*                                              /var/log/secure
 
# 邮件的所有信息存放在/var/log/maillog; 这里有一个-符号, 表示是使用异步的方式记录, 因为日志一般会比较大
mail.*                                                  -/var/log/maillog
 
# 计划任务有关的信息存放在/var/log/cron
cron.*                                                  /var/log/cron
 
# 记录所有的大于等于emerg级别信息, 以wall方式发送给每个登录到系统的人
*.emerg                                                 *
 
# 记录uucp,news.crit等存放在/var/log/spooler
uucp,news.crit                                          /var/log/spooler
 
# 记录启动的相关信息
local7.*                                                /var/log/boot.log
 
###日志转发规则###
#$WorkDirectory /var/spppl/rsyslog # where to place spool files
#$ActionQueueFileName fwdRule1   #unique name prefix for spool files
#$ActionQueueMaxDiskSpace 1g # 1gb space limit (use as much as possible)
#$ActionQueueSaveOnShutdown on   #save messages to disk on shutdown
#$ActionQueueType LinkedList     #run asynchronously
#$ActionResumeRetryCount -1      #infinite retries if host is down
# remote host is: name/ip:port, e.g. 192.168.0.1:514, port optional
#*.*    @@remote-host:514        #@@表示通过tcp协议发送 @表示通过udp进行转发
#local3.info @@localhost :514
#local7.*                        #@@192.168.56.7:514

syslog协议格式

定义如下:

facility.priority action

facility(设施):标识系统需要记录日志的子系统,大概有以下子系统:

auth             #PAM认证相关日志,如login、su命令等;
authpriv         #SSH、FTP登录相关日志,只能被特定用户查看;
console          #针对系统控制台的消息;
cron             #任务计划相关日志;
daemon           #守护进程相关日志;
kern             #内核相关日志;
lpr              #打印相关日志;
ftp              #FTP相关日志;
mail             #邮件相关日志;
mark             #标记时间戳,系统每隔一段时间向日志文件中输出当前时间,判断故障时间;
news             #网络新闻传输协议nntp产生的新闻相关日志;
ntp              #网络时间协议(ntp)产生的消息;
security         #安全相关日志与auth类似;
syslog           #Rsyslog自己的日志;
user             #用户相关日志;
uucp             #UNIX to UNIX UUCP子系统 cp相关日志;
local0 to local7 #用户自定义使用设置日志;
*                #表示所有的facility;

priority(级别):用来标识日志级别,级别越低信息越详细,有以下日志级别,从上到下,级别从低到高,记录的信息越来越少,详细的可以查看手册: man 3 syslog。

none             #没有优先级,不记录任何日志消息;
debug            #程序或系统调试信息;
info             #一般信息;
notice           #不是错误,不影响正常功能需要注意的信息;
warning          #可能影响系统功能提醒用户的重要事件;
error            #一般错误信息;
crit             #比较严重的信息,如硬盘错误,可能阻碍程序的部分功能;
alert            #需要立即修复,必须马上处理的警告信息,如系统数据库损坏;
emerg/panic      #系统奔溃,会导致系统不可用的严重信息,一把通知所有用户;
*                #表示所有日志级别;
none             #跟*相反表示什么都没有;

action(动作):设置日志记录的位置,有以下几种。

1)记录到普通文件或设备文件
*.*     /var/log/file.log   #绝对路径
*.*     /dev/pts/0          #设备文件
2)”|”,管道表示将日志送给其他命令处理
3)”@HOST”,远程主机,将日志发送到特定的主机
*.emerg                     @192.168.10.1
4)”用户”,表示将日志发送到特定的用户,如root
5)”*”,表示将日志发送所有登录到系统上的用户,一般emerg级别的日志
6)终端, 如/dev/console

连接符号:

.                  #表示大于等于xxx级别的信息;
.=                 #表示等于xxx级别的信息;
.!                 #表示在xxx之外的等级的信息;

/etc/rsyslog.conf配置文件格式定义:

# 表示将mail相关的,info级别及以上级别都记录到mail.log文件中
mail.info  /var/log/mail.log
 
# 表示将auth相关的基本为info信息记录到远程主机
auth.=info @192.168.10.1
 
# 表示记录与user和error相反的
user.!=error
 
# 表示记录所有日志信息的info级别及以上级别
*.info
 
# 所有日志及所有级别信息都记录下来
*.*

# 选择所有优先级的内核日志
kern.*

#表示记录mail相关的所有级别的信息
mail.*
            
# 选择所有mail 的优先级高于crit的日志                    
mail.crit

#表示记录mail相关的所有级别的信息,但是不包括info级别的。
mail.*;mail.!=info     

#多个日志来源用“;”隔开
cron.info;mail.info     

#与cron.info;mail.info一个意思
cron,mail.info    

# 选择除了 info 和 debug 优先级的 cron 日志                 
cron.!info,!debug         

多个日志来源可以使用,号隔开,如cron.info;mail.info。

基于属性的过滤器

基于属性的过滤器语法:

:PROPERTY, [!]COMPARE_OPERATION, "STRING"

:PROPERTY是要比较的日志属性,COMPARE_OPERATION 为要执行的比较操作,这个的!表示取反的意思,"STRING"为比较的值。

可以使用的比较操作:

比较操作

描述

contains

匹配提供的字符串值是否是属性的一部分,如果不区分大小写,使用contains_i

isequal

比较属性和值是否相等

startswith

属性是否以指定字符串开始(startswith_i)

regex

正则表达式(POSIX BRE 基本正则)匹配

ereregex

正则表达式(POSIX ERE 扩展正则)匹配

isempty

判断属性是否为空,不需要 value

使用范例:

:msg, contains, "error"
:hostname, isequal, "host1"
:msg, !regex, "fatal .* error"

基于表达式的过滤器

基于表达式的过滤器使用了rsyslog自定义的脚本语言RainerScript构建复杂的filter,这里暂时不对这种方法进行讲述。

Action

Action定义了当匹配指定的 filter 的时候,执行什么操作。

如果要指定多个 ACTION, 使用 &连接多个 ACTION:

kern.=crit user1    & ^test-program;temp    & @192.168.0.1

这里的;temp指定了传递日志给 test-program 程序时( ^ 开头表明日志发送给该可执行文件),使用它 temp 模板格式化日志。 

在 ACTION 后面追加;模板名称可以为指定的 action 使用该模板格式化日志。

保存日志到日志文件

语法:

FILTER PATH

这里的 PATH 指定了日志要保存到的文件。例如 cron.* /var/log/cron.log 指定了所有的定时任务日志都写入到/var/log/cron.log文件。

默认情况下,每次生成 syslog 的时候,日志信息会同步到日志文件。可以在文件路径前使用 - 指定忽略同步(如果系统崩溃,会丢失日志,但是这样可以提高日志性能)。

除了上述方法记录日志(静态),也可以动态的生成日志文件。

FILTER     ?DynamicFile

这里的DynamicFile是预定义的输出路径模板。

通过网络发送syslog

rsyslog可以使用网络将日志消息发送或者接受日志,使用这个特性,可以实现使用单一的日志服务器统一管理多台服务器日志。

@[(zNUMBER)]HOST:[PORT]

这里的@告诉syslog使用 UDP 协议发送日志,要使用 TCP 的话,使用 @@。可选值zNUMBER设置了是否允许使用zlib对日志压缩(压缩级别1-9)。

使用范例:

*.* @192.168.0.1        # 使用 UDP 发送,默认端口514
*.* @@example.com:18    # 使用 TCP 发送到端口18, 默认10514
*.* @(z9)[2001:db8::1]  # UDP, ipv6,使用zlib级别9压缩

丢弃日志

要丢弃日志消息,使用~动作。

FILTER    ~

例如:

cron.* ~

模板

任何rsyslog生成的日志都可以根据需要使用模板进行格式化,要创建模板,使用如下指令:

$template TEMPLATE_NAME,"text %PROPERTY% more text", [OPTION]

这里的$template指令表明了接下来的内容定义了一个模板,TEMPLATE_NAME是模板的名称,接下来双引号之间的内容为模板的内容。

这里还有一个 OPTION , 它指定了模板的功能,支持选项为sql和stdsql,在使用数据库存储的时候会用到。 

生成动态文件名

模板可以用来生成动态文件名,就如之前所述,在使用动态文件名的时候,需要在 ACTION 中的模板名称前增加?表明该文件名是动态生成的。

例如:

$template DynamicFile,"/var/log/test_logs/%timegenerated%-test.log"
*.* ?DynamicFile

timegenerated属性从日志信息中提取出消息的时间戳,这样可以为每个日志生成唯一文件名称。 

属性

在模板中使用的属性是在%之间的内容,使用属性可以访问日志消息中的内容。

%PROPERTY_NAME[:FROM_CHAR:TO_CHAR:OPTION]%

可用的属性列表见man rsyslog.conf。

全局指令

全局指令是rsyslogd守护进程的配置指令。所有的全局指令必须以$开始,每行只能有一个指令,例如:

$MainMsgQueueSize 50000

在新的配置格式中(rsyslog v6),已经不在使用这种方式的指令,但是它们仍然是可用的。

队列

在 rsyslog 中,队列用来传输数据,当 rsyslog 接收到一个消息的时候,首先传递消息预处理器,然后加入到主消息队列,接下来消息会从队列中取出传递给规则处理器。

​规则处理器是一个解析过滤引擎,它会基于配置文件中定义的规则,执行相应的动作(action),每一个动作都有自己的动作队列,消息通过这个队列发送到对应的动作处理器,然后输出。

对于同一个消息来说,可以同时传递这个消息给多个动作队列。

定义队列

在配置文件/etc/rsyslog.conf文件中:

$objectQueueType queue_type

这里的队列类型可选值为 direct , linkedlist , fixedarray (内存队列), 或者 disk 。

默认情况下,对于主队列,使用的是FixedArray队列(10000个消息长度),动作队列采用的是direct 队列。

PHP 使用 syslog 输出日志

在PHP 中,调用系统日志系统的函数有三个:

bool openlog ( string $ident , int $option , int $facility )
bool syslog ( int $priority , string $message )
bool closelog ( void )

函数openlog用于打开到系统日志系统的连接,第一个参数$ident是一个字符串,syslog 会将该字符串自动加到使用syslog函数输出的所有日志消息的前面。第二个参数是日志选项,第三个参数是记录日志的设施。

函数openlog()和closelog()是可选的。

例如,我们在/etc/rsyslog.conf配置文件中增加如下配置:

local5.*     /tmp/php_test.log

增加后需要重启 rsyslog 进程(sudo /etc/init.d/rsyslog restart)

在 PHP 脚本中,执行如下操作:

<?php
openlog("LogHeader", LOG_PID, LOG_LOCAL5);
syslog(LOG_DEBUG, "Hello, Logger");

执行上述脚本,我们可以在/tmp目录中看到出现名为php_test.log的文件:

Mar 10 14:47:04 vm-hp LogHeader[8261]: Hello, Logger

第一部分Mar 10 14:47:04为日志时间,第二部分vm-hp为主机的HOSTNAME , 我们在调用openlog函数的时候,指定了indent为LogHeader, 同时在日志中加入进程的 PID(LOG_PID)。

上述日志消息,如果要使用模板的话,是下面这样的:

$template LOG_TMP,"%timegenerated% %HOSTNAME% %msg%"
local5.*     /tmp/php_test.log;LOG_TMP

我们将所有支持的模板属性变量输出如下:

msg:  Hello, Logger,
rawmsg: <175>Mar 10 15:52:49 LogHeader[13845]: Hello, Logger, 
HOSTNAME: vm-28-234-pro01-hp, 
FROMHOST: vm-28-234-pro01-hp, 
syslogtag: LogHeader[13845]:, 
programname: LogHeader, 
PRI: 175, 
PRI-text: local5.debug, 
IUT: 1, 
syslogfacility: 21, 
syslogfacility-text: local5, 
syslogseverity: 7, 
syslogseverity-text: debug, 
timereported: Mar 10 15:52:49, 
TIMESTAMP: Mar 10 15:52:49,
timegenerated: Mar 10 15:52:49,
PROTOCOL-VERSION: 0, 
STRUCTURED-DATA: -, 
APP-NAME: LogHeader, 
PROCID: 13845, 
MSGID: -

把特定的rsyslog日志文件发送到远程主机的配置:

# 定义从默认的设备文件中读取日志,/dev/log是默认的日志读取设备文件;
$AddUnixListenSocket  /dev/log
 
# 定义从指定的设备文件中读取日志,如PHP程序使用Rsyslog输出日志,同时PHP使用了chroot,那么需要定义chroot后的路径才可以读取日志;
#$AddUnixListenSocket /data/app/dev/log
 
# 定义一个模板,可选;
$template logstash,"%msg%\n" 
 
# Rsyslog默认日志首都有空格,可以使用下面的模板删除空格,可选;
$template logstash,"%msg:2:$%\n"
 
# 使用一个已定义的模板;
$ActionFileDefaultTemplate logstash
 
# 摘取$msg(消息)变量内容,判断如果有keyboard关键字就进行远程传送,没有此关键字的就不传送;
if $msg contains "keyboard"  then
action(type="omfwd" Target="172.18.20.60"\
       Port="8594"\
       Protocol="udp"\
       queue.type="LinkedList"\
       queue.spoolDirectory="/var/spool/rsyslog"\
       queue.filename="test2"\
       queue.size="100000"\
       queue.maxdiskspace="2g"\
       queue.highwatermark="60000"\
       queue.lowwatermark="2000"\
       queue.discardmark="80000"\
       queue.timeoutenqueue="3000"\
       queue.maxfilesize="200m"\
       queue.dequeuebatchsize="1000"\
       )
& stop

上面都是使用$msg为载体进行过滤,$msg就是取日志内容。当然除了$msg外,常用的还有一个变量$programname,就是取程序名称。两种方式都可以使用。 

rsyslog系统有两个守护进程分别是klogd、syslogd,两个进程主要因为内核跟其他信息需要记录的详细程度及格式的不同,位于/etc/rsyslog.d。

klogd:记录内核信息,系统启动中在登录之前使用的都是物理终端/dev/console,这个时候虚拟终端还没有启动而内核启动日志都存放在/var/log/dmesg文件中,使用dmesg命令可以查看。

syslogd:记录非内核系统产生的信息,当系统启动/sbin/init程序时产生的日志都存放在以下各个日志文件中。

常用日志:

/var/log/message    #标准系统错误信息;
/var/log/maillog    #邮件系统产生的日志信息;
/var/log/secure     #记录系统的登录情况;
/var/log/dmesg      #记录linux系统在引导过程中的各种记录信息,dmesg命令进行查看;
/var/log/cron       #记录crond计划任务产生的时间信息;
/var/log/boot.log  # 记录了系统在引导过程中发生的事件,就是Linux系统开机自检过程显示的信息

/var/log/messages

messages 日志是核心系统日志文件。包含了系统启动时的引导消息,以及系统运行时的其他状态消息;IO 错误、网络错误和其他系统错误都会记录到这个文件中;其他信息,比如某个人的身份切换为 root,也在这里列出。

如果服务正在运行,比如 DHCP 服务器,您可以在 messages 文件中观察它的活动。

通常/var/log/messages 是您在做故障诊断时首先要查看的文件:

Jan 23 03:03:04 localhost dhclient[30603]: DHCPOFFER from 192.168.1.1
Jan 23 03:03:04 localhost dhclient[30603]: DHCPREQUEST on eth0 to 255.255.255.255 port 67 (xid=0x2c3377ff)
Jan 23 03:03:05 localhost dhclient[30603]: DHCPACK from 192.168.1.1 (xid=0x2c3377ff)
Jan 23 03:03:07 localhost NET[30879]: /sbin/dhclient-script : updated /etc/resolv.conf
Jan 23 03:03:07 localhost dhclient[30603]: bound to 192.168.1.107 -- renewal in 3569 seconds.
Jan 23 03:26:40 localhost kernel: e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
Jan 23 03:26:40 localhost kernel: ADDRCONF(NETDEV_UP): eth0: link is not ready
Jan 23 03:26:40 localhost kernel: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready

二进制日志:

/var/run/utmp     # 该日志文件记录有关当前登录的每个用户的信息。
/var/log/lastlog    #记录每个用户最近的登录事件;
/var/log/wtmp       #记录每个用户成功登录、注销及系统启动和停机事件,使用last命令查看;   
/var/run/btmp       #记录失败的、错误的登录尝试及验证事件,使用lastb命令查看;

/var/log/btmp:

root     ssh:notty    192.168.1.106    Tue Jan 23 04:56 - 04:56  (00:00)   
root     ssh:notty    192.168.1.106    Tue Jan 23 04:56 - 04:56  (00:00)   
*[A*[B** ssh:notty    192.168.1.154    Mon Jan 22 14:21 - 14:21  (00:00)   
btmp begins Mon Jan 22 14:21:36 2018

/var/log/wtmp:

root     pts/0        192.168.1.106    Tue Jan 23 04:44   still logged in 
root     pts/4        192.168.1.150    Tue Jan 23 03:14   still logged in 
root     pts/3        192.168.1.150    Tue Jan 23 03:02   still logged in 
root     pts/2        192.168.1.107    Tue Jan 23 02:01   still logged in 
root     pts/0        192.168.1.150    Tue Jan 23 01:34 - 04:08  (02:34)   
root     pts/1        192.168.1.150    Tue Jan 23 00:26 - 03:34  (03:08)   
root     pts/0        192.168.1.150    Mon Jan 22 21:59 - 00:26  (02:27)   
root     pts/1        192.168.1.150    Mon Jan 22 19:47 - 23:03  (03:16)   
root     pts/0        192.168.1.150    Mon Jan 22 18:58 - 21:51  (02:53)   
root     pts/3        192.168.1.150    Mon Jan 22 14:22 - 20:58  (06:36)   
root     pts/2        192.168.1.154    Mon Jan 22 14:21 - 14:24  (00:02)   
root     pts/1        192.168.1.150    Mon Jan 22 14:20 - 15:22  (01:01)   
root     tty1                          Mon Jan 22 13:56   still logged in 
root     pts/1        192.168.1.150    Mon Jan 22 11:26 - 13:54  (02:28)   
root     pts/1        192.168.1.150    Mon Jan 22 11:24 - 11:26  (00:01)   
root     pts/0        192.168.1.150    Mon Jan 22 11:22 - 16:08  (04:45)   
reboot   system boot  2.6.32-431.el6.i Mon Jan 22 11:09 - 04:50  (17:41)   
root     tty1                          Mon Jan 22 10:55 - down   (00:13)   
root     pts/1        192.168.1.150    Mon Jan 22 10:47 - 10:47  (00:00)   
root     pts/0        192.168.1.150    Mon Jan 22 10:19 - down   (00:49)   
reboot   system boot  2.6.32-431.el6.i Mon Jan 22 10:17 - 11:09  (00:51)   
root     pts/0        192.168.1.103    Tue Dec 26 10:15 - crash (27+00:02) 
root     pts/1        192.168.1.151    Sun Dec 24 00:33 - down   (08:31)   
root     pts/0        192.168.1.151    Sun Dec 24 00:07 - 00:42  (00:34)   
root     tty1                          Sat Dec 23 23:36 - down   (09:28)   
root     pts/0        192.168.1.151    Sat Dec 23 23:31 - 00:06  (00:35)   
reboot   system boot  2.6.32-431.el6.i Sat Dec 23 23:29 - 09:05  (09:35)   
root     pts/0        192.168.1.151    Sat Dec 23 20:46 - crash  (02:43)   
root     tty1                          Sat Dec 23 20:45 - crash  (02:44)   
reboot   system boot  2.6.32-431.el6.i Sat Dec 23 20:44 - 09:05  (12:20)   
wtmp begins Sat Dec 23 20:44:29 2017

 日志记录的接口

(1)内核空间:printk()

可以使用dmesg命令来查看,使用printk()打印的日志同时也会记录在/var/log/kern.log和/var/log/syslog。当然也可以关闭rsyslogd服务,通过读取/proc/kmsg来查看。

(2)用户空间:syslog()函数和logger(logger可在命令行中直接执行)

void syslog(int priority, char*format,……);

打印的日志记录在 /var/log/syslog文件中。

查看日志三种途径

1)日志访问命令:

dmesg        # 查看硬件相关的日志
last        # 查看用户登陆信息
lastlog      # 查看系统所有用户最近一次登陆情况
lastb       # 查看无效登陆的历史

printk()打印的日志会写到kernel ring buffer(环缓冲区)中,dmesg是从kernel ring buffer中读取内核日志信息。

2) /var/log/

系统所有日志(包括用户日志和系统内核日志)均记录在/var/log/目录下。

rsyslogd守护进程根据/etc/rsyslog.conf和/etc/rsyslog.d/50-default.conf,将不同的服务产生的log记录到不同的文件中。

3)/proc/kmsg

通过读取/proc/kmsg也可以得到ring buffer(环缓冲区)的日志,但是对/proc/kmsg进行读操作后,ring buffer中被读取的数据将被清空。

日志系统框架图

如何将sshd的日志分离到/var/log/sshd.log

sshd是远程登录Linux系统的一个服务,默认工作在22端口,通常情况下它的日志是记录在/var/log/secure 文件中,在之前我们不知道它为什么要记录在这个文件中,我们学习了rsyslog后,就明白了。

首先我们来看看sshd的配置文件:

[root@test ~]#grep "log" /etc/ssh/sshd_config
#SyslogFacility AUTH
SyslogFacility AUTHPRIV
[root@test ~]#

说明:可以看到sshd的配置文件中明确定义了syslogfacility authpriv。通过上面的介绍我们大概知道rsyslog 的facility 中就包括authpriv 这个设施。接下来我们在来看看rsyslog的配置文件:

[root@test ~]#grep "authpriv" /etc/rsyslog.conf
*.info;mail.none;authpriv.none;cron.none                /var/log/messages
# The authpriv file has restricted access.
authpriv.*                                              /var/log/secure
[root@test ~]#

说明:看到以上的结果,结合我们之前介绍的rsyslog,是不是很清楚知道sshd的日志为什么记录在/etc/log/secure中了嘛。rsyslog的配置文件中明确定义了authpriv设施中的任何级别的日志都记录在/var/log/secure中。

更改sshd 配置文件 将日志的设施更改为自定义设施local3:

[root@test ~]#grep "log" /etc/ssh/sshd_config
#SyslogFacility AUTH
#SyslogFacility AUTHPRIV
SyslogFacility local3
[root@test ~]#

在rsyslog配置文件中指定 local3设施中的任何级别的目标文件为/var/log/sshd.log:

[root@test ~]#grep "local" /etc/rsyslog.conf
$ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
# Turn off message reception via local log socket;
# local messages are retrieved through imjournal now.
local7.*                                                /var/log/boot.log
local3.*                                                /var/log/sshd.log
[root@test ~]#

重启rsyslogd 和sshd 服务:

[root@test ~]#systemctl restart rsyslog sshd

查看/var/log/sshd.log:

[root@test ~]#ll /var/log/sshd.log
-rw-------. 1 root root 207 12月 24 19:23 /var/log/sshd.log
[root@test ~]#cat /var/log/sshd.log
Dec 24 19:23:33 test sshd[4532]: Received signal 15; terminating.
Dec 24 19:23:33 test sshd[4575]: Server listening on 0.0.0.0 port 41319.
Dec 24 19:23:33 test sshd[4575]: Server listening on :: port 41319.
[root@test ~]#

说明:要想用rsyslog来管理应用程序的日志,前提是应用程序内部实现rsyslog的日志接口,否则是不可以通过rsyslog来管理日志

统计log中每个IP的访问次数

cat access.log输出该log文件的内容:

#!/bin/bash                                                                 
#将28/Jan/2015全天的访问日志放到a.txt文本
cat access.log |sed -rn '/1\/Apr\/2018/p' > a.txt 
#统计a.txt里面有多少个ip访问
cat access.log |awk '{print $1}'|sort|uniq  > ipnum.txt
#通过shell统计每个ip访问次数
echo>result.txt #清空原文件
for i in `cat ipnum.txt`
do
iptj=`cat  access.log |grep $i |grep -v 400|wc -l`
echo "ip地址"$i"在2018-04-1日全天(24小时)累计成功请求"$iptj"次,平均每分钟>    请求次数为:"$(($iptj/1440)) >> result.txt
done

脚本说明:

sed -rn '/28\/Jan\/2015/p' 将含有该字段的的行输出来,即选定特定的日期。sed主要进行文本操作。

awk '{print $1}' |sort |uniq 输出该行第一项,并sort排序,uniq去除重复的。这样ipnum.txt里面即为所有的被访问ip。

 

遍历ipnum.txt里的每一个ip,在accesss.log里grep $i 查找包含该ip的行,| grep -v 400 查找不包含400的行, wc -l统计行数,这样就得到了每一个IP的访问次数。

最后将其写入到result.txt里:

‘|’符号表示上一段的结果作为这一段的处理内容,例如:

access.log |grep $i |grep -v 400|wc -l

可以作为’且‘方法来用。另外 ||表示上一段为假才执行这一段,&&表示上一段为真才执行这一段。

其中,不管是echo还是sed,后面的>表示追加,>>表示覆盖。我一开始使用>>,由于存在循环,所以每次迭代,都会把上次循环的的内容给覆盖掉;而使用>的话,原文件的内容仍然保留,追加上去不易查看。在遍历ipnum.txt之前,先清空原文件,这样循环里写>,就可以把本次运行的所有内容的都显示出来,而且只显示本次的。

服务器日志分析命令

失败登录次数:

cat /var/log/secure|awk '/Failed/{print $(NF-3)}'|sort|uniq -c|awk '{print $2"="$1;}'

​​​​​​CC攻击日志访问频率脚本:

/usr/local/nginx/logs
cat access.log |sed -rn '/22\/Oct\/2020\:11\:45/p' > a.txt 
cat a.txt |grep 192.73.1.49 |grep -v 400|wc -l

查看有多少个IP访问:

awk '{print $1}' log_file|sort|uniq|wc -l

查看某一个页面被访问的次数:

grep "/index.php" log_file | wc -l

查看每一个IP访问了多少个页面:

awk '{++S[$1]} END {for (a in S) print a,S[a]}' log_file > log.txt
sort -n -t ' ' -k 2 log.txt 配合sort进一步排序

将每个IP访问的页面数进行从小到大排序:

awk '{++S[$1]} END {for (a in S) print S[a],a}' log_file | sort -n

查看某一个IP访问了哪些页面:

grep ^111.111.111.111 log_file| awk '{print $1,$7}'

去掉搜索引擎统计的页面:

awk '{print $12,$1}' log_file | grep ^\"Mozilla | awk '{print $2}' |sort | uniq | wc -l

查看2015年8月16日14时这一个小时内有多少IP访问:

awk '{print $4,$1}' log_file | grep 16/Aug/2015:14 | awk '{print $2}'| sort | uniq | wc -l

查看访问前十个ip地址:

awk '{print $1}' |sort|uniq -c|sort -nr |head -10 access_log
uniq -c 相当于分组统计并把统计数放在最前面
cat access.log|awk '{print $1}'|sort|uniq -c|sort -nr|head -10
cat access.log|awk '{counts[$(11)]+=1}; END {for(url in counts) print counts[url], url}

访问次数最多的10个文件或页面:

cat log_file|awk '{print $11}'|sort|uniq -c|sort -nr | head -10
cat log_file|awk '{print $11}'|sort|uniq -c|sort -nr|head -20
awk '{print $1}' log_file |sort -n -r |uniq -c | sort -n -r | head -20
#访问量最大的前20个ip

通过子域名访问次数,依据referer来计算,稍有不准:

cat access.log | awk '{print $11}' | sed -e ' s/http:\/\///' -e ' s/\/.*//' | sort | uniq -c | sort -rn | head -20

列出传输大小最大的几个文件:

cat www.access.log |awk '($7~/\.php/){print $10 " " $1 " " $4 " " $7}'|sort -nr|head -100

列出输出大于200000byte(约200kb)的页面以及对应页面发生次数:

cat www.access.log |awk '($10 > 200000 && $7~/\.php/){print $7}'|sort -n|uniq -c|sort -nr|head -100

如果日志最后一列记录的是页面文件传输时间,则有列出到客户端最耗时的页面:

cat www.access.log |awk '($7~/\.php/){print $NF " " $1 " " $4 " " $7}'|sort -nr|head -100

列出最最耗时的页面(超过60秒的)的以及对应页面发生次数:

cat www.access.log |awk '($NF > 60 && $7~/\.php/){print $7}'|sort -n|uniq -c|sort -nr|head -100

列出传输时间超过 30 秒的文件:

cat www.access.log |awk '($NF > 30){print $7}'|sort -n|uniq -c|sort -nr|head -20

列出当前服务器每一进程运行的数量,倒序排列:

ps -ef | awk -F ' ' '{print $8 " " $9}' |sort | uniq -c |sort -nr |head -20

查看apache当前并发访问数:

#对比httpd.conf中MaxClients的数字差距多少
netstat -an | grep ESTABLISHED | wc -l

可以使用如下参数查看数据:

ps -ef|grep httpd|wc -l
1388
#统计httpd进程数,连个请求会启动一个进程,使用于Apache服务器。
#表示Apache能够处理1388个并发请求,这个值Apache可根据负载情况自动调整

netstat -nat|grep -i "80"|wc -l
4341
#netstat -an会打印系统当前网络链接状态,而grep -i "80"是用来提取与80端口有关的连接的,wc -l进行连接数统计。
#最终返回的数字就是当前所有80端口的请求总数

netstat -na|grep ESTABLISHED|wc -l
376
#netstat -an会打印系统当前网络链接状态,而grep ESTABLISHED 提取出已建立连接的信息。 然后wc -l统计
#最终返回的数字就是当前所有80端口的已建立连接的总数。

netstat -nat||grep ESTABLISHED|wc
#可查看所有建立连接的详细记录

输出每个ip的连接数,以及总的各个状态的连接数:

netstat -n | awk '/^tcp/ {n=split($(NF-1),array,":");if(n<=2)++S[array[(1)]];else++S[array[(4)]];++s[$NF];++N} END {for(a in S){printf("%-20s %s\n", a, S[a]);++I}printf("%-20s %s\n","TOTAL_IP",I);for(a in s) printf("%-20s %s\n",a, s[a]);printf("%-20s %s\n","TOTAL_LINK",N);}'

分析日志文件下 2012-05-04 访问页面最高的前20个URL并排序:

cat access.log |grep '04/May/2012'| awk '{print $11}'|sort|uniq -c|sort -nr|head -20

查询受访问页面的URL地址中 含有 www.abc.com 网址的IP地址:

cat access_log | awk '($11~/\www.abc.com/){print $1}'|sort|uniq -c|sort -nr

获取访问最高的10个IP地址 同时也可以按时间来查询:

cat linewow-access.log|awk '{print $1}'|sort|uniq -c|sort -nr|head -10

时间段查询日志时间段的情况:

cat log_file | egrep '15/Aug/2015|16/Aug/2015' |awk '{print $1}'|sort|uniq -c|sort -nr|head -10

分析2015/8/15 到 2015/8/16 访问"/index.php?g=Member&m=Public&a=sendValidCode"的IP倒序排列:

cat log_file | egrep '15/Aug/2015|16/Aug/2015' | awk '{if($7 == "/index.php?g=Member&m=Public&a=sendValidCode") print $1,$7}'|sort|uniq -c|sort -nr

($7~/.php/) $7里面包含.php的就输出,本句的意思是最耗时的一百个PHP页面:

cat log_file |awk '($7~/\.php/){print $NF " " $1 " " $4 " " $7}'|sort -nr|head -100

列出最最耗时的页面(超过60秒的)的以及对应页面发生次数:

cat access.log |awk '($NF > 60 && $7~/\.php/){print $7}'|sort -n|uniq -c|sort -nr|head -100

统计网站流量(G):

cat access.log |awk '{sum+=$10} END {print sum/1024/1024/1024}'

统计404的连接:

awk '($9 ~/404/)' access.log | awk '{print $9,$7}' | sort

统计http status:

cat access.log |awk '{counts[$(9)]+=1}; END {for(code in counts) print code, counts[code]}'
cat access.log |awk '{print $9}'|sort|uniq -c|sort -rn

每秒并发:

watch "awk '{if($9~/200|30|404/)COUNT[$4]++}END{for( a in COUNT) print a,COUNT[a]}' log_file|sort -k 2 -nr|head -n10"

带宽统计:

cat apache.log |awk '{if($7~/GET/) count++}END{print "client_request="count}'
cat apache.log |awk '{BYTE+=$11}END{print "client_kbyte_out="BYTE/1024"KB"}'

找出某天访问次数最多的10个IP:

cat /tmp/access.log | grep "20/Mar/2011" |awk '{print $3}'|sort |uniq -c|sort -nr|head

当天ip连接数最高的ip都在干些什么:

cat access.log | grep "10.0.21.17" | awk '{print $8}' | sort | uniq -c | sort -nr | head -n 10

小时单位里ip连接数最多的10个时段:

awk -vFS="[:]" '{gsub("-.*","",$1);num[$2" "$1]++}END{for(i in num)print i,num[i]}' log_file | sort -n -k 3 -r | head -10

找出访问次数最多的几个分钟:

awk '{print $1}' access.log | grep "20/Mar/2011" |cut -c 14-18|sort|uniq -c|sort -nr|head

取5分钟日志:

if [ $DATE_MINUTE != $DATE_END_MINUTE ] ;then #则判断开始时间戳与结束时间戳是否相等
START_LINE=sed -n "/$DATE_MINUTE/=" $APACHE_LOG|head -n1 #如果不相等,则取出开始时间戳的行号,与结束时间戳的行号

查看tcp的链接状态:

netstat -nat |awk '{print $6}'|sort|uniq -c|sort -rn 
netstat -n | awk '/^tcp/ {++S[$NF]};END {for(a in S) print a, S[a]}' 
netstat -n | awk '/^tcp/ {++state[$NF]}; END {for(key in state) print key,"\t",state[key]}' 
netstat -n | awk '/^tcp/ {++arr[$NF]};END {for(k in arr) print k,"\t",arr[k]}' 
netstat -n |awk '/^tcp/ {print $NF}'|sort|uniq -c|sort -rn 
netstat -ant | awk '{print $NF}' | grep -v '[a-z]' | sort | uniq -c
netstat -ant|awk '/ip:80/{split($5,ip,":");++S[ip[1]]}END{for (a in S) print S[a],a}' |sort -n 
netstat -ant|awk '/:80/{split($5,ip,":");++S[ip[1]]}END{for (a in S) print S[a],a}' |sort -rn|head -n 10 
awk 'BEGIN{printf ("http_code\tcount_num\n")}{COUNT[$10]++}END{for (a in COUNT) printf a"\t\t"COUNT[a]"\n"}'

查找请求数前20个IP(常用于查找攻来源):

netstat -anlp|grep 80|grep tcp|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -n20
netstat -ant |awk '/:80/{split($5,ip,":");++A[ip[1]]}END{for(i in A) print A[i],i}' |sort -rn|head -n20

用tcpdump嗅探80端口的访问看看谁最高:

tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F"." '{print $1"."$2"."$3"."$4}' | sort | uniq -c | sort -nr |head -20

查找较多time_wait连接:

netstat -n|grep TIME_WAIT|awk '{print $5}'|sort|uniq -c|sort -rn|head -n20

找查较多的SYN连接:

netstat -an | grep SYN | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | sort -nr | more

根据端口列进程:

netstat -ntlp | grep 80 | awk '{print $7}' | cut -d/ -f1

查看了连接数和当前的连接数:

netstat -ant | grep $ip:80 | wc -l
netstat -ant | grep $ip:80 | grep EST | wc -l

查看IP访问次数:

netstat -nat|grep ":80"|awk '{print $5}' |awk -F: '{print $1}' | sort| uniq -c|sort -n

Linux命令分析当前的链接状况:

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
watch "netstat -n | awk '/^tcp/ {++S[\$NF]} END {for(a in S) print a, S[a]}'" # 通过watch可以一直监控

LAST_ACK 5 #关闭一个TCP连接需要从两个方向上分别进行关闭,双方都是通过发送FIN来表示单方向数据的关闭,当通信双方发送了最后一个FIN的时候,发送方此时处于LAST_ACK状态,当发送方收到对方的确认(Fin的Ack确认)后才真正关闭整个TCP连接;
SYN_RECV 30  # 表示正在等待处理的请求数;
ESTABLISHED 1597 # 表示正常数据传输状态; 
FIN_WAIT1 51 # 表示server端主动要求关闭tcp连接; 
FIN_WAIT2 504 # 表示客户端中断连接; 
TIME_WAIT 1057  # 表示处理完毕,等待超时结束的请求数;

三、日志切割logrotate与logwatch

1、logrotate 

服务又挂了,估计磁盘又爆掉了。登录到web服务上,上来 df -h 一把,果然,挂的一个共享又被撑爆。 

root@websrv001 ~ # df -h  
Filesystem            Size  Used Avail Use% Mounted on  
/dev/mapper/rootvg-rootvol  
                       12G  5.6G  5.6G  50% /  
tmpfs                  14G     0   14G   0% /dev/shm  
/dev/sda1             477M   84M  368M  19% /boot  
/dev/mapper/rootvg-homevol  
                      2.0G  4.0M  1.9G   1% /local/home  
/dev/mapper/rootvg-tmpvol  
                      1.1G  252M  793M  25% /tmp  
/dev/mapper/rootvg-varvol  
                      5.8G  1.1G  4.5G  20% /var  
/dev/mapper/fsvol  
                      298G  298G     0 100% /net/fsvol  
tmpfs                  14G     0   14G   0% /var/tmp 

因为liferay的log太大,这次再看看liferay的log:

root@websrv001 ~ # ll -h /data/tomcat/storage/BU001/liferay/logs/  
total 199M  
drwxr-xr-x 2 tomcat tomcat 4.0K Apr 20 13:14 .  
drwxr-xr-x 5 tomcat tomcat 4.0K Mar 14  2016 .. 
 -rw-r--r-- 1 tomcat tomcat 1.5M Apr 13 23:59 liferay.2020-04-13.log.gzipped_on_2020-04-17.gz  
-rw-r--r-- 1 tomcat tomcat 2.5M Apr 14 23:59 liferay.2020-04-14.log.gzipped_on_2020-04-18.gz  
-rw-r--r-- 1 tomcat tomcat 7.8M Apr 15 23:59 liferay.2020-04-15.log.gzipped_on_2020-04-19.gz  
-rw-r--r-- 1 tomcat tomcat  31M Apr 17 23:58 liferay.2020-04-17.log  
-rw-r--r-- 1 tomcat tomcat 7.0M Apr 18 23:59 liferay.2020-04-18.log  
-rw-r--r-- 1 tomcat tomcat  90G Apr 20 17:54 liferay.2020-04-20.log 

一个liferay log文件,能增长到90G。

又检查了一下其它文件夹,结果发现catalina.out这个日志文件,又是超级无敌大:89G:

root@websrv001 ~ # ll -h /data/tomcat/server/BU001/logs/  
total 104G  
drwxrwxr-x  2 root   tomcat  12K Apr 20 04:45 .  
drwxr-xr-x 13 root   root   4.0K Apr 16 17:26 ..  
-rw-r--r--  1 tomcat tomcat 5.1K Apr 13 10:28 catalina.2020-04-13.log.gz  
-rw-r--r--  1 tomcat tomcat  13K Apr 14 20:46 catalina.2020-04-14.log.gz  
-rw-r--r--  1 tomcat tomcat 7.1K Apr 16 17:51 catalina.2020-04-16.log.gz  
-rw-r--r--  1 tomcat tomcat  89G Apr 20 10:39 catalina.out 
-rw-r--r--  1 tomcat tomcat    0 Feb 10 23:57 catalina.out-20200210  
-rw-r--r--  1 tomcat tomcat 352M Apr 13 03:38 catalina.out-20200413 

问题虽然解决了,但是这个问题本来就不应该发生啊!这就需要我们Linux系统自带的日志切割神器——>logrotate。

Linux会主动的将系统所发生的各种信息都记录到日志中。但随着使用时间的增长,日志文件会越来越大,大型文件不但占容量还会造成读写效能的困扰。logrotate对日志文件可实现自动rotation(日志滚动的,也称日志切割),压缩,删除和通过email发送log文件,日志文件过大时会通过系统crontab定义日志切割,负责备份和删除旧日志,以及更新日志文件,这样既能记录日志信息又能提高读写效率。

大多数日志文件都位于/var/log/目录中。在该目录中,你可能注意到很多日志文件末尾包含一串数字(如 maillog-20150301 ),这说明这些日志文件经过了日志转储,这样可以避免日志文件过大。

logrotate中包含了一个定时任务,根据配置文件/etc/logrotate.conf文件和/etc/logrotate.d/目录中的的配置定期rotate日志文件。logrotate颗粒度控制也很好,logrotate是基于每天的cron job来执行的,可以针对每一个log文件进行每天,每周,每个月或者当log文件过大时进行rotate。

一般情况下呢,对某个log文件的rotae每天执行一次,除非rotate的执行标准是基于log文件大小,并且你logrotate这个命令每天被执行了多次,也就是你自定义了定时任务,让logrotate每x分钟或者每x小时执行一次,再或者你手动执行这个命令添加了-f/--force这个选项。

logrotate的conf文件在/etc/下: 

[root@labhost ~]# ll /etc/logrotate.  
logrotate.conf  logrotate.d/  
[root@labhost ~]# cat /etc/logrotate.conf 

logrotate.conf文件里面的内容: 

cat /etc/logrotate.conf

# see "man logrotate" for details  //可以查看帮助文档
# rotate log files weekly          //每周rotate log文件一次  
weekly                             //设置每周转储一次(daily、weekly、monthly当然可以使用这些参数每天、星期,月 )
# keep 4 weeks worth of backlogs   //保存最近4周的log日志,因为上面是每周rotate一次  
rotate 4                           //最多转储4次
# create new (empty) log files after rotating old ones  //rotate老日志文件之后,创建一个新的空日志文件  
create                             //当转储后文件不存在时创建它
# use date as a suffix of the rotated file:rotate的文件以日期格式为后缀,比如:access_log-20200422,如果不加这个选项,rotate的格式为:access_log.1,access_log.2等等。  
dateext  
# uncomment this if you want your log files compressed  //如果想压缩rotate后的文件,把下面compress前面的#号去掉就可以了。  
compress                          //通过gzip压缩方式转储(nocompress可以不压缩)
# RPM packages drop log rotation information into this directory //RPM包的日志rotation配置信息,建议放到/etc/logrotate.d这个文件夹下,实现自定义控制log文件rotate  
include /etc/logrotate.d           //其他日志文件的转储方式配置文件,包含在该目录下
# no packages own wtmp -- we'll rotate them here  //wtmp和btmp这两个不属于任何package,我们就把rotate的规则写到这里  
/var/log/wtmp {                    //设置/var/log/wtmp日志文件的转储参数
    monthly                        //每月转储
    create 0664 root utmp          //转储后文件不存在时创建它,文件所有者为root,所属组为utmp,对应的权限为0664
    rotate 1                       //最多转储一次,只保留一份rotate文件  
    minsize 1M                     //日志文件大小超过1M才执行rotate,否则跳过  
}

/var/log/btmp {  
    missingok  
    monthly  
    create 0600 root utmp  
    rotate 1  
}  
# system-specific logs may be also be configured here.#其它系统日志也可以在这里配置rotate规则 

说明:从上面的配置文件看,我们可以了解到/var/log/wtmp 这个日志文件是每一个月转储一次,并创建新的日志文件 其权限是0644 属主是root 属组是utmp ,日志文件小大超过1M,日志文件就会转储, 保留一个备份文件。这个文件定义了系统的软件日志文件的转储规则,其中include /etc/logrotate.d/表示将/etc/logrotate.d目录下的所有转储规则都导入配置文件中。这样一来就可以实现单独的应用可以用单独的配置文件存储。这样一来就很方便的实现了管理转储规则的目的。 

关于rotate规则的配置,从上面的logrotate.conf文件里可以看到,有两个地方可以配置:

  • 一种是直接在logrotate.conf里配置,不过一般适用于非RPM包的系统日志文件。
  • 另外一种是如果你要做rotate的日志文件是由第三方RPM包软件产生的,需要在/etc/logrotate.d这个文件夹下新建一个配置文件,配置相关rotate规则。(UnleBen发现,其实如果你安装了第三方的软件包之后,在/etc/logrotate.d这个文件夹下就会自动创建了对应软件的rotate配置文件。)

/etc/logrotate.d这个文件夹下面都有哪些配置文件:

[root@labhost ~]# ll /etc/logrotate.d/  
total 20  
-rw-r--r--. 1 root root  91 Apr 11  2018 bootlog  
-rw-r--r--. 1 root root 224 Oct 30  2018 syslog  
-rw-r--r--. 1 root root 100 Oct 31  2018 wpa_supplicant  
-rw-r--r--. 1 root root 103 Nov  5  2018 yum  
[root@labhost ~]# 

我们现在安装一下httpd服务: 

[root@labhost ~]# yum install httpd -y  

再去/etc/logrotate.d这个文件夹下看一下: 

[root@labhost ~]# ll /etc/logrotate.d/  
total 24  
-rw-r--r--. 1 root root  91 Apr 11  2018 bootlog  
-rw-r--r--. 1 root root 194 Aug  6  2019 httpd  
-rw-r--r--. 1 root root 224 Oct 30  2018 syslog  
-rw-r--r--. 1 root root 100 Oct 31  2018 wpa_supplicant  
-rw-r--r--. 1 root root 103 Nov  5  2018 yum  

可以看到,安装httpd之后,自动创建好了针对httpd服务的log rotate配置文件,打开看看: 

[root@labhost ~]# cat /etc/logrotate.d/httpd  
/var/log/httpd/*log {   
    missingok   
    notifempty  
    sharedscripts  
    delaycompress  
    postrotate  
        /bin/systemctl reload httpd.service > /dev/null 2>/dev/null || true  
    endscript  
}  
[root@labhost ~]# 

这就是一个标准的,针对第三方软件的一个logrotate配置文件。

格式:

log文件的路径(支持通配符*),再加上一对花括号{}
花括号里面的内容就是logrotate的规则参数,需要单独成行。

参数解读:

missingok: 如果日志不存在,不产生错误信息
notifempty:如果日志文件为空,不做rotate,这个跟你ifempty互斥
sharedscripts:配合prerotate and postrotate 使用,sharedscripts 开启的话,如果使用了对需要做rotate的log文件使用了通配符,那么*
prerotate** and postrotate 的脚本只会执行一次。没有sharedscripts 的话,每个需要log文件做rotate的时候都会执行一遍prerotate and postrotate 的脚本
delaycompress:延迟压缩旧的日志文件,先rotate,不进行压缩,等到下次rotate时,才会压缩上次rotate的文件。这个需要跟compress一起使用,单独使用不生效。
postrotate/endscript:rotate之后想要执行的脚本,需要放在postrotate 与 endscript中间,这两个选项要单独成行。

除了上面的参数外,还有以下常见参数: 

daily            指定rotate周期为每天,还有weekly, monthly。  
rotate count    指定rotate日志文件保留的数量,如果没有配置这个参数,就不保留备份,设置1的话,就是保                    留1个rotate备份,10就是保留10个rotate备份。  
size size        当日志文件到达指定的大小时才转储,默认的大小单位是bytes,可以以k,M,G。比如size 10k,                  10M, 10G。  
compress        通过gzip压缩然后备份日志。  
nocompress      默认值,不做gzip压缩处理。  
delaycompress   和compress配合使用,rotate的日志文件到下一次执行logrotate时才进行压缩处理。  
copytruncate    把当前日志备份并截断,先拷贝原日志文件再清空,由于拷贝和清空之间有一个时间差,可能会丢失部                 分日志数据。  
create mode owner group        rotate之后,创建新文件的日志文件并指定新文件的属性,比如:  
                            create 644 tomcat tomcat  
mail address     把rotate的日志文件发送到指定的E-mail。  
dateext          使用当期日期作为命名格式,如果指定的rotate大于1,默认rotate之后的文件名是:xx.log.1,                     xx.log.2, xx.log3,如果配置dateext规则,那么rotate之后的文件名就会以日期结                     尾:xx.log.2020-04-20,xx.log.2020-04-21, xx.log.2020-04-22 
dateformat -%Y%m%d%H.%s   定义文件rotate后的文件名的日期格式,必须配合dateext使用,查了一下资料,目前只支持: %Y %m %d %H %s 这几个个参数(年,月,日,时,秒) 

 更多配置:

[root@test ~]#ll /etc/logrotate.d/
总用量 40
-rw-r--r--. 1 root root  91 4月  11 2018 bootlog
-rw-r--r--. 1 root root 160 9月  19 2018 chrony
-rw-r--r--. 1 root root 194 8月   6 21:44 httpd
-rw-r--r--. 1 root root 893 8月   8 19:49 mariadb
-rw-r--r--. 1 root root 243 5月  10 2019 nginx
-rw-r--r--. 1 root root 136 6月  10 2014 ppp
-rw-r--r--. 1 root root 115 8月   9 22:39 samba
-rw-r--r--. 1 root root 224 10月 18 23:48 syslog
-rw-r--r--. 1 root root 100 10月 31 2018 wpa_supplicant
-rw-r--r--. 1 root root 103 11月  5 2018 yum
[root@test ~]#cat /etc/logrotate.d/chrony 
/var/log/chrony/*.log {
    missingok
    nocreate
    sharedscripts
    postrotate
        /usr/bin/chronyc cyclelogs > /dev/null 2>&1 || true
    endscript
}
[root@test ~]#cat /etc/logrotate.d/nginx 
/var/log/nginx/*log {
    create 0644 nginx nginx
    daily
    rotate 10
    missingok
    notifempty
    compress
    sharedscripts
    postrotate
        /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
    endscript
}

[root@test ~]#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
}
[root@test ~]#cat /etc/logrotate.d/yum
/var/log/yum.log {
    missingok
    notifempty
    maxsize 30k
    yearly
    create 0600 root root
}
[root@test ~]#

logrotate的规则是配置好了,但是怎么来执行呢?

logrotate使用方法:

[root@test ~]#logrotate --help
用法: logrotate [OPTION...] <configfile>
  -d, --debug               Don't do anything, just test (implies -v)
  -f, --force               Force file rotation
  -m, --mail=command        Command to send mail (instead of `/bin/mail')
  -s, --state=statefile     Path of state file
  -v, --verbose             Display messages during rotation
  -l, --log=STRING          Log file
  --version                 Display version information

Help options:
  -?, --help                Show this help message
  --usage                   Display brief usage message
[root@test ~]#

这里着重说一下-d和-f两个选项:

-d:debug模式,就是先演练一遍,不是真干。
-f:强制模式,实打实的执行。

通常我们在测试自己写的转储规则时,我们可以用 logrotate -f /etc/logrotate.d/xxx,这条命令的的作用就是强制读取/etc/logrotate.d/xxx 来转储日志文件。

-d表示--debug,debug模式,测试配置文件是否有误,-f表示--force强制转储日志文件,-m指定压缩后的日志文件发送到邮箱地址,-s表示使用指定的状态文件,-v表示显示其转储过程。有了这个工具管理日志文件就很轻松,我们只需要定义其日志文件的转储规则即可。

从上面我们man logrotate的信息可以了解到:一般情况下呢,logrotate是基于每天的cron job来执行的,所以对某个log文件的rotae每天执行一次,除非rotate的执行标准是基于log文件大小,并且你logrotate这个命令每天被执行了多次,也就是你自定义了定时任务,让logrotate每x分钟或者每x小时执行一次,再或者你手动执行这个命令添加了-f/--force这个选项。

为什么是每天执行一次呢?我们去/etc/cron.daily/,/etc/cron.weekly/,/etc/cron.monthly/,/etc/cron.hourly/可以看到,在/etc/cron.daily/这个文件夹下有一个logrotate可执行脚本,那每天就会跑一次啦! 

我们可以在/etc/logrotate.d目录下定义各种应用程序日志转储的规则,用来覆盖其logrotate的默认值。

[root@labhost ~]# ll /etc/cron.daily/  
total 8  
-rwx------. 1 root root 219 Oct 31  2018 logrotate  
-rwxr-xr-x. 1 root root 618 Oct 30  2018 man-db.cron  
[root@labhost ~]# ll /etc/cron.weekly/  
total 0  
[root@labhost ~]# ll /etc/cron.monthly/  
total 0  
[root@labhost ~]# ll /etc/cron.hourly/  
total 4  
-rwxr-xr-x. 1 root root 392 Apr 11  2018 0anacron  
[root@labhost ~]# 

logrotate脚本里写的什么内容: 

[root@labhost ~]# 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  
[root@labhost ~]# 

简单理解就是执行logrotate命令,并且指定执行logrotate时状态文件和执行的conf文件:/etc/logrotate.conf。大家还记不记得在这个文件里,有一行:include /etc/logrotate.d,也就是说在执行logrotate.conf这个文件时,一并执行/etc/logrotate.d文件夹下的配置文件。下面几行就是执行出错时,logger一下。

所以,我们执行logrotate时,可以直接运行:logrotate + confi文件名 :

[root@labhost ~]# logrotate /etc/logrotate.d/httpd 

如果一切顺利,那么logrotate命令会执行成功,httpd的日志文件会被按照你配置的规则进行rotate。但是如果没有达到你的期望结果,你就需要来debug了。其实推荐大家在放到生产环境之前,最好好是用-d选项来测试一下你写的配置文件是否可以达到你的预期。我们来看一下加上-d选项的运行结果: 

[root@labhost ~]# logrotate -d /etc/logrotate.d/httpd  
reading config file /etc/logrotate.d/httpd  
Allocating hash table for state file, size 15360 B  
Handling 1 logs  
rotating pattern: /var/log/httpd/*log  1048576 bytes (no old logs will be kept)  
empty log files are not rotated, old logs are removed  
considering log /var/log/httpd/access_log  
  log does not need rotating (log size is below the 'size' threshold)  
considering log /var/log/httpd/error_log  
  log does not need rotating (log size is below the 'size' threshold)  
not running postrotate script, since no logs were rotated  
[root@labhost ~]# 

现在我们把httpd这个logrotate的流程梳理一下:

  • httpd这个logrotate的配置文件会每天被执行一次,因为logrotate脚本默认放置在/etc/cron.daily/下,脚本会根据/etc/logrotate.conf配置文件来执行logrotate命令,而针对httpd服务的logrotate配置文件在/etc/logrotate.d/下,此文件夹被包含在了/etc/logrotate.conf配置文件里。
  • 如果/var/log/httpd/下没有以log结尾的文件也不会记录错误信息。
  • 如果/var/log/httpd/下的log文件是空文件,那么不会执行rotate操作。
  • 在执行logrotate之后,httpd服务会被重新加载

对于大多数情况下,每天把日志备份一下已经足够了。但是像周一遇到的这种案例:一天之内,log日志把磁盘给撑爆了。那这种case,用logrotate该如何解决呢?

首先我们来捋一下需求:

  • 要解决log文件一天之内增长过快,撑爆磁盘的问题。所以关键词就是:一天之内->时间,撑爆磁盘->文件大小

执行周期

logrotate默认是每天,我们的需求是一天之内,所以可以让logrotate每半天(每12小时)、每8个小时、每4个小时、每2个小时,甚至是每小时执行一次,都可以。这个看各位心情。

文件大小

超过多大才执行logrotate,这个也是根据实际环境来确定。遇到这个案例,日志竟然暴涨到89G,我这里就设置成超过1G大小就进行rotate。

为了能让各位客官老爷们看到真是的效果,我这里做了一点小小的改动,话不多说了,上demo:

httpd logrotate的配置文件更改如下:

version1:在原来基础上增加了一行:rotate 3:

[root@labhost ~]# cat /etc/logrotate.d/httpd  
/var/log/httpd/*log {  
    rotate 3  
    missingok  
    notifempty  
    sharedscripts  
    delaycompress  
    postrotate  
        /bin/systemctl reload httpd.service > /dev/null 2>/dev/null || true  
    endscript  
}  
[root@labhost ~]# 

然后我来创建一个cron job,每分钟执行一次: 

*/1 * * * * /usr/sbin/logrotate /etc/logrotate.d/httpd 

然后创建一个监控httpd文件夹下log文件的脚本: 

[root@labhost ~]# cat monitorlog.sh  
#!/bin/bash  
while :  
do  
    sleep 2  
    ls -hl /var/log/httpd/  
done 

我们来执行一下monitorlog.sh,来观察一下httpd的日志文件。注意:我这里是访问了Apache默认的站点,然后手动刷新Apache站点,来产生点access log,然后停止刷新页面。 

[root@labhost ~]# ./monitorlog.sh  
total 140K  
-rw-r--r--. 1 root root 79K Apr 24 14:09 access_log  
-rw-r--r--. 1 root root 12K Apr 24 14:09 error_log  
total 140K  
-rw-r--r--. 1 root root 79K Apr 24 14:09 access_log  
-rw-r--r--. 1 root root 12K Apr 24 14:09 error_log  
total 96K  
-rw-r--r--. 1 root root   0 Apr 24 14:10 access_log  
-rw-r--r--. 1 root root 79K Apr 24 14:09 access_log.1  
-rw-r--r--. 1 root root 370 Apr 24 14:10 error_log  
-rw-r--r--. 1 root root 12K Apr 24 14:10 error_log.1  
total 96K  
-rw-r--r--. 1 root root   0 Apr 24 14:10 access_log  
-rw-r--r--. 1 root root 79K Apr 24 14:09 access_log.1  
-rw-r--r--. 1 root root 370 Apr 24 14:10 error_log  
-rw-r--r--. 1 root root 12K Apr 24 14:10 error_log.1  
... 

我们可以看到:

  • 由于我设定的是每分钟执行一次logrotate,并且指定了httpd这个logrotate配置文件,所以我们配置的规则会每分钟被执行一次。
  • /var/log/httpd/这个文件夹下:
    • 只有access_log和error_log这两个文件。
    • Apr 24 14:09时,access_log文件大小是79K, error_log文件大小是12K。
  • 停止刷新页面,等待一分钟之后/var/log/httpd/这个文件夹下:
    • 增加了两个文件:access_log.1和error_log.1
    • Apr 24 14:10时,access_log文件被清空,大小为0;而error_log不是空的,证明一直有error信息产生。
  • 为了验证notifempty这个参数是否生效,我们不刷新页面,再多等两分钟,然后从monitorlog.sh执行的结果来看:
  • access_log没有被rotate,因为在第一次access log文件被rotate之后,没有访问日志产生,它的大小为0,我们在配置文件里加了notifempty这个参数,意思就是如果为空,不做rotate。

Apr 24 14:13 /var/log/httpd/文件夹下信息: 

total 96K  
-rw-r--r--. 1 root root   0 Apr 24 14:10 access_log  
-rw-r--r--. 1 root root 79K Apr 24 14:09 access_log.1  
-rw-r--r--. 1 root root 370 Apr 24 14:13 error_log  
-rw-r--r--. 1 root root 663 Apr 24 14:13 error_log.1  
-rw-r--r--. 1 root root 663 Apr 24 14:12 error_log.2  
-rw-r--r--. 1 root root 663 Apr 24 14:11 error_log.3 

rotate 3这个参数:

  • 始终保留3份rotate的文件,那我们多等几分钟,再看看/var/log/httpd/这个文件夹下有哪些文件,即可验证。
  • rotate后的文件名:是以.数字结尾。

Apr 24 14:14 /var/log/httpd/文件夹下信息: 

total 96K  
-rw-r--r--. 1 root root   0 Apr 24 14:10 access_log  
-rw-r--r--. 1 root root 79K Apr 24 14:09 access_log.1  
-rw-r--r--. 1 root root 370 Apr 24 14:14 error_log  
-rw-r--r--. 1 root root 663 Apr 24 14:14 error_log.1  
-rw-r--r--. 1 root root 663 Apr 24 14:13 error_log.2  
-rw-r--r--. 1 root root 663 Apr 24 14:12 error_log.3 

Apr 24 14:15 /var/log/httpd/文件夹下信息: 

total 96K  
-rw-r--r--. 1 root root   0 Apr 24 14:10 access_log  
-rw-r--r--. 1 root root 79K Apr 24 14:09 access_log.1  
-rw-r--r--. 1 root root 370 Apr 24 14:15 error_log  
-rw-r--r--. 1 root root 663 Apr 24 14:15 error_log.1  
-rw-r--r--. 1 root root 663 Apr 24 14:14 error_log.2  
-rw-r--r--. 1 root root 663 Apr 24 14:13 error_log.3 

delaycompress这个参数:

  • 是必须要和compress一起使用的,单独使用无效,可以看到没有任何log文件被压缩处理,rotate前和rotate后的文件大小保持一致。

postrotate/endscript这个参数里的脚本:

/bin/systemctl reload httpd.service > /dev/null 2>/dev/null || true endscript

就是在log日志被rotate之后,需要重新reload httpd service,如果没有这个脚本会怎么样呢?我们来到/etc/logrotate.d/httpd里,把这3行注释掉,再到monitorlog.sh执行的结果来看看: 

total 92K  
-rw-r--r--. 1 root root   0 Apr 24 14:10 access_log  
-rw-r--r--. 1 root root 79K Apr 24 14:09 access_log.1  
-rw-r--r--. 1 root root 370 Apr 24 14:47 error_log.1  
-rw-r--r--. 1 root root 663 Apr 24 14:47 error_log.2  
-rw-r--r--. 1 root root 663 Apr 24 14:46 error_log.3 

注释掉postrotate/endscript脚本后,我们发现:

  • error_log文件在执行rotate之后,新的error_log并没有被创建出来。
  • 我们来刷新一下页面,尝试产生新的access log,发现可以正常写入,大小有变化。 
total 136K  
-rw-r--r--. 1 root root  38K Apr 24 14:52 access_log  
-rw-r--r--. 1 root root  79K Apr 24 14:09 access_log.1  
-rw-r--r--. 1 root root 5.4K Apr 24 14:52 error_log.1  
-rw-r--r--. 1 root root  663 Apr 24 14:47 error_log.2  
-rw-r--r--. 1 root root  663 Apr 24 14:46 error_log.3 
  • 但是我们等待文件被rotate之后,再来观察一下,我们发现,access_log在被rotate之后,新的access_log文件同样没有被创建出来。 
total 136K  
-rw-r--r--. 1 root root  38K Apr 24 14:52 access_log.1  
-rw-r--r--. 1 root root  79K Apr 24 14:09 access_log.2  
-rw-r--r--. 1 root root 5.4K Apr 24 14:52 error_log.1  
-rw-r--r--. 1 root root  663 Apr 24 14:47 error_log.2  
-rw-r--r--. 1 root root  663 Apr 24 14:46 error_log.3 
  • 如果我们继续尝试刷新页面,发现access_log.1和error_log.1日志大小都会增长。这个就可以说明postrotate/endscript中间脚本的作用了,如果没有这个脚本,也就是在执行logrotate之后,没有reload httpd service,那么httpd服务会继续往旧的log日志中写信息,那么针对/var/log/httpd/*log后续的logrotate命令都不会被执行。为什么?
  • 配置文件里的文件路径写了:/var/log/httpd/*log,你是针对以log结尾的文件名。
  • 现在被rotate之后的文件名全都是以 . 数字结尾的。 
total 148K  
-rw-r--r--. 1 root root  49K Apr 24 15:30 access_log.1  
-rw-r--r--. 1 root root  79K Apr 24 14:09 access_log.2  
-rw-r--r--. 1 root root 6.9K Apr 24 15:30 error_log.1  
-rw-r--r--. 1 root root  663 Apr 24 14:47 error_log.2  
-rw-r--r--. 1 root root  663 Apr 24 14:46 error_log.3 

记不记得我们还有一个参数叫copytruncate,我们来试试,在没有postrotate/endscript脚本时,加上这个参数是什么效果。

version2:删除postrotate/endscript脚本,增加copytruncate 

[root@labhost ~]# cat /etc/logrotate.d/httpd  
/var/log/httpd/*log {  
    rotate 3  
    missingok  
    notifempty  
    sharedscripts  
    delaycompress  
    copytruncate  
} 

我们先stop httpd service,然后删除所有的access_log和error_log, 最后start httpd service,可以看到,httpd的日志文件正常产生了。

[root@labhost ~]# systemctl stop httpd  
[root@labhost ~]# rm -rf /var/log/httpd/*  
[root@labhost ~]# ll /var/log/httpd/  
total 0  
[root@labhost ~]#  
[root@labhost ~]# systemctl start httpd  
[root@labhost ~]# ll /var/log/httpd/  
total 4  
-rw-r--r--. 1 root root   0 Apr 24 15:47 access_log  
-rw-r--r--. 1 root root 812 Apr 24 15:47 error_log  
[root@labhost ~]# 

接下来我们再刷新一下页面,产生一些access log和error log,等待几分钟,执行mornitorlog.sh来看一下:

  • access_log和error_log都可以正常rotate。
  • 新的access_log和error_log文件都可以被创建出来,并且可以正常写入log日志。 
total 60K  
-rw-r--r--. 1 root root  17K Apr 24 15:51 access_log  
-rw-r--r--. 1 root root  27K Apr 24 15:51 access_log.1  
-rw-r--r--. 1 root root 2.3K Apr 24 15:51 error_log  
-rw-r--r--. 1 root root 3.6K Apr 24 15:51 error_log.1  
-rw-r--r--. 1 root root  812 Apr 24 15:48 error_log.2 

所以,比起放在postrotate/endscript中间的reload httpd service脚本,我更喜欢用copytruncate这个参数。

version3:在version2的基础上,增加dateext参数 

[root@labhost ~]# cat /etc/logrotate.d/httpd  
/var/log/httpd/*log {  
    rotate 3  
    missingok  
    notifempty  
    sharedscripts  
    delaycompress  
    copytruncate  
    dateext  
} 

我们尝试访问页面,刷新,产生一些access log和error log。等待几分钟,我们执行monitorlog.sh来看一下,可以发现:

  • 最近一次被rotate log文件时以日期格式结尾的。
  • 我们的cron job规定每分钟执行一次logrotate,但是在添加dateext参数之后失效了。所以:
  • 如果你想要logrotate每天执行多次(大于一次),就不要添加dateext参数。
  • 如果你既想要logrotate每天执行多次(大于一次),还想rotate之后的文件以日期格式结尾,有一种方法就是添加dateformat .%s参数。 
total 144K  
-rw-r--r--. 1 root root  30K Apr 24 16:55 access_log  
-rw-r--r--. 1 root root 9.3K Apr 24 15:56 access_log.1  
-rw-r--r--. 1 root root  17K Apr 24 15:52 access_log.2  
-rw-r--r--. 1 root root  26K Apr 24 16:07 access_log-20200424  
-rw-r--r--. 1 root root  27K Apr 24 15:51 access_log.3  
-rw-r--r--. 1 root root 4.1K Apr 24 16:55 error_log  
-rw-r--r--. 1 root root 1.3K Apr 24 15:56 error_log.1  
-rw-r--r--. 1 root root 2.3K Apr 24 15:52 error_log.2  
-rw-r--r--. 1 root root 3.6K Apr 24 16:07 error_log-20200424  
-rw-r--r--. 1 root root 3.6K Apr 24 15:51 error_log.3 

version4:在version3的基础上,增加dateformat -%Y%m%d%H.%s参数

[root@labhost ~]# cat /etc/logrotate.d/httpd  
/var/log/httpd/*log {  
    rotate 3  
    missingok  
    notifempty  
    sharedscripts  
    delaycompress  
    copytruncate  
    dateext  
    dateformat -%Y%m%d%H.%s  
} 

我们再次尝试访问页面,刷新,产生一些access log和error log。等待几分钟,我们执行monitorlog.sh来看一下,可以发现:

  • 我们的cron job现在执行正常了,当log文件非空并且有更新时,可以被执行多次。
  • 被rotate之后的文件是以日期格式结尾,-横杠开头,接着时年月日时,然后句点. 最后是秒,但是最后的.s%是从1970年1月1日00:00:00到目前经历的秒数。 
total 172K  
-rw-r--r--. 1 root root 7.5K Apr 24 17:41 access_log  
-rw-r--r--. 1 root root  26K Apr 24 16:07 access_log-20200424  
-rw-r--r--. 1 root root  25K Apr 24 17:32 access_log-2020042417.1587720721  
-rw-r--r--. 1 root root  14K Apr 24 17:39 access_log-2020042417.1587721141  
-rw-r--r--. 1 root root 3.8K Apr 24 17:40 access_log-2020042417.1587721201  
-rw-r--r--. 1 root root 1.1K Apr 24 17:41 error_log  
-rw-r--r--. 1 root root 3.6K Apr 24 16:07 error_log-20200424 
-rw-r--r--. 1 root root 3.3K Apr 24 17:32 error_log-2020042417.1587720721  
-rw-r--r--. 1 root root 1.8K Apr 24 17:39 error_log-2020042417.1587721141  
-rw-r--r--. 1 root root  514 Apr 24 17:40 error_log-2020042417.1587721201 

version5:在version4的基础上,增加size 50K参数 

[root@labhost ~]# cat /etc/logrotate.d/httpd  
/var/log/httpd/*log {  
    size 50K  
    rotate 3  
    missingok  
    notifempty  
    sharedscripts  
    delaycompress  
    copytruncate  
    dateext  
    dateformat -%Y%m%d%H.%s  
} 

这一次,我们先执行monitorlog.sh来看一下access_log和error_log的大小,再尝试访问页面,刷新,产生一些access log和error log,注意一下,因为我配置的size大小是50K,所以让access_log文件大小<50K,然后等待几分钟,观察monitorlog.sh输出,可以发现:

  • access_log和error_log文件都没有被rotate,因为他们的大小都没有超过50K,从下面的结果可以看出:
  • access_log大小是49K
  • error_log大小是6.6K 
total 132K  
-rw-r--r--. 1 root root  49K Apr 24 18:04 access_log  
-rw-r--r--. 1 root root  26K Apr 24 16:07 access_log-20200424  
-rw-r--r--. 1 root root 1.9K Apr 24 17:56 access_log-2020042417.1587722161  
-rw-r--r--. 1 root root 3.8K Apr 24 17:58 access_log-2020042417.1587722281  
-rw-r--r--. 1 root root 7.5K Apr 24 17:59 access_log-2020042417.1587722341  
-rw-r--r--. 1 root root 6.6K Apr 24 18:04 error_log  
-rw-r--r--. 1 root root 3.6K Apr 24 16:07 error_log-20200424  
-rw-r--r--. 1 root root  257 Apr 24 17:56 error_log-2020042417.1587722161  
-rw-r--r--. 1 root root  514 Apr 24 17:58 error_log-2020042417.1587722281  
-rw-r--r--. 1 root root 1.1K Apr 24 17:59 error_log-2020042417.1587722341 
  • 现在我们继续刷新页面,让access_log大小>50K,观察monitorlog.sh输出,可以发现:
  • Apr 24 18:12时logrotate被执行了一次,由于access_log文件大小>50K,所以就被rotate了。并保存为:access_log-2020042418.1587723121,由于error_log文件大小<50K,所以此次logrotate忽略了这个文件。 
total 132K  
-rw-r--r--. 1 root root  52K Apr 24 18:11 access_log  
-rw-r--r--. 1 root root  26K Apr 24 16:07 access_log-20200424  
-rw-r--r--. 1 root root 1.9K Apr 24 17:56 access_log-2020042417.1587722161  
-rw-r--r--. 1 root root 3.8K Apr 24 17:58 access_log-2020042417.1587722281  
-rw-r--r--. 1 root root 7.5K Apr 24 17:59 access_log-2020042417.1587722341  
-rw-r--r--. 1 root root 7.1K Apr 24 18:11 error_log 
-rw-r--r--. 1 root root 3.6K Apr 24 16:07 error_log-20200424  
-rw-r--r--. 1 root root  257 Apr 24 17:56 error_log-2020042417.1587722161  
-rw-r--r--. 1 root root  514 Apr 24 17:58 error_log-2020042417.1587722281  
-rw-r--r--. 1 root root 1.1K Apr 24 17:59 error_log-2020042417.1587722341  
total 128K  
-rw-r--r--. 1 root root    0 Apr 24 18:12 access_log  
-rw-r--r--. 1 root root  26K Apr 24 16:07 access_log-20200424  
-rw-r--r--. 1 root root 3.8K Apr 24 17:58 access_log-2020042417.1587722281  
-rw-r--r--. 1 root root 7.5K Apr 24 17:59 access_log-2020042417.1587722341  
-rw-r--r--. 1 root root  52K Apr 24 18:12 access_log-2020042418.1587723121  
-rw-r--r--. 1 root root 7.1K Apr 24 18:11 error_log  
-rw-r--r--. 1 root root 3.6K Apr 24 16:07 error_log-20200424  
-rw-r--r--. 1 root root  257 Apr 24 17:56 error_log-2020042417.1587722161  
-rw-r--r--. 1 root root  514 Apr 24 17:58 error_log-2020042417.1587722281  
-rw-r--r--. 1 root root 1.1K Apr 24 17:59 error_log-2020042417.1587722341 

version6:在version5的基础上,增加compress参数 

[root@labhost ~]# cat /etc/logrotate.d/httpd  
/var/log/httpd/*log {  
    compress  
    size 50K  
    rotate 3  
    missingok  
    notifempty  
    sharedscripts  
    delaycompress  
    copytruncate  
    dateext  
    dateformat -%Y%m%d%H.%s  
} 

我们继续刷新页面,让access_log大小>50K,观察monitorlog.sh输出,可以发现:

  • Apr 24 17:59时logrotate被执行了一次,由于access_log文件大小>50K,所以就被rotate了,并且被做了压缩处理,保存为:access_log-2020042417.1587722341.gz被压缩之前大小是7.5K,被压缩后是398,不到1k,所以强烈推荐添加这个参数,节省空间啊!!!
  • 由于error_log文件大小<50K,所以此次logrotate忽略了这个文件。 
total 168K  
-rw-r--r--. 1 root root    0 Apr 24 18:20 access_log  
-rw-r--r--. 1 root root  26K Apr 24 16:07 access_log-20200424  
-rw-r--r--. 1 root root  398 Apr 24 17:59 access_log-2020042417.1587722341.gz  
-rw-r--r--. 1 root root 1.3K Apr 24 18:12 access_log-2020042418.1587723121.gz  
-rw-r--r--. 1 root root  84K Apr 24 18:20 access_log-2020042418.1587723601  
-rw-r--r--. 1 root root  19K Apr 24 18:19 error_log  
-rw-r--r--. 1 root root 3.6K Apr 24 16:07 error_log-20200424  
-rw-r--r--. 1 root root  257 Apr 24 17:56 error_log-2020042417.1587722161  
-rw-r--r--. 1 root root  514 Apr 24 17:58 error_log-2020042417.1587722281  
-rw-r--r--. 1 root root 1.1K Apr 24 17:59 error_log-2020042417.1587722341 

2、logwatch

如果系统发生了问题等,绝大部分的错误信息都会被记录到日志文件中, 因此系统管理员的重要任务之一就是分析日志。但你不可能手动通过 vim 等软件去查看日志文件,因为数据量太大! 我们可以通过一个叫“ logwatch ”的程序分析日志信息,在启动邮件服务的前提下,你的 root 老是会收到标题为 logwatch 的信件。

Logwatch是一款Perl脚本编写的、开源的日志分析工具。它能对原始的日志文件进行解析并转换成结构化格式的文档,也能根据您的使用情况和需求来定制报告。Logwatch的特点是配置简单、监控、分析日志方便,而且可以对某些功能进行定制化。

Logwatch安装

源码安装:

[root@DB-Server tmp]# tar -xzvf logwatch-7.4.3.tar.gz 
[root@DB-Server tmp]# cd logwatch-7.4.3
[root@DB-Server logwatch-7.4.3]# ./install_logwatch.sh

 在线yum安装:

yum -y install logwatch

Logwatch的配置文件

Logwatch的配置文件为 /etc/logwatch/conf/logwatch.conf ,初始安装后,这个配置文件是空的。你可以将配置文件的模板拷贝过来,如果不做这一步,就会默认使用/usr/share/logwatch/default.conf/logwatch.conf 这个配置文件。

[root@DB-Server ~]# cp  /usr/share/logwatch/default.conf/logwatch.conf  /etc/logwatch/conf/logwatch.conf 

配置的具体参数介绍:

LogDir = /var/log                系统日志或需要分析日志所在路径,logwatch会分析和统计/var/log/中的日志
TmpDir = /var/cache/logwatch     指定logwatch临时目录位置
Output = stdout                  输出格式(stdout 屏幕上显示)
Format = text                    输出格式,有text、html选项可以选择
Encode = none                    编码格式
MailTo = root                    分析结果发送给那些人或邮件组。多个邮箱逗号隔开
MailFrom = Logwatch              邮件的发件人
Range = yesterday                处理什么时候的日志 , 可选项 All(所有) ,Yesterday(昨天) , Today(今天)
                                 Range = "1 hours ago for that hour"
                                 Range = "-7 days"
                                 Range = "between -7 days and -3 days"
                                 Range = "since March 15, 2017"
                                 Range = "first Friday in October"
                                 Range = "2017/04/15 12:50:15 for that second"
Detail = Low                     该参数控制着 Logwatch 报告的详细程, 可选项:Low , Med , High 也可以用0-10数字表示
                                 其中High、Med、Low 几个选项分别代表着10、5和0数字。
Service = All                    监控所有服务 all
Service = "-httpd"               但是不监控的服务前面加 “-” , 如 -httpd ,即不监控 httpd 服务 , 可以写多条
mailer = "/usr/sbin/sendmail -t" 发送邮件的方式(可以选sendmail,postfix,Qmail)

注意不同版本的Logwatch的参数有所区别,例如如下logwatch-7.3-9与logwatch-7.4.3的对比如下:

[root@DB-Server01 ~]# sed -n "/^\s*[^#\t].*$/p" /usr/share/logwatch/default.conf/logwatch.conf
LogDir = /var/log
TmpDir = /var/cache/logwatch
MailTo = root
MailFrom = Logwatch
Print = No
Range = yesterday
Detail = Low 
Service = All
Service = "-zz-network"     # Prevents execution of zz-network service, which
                            # prints useful network configuration info.
Service = "-zz-sys"         # Prevents execution of zz-sys service, which
                            # prints useful system configuration info.
Service = "-eximstats"      # Prevents execution of eximstats service, which
                            # is a wrapper for the eximstats program.
mailer = "sendmail -t"
[root@DB-Server ~]# sed -n "/^\s*[^#\t].*$/p" /etc/logwatch/conf/logwatch.conf 
LogDir = /var/log
TmpDir = /var/cache/logwatch
Output = stdout
Format = text
Encode = none
MailTo = root
MailFrom = Logwatch
Range = yesterday
Detail = Low
Service = All
Service = "-zz-network"     # Prevents execution of zz-network service, which
                            # prints useful network configuration info.
Service = "-zz-sys"         # Prevents execution of zz-sys service, which
                            # prints useful system configuration info.
Service = "-eximstats"      # Prevents execution of eximstats service, which
                            # is a wrapper for the eximstats program.
mailer = "/usr/sbin/sendmail -t"
[root@DB-Server ~]# 

这个配置文件基本不需要修改(我在实验时把 Range 项改为了 All,否则一会儿的实验可以分析的日志过少),它就会默认每天执行。它为什么会每天执行呢?聪明的读者已经想到了,一定是 crond 服务的作用。没错,logwatch 一旦安装,就会在 /etc/cron.daily/ 目录中建立“0logwatch”文件 ,有些版本是一个软链,用于在每天定时执行 logwatch 命令,分析和监控相关日志。

[root@DB-Server tmp]# more  /etc/cron.daily/0logwatch
#!/bin/sh
#Set logwatch location
LOGWATCH_SCRIPT="/usr/sbin/logwatch"
#Add options to this line. Most options should be defined in /etc/logwatch/conf/logwatch.conf,
#but some are only for the nightly cronrun such as --output mail and should be set here.
#Other options to consider might be "--format html" or "--encode base64", man logwatch for more details.
OPTIONS="--output mail"
#Call logwatch
$LOGWATCH_SCRIPT $OPTIONS
exit 0
[root@DB-Server tmp]# ls -l  /etc/cron.daily/0logwatch
-rwxr-xr-x 1 root root 434 Apr 27 15:09 /etc/cron.daily/0logwatch
[root@DB-Server tmp]# 

Logwatch使用

1. 查看logwatch的帮助信息(注意不同版本间的区别)

[root@DB-Server log]# logwatch --help
Usage: /usr/sbin/logwatch [--detail <level>] [--logfile <name>] [--output <output_type>]
   [--format <format_type>] [--encode <enconding>] [--numeric]
   [--mailto <addr>] [--archives] [--range <range>] [--debug <level>]
   [--filename <filename>] [--help|--usage] [--version] [--service <name>]
   [--hostformat <host_format type>] [--hostlimit <host1,host2>] [--html_wrap <num_characters>]
--detail <level>: Report Detail Level - High, Med, Low or any #.
--logfile <name>: *Name of a logfile definition to report on.
--logdir <name>: Name of default directory where logs are stored.
--service <name>: *Name of a service definition to report on.
--output <output type>: Report Output - stdout [default], mail, file.
--format <formatting>: Report Format - text [default], html.
--encode <encoding>: Enconding to use - none [default], base64.
--mailto <addr>: Mail report to <addr>.
--archives: Use archived log files too.
--filename <filename>: Used to specify they filename to save to. --filename <filename> [Forces output to file].
--range <range>: Date range: Yesterday, Today, All, Help
                             where help will describe additional options
--numeric: Display addresses numerically rather than symbolically and numerically
           (saves  a  nameserver address-to-name lookup).
--debug <level>: Debug Level - High, Med, Low or any #.
--hostformat: Host Based Report Options - none [default], split, splitmail.
--hostlimit: Limit report to hostname - host1,host2.
--hostname: overwrites hostname
--html_wrap <num_characters>: Default is 80.
--version: Displays current version.
--help: This message.
--usage: Same as --help.
* = Switch can be specified multiple times...

使用案例:

perl /usr/share/logwatch/scripts/logwatch.pl
logwatch --service sshd --print
logwatch --detail High --Service All --range All --print
logwatch --detail High --Service All --range All --output stdout
logwatch --detail 10 --range today --service http --service postfix --service zz-disk_space --format html --output file --filename /tmp/logwatch.html

注意上面有些版本不能执行,例如logwatch-7.4.3中就没有参数--print,需要用参数--output。

[root@MyLinx ~]#  logwatch --service sshd --print  
 ################### Logwatch 7.3 (03/24/06) #################### 
        Processing Initiated: Mon Apr 24 08:11:00 2017
        Date Range Processed: yesterday
                              ( 2017-Apr-23 )
                              Period is day.
      Detail Level of Output: 10
              Type of Output: unformatted
           Logfiles for Host: xxx.xxx.xxx
  ################################################################## 
 --------------------- SSHD Begin ------------------------ 
 Users logging in through sshd:
    xxxxx:
       192.168.xxx.xxx (xxxx): 276 times
    oracle:
       192.168.xxx.xxx (xxxxx): 1 time
 Received disconnect:
    11: The user disconnected the application
       192.168.xxx.xxx : 276 Time(s)
 ---------------------- SSHD End ------------------------- 
 ###################### Logwatch End ######################### 
[root@DB-Server log]# logwatch --detail 10 --range all --service sshd --format text --output file --filename /tmp/logwatch.txt
[root@DB-Server log]# more /tmp/logwatch.txt 
 ################### Logwatch 7.4.3 (04/27/16) #################### 
        Processing Initiated: Thu Apr 27 17:17:42 2017
        Date Range Processed: all
        Detail Level of Output: 10
        Type of Output/Format: file / text
        Logfiles for Host: DB-Server.localdomain
 ################################################################## 
 --------------------- SSHD Begin ------------------------ 
 Couldn't resolve these IPs:
    get253194.gfg1.esquel.com(192.168.103.21): 1 Time(s)
    get253194.gfg1.esquel.com(192.168.103.26): 1 Time(s)
 Failed logins from:
    192.168.7.xxx: 1 time
       root/password: 1 time
 Users logging in through sshd:
    root:
       192.168.103.15 (xxxxx): 4 times
       192.168.103.21 (xxxxx): 4 times
       192.168.103.22 (xxxxx): 3 times
       192.168.103.26 (xxxxx): 2 times
 SFTP subsystem requests: 6 Time(s)
 ---------------------- SSHD End ------------------------- 
 ###################### Logwatch End #########################

如果想要让这个日志分析马上执行,则只需执行 logrotate 命令即可。命令如下:

[root@localhost ~]# logwatch
#马上执行logwatch日志分析工具
[root01ocalhost ~]# mail
#查看邮件
Heirloom Mail version 12.4 7/29/08. Type ? for help, "/var/spool/mail/root": 5 messages 1 new 2 unread
1 [email protected] Fri Jun 7 11:17 42/1482 "Logwatch for localhost.localdomain (Linux)"
U 2 [email protected] Fri Jun 7 11:19 42/1481 "Logwatch for localhost.localdomain (Linux)"
3 [email protected] Fri Jun 7 11:23 1234/70928 "Logwatch for localhost.localdomain (Linux)"
4 [email protected] Fri Jun 7 11:24 190/5070 "Logwatch for localhost.localdomain (Linux)"
5 [email protected] Fri Jun 7 11:55 41/1471 "Logwatch for localhost.localdomain (Linux)"
>N 6 [email protected] Fri Jun 7 11:57 189/5059 "Logwatch for localhost.localdomain (Linux)"
#第6封邮件就是刚刚生成的曰志分析邮件,"N"代表没有查看
& 6
Message 6:
From [email protected] Fri Jun 7 11:57:35 2013 Return-Path: <[email protected]>
X-Original-To: root
Delivered-To: [email protected]
To: [email protected]
From: [email protected]
Subject: Logwatch for localhost.localdomain (Linux)
Content-Type: text/plain; charset="iso-8859-1"
Date: Fri, 7 Jun 2013 11:57:33 +0800 (CST)
Status: R
######## Logwatch 7.3.6 (05/19/07) ################
Processing Initiated: Fri Jun 7 11:57:33 2013
Date Range Processed: all
Detail Level of Output: 0
Type of Output: unformatted
Logfiles for Host: localhost.localdomain
###################################################
#上面是曰志分析的时间和日期
...省略部分输出...
--------- Connections (secure-log) Begin-----------
#分析secure.log日志的内容。统计新建立了哪些用户和组,以及错误登录信息 New Users:
    bb (501)
    def (503)
    hjk (504)
    zhangsan (505)
    dovecot (97)
    dovenull (498)
    aa (500)

New Groups:
    bb (501)
    def (503)
    hjk (504)
    zhangsan (505)
    dovecot (97)
    dovenull (498)
    aa (500)

Failed logins:
    User root:
    (null): 3 Time(s)

Root logins on tty's: 7 Time(s).

**Unmatched Entries**
groupadd: group added to /etc/group: name=dovecot, GID=97: 1 Time(s)
groupadd: group added to /etc/group: name=dovenul1, GID=498: 1 Time(s)
groupadd: group added to /etc/gshadow: name=dovecot: 1 Time(s)groupadd: group added to /etc/gshadow: name=dovenull: 1 Time(s)
--------Connections (secure-log)End-------
-------------SSHD Begin-------------------
#分析SSHD的日志。可以知道哪些IP地址连接过服务器
SSHD Killed: 7 Time(s)
SSHD Started: 24 Time(s)
Users logging in through sshd:
192.168.0.104: 10 times
192.168.0.108: 8 times
192.168.0.101: 6 times
192.168.0.126: 4 times
192.168.0.100: 3 times
192.168.0.105: 3 times
192.168.0.106: 2 times
192.168.0.102: 1 time
192.168.0.103: 1 time
SFTP subsystem requests: 3. Time(s)
**Unmatched Entries**
Exiting on signal 15 : 6 time(s)
----------------SSHD End-----------

--------------- yum Begin ---------
#统计yum安装的软件。可以知道我们安装了哪些软件

Packages Installed:
    perl-YAML-Syck-1.07-4.el6.i686
    perl-Date-Manip-6.24-1.el6.noarch
    logwatch-7.3.6-49.el6.noarch
-----------yum End-------------

--------Disk Space Begin-------
#统计磁盘空间情况
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 20G 1.9G 17G 11% /
/dev/sda1 194M 26M 158M 15% /boot
/dev/sr0 3.5G 3.5G 0 100% /mnt/cdrom
---------Disk Space End-----------------
#########Logwatch End ##################

有了这个日志分析工具,日志管理工作就会轻松很多。

3、syslog-ng结合cron logrotate和logwatch管理日志

syslog-ng 的配置是基于框架: LOG STATEMENTS『SOURCES - FILTERS -DESTINATIONS』。即 日志描述 日志源-过滤器-日志服务器。

整个syslog-ng的配置文件/etc/syslog-ng/syslog-ng.conf可以分为五个部分:

options(全局配置){
            chain_hostnames(yes|no) # 是否打开主机名链功能,打开后可在多网络段转发日志时有效
            long_hostnames(yes|no) # 是否使用chain_hostnames的别名,已不建议使用
            keep_hostname(yes|no) # 是否保留日志消息中保存的主机名称
            use_dns(yes|no) # 是否打开DNS查询功能,
            use_fqdn(yes|no) # 是否使用完整的域名
            check_hostname(yes|no) # 是否检查主机名有没有包含不合法的字符
            bad_hostname(regexp) # 可通过正规表达式指定某主机的信息不被接受
            dns_cache(yes|no) # 是否打开DNS缓存功能
            dns_cache_expire(n) # DNS缓存功能打开时,一个成功缓存的过期时间dns_cache_expire_failed(n) # DNS缓存功能打开时,一个失败缓存的过期时间
            dns_cache_size(n) # DNS缓存保留的主机名数量
            create_dirs(yes|no) # 当指定的目标目录不存在时,是否创建该目录
            dir_owner(uid) # 目录的UID
            dir_group(gid) # 目录的GID
            dir_perm(perm) # 目录的权限
            owner(uid) # 文件的UID
            group(gid) # 文件的GID
            perm(perm) # 文件的权限
            gc_busy_threshold(n) # 当syslog-ng忙时,其进入垃圾信息收集状态的时间一旦分派的对象达到这个数字,syslog-ng就启动垃圾信息收集状态。默认值是:3000
            gc_idle_threshold(n) # 当syslog-ng空闲时,其进入垃圾信息收集状态的时间一旦被分派的对象到达这个数字,syslog-ng就会启动垃圾信息收集状态,默认值是:100
            log_fifo_size(n) # 输出队列的行数
            log_msg_size(n) # 消息日志的最大值(bytes)
            mark(n) # 多少时间(秒)写入两行MARK信息供参考,目前没有实现
            stats(n) # 多少时间(秒)写入两行STATUS信息,默认值是:600
            sync(n) # 缓存多少行的信息再写入文件中,0为不缓存,局部参数可以覆盖该值。
            time_reap(n) # 在没有消息前,到达多少秒,即关闭该文件的连接
            time_reopen(n) # 对于死连接,到达多少秒,会重新连接
            use_time_recvd(yes|no) # 宏产生的时间是使用接受到的时间,还是日志中记录的时间;建议使用R_的宏代替接收时间,S_的宏代替日志记录的时间,而不要依靠该值定义。
}

source(日志源){
            internal()    #syslog-ng内部产生的消息
            file()          #从指定文件读取日志信息
            pipe()        #从指定的管道,读取日志信息
            fifo()         #从指定的FIFO设备,读取日志信息
            program() # 打开指定的应用程序,从它的标准输出读取消息
            sun-stream(), sun-streams() # 在solaris系统中,打开一个(多个)指定的STREAM设备,从其中读取日志消息
            system()#从系统读取信息
            tcp(), tcp6() # 在指定的TCP端口接收日志消息
            udp(), udp6() # 在指定的UDP端口接收日志消息
            unix-dgram() # 打开指定的SOCK_DGRAM模式的unix套接字,接收日志消息

            unix-stream() # 打开指定的SOCK_STREAM模式的unix套接字,接收日志消息
}


destination(日志目的地){
            file() # 把日志消息写入指定的文件
            pipe() # 把日志消息发送到指定的管道
            fifo() # 把日志消息发送到指定的FIFO设备
            program() # 启动指定的程序,并把日志消息发送到该进程的标准输入
            sql() # 把日志消息写入数据库,适用于3.x版本及更高版本的syslog-ng
            tcp() and tcp6() # 把日志消息发送到指定的TCP端口
            udp() and udp6() # 把日志消息发送到指定的UDP端口
            unix-dgram() # 把日志消息写入指定的SOCK_DGRAM模式的unix套接字
            unix-stream() # 把日志消息写入指定的SOCK_STREAM模式的unix套接字
            usertty() # 把日志消息发送到已经登陆的指定用户终端窗口
}

filtier(过滤器){
            facility() # 根据facility(设备)选择日志消息
            filter() # 调用另一条过滤规则
            host() # 日志消息的主机名是否和一个正则表达式匹配
            level() or priority() # 根据level(优先级)选择日志消息
            match() # 对日志消息的内容进行正则匹配
            message()#使用正则表达式过滤信息
            netmask()#基于 IP 地址过滤信息
            program()#基于发送程序过滤信息
}

log(日志规则)
{source S1; source S2; ...filter F1; filter F2; ... destination D1; destination D2; ...}

单机配置实例:

options {
        chain_hostnames(no); # The default action of syslog-ng is to log a STATS line
        # to the file every 10 minutes.  That's pretty ugly after a while.
        # Change it to every 12 hours so you get a nice daily update of
        # how many messages syslog-ng missed (0). stats_freq(43200);
};
 
source src {
    unix-stream("/dev/log" max-connections(256));
    internal();
};
 
source kernsrc { file("/proc/kmsg"); }; # define destinations destination authlog { file("/var/log/auth.log"); };
destination syslog { file("/var/log/syslog"); };
destination cron { file("/var/log/cron.log"); };
destination daemon { file("/var/log/daemon.log"); };
destination kern { file("/var/log/kern.log"); };
destination lpr { file("/var/log/lpr.log"); };
destination user { file("/var/log/user.log"); };
destination mail { file("/var/log/mail.log"); };
 
destination mailinfo { file("/var/log/mail.info"); };
destination mailwarn { file("/var/log/mail.warn"); };
destination mailerr { file("/var/log/mail.err"); };
 
destination newscrit { file("/var/log/news/news.crit"); };
destination newserr { file("/var/log/news/news.err"); };
destination newsnotice { file("/var/log/news/news.notice"); };
 
destination debug { file("/var/log/debug"); };
destination messages { file("/var/log/messages"); };
destination console { usertty("root"); }; # By default messages are logged to tty12... destination console_all { file("/dev/tty12"); }; # ...if you intend to use /dev/console for programs like xconsole
# you can comment out the destination line above that references /dev/tty12
# and uncomment the line below. #destination console_all { file("/dev/console"); }; # create filters filter f_authpriv { facility(auth, authpriv); };
filter f_syslog { not facility(authpriv, mail); };
filter f_cron { facility(cron); };
filter f_daemon { facility(daemon); };
filter f_kern { facility(kern); };
filter f_lpr { facility(lpr); };
filter f_mail { facility(mail); };
filter f_user { facility(user); };
filter f_debug { not facility(auth, authpriv, news, mail); };
filter f_messages { level(info..warn)
        and not facility(auth, authpriv, mail, news); };
filter f_emergency { level(emerg); };
 
filter f_info { level(info); };
filter f_notice { level(notice); };
filter f_warn { level(warn); };
filter f_crit { level(crit); };
filter f_err { level(err); };
filter f_failed { message("failed"); };
filter f_denied { message("denied"); }; # connect filter and destination log { source(src); filter(f_authpriv); destination(authlog); };
log { source(src); filter(f_syslog); destination(syslog); };
log { source(src); filter(f_cron); destination(cron); };
log { source(src); filter(f_daemon); destination(daemon); };
log { source(kernsrc); filter(f_kern); destination(kern); };
log { source(src); filter(f_lpr); destination(lpr); };
log { source(src); filter(f_mail); destination(mail); };
log { source(src); filter(f_user); destination(user); };
log { source(src); filter(f_mail); filter(f_info); destination(mailinfo); };
log { source(src); filter(f_mail); filter(f_warn); destination(mailwarn); };
log { source(src); filter(f_mail); filter(f_err); destination(mailerr); };
 
log { source(src); filter(f_debug); destination(debug); };
log { source(src); filter(f_messages); destination(messages); };
log { source(src); filter(f_emergency); destination(console); }; # default log log { source(src); destination(console_all); };

cron分为系统工作和用户工作两种。用户的工作用 crontab 指令下达,内容保存在 /var/spool/cron/$user;系统工作直接编辑/etc/crontab文件进行设定。
/etc/cron.allow:将可以使用crontab的用户名写入其中
/etc/cron.deny:将不可以使用crontab的用户名写入其中

两个文件都存在的情况下,/etc/cron.allow的优先权比/etc/cron.deny高。系统默认保留/etc/cron.deny,把限制使用crontab的用户写入其中,其他用户默认都可以使用crontab。

用户工作:

下达编辑指令后,会出现 vi 的编辑界面。

系统工作要直接编辑/etc/crontab文件:

说明:

00 20 * * * root    run-parts /etc/cron.daily    #每天晚上8点运行/etc/cron.daily目录内的脚本
00 20 * * 0 root    run-parts /etc/cron.weekly    #每周日晚上8点运行/etc/cron.weekly目录内的脚本

特殊字符含义:

anacron配置

 anacron存在的目的是为了弥补不能够24小时开机的服务器的cron的不足。以我的设置为例,我设定每周日运行/etc/cron.weekly目录下的档案,如果我有一周周日刚好去约会了(虽然不太可能),没有开电脑,那么就要等下一周的周日再继续执行。这势必会延误一些日程的安排。基于此,anacron出现了。anacron会以用户设定的时间频率去侦测系统未进行的cron任务并将它执行。

anacron的配置很简单,配置文件在/etc/anacrontab。我的anacron配置如下:

anacron的每项任务由4个字段组成:天数,延迟时间,工作名称,执行的指令。以上两项任务的意思是:每天开机5分钟后执行/etc/cron.daily目录内的脚本;每周开机10分钟后运行/etc/cron.weekly目录内的脚本。

anacron在执行前,会比对对应目录内,脚本最近一次执行的时间戳,若差异不足一天,则不执行脚本。

logrotate配置

logrotate被设计用来整理归档日志文件。想象一下,如果配置好 syslog-ng 后,就再也不对日志进行管理,那么/var/log目录下的日志文件将会越来越大,变得难以读取和分析。基于此,产生了logrotate。logrotate 的主要功能是将旧的日志备份,并产生新的日志文件继续记录,到达用户规定的备份数量之后,就将其删除。

它的原理可以用下图描述:

配置文件包括/etc/logrotate.conf和/etc/logrotate.d/。前者是针对整体设定,后者是针对具体 daemon 设定。

vim /etc/logrotate.conf      

#每周备份
weekly
#保留四个文件
rotate 4
#每次建立新的日志记录档案
create
#是否启用压缩
#compress
 
#将 logrotate.d 目录内的档案读取进来进行 rotate
include /etc/logrotate.d
 
#仅针对 wtmp 的设定
/var/log/wtmp{
    monthly
    size 1M
    create 0664 root utmp
    rotate 1
}

虽然可以将所有的 logrotate 工作都记录到 logrotate.conf 档案内,但是由于系统存在很多 dameon,这样会使 logrotate.conf 档案显得冗长,而且不方便服务的管理。所以建议对于每个服务,建立单独的 logrotate 文件并放在 /etc/logrotate.d 目录内。

基于 syslog-ng 设定的logrotate:/etc/logrotate.d/syslog-ng。在 syslog-ng 的配置文件中,我设定了16个日志记录档案,所以,syslog-ng 的 logrotate 要针对这 16 个档案,如下:

这样,就可以利用 logrotate 进行日志档案的备份工作了。logrotate 默认是利用 cron 来进行工作的,在 /etc/cron.weekly 目录下,有一个名为 logrotate 的脚本,内容是: 

所以,在每周执行 cron 的时候,都会运行 logrotate 脚本,它读取 logrotate.conf 对日志进行备份。

logwatch配置

logwatch 是一个日志分析工具,它根据用户设定的频率来分析日志并给指定用户发送邮件。同样,可以使用 emerge 安装。安装完成后,默认的配置文件在 /usr/share/logwatch/default.conf/logwatch.conf。

用户自定义的配置文件在 /etc/logwatch/。将 /usr/share/logwatch/default.conf/logwatch.conf 复制到 /etc/logwatch/,并稍加修改即可使用。一些典型配置选项如下:

LogDir = /var/log                    #logwatch 会去 /var/log 找你定义的 log 文件
TmpDir = /var/cache/logwatch   #缓存目录
Output = mail                         #输出形式为 mail
MailTo = root                          #发送给 root
MailFrom = Logwatch                #邮件发送者
Range = yesterday                    #处理什么时候的日志 , 可选项  All , Yesterday , Today 
Detail = High                           #日志详细度, 可选项 Low , Med , High , 或是 0-10数字
Print = No                              #可选项, Yes 会被打印到系统标准输出, 并且不会以邮件的形式发送到 MailTo 设定的邮箱里 , No 选项则会发到邮箱中
Server = All                             #监控所有服务 all
mailer = "/usr/sbin/sendmail -t" #发送邮件的服务        

 logwatch 也是用 cron 来执行的,在 /etc/cron.daily 目录下,有 logwatch 执行脚本。

整个流程可以这样解释:syslog-ng 负责记录日志,logrotate 通过 cron 和 anacron 进行日志的整理,logwatch 通过 cron 和 anacron 进行日志分析并发送给 root。

四、统一日志管理

1、logger

logger这个小工具可以生成日志,主要用于我们配置的日志系统是否可以正常的记录日志。

[root@test ~]#logger  --help

用法:
 logger [选项] [消息]

选项:
 -T, --tcp             只使用 TCP
 -d, --udp             只使用 UDP
 -i, --id              同时记录进程 ID
 -f, --file <文件>     记录此文件的内容
 -h, --help            显示此帮助并退出
 -S, --size <num>      maximum size for a single message (default 1024)
 -n, --server <name>   write to this remote syslog server
 -P, --port <port>     use this port for UDP or TCP connection
 -p, --priority <prio> mark given message with this priority
 -s, --stderr          output message to standard error as well
 -t, --tag <标志>      用此标志标记每一行
 -u, --socket <套接字> 写入此 Unix 套接字
 -V, --version         输出版本信息并退出

 tail /var/log/messages  查看最后十条,  tail -f 可以实时查看最后的十条:

可以使用logger命令发送系统日志。logger将消息发送到rsyslog服务,默认严重性为notice(user.notice)的消息发送,除非通过-p(priority)另外指定:

logger -p user.notice hello world!

给local3发送一条info级别或以上级别的日志:

[root@test ~]#logger -p "local3.info" "this is test log" 
[root@test ~]#tail /var/log/sshd.log 
Dec 24 19:23:33 test sshd[4532]: Received signal 15; terminating.
Dec 24 19:23:33 test sshd[4575]: Server listening on 0.0.0.0 port 41319.
Dec 24 19:23:33 test sshd[4575]: Server listening on :: port 41319.
Dec 24 19:42:49 test qiuhom: this is test log
[root@test ~]#

有了这个工具我们可以很好的测试日志系统是否在正常记录日志。

配置local4 的所有级别消息都发送给所有登录到系统的用户终端进行显示:

[root@test ~]#grep "local" /etc/rsyslog.conf
$ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
# Turn off message reception via local log socket;
# local messages are retrieved through imjournal now.
local7.*                                                /var/log/boot.log
local3.*                                                /var/log/sshd.log
local4.*                                                *
[root@test ~]#systemctl restart rsyslog
[root@test ~]#syst^C
[root@test ~]#who 
root     tty1         2019-12-24 19:50
qiuhom   pts/0        2019-12-24 19:03 (192.168.0.232)
qiuhom   pts/1        2019-12-24 19:50 (192.168.0.232)
[root@test ~]#logger -p "local4.info" "this is test log"

Message from syslogd@test at Dec 24 19:53:02 ...
 qiuhom:this is test log
[root@test ~]#

2、journalctl

journalctl工具是centos7上的一个日志管理工具,红帽7的systemd日志默认存储在/run/log目录中,其内容将在重启后清除。

Systemd 是一系列工具的集合,并且统一管理所有unit的启动日志, 这个专用的系统日志管理服务便是​​Journald​​​。这个服务的设计初衷是克服现有 Syslog 服务的日志内容易伪造和日志格式不统一等缺点,Journald 用二进制格式保存所有的日志信息,必须使用 Journald 提供的 journalctl 来查看,因而日志内容很难被手工伪造。

Journald 还提供了一个 journalctl 命令来查看日志信息,用journalctl一个命令查看所有日志(内核日志和应用日志),这样就使得不同服务输出的日志具有相同的排版格式, 便于数据的二次处理。

journalctl 将其管理的所有后台进程打印到 std:out(即控制台)的输出重定向到了日志文件,默认不带任何参数时会输出系统和所有后台进程的混合日志。

日志的配置文件/etc/systemd/journald.conf,默认日志最大限制为所在文件系统容量的 10%,可以修改 /etc/systemd/journald.conf 中的 SystemMaxUse 来指定该最大限制。

二进制文件只能通过journalctl查找事件:

journalctl:以less的形式从最旧的日志条目显示完整的系统日志;
journalctl -n number:显示最后number条日志;
journalctl  -p  err :根据日志优先级过滤日志条目;
journalctl -f :持续动态输出最后十行;
journalctl --since today:今天的日志;
journalctl --since "2021-5-1 20:00:00  --until  "2021-5-1 21:00:00" :读取时间段的日志条目。
journalctl  -o  verbose:显示日志的详细信息

同时,可以通过日志的详细信息中的特定的信息来搜索日志条目,比如:

journalctl  _PID=1234  :根据PID号搜索日志;
journalctl  _UID=1234  :根据用户UID号搜索日志;

journalctl使用案例

1)查看所有日志(默认情况下,只保存本次启动的日志)

[root@test ~]#journalctl 
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 20:01:01 CST. --
12月 23 12:42:48 docker systemd-journal[105]: Runtime journal is using 8.0M (max allowed 91.3M, trying to leave 136.9
12月 23 12:42:48 docker kernel: Initializing cgroup subsys cpuset
12月 23 12:42:48 docker kernel: Initializing cgroup subsys cpu
12月 23 12:42:48 docker kernel: Initializing cgroup subsys cpuacct
12月 23 12:42:48 docker kernel: Linux version 3.10.0-957.27.2.el7.x86_64 ([email protected]) (gcc ve
12月 23 12:42:48 docker kernel: Command line: BOOT_IMAGE=/vmlinuz-3.10.0-957.27.2.el7.x86_64 root=/dev/mapper/centos-
12月 23 12:42:48 docker kernel: Disabled fast string operations
12月 23 12:42:48 docker kernel: e820: BIOS-provided physical RAM map:
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x0000000000000000-0x000000000009ffff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000000a0000-0x00000000000fffff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x0000000000100000-0x000000007f045fff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f046000-0x000000007f0ccfff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f0cd000-0x000000007f0cefff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f0cf000-0x000000007f0d6fff] ACPI data
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f0d7000-0x000000007f103fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f104000-0x000000007f104fff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f105000-0x000000007f105fff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f106000-0x000000007f125fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f126000-0x000000007f130fff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f131000-0x000000007f158fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f159000-0x000000007f19bfff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f19c000-0x000000007f586fff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f587000-0x000000007f6e3fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f6e4000-0x000000007f6effff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f6f0000-0x000000007fffffff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000e0000000-0x00000000efffffff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000fed00000-0x00000000fed00fff] reserved

2)查看内核日志(不显示应用日志)

[root@test ~]#journalctl -k
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 20:01:01 CST. --
12月 23 12:42:48 docker kernel: Initializing cgroup subsys cpuset
12月 23 12:42:48 docker kernel: Initializing cgroup subsys cpu
12月 23 12:42:48 docker kernel: Initializing cgroup subsys cpuacct
12月 23 12:42:48 docker kernel: Linux version 3.10.0-957.27.2.el7.x86_64 ([email protected]) (gcc ve
12月 23 12:42:48 docker kernel: Command line: BOOT_IMAGE=/vmlinuz-3.10.0-957.27.2.el7.x86_64 root=/dev/mapper/centos-
12月 23 12:42:48 docker kernel: Disabled fast string operations
12月 23 12:42:48 docker kernel: e820: BIOS-provided physical RAM map:
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x0000000000000000-0x000000000009ffff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000000a0000-0x00000000000fffff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x0000000000100000-0x000000007f045fff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f046000-0x000000007f0ccfff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f0cd000-0x000000007f0cefff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f0cf000-0x000000007f0d6fff] ACPI data
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f0d7000-0x000000007f103fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f104000-0x000000007f104fff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f105000-0x000000007f105fff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f106000-0x000000007f125fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f126000-0x000000007f130fff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f131000-0x000000007f158fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f159000-0x000000007f19bfff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f19c000-0x000000007f586fff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f587000-0x000000007f6e3fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f6e4000-0x000000007f6effff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f6f0000-0x000000007fffffff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000e0000000-0x00000000efffffff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved

3)查看系统本次启动的日志

[root@test ~]#journalctl -b 0
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 20:01:01 CST. --
12月 23 12:42:48 docker systemd-journal[105]: Runtime journal is using 8.0M (max allowed 91.3M, trying to leave 136.9
12月 23 12:42:48 docker kernel: Initializing cgroup subsys cpuset
12月 23 12:42:48 docker kernel: Initializing cgroup subsys cpu
12月 23 12:42:48 docker kernel: Initializing cgroup subsys cpuacct
12月 23 12:42:48 docker kernel: Linux version 3.10.0-957.27.2.el7.x86_64 ([email protected]) (gcc ve
12月 23 12:42:48 docker kernel: Command line: BOOT_IMAGE=/vmlinuz-3.10.0-957.27.2.el7.x86_64 root=/dev/mapper/centos-
12月 23 12:42:48 docker kernel: Disabled fast string operations
12月 23 12:42:48 docker kernel: e820: BIOS-provided physical RAM map:
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x0000000000000000-0x000000000009ffff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000000a0000-0x00000000000fffff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x0000000000100000-0x000000007f045fff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f046000-0x000000007f0ccfff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f0cd000-0x000000007f0cefff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f0cf000-0x000000007f0d6fff] ACPI data
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f0d7000-0x000000007f103fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f104000-0x000000007f104fff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f105000-0x000000007f105fff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f106000-0x000000007f125fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f126000-0x000000007f130fff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f131000-0x000000007f158fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f159000-0x000000007f19bfff] ACPI NVS
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f19c000-0x000000007f586fff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f587000-0x000000007f6e3fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f6e4000-0x000000007f6effff] usable
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x000000007f6f0000-0x000000007fffffff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000e0000000-0x00000000efffffff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000fed00000-0x00000000fed00fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000fed1c000-0x00000000fed8ffff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
12月 23 12:42:48 docker kernel: BIOS-e820: [mem 0x00000000ffe00000-0x00000000ffffffff] reserved
12月 23 12:42:48 docker kernel: NX (Execute Disable) protection: active
12月 23 12:42:48 docker kernel: e820: update [mem 0x0b91c018-0x0b92c057] usable ==> usable
12月 23 12:42:48 docker kernel: e820: update [mem 0x0b92d018-0x0b93d057] usable ==> usable
12月 23 12:42:48 docker kernel: extended physical RAM map:
12月 23 12:42:48 docker kernel: reserve setup_data: [mem 0x0000000000000000-0x000000000009ffff] usable
12月 23 12:42:48 docker kernel: reserve setup_data: [mem 0x00000000000a0000-0x00000000000fffff] reserved
12月 23 12:42:48 docker kernel: reserve setup_data: [mem 0x0000000000100000-0x000000000b91c017] usable

4)查看指定时间的日志

journalctl --since="2017-10-30 18:10:30"
journalctl --since "20 min ago"
journalctl --since yesterday
journalctl --since "2017-01-10" --until "2017-01-11 03:00"
journalctl --since 09:00 --until "1 hour ago"
[root@test ~]#journalctl --since 09:00 --until "1 hour ago"
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 20:01:01 CST. --
12月 24 09:01:01 test systemd[1]: Created slice User Slice of root.
12月 24 09:01:01 test systemd[1]: Started Session 22 of user root.
12月 24 09:01:01 test CROND[2543]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 09:01:01 test run-parts(/etc/cron.hourly)[2546]: starting 0anacron
12月 24 09:01:01 test run-parts(/etc/cron.hourly)[2552]: finished 0anacron
12月 24 09:01:02 test systemd[1]: Removed slice User Slice of root.
12月 24 10:01:01 test systemd[1]: Created slice User Slice of root.
12月 24 10:01:01 test systemd[1]: Started Session 23 of user root.
12月 24 10:01:01 test CROND[2561]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 10:01:01 test run-parts(/etc/cron.hourly)[2564]: starting 0anacron
12月 24 10:01:01 test run-parts(/etc/cron.hourly)[2570]: finished 0anacron
12月 24 10:01:01 test systemd[1]: Removed slice User Slice of root.
12月 24 11:01:01 test systemd[1]: Created slice User Slice of root.
12月 24 11:01:01 test systemd[1]: Started Session 24 of user root.
12月 24 11:01:01 test CROND[2579]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 11:01:01 test run-parts(/etc/cron.hourly)[2582]: starting 0anacron
12月 24 11:01:01 test run-parts(/etc/cron.hourly)[2588]: finished 0anacron
12月 24 11:01:01 test systemd[1]: Removed slice User Slice of root.
12月 24 12:01:01 test systemd[1]: Created slice User Slice of root.
12月 24 12:01:01 test systemd[1]: Started Session 25 of user root.
12月 24 12:01:01 test CROND[2597]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 12:01:01 test run-parts(/etc/cron.hourly)[2600]: starting 0anacron
12月 24 12:01:01 test run-parts(/etc/cron.hourly)[2606]: finished 0anacron
12月 24 12:01:01 test systemd[1]: Removed slice User Slice of root.
12月 24 12:58:31 test systemd[1]: Starting Cleanup of Temporary Directories...
12月 24 12:58:32 test systemd[1]: Started Cleanup of Temporary Directories.
12月 24 13:01:01 test systemd[1]: Created slice User Slice of root.

说明:指定时间不能超过记录时间的最早时间。

5)显示尾部的最新日志默认是现实10行

[root@test ~]#journalctl -n
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 20:01:01 CST. --
12月 24 19:52:16 test rsyslogd[6118]: error during parsing file /etc/rsyslog.conf, on or before line 75: warnings occ
12月 24 19:52:16 test polkitd[752]: Unregistered Authentication Agent for unix-process:6111:11217058 (system bus name
12月 24 19:53:02 test qiuhom[6222]: this is test log
12月 24 19:53:47 test su[6256]: (to root) qiuhom on pts/1
12月 24 19:53:47 test su[6256]: pam_unix(su-l:session): session opened for user root by qiuhom(uid=1000)
12月 24 19:53:54 test qiuhom[6466]: this is test log
12月 24 20:01:01 test systemd[1]: Started Session 37 of user root.
12月 24 20:01:01 test CROND[6791]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 20:01:01 test run-parts(/etc/cron.hourly)[6794]: starting 0anacron
12月 24 20:01:01 test run-parts(/etc/cron.hourly)[6800]: finished 0anacron
[root@test ~]#journalctl -n 15
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 20:01:01 CST. --
12月 24 19:52:16 test systemd[1]: Stopped System Logging Service.
12月 24 19:52:16 test systemd[1]: Starting System Logging Service...
12月 24 19:52:16 test rsyslogd[6118]:  [origin software="rsyslogd" swVersion="8.24.0-34.el7" x-pid="6118" x-info="htt
12月 24 19:52:16 test rsyslogd[6118]: action '*' treated as ':omusrmsg:*' - please use ':omusrmsg:*' syntax instead, 
12月 24 19:52:16 test systemd[1]: Started System Logging Service.
12月 24 19:52:16 test rsyslogd[6118]: error during parsing file /etc/rsyslog.conf, on or before line 75: warnings occ
12月 24 19:52:16 test polkitd[752]: Unregistered Authentication Agent for unix-process:6111:11217058 (system bus name
12月 24 19:53:02 test qiuhom[6222]: this is test log
12月 24 19:53:47 test su[6256]: (to root) qiuhom on pts/1
12月 24 19:53:47 test su[6256]: pam_unix(su-l:session): session opened for user root by qiuhom(uid=1000)
12月 24 19:53:54 test qiuhom[6466]: this is test log
12月 24 20:01:01 test systemd[1]: Started Session 37 of user root.
12月 24 20:01:01 test CROND[6791]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 20:01:01 test run-parts(/etc/cron.hourly)[6794]: starting 0anacron
12月 24 20:01:01 test run-parts(/etc/cron.hourly)[6800]: finished 0anacron
[root@test ~]#

6)实时滚动显示最新日志

[root@test ~]#journalctl -f
-- Logs begin at 一 2019-12-23 12:42:48 CST. --
12月 24 19:52:16 test rsyslogd[6118]: error during parsing file /etc/rsyslog.conf, on or before line 75: warnings occured in file '/etc/rsyslog.conf' around line 75 [v8.24.0-34.el7 try http://www.rsyslog.com/e/2207 ]
12月 24 19:52:16 test polkitd[752]: Unregistered Authentication Agent for unix-process:6111:11217058 (system bus name :1.95, object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale zh_CN.UTF-8) (disconnected from bus)
12月 24 19:53:02 test qiuhom[6222]: this is test log
12月 24 19:53:47 test su[6256]: (to root) qiuhom on pts/1
12月 24 19:53:47 test su[6256]: pam_unix(su-l:session): session opened for user root by qiuhom(uid=1000)
12月 24 19:53:54 test qiuhom[6466]: this is test log
12月 24 20:01:01 test systemd[1]: Started Session 37 of user root.
12月 24 20:01:01 test CROND[6791]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 20:01:01 test run-parts(/etc/cron.hourly)[6794]: starting 0anacron
12月 24 20:01:01 test run-parts(/etc/cron.hourly)[6800]: finished 0anacron
12月 24 20:51:28 test qiuhom[8356]: this is a test log

说明:此选项同tail -f 类似

7)查看指定服务的日志

[root@test ~]#journalctl /sbin/nginx
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 20:51:28 CST. --
12月 23 12:43:07 test nginx[1050]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
12月 23 12:43:07 test nginx[1050]: nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@test ~]#journalctl /usr/lib/systemd/systemd
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 20:51:28 CST. --
12月 23 12:42:49 docker systemd[1]: Started Setup Virtual Console.
12月 23 12:42:49 docker systemd[1]: Started dracut cmdline hook.
12月 23 12:42:49 docker systemd[1]: Starting dracut pre-udev hook...
12月 23 12:42:49 docker systemd[1]: Started dracut pre-udev hook.
12月 23 12:42:49 docker systemd[1]: Starting udev Kernel Device Manager...
12月 23 12:42:49 docker systemd[1]: Started udev Kernel Device Manager.
12月 23 12:42:49 docker systemd[1]: Starting udev Coldplug all Devices...
12月 23 12:42:49 docker systemd[1]: Mounting Configuration File System...
12月 23 12:42:49 docker systemd[1]: Mounted Configuration File System.
12月 23 12:42:49 docker systemd[1]: Started udev Coldplug all Devices.
12月 23 12:42:49 docker systemd[1]: Reached target System Initialization.
12月 23 12:42:49 docker systemd[1]: Starting Show Plymouth Boot Screen...
12月 23 12:42:49 docker systemd[1]: Starting dracut initqueue hook...
12月 23 12:42:49 docker systemd[1]: Started Show Plymouth Boot Screen.
12月 23 12:42:49 docker systemd[1]: Started Forward Password Requests to Plymouth Directory Watch.
12月 23 12:42:49 docker systemd[1]: Reached target Paths.
12月 23 12:42:49 docker systemd[1]: Reached target Basic System.
12月 23 12:42:51 docker systemd[1]: Found device /dev/mapper/centos-root.
12月 23 12:42:51 docker systemd[1]: Starting File System Check on /dev/mapper/centos-root...
12月 23 12:42:51 docker systemd[1]: Started File System Check on /dev/mapper/centos-root.
12月 23 12:42:51 docker systemd[1]: Started dracut initqueue hook.
12月 23 12:42:51 docker systemd[1]: Reached target Remote File Systems (Pre).
12月 23 12:42:51 docker systemd[1]: Reached target Remote File Systems.
12月 23 12:42:51 docker systemd[1]: Mounting /sysroot...
12月 23 12:42:52 docker systemd[1]: Mounted /sysroot.
12月 23 12:42:52 docker systemd[1]: Reached target Initrd Root File System.
12月 23 12:42:52 docker systemd[1]: Starting Reload Configuration from the Real Root...
12月 23 12:42:52 docker systemd[1]: Reloading.
12月 23 12:42:52 docker systemd[1]: Started Reload Configuration from the Real Root.
12月 23 12:42:52 docker systemd[1]: Reached target Initrd File Systems.
12月 23 12:42:52 docker systemd[1]: Reached target Initrd Default Target.
12月 23 12:42:52 docker systemd[1]: Starting dracut pre-pivot and cleanup hook...
12月 23 12:42:52 docker systemd[1]: Started dracut pre-pivot and cleanup hook.
12月 23 12:42:52 docker systemd[1]: Starting Cleaning Up and Shutting Down Daemons...
12月 23 12:42:52 docker systemd[1]: Stopped target Timers.
12月 23 12:42:52 docker systemd[1]: Starting Plymouth switch root service...
12月 23 12:42:52 docker systemd[1]: Stopped Cleaning Up and Shutting Down Daemons.
12月 23 12:42:52 docker systemd[1]: Stopped dracut pre-pivot and cleanup hook.
lines 1-39

8)查看指定进程的日志

[root@test ~]#journalctl _PID=757
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 21:08:23 CST. --
12月 23 12:42:56 test chronyd[757]: chronyd version 3.4 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SI
12月 23 12:42:56 test chronyd[757]: Frequency -5.019 +/- 0.085 ppm read from /var/lib/chrony/drift
12月 23 12:43:07 test chronyd[757]: Selected source 84.16.67.12
[root@test ~]#journalctl _PID=10781
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 21:08:23 CST. --
12月 24 21:08:08 test setroubleshoot[10781]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:08:08 test python[10781]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tcp_socket
                                      
                                      *****  Plugin connect_ports (85.9 confidence) suggests   *********************
                                      
                                      If you want to allow /usr/sbin/nginx to connect to network port 8888
                                      Then you need to modify the port type.
                                      Do
                                      # semanage port -a -t PORT_TYPE -p tcp 8888
                                          where PORT_TYPE is one of the following: dns_port_t, dnssec_port_t, http_po
                                      
                                      *****  Plugin catchall_boolean (7.33 confidence) suggests   ******************
                                      
                                      If you want to allow httpd to can network connect
                                      Then you must tell SELinux about this by enabling the 'httpd_can_network_connec
                                      
                                      Do
                                      setsebool -P httpd_can_network_connect 1

9)查看某个路径下脚本的日志

[root@test ~]#journalctl /usr/bin/bash
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 21:08:23 CST. --
12月 23 12:42:56 test augenrules[730]: /sbin/augenrules: No change
12月 23 12:42:56 test augenrules[730]: No rules
12月 23 12:43:06 test network[883]: 正在打开环回接口: [  确定  ]
12月 23 12:43:06 test network[883]: 正在打开接口 enp2s0: [  确定  ]
12月 23 13:01:01 test CROND[1515]: (root) CMD (run-parts /etc/cron.hourly)
12月 23 14:01:01 test CROND[2160]: (root) CMD (run-parts /etc/cron.hourly)
12月 23 15:01:01 test CROND[2185]: (root) CMD (run-parts /etc/cron.hourly)
12月 23 16:01:01 test CROND[2203]: (root) CMD (run-parts /etc/cron.hourly)
12月 23 17:01:01 test CROND[2221]: (root) CMD (run-parts /etc/cron.hourly)
12月 23 18:01:01 test CROND[2239]: (root) CMD (run-parts /etc/cron.hourly)
12月 23 19:01:02 test CROND[2256]: (root) CMD (run-parts /etc/cron.hourly)
12月 23 20:01:01 test CROND[2275]: (root) CMD (run-parts /etc/cron.hourly)
12月 23 21:01:01 test CROND[2291]: (root) CMD (run-parts /etc/cron.hourly)
12月 23 22:01:01 test CROND[2309]: (root) CMD (run-parts /etc/cron.hourly)
12月 23 23:01:01 test CROND[2328]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 01:01:01 test CROND[2368]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 02:01:01 test CROND[2388]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 03:01:01 test CROND[2408]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 04:01:01 test CROND[2455]: (root) CMD (run-parts /etc/cron.hourly)
12月 24 07:01:01 test CROND[2507]: (root) CMD (run-parts /etc/cron.hourly)

10)查看指定用户的日志

[root@test ~]#id qiuhom
uid=1000(qiuhom) gid=1000(qiuhom) 组=1000(qiuhom)
[root@test ~]#journalctl _UID=1000
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 21:08:23 CST. --
12月 23 13:23:58 test su[1912]: (to root) qiuhom on pts/0
12月 23 13:23:58 test su[1912]: pam_unix(su-l:session): session opened for user root by qiuhom(uid=1000)
12月 23 14:07:46 test su[1912]: pam_unix(su-l:session): session closed for user root
12月 24 13:16:28 test su[2673]: (to root) qiuhom on pts/0
12月 24 13:16:28 test su[2673]: pam_unix(su-l:session): session opened for user root by qiuhom(uid=1000)
12月 24 14:02:19 test su[2673]: pam_unix(su-l:session): session closed for user root
12月 24 19:03:55 test su[3562]: (to root) qiuhom on pts/0
12月 24 19:03:55 test su[3562]: pam_unix(su-l:session): session opened for user root by qiuhom(uid=1000)
12月 24 19:53:47 test su[6256]: (to root) qiuhom on pts/1
12月 24 19:53:47 test su[6256]: pam_unix(su-l:session): session opened for user root by qiuhom(uid=1000)
[root@test ~]#

11)查看某个unit的日志

[root@test ~]#journalctl -u nginx.service
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 21:08:23 CST. --
12月 23 12:43:07 test systemd[1]: Starting The nginx HTTP and reverse proxy server...
12月 23 12:43:07 test nginx[1050]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
12月 23 12:43:07 test nginx[1050]: nginx: configuration file /etc/nginx/nginx.conf test is successful
12月 23 12:43:08 test systemd[1]: Started The nginx HTTP and reverse proxy server.
[root@test ~]#journalctl -u nginx.service --since today
-- No entries --
[root@test ~]#systemctl restart nginx
[root@test ~]#journalctl -u nginx.service --since today
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 21:14:31 CST. --
12月 24 21:14:31 test systemd[1]: Stopping The nginx HTTP and reverse proxy server...
12月 24 21:14:31 test systemd[1]: Stopped The nginx HTTP and reverse proxy server.
12月 24 21:14:31 test systemd[1]: Starting The nginx HTTP and reverse proxy server...
12月 24 21:14:31 test nginx[11296]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
12月 24 21:14:31 test nginx[11296]: nginx: configuration file /etc/nginx/nginx.conf test is successful
12月 24 21:14:31 test systemd[1]: Started The nginx HTTP and reverse proxy server.
[root@test ~]#

说明:可以同时指定多个unit,分别用-u指定其名即可,也可以用--since 指定时间,也可以用-f来跟踪某个nuit的最新日志

12)查看指定优先级(及其以上级别)的日志,共有8级

[root@test ~]#journalctl -p err
-- Logs begin at 一 2019-12-23 12:42:48 CST, end at 二 2019-12-24 21:14:31 CST. --
12月 23 12:42:50 docker kernel: gma500 0000:00:02.0: GPU: power management timed out.
12月 24 19:47:41 test rsyslogd[5521]: error during parsing file /etc/rsyslog.conf, on or before line 75: warnings occ
12月 24 19:52:16 test rsyslogd[6118]: error during parsing file /etc/rsyslog.conf, on or before line 75: warnings occ
12月 24 21:07:45 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:48 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:49 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:50 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:50 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:51 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:52 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:53 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:53 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:54 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:55 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:56 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:56 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:57 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:58 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:58 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:07:59 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:08:00 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:08:01 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:08:01 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:08:02 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:08:03 test setroubleshoot[10603]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:08:08 test setroubleshoot[10781]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
12月 24 21:08:23 test setroubleshoot[10826]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tc
[root@test ~]#

13)日志默认分页输出,--no-pager 改为正常的标准输出

……省略部分信息
12月 24 21:14:31 test polkitd[752]: Registered Authentication Agent for unix-process:11283:11710498 (system bus name :1.105 [/usr/bin/pkttyagent --notify-fd 5 --fallback], object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale zh_CN.UTF-8)
12月 24 21:14:31 test systemd[1]: Stopping The nginx HTTP and reverse proxy server...
12月 24 21:14:31 test systemd[1]: Stopped The nginx HTTP and reverse proxy server.
12月 24 21:14:31 test systemd[1]: Starting The nginx HTTP and reverse proxy server...
12月 24 21:14:31 test nginx[11296]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
12月 24 21:14:31 test nginx[11296]: nginx: configuration file /etc/nginx/nginx.conf test is successful
12月 24 21:14:31 test systemd[1]: Started The nginx HTTP and reverse proxy server.
12月 24 21:14:31 test polkitd[752]: Unregistered Authentication Agent for unix-process:11283:11710498 (system bus name :1.105, object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale zh_CN.UTF-8) (disconnected from bus)
[root@test ~]#

14)以json格式(单行)输出

[root@test ~]#journalctl -b -u nginx.service -o json
{ "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=4fe;b=e3110b5a73e44bebb9ac87b21fad016d;m=1401ea7;t=59a57a9eb3d4c
{ "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=50a;b=e3110b5a73e44bebb9ac87b21fad016d;m=1488bea;t=59a57a9f3aa8f
{ "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=50b;b=e3110b5a73e44bebb9ac87b21fad016d;m=1489f61;t=59a57a9f3be06
{ "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=50d;b=e3110b5a73e44bebb9ac87b21fad016d;m=14d1bc8;t=59a57a9f83a6e
{ "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=6b9;b=e3110b5a73e44bebb9ac87b21fad016d;m=1b44014f22;t=59a72ecac6
{ "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=6ba;b=e3110b5a73e44bebb9ac87b21fad016d;m=1b44020532;t=59a72ecad2
{ "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=6bb;b=e3110b5a73e44bebb9ac87b21fad016d;m=1b44024a99;t=59a72ecad6
{ "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=6bc;b=e3110b5a73e44bebb9ac87b21fad016d;m=1b44046779;t=59a72ecaf8
{ "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=6bd;b=e3110b5a73e44bebb9ac87b21fad016d;m=1b44046be4;t=59a72ecaf8
{ "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=6be;b=e3110b5a73e44bebb9ac87b21fad016d;m=1b440637c3;t=59a72ecb15
[root@test ~]#

多行输出,可读性更好:

[root@test ~]#journalctl -b -u nginx.service -o json-pretty
{
        "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=4fe;b=e3110b5a73e44bebb9ac87b21fad016d;m=1401ea7;t=59a57a9
        "__REALTIME_TIMESTAMP" : "1577076187151692",
        "__MONOTONIC_TIMESTAMP" : "20979367",
        "_BOOT_ID" : "e3110b5a73e44bebb9ac87b21fad016d",
        "PRIORITY" : "6",
        "_UID" : "0",
        "_GID" : "0",
        "_MACHINE_ID" : "931bcb70deb1435eaea1d542d13878cc",
        "SYSLOG_FACILITY" : "3",
        "SYSLOG_IDENTIFIER" : "systemd",
        "_TRANSPORT" : "journal",
        "_PID" : "1",
        "_COMM" : "systemd",
        "_EXE" : "/usr/lib/systemd/systemd",
        "_CAP_EFFECTIVE" : "1fffffffff",
        "_SYSTEMD_CGROUP" : "/",
        "CODE_FILE" : "src/core/unit.c",
        "CODE_FUNCTION" : "unit_status_log_starting_stopping_reloading",
        "MESSAGE_ID" : "7d4958e842da4a758f6c1cdc7b36dcc5",
        "_HOSTNAME" : "test",
        "_CMDLINE" : "/usr/lib/systemd/systemd --switched-root --system --deserialize 22",
        "_SELINUX_CONTEXT" : "system_u:system_r:init_t:s0",
        "CODE_LINE" : "1395",
        "UNIT" : "nginx.service",
        "MESSAGE" : "Starting The nginx HTTP and reverse proxy server...",
        "_SOURCE_REALTIME_TIMESTAMP" : "1577076187143557"
}
{
        "__CURSOR" : "s=1757eca9c8674c60bc078967261ae3d2;i=50a;b=e3110b5a73e44bebb9ac87b21fad016d;m=1488bea;t=59a57a9
        "__REALTIME_TIMESTAMP" : "1577076187703951",
        "__MONOTONIC_TIMESTAMP" : "21531626",
        "_BOOT_ID" : "e3110b5a73e44bebb9ac87b21fad016d",
        "PRIORITY" : "6",
        "_UID" : "0",
        "_GID" : "0",
        "_SYSTEMD_SLICE" : "system.slice",
        "_MACHINE_ID" : "931bcb70deb1435eaea1d542d13878cc",
        "SYSLOG_FACILITY" : "3",
[root@test ~]#

15)显示日志占据的磁盘空间

[root@test ~]#journalctl --disk-usage
Archived and active journals take up 8.0M on disk.
[root@test ~]#

指定日志文件占据的最大空间:

[root@test ~]#journalctl --vacuum-size=1G
Vacuuming done, freed 0B of archived journals on disk.
[root@test ~]#

指定日志文件保存多久:

[root@test ~]#journalctl --vacuum-time=1years
Vacuuming done, freed 0B of archived journals on disk.
[root@test ~]#

16)journalctl 使用汇总:

# 查看所有日志(默认情况下 ,只保存本次启动的日志)
$ sudo journalctl

# 查看内核日志(不显示应用日志):--dmesg 或 -k
$ sudo journalctl -k

# 查看系统本次启动的日志(其中包括了内核日志和各类系统服务的控制台输出):--system 或 -b
$ sudo journalctl -b
$ sudo journalctl -b -0

# 查看上一次启动的日志(需更改设置)
$ sudo journalctl -b -1

# 查看指定服务的日志:--unit 或 -u
$ sudo journalctl -u docker.servcie

# 查看指定服务的日志
$ sudo journalctl /usr/lib/systemd/systemd

# 实时滚动显示最新日志
$ sudo journalctl -f

# 查看指定时间的日志
$ sudo journalctl --since="2012-10-30 18:17:16"
$ sudo journalctl --since "20 min ago"
$ sudo journalctl --since yesterday
$ sudo journalctl --since "2015-01-10" --until "2015-01-11 03:00"
$ sudo journalctl --since 09:00 --until "1 hour ago"

# 显示尾部的最新 10 行日志:--lines 或 -n
$ sudo journalctl -n

# 显示尾部指定行数的日志
$ sudo journalctl -n 20

# 将最新的日志显示在前面
$ sudo journalctl -r -u docker.service

# 改变输出的格式:--output 或 -o
$ sudo journalctl -r -u docker.service -o json-pretty

# 查看指定进程的日志
$ sudo journalctl _PID=1

# 查看某个路径的脚本的日志
$ sudo journalctl /usr/bin/bash

# 查看指定用户的日志
$ sudo journalctl _UID=33 --since today

# 查看某个 Unit 的日志
$ sudo journalctl -u nginx.service
$ sudo journalctl -u nginx.service --since today

# 实时滚动显示某个 Unit 的最新日志
$ sudo journalctl -u nginx.service -f

# 合并显示多个 Unit 的日志
$ journalctl -u nginx.service -u php-fpm.service --since today

# 查看指定优先级(及其以上级别)的日志,共有 8 级
# 0: emerg
# 1: alert
# 2: crit
# 3: err
# 4: warning
# 5: notice
# 6: info
# 7: debug
$ sudo journalctl -p err -b

# 日志默认分页输出,--no-pager 改为正常的标准输出
$ sudo journalctl --no-pager

# 以 JSON 格式(单行)输出
$ sudo journalctl -b -u nginx.service -o json

# 以 JSON 格式(多行)输出,可读性更好
$ sudo journalctl -b -u nginx.serviceqq
 -o json-pretty

# 显示日志占据的硬盘空间
$ sudo journalctl --disk-usage

# 指定日志文件占据的最大空间
$ sudo journalctl --vacuum-size=1G

# 指定日志文件保存多久
$ sudo journalctl --vacuum-time=1years

3、日志持久化

红帽7的systemd日志默认存储在/run/log目录中,其内容将在重启后清除。但是在红帽8中,日志在/var/log/journal中,可以永久保存日志。

即便是永久保存,并非所有数据都永久保存,该日志有内置的日志轮换机制,会在每月触发。配置文件在/etc/systemd/journald.conf  ,默认情况下日志的大小不超过文件系统的10%,也不造成文件系统的可用空间小于15% 。

五、实时同步远程日志

1、rsyslog远程日志服务器

1)启动网络日志服务,rsyslog工作在tcp或者udp协议的514端口配置。

[root@test ~]#grep -i "tcp" /etc/rsyslog.conf    
# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514
# Remote Logging (we use TCP for reliable delivery)
[root@test ~]#grep -i "udp" /etc/rsyslog.conf   
# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514
[root@test ~]#

说明:以上配置是将rsyslog配置成工作在udp 514端口上,此时配置好配置文件后重启服务,此服务器就成为了rsyslog日志服务器了,它可以帮助其他服务器记录日志。

2)重启rsyslog服务,在其客户机上配置rsyslog,让其日志发送给rsyslog服务器记录。

[root@test ~]#systemctl restart rsyslog
[root@test ~]#ss -ntul
Netid State      Recv-Q Send-Q           Local Address:Port                          Peer Address:Port              
udp   UNCONN     0      0                            *:123                                      *:*                  
udp   UNCONN     0      0                    127.0.0.1:323                                      *:*                  
udp   UNCONN     0      0                            *:514                                      *:*                  
udp   UNCONN     0      0                          ::1:323                                     :::*                  
udp   UNCONN     0      0                           :::514                                     :::*                  
tcp   LISTEN     0      100                  127.0.0.1:25                                       *:*                  
tcp   LISTEN     0      25                           *:514                                      *:*                  
tcp   LISTEN     0      128                          *:41319                                    *:*                  
tcp   LISTEN     0      50                           *:3306                                     *:*                  
tcp   LISTEN     0      100                        ::1:25                                      :::*                  
tcp   LISTEN     0      25                          :::514                                     :::*                  
tcp   LISTEN     0      128                         :::41319                                   :::*                  
tcp   LISTEN     0      128                         :::80                                      :::*                  
[root@test ~]#

可以看到重启了服务后,514端口已经起来,接下来配置客户机的rsyslog,让其通过网络发送日志到日志服务器上:

[root@test-node1 ~]#grep "192.168.0.99" /etc/rsyslog.conf
*.info;mail.none;authpriv.none;cron.none                @192.168.0.99
[root@test-node1 ~]#

说明:以上配置的意思是除了mail ,authpriv,cron这三个以外的所有设施的info及info以上级别的日志都发往192.168.0.99记录,这里需要注意一点,一个“@”表示连接服务器是通过udp协议连接,日志通过udp协议传送,两个“@”表示连接服务器通过tcp去连接,日志通过tcp协议传送

3)重启客户机上的rsyslog服务,在服务器上查看客户机的日志

[root@test-node1 ~]#/etc/init.d/rsyslog restart
Shutting down system logger:                               [  OK  ]
Starting system logger:                                    [  OK  ]
[root@test-node1 ~]#logger "i am test-node1"
[root@test-node1 ~]#tail /var/log/messages
Dec 24 23:06:17 test kernel: cfg80211:   (57240000 KHz - 63720000 KHz @ 2160000 KHz), (N/A, 0 mBm), (N/A)
Dec 24 23:06:17 test kernel: EXT4-fs (sda1): mounted filesystem with ordered data mode. Opts: 
Dec 24 23:06:17 test kernel: EXT4-fs (dm-2): mounted filesystem with ordered data mode. Opts: 
Dec 24 23:06:17 test kernel: Adding 4128764k swap on /dev/mapper/VolGroup-lv_swap.  Priority:-1 extents:1 across:4128764k 
Dec 24 23:06:17 test kernel: sky2 eth0: enabling interface
Dec 24 23:06:17 test kernel: ADDRCONF(NETDEV_UP): eth0: link is not ready
Dec 24 23:06:17 test kernel: sky2 eth0: Link is up at 1000 Mbps, full duplex, flow control both
Dec 24 23:06:17 test kernel: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
Dec 24 23:23:06 test kernel: Kernel logging (proc) stopped.
Dec 24 23:23:06 test rsyslogd: [origin software="rsyslogd" swVersion="5.8.10" x-pid="1471" x-info="http://www.rsyslog.com"] exiting on signal 15.
[root@test-node1 ~]#

可以看到客户机上没有记录日志了。

[root@test ~]#tail /var/log/messages
Dec 24 21:43:07 test systemd: Started System Logging Service.
Dec 24 23:26:04 test systemd: Stopping System Logging Service...
Dec 24 23:26:04 test rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-41.el7_7.2" x-pid="16136" x-info="http://www.rsyslog.com"] exiting on signal 15.
Dec 24 23:26:04 test systemd: Stopped System Logging Service.
Dec 24 23:26:04 test systemd: Starting System Logging Service...
Dec 24 23:26:04 test rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-41.el7_7.2" x-pid="16359" x-info="http://www.rsyslog.com"] start
Dec 24 23:26:04 test rsyslogd: action '*' treated as ':omusrmsg:*' - please use ':omusrmsg:*' syntax instead, '*' will not be supported in the future [v8.24.0-41.el7_7.2 try http://www.rsyslog.com/e/2184 ]
Dec 24 23:26:04 test systemd: Started System Logging Service.
Dec 24 23:26:04 test rsyslogd: error during parsing file /etc/rsyslog.conf, on or before line 76: warnings occured in file '/etc/rsyslog.conf' around line 76 [v8.24.0-41.el7_7.2 try http://www.rsyslog.com/e/2207 ]
Dec 24 23:26:13 test-node1 qiuhom: i am test-node1
[root@test ~]#

在日志服务器上可以看到我们刚才的测试日志信息,这里需要说一下,我们客户端通过网络把日志发送给服务端,服务端里怎么储存要看服务端配置,服务端可以把它储存到数据库,储存到文件都可以。

4)rsyslog将日志记录于mysql中

准备数据库服务器:

[root@test ~]#yum install mariadb
已加载插件:fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
base                                                                                          | 3.6 kB  00:00:00     
dockerrepo                                                                                    | 2.9 kB  00:00:00     
epel                                                                                          | 5.3 kB  00:00:00     
extras                                                                                        | 2.9 kB  00:00:00     
updates                                                                                       | 2.9 kB  00:00:00     
软件包 1:mariadb-5.5.64-1.el7.x86_64 已安装并且是最新版本
无须任何处理
[root@test ~]#systemctl status mariadb
● mariadb.service - MariaDB database server
   Loaded: loaded (/usr/lib/systemd/system/mariadb.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
[root@test ~]#systemctl start mariadb 
[root@test ~]#mysql
Welcome to the MariaDB monitor.  Commands end with ; or g.
Your MariaDB connection id is 2
Server version: 5.5.64-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

MariaDB [(none)]> 

mariadb同mysql类似,yum安装mariadb 并启动服务即可

5)在mariadb server上授权rsyslog能连接至当前数据库服务器

MariaDB [(none)]> select user,host,password from mysql.user
    -> ;
+------+-----------+----------+
| user | host      | password |
+------+-----------+----------+
| root | localhost |          |
+------+-----------+----------+
1 row in set (0.00 sec)

MariaDB [(none)]> grant all on Syslog.* to 'rsyslog'@'%' identified by 'rsyslogpass';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> select user,host,password from mysql.user;
+---------+-----------+-------------------------------------------+
| user    | host      | password                                  |
+---------+-----------+-------------------------------------------+
| root    | localhost |                                           |
| rsyslog | %         | *3AABCFD2E87DD4D86B283A77A7B21E449FBA9AFA |
+---------+-----------+-------------------------------------------+
2 rows in set (0.00 sec)

MariaDB [(none)]> 

6)在rsyslog服务器上安装mysql模块相关的程序包rsyslog-mysql

[root@test ~]#yum install rsyslog-mysql
已加载插件:fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
正在解决依赖关系
--> 正在检查事务
---> 软件包 rsyslog-mysql.x86_64.0.8.24.0-41.el7_7.2 将被 安装
--> 正在处理依赖关系 rsyslog = 8.24.0-41.el7_7.2,它被软件包 rsyslog-mysql-8.24.0-41.el7_7.2.x86_64 需要
--> 正在检查事务
---> 软件包 rsyslog.x86_64.0.8.24.0-34.el7 将被 升级
---> 软件包 rsyslog.x86_64.0.8.24.0-41.el7_7.2 将被 更新
--> 解决依赖关系完成

依赖关系解决

=====================================================================================================================
 Package                      架构                  版本                                源                      大小
=====================================================================================================================
正在安装:
 rsyslog-mysql                x86_64                8.24.0-41.el7_7.2                   updates                 42 k
为依赖而更新:
 rsyslog                      x86_64                8.24.0-41.el7_7.2                   updates                616 k

事务概要
=====================================================================================================================
安装  1 软件包
升级           ( 1 依赖软件包)

总下载量:659 k
Is this ok [y/d/N]: y
Downloading packages:
Delta RPMs disabled because /usr/bin/applydeltarpm not installed.
(1/2): rsyslog-mysql-8.24.0-41.el7_7.2.x86_64.rpm                                             |  42 kB  00:00:00     
(2/2): rsyslog-8.24.0-41.el7_7.2.x86_64.rpm                                                   | 616 kB  00:00:00     
---------------------------------------------------------------------------------------------------------------------
总计                                                                                 858 kB/s | 659 kB  00:00:00     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  正在更新    : rsyslog-8.24.0-41.el7_7.2.x86_64                                                                 1/3 
  正在安装    : rsyslog-mysql-8.24.0-41.el7_7.2.x86_64                                                           2/3 
  清理        : rsyslog-8.24.0-34.el7.x86_64                                                                     3/3 
  验证中      : rsyslog-8.24.0-41.el7_7.2.x86_64                                                                 1/3 
  验证中      : rsyslog-mysql-8.24.0-41.el7_7.2.x86_64                                                           2/3 
  验证中      : rsyslog-8.24.0-34.el7.x86_64                                                                     3/3 

已安装:
  rsyslog-mysql.x86_64 0:8.24.0-41.el7_7.2                                                                           

作为依赖被升级:
  rsyslog.x86_64 0:8.24.0-41.el7_7.2                                                                                 

完毕!
[root@test ~]#

此插件必须在rsyslog服务器上安装,也就说你准备把那台服务器的日志记录到数据库中你就在那台日志服务器上安装此插件即可。

7)为rsyslog创建数据库及表

[root@test ~]#rpm -ql rsyslog-mysql
/usr/lib64/rsyslog/ommysql.so
/usr/share/doc/rsyslog-8.24.0/mysql-createDB.sql
[root@test ~]#mysql < /usr/share/doc/rsyslog-8.24.0/mysql-createDB.sql
[root@test ~]#mysql 
Welcome to the MariaDB monitor.  Commands end with ; or g.
Your MariaDB connection id is 4
Server version: 5.5.64-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| Syslog             |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.00 sec)

MariaDB [(none)]> use Syslog
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [Syslog]> show tables;
+------------------------+
| Tables_in_Syslog       |
+------------------------+
| SystemEvents           |
| SystemEventsProperties |
+------------------------+
2 rows in set (0.00 sec)

MariaDB [Syslog]> 

本人使用的是一台主机,若需要把远程主机上的日志记录到数据库中,导入sql脚本时需要指定用户名,主机以及密码

8)配置rsyslog将日志保存到mysql中

[root@test ~]#grep "ommysql" /etc/rsyslog.conf
$ModLoad ommysql
*.info;mail.none;authpriv.none;cron.none                :ommysql:192.168.0.99,Syslog,rsyslog,rsyslogpass
[root@test ~]#

在需要将日志记录到mysql的主机上编辑/etc/rsyslog.conf  将其$ModLoad ommysql 写在#### MODULES #### 下,将需要记录的日志设施和日志级别以及数据库的地址,数据库名,连接数据库用户名和密码写在#### RULES ####下,如上所示。

9)重启rsyslog服务

[root@test ~]#systemctl restart rsyslog

到此rsyslog就会将日志记录到配置文件里指定的数据库里。

10)在数据库中查看日志

[root@test ~]#mysql
Welcome to the MariaDB monitor.  Commands end with ; or g.
Your MariaDB connection id is 6
Server version: 5.5.64-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

MariaDB [(none)]> use Syslog
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [Syslog]> show tables;
+------------------------+
| Tables_in_Syslog       |
+------------------------+
| SystemEvents           |
| SystemEventsProperties |
+------------------------+
2 rows in set (0.00 sec)

MariaDB [Syslog]> select * from SystemEvents;
+----+------------+---------------------+---------------------+----------+----------+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+-------------+-----------+---------------+---------+-----------------+--------------+-----------+----------+----------+------------+-----------+--------------+-----------------+----------+
| ID | CustomerID | ReceivedAt          | DeviceReportedTime  | Facility | Priority | FromHost | Message                                                                                                                                                                                | NTSeverity | Importance | EventSource | EventUser | EventCategory | EventID | EventBinaryData | MaxAvailable | CurrUsage | MinUsage | MaxUsage | InfoUnitID | SysLogTag | EventLogType | GenericFileName | SystemID |
+----+------------+---------------------+---------------------+----------+----------+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+-------------+-----------+---------------+---------+-----------------+--------------+-----------+----------+----------+------------+-----------+--------------+-----------------+----------+
|  1 |       NULL | 2019-12-24 22:00:51 | 2019-12-24 22:00:51 |        3 |        6 | test     | Stopping System Logging Service...                                                                                                                                                     |       NULL |       NULL | NULL        | NULL      |          NULL |    NULL | NULL            |         NULL |      NULL |     NULL |     NULL |          1 | systemd:  | NULL         | NULL            |     NULL |
|  2 |       NULL | 2019-12-24 22:00:51 | 2019-12-24 22:00:51 |        5 |        6 | test     |  [origin software="rsyslogd" swVersion="8.24.0-41.el7_7.2" x-pid="12777" x-info="http://www.rsyslog.com"] exiting on signal 15.                                                        |       NULL |       NULL | NULL        | NULL      |          NULL |    NULL | NULL            |         NULL |      NULL |     NULL |     NULL |          1 | rsyslogd: | NULL         | NULL            |     NULL |
|  3 |       NULL | 2019-12-24 22:00:51 | 2019-12-24 22:00:51 |        3 |        6 | test     | Stopped System Logging Service.                                                                                                                                                        |       NULL |       NULL | NULL        | NULL      |          NULL |    NULL | NULL            |         NULL |      NULL |     NULL |     NULL |          1 | systemd:  | NULL         | NULL            |     NULL |
|  4 |       NULL | 2019-12-24 22:00:51 | 2019-12-24 22:00:51 |        3 |        6 | test     | Starting System Logging Service...                                                                                                                                                     |       NULL |       NULL | NULL        | NULL      |          NULL |    NULL | NULL            |         NULL |      NULL |     NULL |     NULL |          1 | systemd:  | NULL         | NULL            |     NULL |
|  5 |       NULL | 2019-12-24 22:00:51 | 2019-12-24 22:00:51 |        5 |        6 | test     |  [origin software="rsyslogd" swVersion="8.24.0-41.el7_7.2" x-pid="13125" x-info="http://www.rsyslog.com"] start                                                                        |       NULL |       NULL | NULL        | NULL      |          NULL |    NULL | NULL            |         NULL |      NULL |     NULL |     NULL |          1 | rsyslogd: | NULL         | NULL            |     NULL |
|  6 |       NULL | 2019-12-24 22:00:51 | 2019-12-24 22:00:51 |        5 |        4 | test     | action '*' treated as ':omusrmsg:*' - please use ':omusrmsg:*' syntax instead, '*' will not be supported in the future [v8.24.0-41.el7_7.2 try http://www.rsyslog.com/e/2184 ]         |       NULL |       NULL | NULL        | NULL      |          NULL |    NULL | NULL            |         NULL |      NULL |     NULL |     NULL |          1 | rsyslogd: | NULL         | NULL            |     NULL |
|  7 |       NULL | 2019-12-24 22:00:51 | 2019-12-24 22:00:51 |        3 |        6 | test     | Started System Logging Service.                                                                                                                                                        |       NULL |       NULL | NULL        | NULL      |          NULL |    NULL | NULL            |         NULL |      NULL |     NULL |     NULL |          1 | systemd:  | NULL         | NULL            |     NULL |
|  8 |       NULL | 2019-12-24 22:00:51 | 2019-12-24 22:00:51 |        5 |        3 | test     | error during parsing file /etc/rsyslog.conf, on or before line 76: warnings occured in file '/etc/rsyslog.conf' around line 76 [v8.24.0-41.el7_7.2 try http://www.rsyslog.com/e/2207 ] |       NULL |       NULL | NULL        | NULL      |          NULL |    NULL | NULL            |         NULL |      NULL |     NULL |     NULL |          1 | rsyslogd: | NULL         | NULL            |     NULL |
|  9 |       NULL | 2019-12-24 22:01:01 | 2019-12-24 22:01:01 |        3 |        6 | test     | Started Session 39 of user root.                                                                                                                                                       |       NULL |       NULL | NULL        | NULL      |          NULL |    NULL | NULL            |         NULL |      NULL |     NULL |     NULL |          1 | systemd:  | NULL         | NULL            |     NULL |
+----+------------+---------------------+---------------------+----------+----------+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+-------------+-----------+---------------+---------+-----------------+--------------+-----------+----------+----------+------------+-----------+--------------+-----------------+----------+
9 rows in set (0.00 sec)

MariaDB [Syslog]> select * from SystemEventsG
*************************** 1. row ***************************
                ID: 1
        CustomerID: NULL
        ReceivedAt: 2019-12-24 22:00:51
DeviceReportedTime: 2019-12-24 22:00:51
          Facility: 3
          Priority: 6
          FromHost: test
           Message: Stopping System Logging Service...
        NTSeverity: NULL
        Importance: NULL
       EventSource: NULL
         EventUser: NULL
     EventCategory: NULL
           EventID: NULL
   EventBinaryData: NULL
      MaxAvailable: NULL
         CurrUsage: NULL
          MinUsage: NULL
          MaxUsage: NULL
        InfoUnitID: 1
         SysLogTag: systemd:
      EventLogType: NULL
   GenericFileName: NULL
          SystemID: NULL
*************************** 2. row ***************************
                ID: 2
        CustomerID: NULL
        ReceivedAt: 2019-12-24 22:00:51
DeviceReportedTime: 2019-12-24 22:00:51
          Facility: 5
          Priority: 6
          FromHost: test
           Message:  [origin software="rsyslogd" swVersion="8.24.0-41.el7_7.2" x-pid="12777" x-info="http://www.rsyslog.com"] exiting on signal 15.
        NTSeverity: NULL
        Importance: NULL
       EventSource: NULL
         EventUser: NULL
     EventCategory: NULL
           EventID: NULL
   EventBinaryData: NULL
      MaxAvailable: NULL
         CurrUsage: NULL
          MinUsage: NULL
          MaxUsage: NULL
        InfoUnitID: 1
         SysLogTag: rsyslogd:
      EventLogType: NULL
   GenericFileName: NULL
          SystemID: NULL
*************************** 3. row ***************************
                ID: 3
        CustomerID: NULL
        ReceivedAt: 2019-12-24 22:00:51
DeviceReportedTime: 2019-12-24 22:00:51
          Facility: 3
          Priority: 6
          FromHost: test
           Message: Stopped System Logging Service.
        NTSeverity: NULL
        Importance: NULL
       EventSource: NULL
         EventUser: NULL
     EventCategory: NULL
           EventID: NULL
   EventBinaryData: NULL
      MaxAvailable: NULL
         CurrUsage: NULL
          MinUsage: NULL
          MaxUsage: NULL
        InfoUnitID: 1
         SysLogTag: systemd:
      EventLogType: NULL
   GenericFileName: NULL
          SystemID: NULL
*************************** 4. row ***************************
                ID: 4
        CustomerID: NULL
        ReceivedAt: 2019-12-24 22:00:51
DeviceReportedTime: 2019-12-24 22:00:51
          Facility: 3
          Priority: 6
          FromHost: test
           Message: Starting System Logging Service...
        NTSeverity: NULL
        Importance: NULL
       EventSource: NULL
         EventUser: NULL
     EventCategory: NULL
           EventID: NULL
   EventBinaryData: NULL
      MaxAvailable: NULL
         CurrUsage: NULL
          MinUsage: NULL
          MaxUsage: NULL
        InfoUnitID: 1
         SysLogTag: systemd:
      EventLogType: NULL
   GenericFileName: NULL
          SystemID: NULL
*************************** 5. row ***************************
                ID: 5
        CustomerID: NULL
        ReceivedAt: 2019-12-24 22:00:51
DeviceReportedTime: 2019-12-24 22:00:51
          Facility: 5
          Priority: 6
          FromHost: test
           Message:  [origin software="rsyslogd" swVersion="8.24.0-41.el7_7.2" x-pid="13125" x-info="http://www.rsyslog.com"] start
        NTSeverity: NULL
        Importance: NULL
       EventSource: NULL
         EventUser: NULL
     EventCategory: NULL
           EventID: NULL
   EventBinaryData: NULL
      MaxAvailable: NULL
         CurrUsage: NULL
          MinUsage: NULL
          MaxUsage: NULL
        InfoUnitID: 1
         SysLogTag: rsyslogd:
      EventLogType: NULL
   GenericFileName: NULL
          SystemID: NULL
*************************** 6. row ***************************
                ID: 6
        CustomerID: NULL
        ReceivedAt: 2019-12-24 22:00:51
DeviceReportedTime: 2019-12-24 22:00:51
          Facility: 5
          Priority: 4
          FromHost: test
           Message: action '*' treated as ':omusrmsg:*' - please use ':omusrmsg:*' syntax instead, '*' will not be supported in the future [v8.24.0-41.el7_7.2 try http://www.rsyslog.com/e/2184 ]
        NTSeverity: NULL
        Importance: NULL
       EventSource: NULL
         EventUser: NULL
     EventCategory: NULL
           EventID: NULL
   EventBinaryData: NULL
      MaxAvailable: NULL
         CurrUsage: NULL
          MinUsage: NULL
          MaxUsage: NULL
        InfoUnitID: 1
         SysLogTag: rsyslogd:
      EventLogType: NULL
   GenericFileName: NULL
          SystemID: NULL
*************************** 7. row ***************************
                ID: 7
        CustomerID: NULL
        ReceivedAt: 2019-12-24 22:00:51
DeviceReportedTime: 2019-12-24 22:00:51
          Facility: 3
          Priority: 6
          FromHost: test
           Message: Started System Logging Service.
        NTSeverity: NULL
        Importance: NULL
       EventSource: NULL
         EventUser: NULL
     EventCategory: NULL
           EventID: NULL
   EventBinaryData: NULL
      MaxAvailable: NULL
         CurrUsage: NULL
          MinUsage: NULL
          MaxUsage: NULL
        InfoUnitID: 1
         SysLogTag: systemd:
      EventLogType: NULL
   GenericFileName: NULL
          SystemID: NULL
*************************** 8. row ***************************
                ID: 8
        CustomerID: NULL
        ReceivedAt: 2019-12-24 22:00:51
DeviceReportedTime: 2019-12-24 22:00:51
          Facility: 5
          Priority: 3
          FromHost: test
           Message: error during parsing file /etc/rsyslog.conf, on or before line 76: warnings occured in file '/etc/rsyslog.conf' around line 76 [v8.24.0-41.el7_7.2 try http://www.rsyslog.com/e/2207 ]
        NTSeverity: NULL
        Importance: NULL
       EventSource: NULL
         EventUser: NULL
     EventCategory: NULL
           EventID: NULL
   EventBinaryData: NULL
      MaxAvailable: NULL
         CurrUsage: NULL
          MinUsage: NULL
          MaxUsage: NULL
        InfoUnitID: 1
         SysLogTag: rsyslogd:
      EventLogType: NULL
   GenericFileName: NULL
          SystemID: NULL
*************************** 9. row ***************************
                ID: 9
        CustomerID: NULL
        ReceivedAt: 2019-12-24 22:01:01
DeviceReportedTime: 2019-12-24 22:01:01
          Facility: 3
          Priority: 6
          FromHost: test
           Message: Started Session 39 of user root.
        NTSeverity: NULL
        Importance: NULL
       EventSource: NULL
         EventUser: NULL
     EventCategory: NULL
           EventID: NULL
   EventBinaryData: NULL
      MaxAvailable: NULL
         CurrUsage: NULL
          MinUsage: NULL
          MaxUsage: NULL
        InfoUnitID: 1
         SysLogTag: systemd:
      EventLogType: NULL
   GenericFileName: NULL
          SystemID: NULL
9 rows in set (0.00 sec)

MariaDB [Syslog]>

可看到我们重启rsyslog服务产生的日志都记录于数据库里了。

11)通过loganalyzer展示数据库中的日志

在rsyslog服务器上准备amp或者nmp组合:

[root@test ~]#yum install httpd php php-mysql php-gd -y
已加载插件:fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
软件包 httpd-2.4.6-90.el7.centos.x86_64 已安装并且是最新版本
正在解决依赖关系
--> 正在检查事务
---> 软件包 php.x86_64.0.5.4.16-46.1.el7_7 将被 安装
--> 正在处理依赖关系 php-common(x86-64) = 5.4.16-46.1.el7_7,它被软件包 php-5.4.16-46.1.el7_7.x86_64 需要
--> 正在处理依赖关系 php-cli(x86-64) = 5.4.16-46.1.el7_7,它被软件包 php-5.4.16-46.1.el7_7.x86_64 需要
---> 软件包 php-gd.x86_64.0.5.4.16-46.1.el7_7 将被 安装
--> 正在处理依赖关系 libt1.so.5()(64bit),它被软件包 php-gd-5.4.16-46.1.el7_7.x86_64 需要
---> 软件包 php-mysql.x86_64.0.5.4.16-46.1.el7_7 将被 安装
--> 正在处理依赖关系 php-pdo(x86-64) = 5.4.16-46.1.el7_7,它被软件包 php-mysql-5.4.16-46.1.el7_7.x86_64 需要
--> 正在检查事务
---> 软件包 php-cli.x86_64.0.5.4.16-46.1.el7_7 将被 安装
---> 软件包 php-common.x86_64.0.5.4.16-46.1.el7_7 将被 安装
--> 正在处理依赖关系 libzip.so.2()(64bit),它被软件包 php-common-5.4.16-46.1.el7_7.x86_64 需要
---> 软件包 php-pdo.x86_64.0.5.4.16-46.1.el7_7 将被 安装
---> 软件包 t1lib.x86_64.0.5.1.2-14.el7 将被 安装
--> 正在检查事务
---> 软件包 libzip.x86_64.0.0.10.1-8.el7 将被 安装
--> 解决依赖关系完成

依赖关系解决

=====================================================================================================================
 Package                    架构                   版本                                源                       大小
=====================================================================================================================
正在安装:
 php                        x86_64                 5.4.16-46.1.el7_7                   updates                 1.4 M
 php-gd                     x86_64                 5.4.16-46.1.el7_7                   updates                 128 k
 php-mysql                  x86_64                 5.4.16-46.1.el7_7                   updates                 101 k
为依赖而安装:
 libzip                     x86_64                 0.10.1-8.el7                        base                     48 k
 php-cli                    x86_64                 5.4.16-46.1.el7_7                   updates                 2.7 M
 php-common                 x86_64                 5.4.16-46.1.el7_7                   updates                 565 k
 php-pdo                    x86_64                 5.4.16-46.1.el7_7                   updates                  99 k
 t1lib                      x86_64                 5.1.2-14.el7                        base                    166 k

事务概要
=====================================================================================================================
安装  3 软件包 (+5 依赖软件包)

总下载量:5.2 M
安装大小:18 M
Downloading packages:
(1/8): libzip-0.10.1-8.el7.x86_64.rpm                                                         |  48 kB  00:00:00     
(2/8): php-cli-5.4.16-46.1.el7_7.x86_64.rpm                                                   | 2.7 MB  00:00:00     
(3/8): php-common-5.4.16-46.1.el7_7.x86_64.rpm                                                | 565 kB  00:00:00     
(4/8): php-gd-5.4.16-46.1.el7_7.x86_64.rpm                                                    | 128 kB  00:00:00     
(5/8): php-mysql-5.4.16-46.1.el7_7.x86_64.rpm                                                 | 101 kB  00:00:00     
(6/8): php-pdo-5.4.16-46.1.el7_7.x86_64.rpm                                                   |  99 kB  00:00:00     
(7/8): php-5.4.16-46.1.el7_7.x86_64.rpm                                                       | 1.4 MB  00:00:01     
(8/8): t1lib-5.1.2-14.el7.x86_64.rpm                                                          | 166 kB  00:00:00     
---------------------------------------------------------------------------------------------------------------------
总计                                                                                 3.7 MB/s | 5.2 MB  00:00:01     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  正在安装    : libzip-0.10.1-8.el7.x86_64                                                                       1/8 
  正在安装    : php-common-5.4.16-46.1.el7_7.x86_64                                                              2/8 
  正在安装    : php-cli-5.4.16-46.1.el7_7.x86_64                                                                 3/8 
  正在安装    : php-pdo-5.4.16-46.1.el7_7.x86_64                                                                 4/8 
  正在安装    : t1lib-5.1.2-14.el7.x86_64                                                                        5/8 
  正在安装    : php-gd-5.4.16-46.1.el7_7.x86_64                                                                  6/8 
  正在安装    : php-mysql-5.4.16-46.1.el7_7.x86_64                                                               7/8 
  正在安装    : php-5.4.16-46.1.el7_7.x86_64                                                                     8/8 
  验证中      : php-cli-5.4.16-46.1.el7_7.x86_64                                                                 1/8 
  验证中      : t1lib-5.1.2-14.el7.x86_64                                                                        2/8 
  验证中      : libzip-0.10.1-8.el7.x86_64                                                                       3/8 
  验证中      : php-5.4.16-46.1.el7_7.x86_64                                                                     4/8 
  验证中      : php-common-5.4.16-46.1.el7_7.x86_64                                                              5/8 
  验证中      : php-mysql-5.4.16-46.1.el7_7.x86_64                                                               6/8 
  验证中      : php-gd-5.4.16-46.1.el7_7.x86_64                                                                  7/8 
  验证中      : php-pdo-5.4.16-46.1.el7_7.x86_64                                                                 8/8 

已安装:
  php.x86_64 0:5.4.16-46.1.el7_7     php-gd.x86_64 0:5.4.16-46.1.el7_7     php-mysql.x86_64 0:5.4.16-46.1.el7_7    

作为依赖被安装:
  libzip.x86_64 0:0.10.1-8.el7         php-cli.x86_64 0:5.4.16-46.1.el7_7   php-common.x86_64 0:5.4.16-46.1.el7_7  
  php-pdo.x86_64 0:5.4.16-46.1.el7_7   t1lib.x86_64 0:5.1.2-14.el7         

完毕!
[root@test ~]#

12)安装loganalyzer

[root@test ~]#rz
rz waiting to receive.
 zmodem trl+C ȡ

  100%    1022 KB 1022 KB/s 00:00:01       0 Errorsgz...

[root@test ~]#ls
checkip.sh  dos.sh  install_nginx.yml  loganalyzer-3.6.5.tar.gz  nginx_role.yml  roles  selinux.sh  templates
[root@test ~]#tar xf loganalyzer-3.6.5.tar.gz 
[root@test ~]#cp -a loganalyzer-3.6.5/src/ /var/www/html/loganalyzer
[root@test ~]#cd /var/www/html/loganalyzer
[root@test loganalyzer]#touch config.php
[root@test loganalyzer]#chmod 666 config.php
[root@test loganalyzer]#

13)配置loganalyzer

[root@test ~]#systemctl start httpd

启动httpd服务后,在浏览器上配置loganalyzer ,用浏览器打开http://192.168.0.99/loganalyzer   192.168.0.99是本人环境的httpd服务器地址

至此loganalyzer就配置安装完毕了,最后还需要注意一点的是 /var/www/html/loganalyzer/config.php 的权限需要改一下,把组和其他的写权限取消掉 :

[root@test ~]#cd /var/www/html/loganalyzer/
[root@test loganalyzer]#chmod 644 config.php 

2、rsync远程日志同步

1)保持系统时间准确

保持准确的时间同步和时区设置,确保日志系统中的时间戳准确。

网络事件协议NTP,通过互联网保持时间同步。

timedatectl显示时间相关的系统设置:

timedatectl list-timezones列出所有时区。
timedatectl set-timezones + 时区来设置时区。
timedatectl set-time + 时间来设置时间。
timedatectl set-ntp true 启用ntp
timedatectl set-ntp false 禁用ntp

chronyd服务配置客服端与NTP服务器同步。默认情况下chrond使用NTP pool project服务器池,不需要额外配置。但是孤立网络中的服务器时,需要配置,更改/etc/chrond.conf配置文件。

2)rsync远程日志同步

如何将服务器中日志文件即时同步到另一个服务器中?

1.  通过 rsync 进行文件的同步;

2. 通过计划任务完成准实时的同步;

rsync介绍

rsync命令是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件。rsync使用所谓的“rsync算法”来使本地和远程两个主机之间的文件达到同步,这个算法只传送两个文件的不同部分,而不是每次都整份传送,因此速度相当快。 rsync是一个功能非常强大的工具,其命令也有很多功能特色选项,我们下面就对它的选项一一进行分析说明。

常用格式:

rsync -av SRC源 DEST目标        # 常用方法
rsync -av SRC源 user@host:DEST目标 # 远程文件copy到目标
rsync -av user@host:SRC源 DEST目标 #远程文件copy到本地
rsync -av SRC源 user@host::DEST目标 # 远程文件copy到目标
rsync -av user@host::SRC源 DEST目标 #远程文件copy到本地

常用参数:

-a                # 归档以递归形式传输文件,a ==“rlptgoD”。
-v                # 打印信息,”可视“化。
-r                # copy”目录“时使用。
-l                # 软链接的”链接文件“copy到目标目录。
-L                # ”软连接源文件“copy到目标目录。
-p                # 保留”文件权限“。
-o                # 保留文件”属主“信息。
-g                # 保留文件”属组“信息。
-D                # 保留“设备文件”信息。
-t                # 保留“时间”相关信息。
-u                # 判断“新旧文件”,源文件是新文件就不会覆盖。
--delete          # 删除目标的“同名目录”。
--exclude         # 指定排除不需要传输的文件模式。
--progress        # 查看“同步”文件状态,传输速度,--progress==-P。
--checksum        # 根据校验和决定是否跳过文件

-q, --quiet 精简输出模式。
-c, --checksum 打开校验开关,强制对文件传输进行校验。
-R, --relative 使用相对路径信息。
-b, --backup 创建备份,也就是对于目的已经存在有同样的文件名时,将老的文件重新命名为~filename。可以使用--suffix选项来指定不同的备份文件前缀。
--backup-dir 将备份文件(如~filename)存放在在目录下。
-suffix=SUFFIX 定义备份文件前缀。
--copy-unsafe-links 仅仅拷贝指向SRC路径目录树以外的链结。
--safe-links 忽略指向SRC路径目录树以外的链结。
-H, --hard-links 保留硬链结。
-S, --sparse 对稀疏文件进行特殊处理以节省DST的空间。
-n, --dry-run现实哪些文件将被传输。
-w, --whole-file 拷贝文件,不进行增量检测。
-x, --one-file-system 不要跨越文件系统边界。
-B, --block-size=SIZE 检验算法使用的块尺寸,默认是700字节。
-e, --rsh=command 指定使用rsh、ssh方式进行数据同步。
--rsync-path=PATH 指定远程服务器上的rsync命令所在路径信息。
-C, --cvs-exclude 使用和CVS一样的方法自动忽略文件,用来排除那些不希望传输的文件。
--existing 仅仅更新那些已经存在于DST的文件,而不备份那些新创建的文件。
--delete-excluded 同样删除接收端那些被该选项指定排除的文件。
--delete-after 传输结束以后再删除。
--ignore-errors 及时出现IO错误也进行删除。
--max-delete=NUM 最多删除NUM个文件。
--partial 保留那些因故没有完全传输的文件,以是加快随后的再次传输。
--force 强制删除目录,即使不为空。
--numeric-ids 不将数字的用户和组id匹配为用户名和组名。
--timeout=time ip超时时间,单位为秒。
-I, --ignore-times 不跳过那些有同样的时间和长度的文件。
--size-only 当决定是否要备份文件时,仅仅察看文件大小而不考虑文件时间。
--modify-window=NUM 决定文件是否时间相同时使用的时间戳窗口,默认为0。
-T --temp-dir=DIR 在DIR中创建临时文件。
--compare-dest=DIR 同样比较DIR中的文件来决定是否需要备份。
-P 等同于 --partial。
--progress 显示备份过程。
-z, --compress 对备份的文件在传输时进行压缩处理。
--exclude=PATTERN 指定排除不需要传输的文件模式。
--include=PATTERN 指定不排除而需要传输的文件模式。
--exclude-from=FILE 排除FILE中指定模式的文件。
--include-from=FILE 不排除FILE指定模式匹配的文件。
--version 打印版本信息。
--address 绑定到特定的地址。
--config=FILE 指定其他的配置文件,不使用默认的rsyncd.conf文件。
--port=PORT 指定其他的rsync服务端口。
--blocking-io 对远程shell使用阻塞IO。
-stats 给出某些文件的传输状态。
--progress 在传输时现实传输过程。
--log-format=formAT 指定日志文件格式。
--password-file=FILE 从FILE中得到密码。
--bwlimit=KBPS 限制I/O带宽,KBytes per second。
-h, --help 显示帮助信息。

主机内同步案例:

# 将源目录同步到目标目录内,目标目录自动创建。
# 同步,文件,目录,属主,属组,权限,时间,软连接
rsync -av 123/ /tmp/111/
# 同步,文件,目录,属主,属组,权限,时间,软连接对应源文件
# -L会将软连接对应的链接文件直接覆盖给目标
rsync -avL 123/ /tmp/111/
# -u防止新文件被覆盖,如果目标文件是新文件就不覆盖
rsync -avLu 123/ /tmp/111/
--exclude不同步筛选文件
#  --exclude=*.expect 不同步源文件下后缀一.expect的文件。
rsync -av --exclude=*.expect  123/ /tmp/111/
#  --exclude=chenpen/ 不同步源文件下的chenpen/目录。
rsync -av --exclude=chenpen/  123/ /tmp/111/
#  --exclude=*.expect 不同步源文件下后缀为.expect的1,2,3文件。
rsync -av --exclude=[123].expect 123/ /tmp/111/
--delete 同步删除
# --deletc 源文件中已经删除,目标文件还未删除的,文件删除。
rsync -av --delete 123/ /tmp/111/
同步测试打印详细信息
# -P 打印详细的同步信息
rsync -avP 123/ /tmp/111/
1.expect
           4 100%    0.00kB/s    0:00:00 (xfer#1, to-check=3/5)
2.expect
           0 100%    0.00kB/s    0:00:00 (xfer#2, to-check=2/5)
4.expect
           0 100%    0.00kB/s    0:00:00 (xfer#3, to-check=1/5)
chenpen/
远程同步文件
# 远程192.168.1.108主机root用户,同步文件。
rsync -av /root/123/ [email protected]:/tmp/111/
# 远程192.168.1.108主机默认whoami(当前)用户,同步文件。
rsync -av /root/123/ 192.168.1.108:/tmp/111/
报错
#-----------------------------------------------------
rsync: Failed to exec ssh: No such file or directory (2)
rsync error: error in IPC code (code 14) at pipe.c(84) [sender=3.0.6]
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in IPC code (code 14) at io.c(600) [sender=3.0.6]
#-----------------------------------------------------
解决方案1:
安装:yum -y install openssh-clients
解决方案2:
注:远程同步需要确保两端都安装了rsync。

本地环境同步两个文件夹为例,源文件夹为/root/123/ ,目标文件夹为 /tmp/111/:

可通过如下命令完成一次两个文件夹的同步:

$ rsync -r /root/123 /tmp/123

假设在 app 路径下有一个持续输出的日志文件 app.log,通过执行上述命令,app.log 文件被同步到了目标路径下,Well Done!

不过等一下,我们 tail -f /root/app/app.log 时,会发现,目标路径下的日志文件并没有持续刷新,即使我们不停的手动执行上面的 rsync 命令也不行。

在 rsync 命令后面增加 -v 参数,可以看到每次同步时,整个日志文件都被进行了传输。默认情况下,rsync 在发现文件发生变化时,会将目标位置的旧文件删除掉,并将源位置的新文件发送过去。

这就会导致我们的 tail 始终是一个内容不变的文件。那么想让目标路径的日志文件也能被 tail 时该怎么办呢?

tail 目标路径日志文件,内容不变

--append
  This special copy mode only works to efficiently update files that are known to be growing larger where any existing content on the receiving side is also known to be the same as the content on the sender. The use of --append can be dangerous if you aren't 100% sure that all the files in the transfer are shared, growing files. You should thus use filter rules to ensure that you weed out any files that do not fit this criteria.

  Rsync updates these growing file in-place without verifying any of the existing content in the file (it only verifies the content that it is appending). Rsync skips any files that exist on the receiving side that are not shorter than the associated file on the sending side (which means that new files are trasnferred).

  This does not interfere with the updating of a file's non-content attributes (e.g. permissions, ownership, etc.) when the file does not need to be transferred, nor does it affect the updating of any directories or non-regular files.

--append-verify
  This special copy mode works like --append except that all the data in the file is included in the checksum verification (making it much less efficient but also potentially safer). This option can be dangerous if you aren't 100% sure that all the files in the transfer are shared, growing files. See the --append option for more details.

  Note: prior to rsync 3.0.0, the --append option worked like --append-verify, so if you are interacting with an older rsync (or the transfer is using a protocol prior to 30), specifying either append option will initiate an --append-verify transfer.

大意就是,可以通过增加 --append 参数来实现文件的增量传输。当需要验证所有文件内容(未传输部分)时,可以使用 --append-verify 参数。

对于我们的场景,--append 参数即可满足需求,调整后的同步命令变为了:

$ rsync -r --append /Users/alphahinex/Desktop/app /Users/alphahinex/Desktop/sync

此时再去 tail 目标路径日志文件,发现在执行同步命令后,更新的日志文件内容会显示到 tail 中。

由于对实时性要求不是很高,所以每秒同步一次就可以了。让计划任务每秒执行一次上述命令不就好了吗?

理想总是很丰满。cron 表达式 * * * * * 是 分钟 小时 日 月 星期几,也就是说最快也只能每分钟执行一次。这个时候可以采用一些变通方案,来使得 cron 支持每秒执行一次,比如写一个简单的脚本 sync.sh:

#!/bin/bash
for((i=0;i<60;i++));
do
rsync -r --append /root/app/ /tmp/123
sleep 1
done

这个脚本的作用是,每次执行一次同步命令后,休眠 1 秒,执行 60 次。这样就变相实现了每秒执行一次同步指令。再通过 crontab -e 进行计划任务的配置,如:

* * * * * /Users/alphahinex/Desktop/app/sync.sh

使用rsync远程服务端日志同步:

服务端搭建
    • # 创建配置文件
    • vim /etc/rsyncd.conf
主配置文件
#--- 全局配置文件 ----#
# 端口,可省略 默认873
port=873
# 日志路径
log file=/var/log/rsync.log
# PID文件路径
pid file=/var/run/rsyncd.pid
# 指定 监听IP,可省略 默认监听所有IP
address=192.168.1.107
#-----------------------------#
#----------test模块-----------#
# 添加 test模块名字
[test]
# 指定 同步共享目录
path =/usr/local/apache-tomcat/logs/
# 注:如果同步加入L同步源链接文件在path外就需要false。
# 是否需要限定在自己的家目录,只能在path下活动
use chroot=true
# Ture 只能读不能写 false 可以读写
read only=false 
# 设置 同步文件所属主,可省略默认root
uid=root
# 设置 同步文件所属组,可省略默认root
gid=root
# 用户文件不需要在系统额外创建用户。
# 限制 指定用户可以访问,可省略默认root
auth users=test
# 指定 用户密码文件,可省略 默认不用密码验证
secrets file=/etc/rsyncd.passwd
# 限制 那些IP可以访问同步,可省略 默认不限制
hosts allow=192.168.1.0/24
#-----------------------------#
    • # 添加 写入密码文件
    • vim /etc/rsyncd.passwd
密码配置文件
# 设置用户名,密码
test:123123
    • # 修改密码文件权限
    • chmod 600 /etc/rsyncd.passwd
    • # 启动服务
    • rsync --daemon
查看rsync服务运行状态
# 查看进程是否开启
ps aux | grep rsync
root 32184 0.0 0.1 6236 624 ? Ss 13:18 0:00 rsync --daemon
# 查看监听端口
netstat -lnp | grep 873
tcp 0 0 192.168.1.107:873 0.0.0.0:* LISTEN 32184/rsync
# 查看日志文件
cat /var/log/rsync.log
2018/01/23 13:18:00 [32184] rsyncd version 3.0.6 starting, listening on port 873

# 关闭防火墙,或设置开放防火墙873端口
service iptahles stop

客户端
    •  # 发送文件 test用户@IP地址::服务指定目录/
    •  rsync -av /usr/local/apache-tomcat/logs/ [email protected]::/data/prod-logs/adcom/
服务端添加多个用户
修改配置文件:vim /etc/rsyncd.conf
注:用户,用户,... 添加多用户
auth users=test,xsk
修改密码文件:vim /etc/rsyncd.passwd
test:123123
xsk:123123
注:修改完配置文件及时生效无需重启。
服务端限制多个网段或指定IP
修改配置文件:vim /etc/rsyncd.conf
注:添加其他ip用空格分割
hosts allow=192.168.1.0/24 192.168.2.0/24
# 客户端不输入用户密码直接IP访问
rsync -av 1233/ 192.168.1.107::test/
[root@iZbp167av7wvow0nqs68rlZ dist]# crontab -l
*/3 * * * * sshpass -p 'X######111.' rsync -avz -e 'ssh -p 3321' /usr/local/apache-tomcat/logs/ [email protected]:/data/prod-logs/task/
*/3 * * * * sshpass -p 'X######111.' rsync -avz -e 'ssh -p 3321' /usr/local/adcom/logs/ [email protected]:/data/prod-logs/adcom/

六、用户审计auditd

1、audit简介

syslog会记录系统状态(硬件警告、软件的log), 但syslog属于应用层, log归咎于软件, 所以并不会记录所有动作,于是才有了audit。

auditd工具可以记录文件变化、记录用户对文件的读写访问,甚至记录系统调用,文件变化通知等。同时auditd工具可以将审计记录写入日志文件,包括记录系统调用和文件访问。管理员可以检查这些日志,确定是否存在安全漏洞。

但是auditd本身不提供额外的安全性保障,它不会保护你的系统免受代码故障或者任何类型的漏洞攻击。Audit服务对跟踪这些安全问题非常有用,并且有效帮助我们采取何种针对性的安全措施。

audit功能:

1. 将用户与进程关联

Audit将进程映射到启动它们的用户标识。这使得管理员或安全人员能够精确地跟踪哪个用户拥有哪个进程并且可能在系统上进行恶意操作。

2. 审查审计线索

Linux Audit 提供了将审计报告写入磁盘并将其转​​换为可读格式的工具。

3. 审查特定的审计事件

Audit提供了一个实用程序,允许筛选特定感兴趣事件的审计报告。可以根据下面的内容过滤:

  • User

  • Group

  • Audit ID

  • Remote Host Name

  • Remote Host Address

  • System Call

  • System Call Arguments

  • File

  • File Operations

  • Success or Failure 

4. 应用选择性审计

Audit提供了筛选感兴趣事件的审计报告并调整审计以仅记录所选事件的手段。您可以创建自己的一组规则,并让审计守护进程仅记录您感兴趣的规则。

5. 保证报告数据的可用性

审计报告由root拥有,因此只能由root用户移除。未经授权的用户不能删除审计日志。

6. 防止审计数据丢失

如果内核内存不足,审计守护进程的积压被超过,或者超过了速率限制,审计可以触发系统关闭,以防止事件逃离审计的控制。此关闭将立即停止由审核内核组件触发的系统,而不会将最新日志同步到磁盘。默认配置是将警告记录到系统日志中,而不是挂起系统。

如果系统在记录时磁盘空间不足,则可以将审计系统配置为执行干净关闭。缺省配置指示审计守护程序在磁盘空间不足时停止记录。

2、audit架构

audit由几个组件组成,每个组件都为整个框架提供重要功能:

1.auditd

审计守护进程负责将通过审计内核接口生成并由应用程序和系统活动触发的审计消息写入磁盘。审计守护进程启动的方式由systemd控制。审计系统功能(启动时)由/etc/audit/auditd.conf控制。

2.auditctl

auditctl实用程序控制审计系统。它控制审计界面的日志生成参数和内核设置,以及确定哪些事件被跟踪的规则集。

3. audit rules

文件/etc/audit/audit.rules包含一系列auditctl命令,它们在启动审计守护程序后立即在系统引导时加载。

4. aureport

aureport实用程序允许您从审核事件日志中创建自定义报告。这种报告生成可以很容易地编写脚本,输出可以被各种其他应用程序使用,例如,绘制这些结果。

5. ausearch

ausearch实用程序可以使用各种密钥或记录格式的其他特征在审计日志文件中搜索某些事件。

6.audispd

审计调度程序守护进程(audispd)可用于将事件通知转发给其他应用程序,而不是将它们写入审计日志中的磁盘(或除此之外)。

7.autrace

autrace实用程序以与strace类似的方式跟踪各个进程。 autrace的输出被记录到审计日志中。打印上次登录用户的列表,与上次类似。 aulast通过审计日志(或给定的审计日志文件)进行搜索,并根据审计日志中的时间范围显示所有用户登录和注销的列表。

8.aulastlog

为类似于lastlog的机器的所有用户打印上次登录。登录名称,端口和上次登录时间将被打印。

简而言之:Linux audit(kauditd) 内核模块拦截系统调用并记录相关事件, auditd守护进程将审计报告写入磁盘。各种命令行实用程序负责显示,查询和存档审计跟踪。 

auditd架构示意图:

说明: 

元素 说明
User 记录用户空间中产生的事件。它的作用是过滤消息的,内核传递给审计后台进程之前先查询它。
Task 跟踪应用程序的子进程(fork),当一个任务被创建时,也就是父进程通过 fork 和克隆创建子进程时记录该事件。
Exit 当一个系统调用结束时判断是否记录该调用
Exclude 删除(过滤)不合格事件,Exclude 是用来过滤消息的,也就是不想看到的消息可以在这里写规则进行过滤。
auditctl 即时控制审计守护进程行为的工具
/etc/audit/audit.rules 记录审计规则的文件
aureport 查看和生成审计报告的工具
ausearch 查找审计事件的工具
auditspd 转发事件通知给其他应用程序,而不是写入到审计日志文件中
autrace 一个用于跟踪进程的命令
/etc/audit/auditd.conf auditd工具的配置文件

3、audit配置

启动audit内核模块    

有些系统audit的内核模块时默认关闭的。可以查看/proc/cmdline,看audit=0,如果为0,则默认不启动audit。通过设置/boot/grub2/grub.cfg文件,使audit=1,或者去掉audit=0,然后重启系统,使audit内核模块启动。再次查看/proc/cmdline已修改为audit=1。

如果audit的内核模块启动了,用auditctl -s查询enabled为1,但是用户空间的auditd守护进程没有运行,审计日志无人接管,就会被写到/var/log/messages中。

启动auditd守护进程

我们习惯使用systemctl start xxx来启动一个服务,但是auditd手册中,明确指出使用service命令是唯一一个正确开启auditd守护进程的方式。使用systemctl只是enable,status这两个动作可以。

正常一个服务,我们使用service xx start时都会显示Redirecting to /bin/systemctl start xxx.service。

我们可以通过which service来查看这个命令的源文件,/usr/sbin/service。这里对于不同的情况,有不同的处理:

1)/etc/init.d目录下有这个服务;

2)/usr/libexec/initscripts/legacy-actions目录下有这个服务;

3)除了以上两种情况,其他情况下会定向到systemctl cmd xxx.service;

auditd属于第二种情况,/usr/libexec/initscripts/legacy-actions目录有auditd目录,如下:

linux-xdYUnA:/usr/libexec/initscripts/legacy-actions/auditd # ls
condrestart  restart  resume  rotate  stop

设置开机启动/不启动:

systemctl enable auditd
systemctl disable auditd

stop:

service auditd stop

reload:

service auditd reload

重新加载auditd的配置文件/etc/audit/auditd.conf。使用systemctl reload auditd也是生效的。

rotate:

service auditd rotate

在/var/log/audit/目录下rotate。

resume:

service auditd resume

当日志记录停止时,用于恢复日志记录。

condrestart:

service auditd condrestart

当服务正在运行时,重启服务。

service启动文件

[Unit]
Description=Security Auditing Service
DefaultDependencies=no
## If auditd.conf has tcp_listen_port enabled, copy this file to## /etc/systemd/system/auditd.service and add network-online.target## to the next line so it waits for the network to start before launching.
## 如果在auditd.conf中已经配置了tcp_listen_port,那么需要在After后面增加network-online.target,保证先启动网络,后再启动auditd
After=local-fs.target systemd-tmpfiles-setup.service
Conflicts=shutdown.target
Before=sysinit.target shutdown.target
RefuseManualStop=yes
ConditionKernelCommandLine=!audit=0
Documentation=man:auditd(8) https://github.com/linux-audit/audit-documentation

[Service]
Type=forking
PIDFile=/var/run/auditd.pid
ExecStart=/sbin/auditd
## To not use augenrules, copy this file to /etc/systemd/system/auditd.service## and comment/delete the next line and uncomment the auditctl line.## NOTE: augenrules expect any rules to be added to /etc/audit/rules.d/
## ungenrules这个工具是把/etc/audit/rules.d/目录下的规则文件,按照顺序加载进来,写入到/etc/audit/audit.rules文件中。如果不使用这个工具,下面这一行需要注释或删掉。auditctl那一行取消注释。
ExecStartPost=-/sbin/augenrules --load#ExecStartPost=-/sbin/auditctl -R /etc/audit/audit.rules
ExecReload=/bin/kill -HUP $MAINPID
# By default we don't clear the rules on exit. To enable this, uncomment
# the next line after copying the file to /etc/systemd/system/auditd.service## 这个是stop后执行的动作。stop.rulse主要是 -e 0 disable 和-D删除所有规则 ## 如果不删除已经配置好的规则的话,在stop后,用auditctl -l查询可以看到有很多规则,并且enabled为1,这样的话,当auditd服务关闭了,但规则还在,那就会有大量的日志记录在messages中。stop.rules中通过-e 0使audit不工作,日志也不会记录在messages中
#ExecStopPost=/sbin/auditctl -R /etc/audit/audit-stop.rules

[Install]
WantedBy=multi-user.target

audit配置文件

 通过auditctl -s查询可以看到audit的状态,这个是查询audit内核模块的状态:

linux-xdYUnA:/etc/audit # auditctl -s
enabled 0
failure 1
pid 0
rate_limit 0
backlog_limit 8192
lost 219
backlog 0

其中“enabled”这个选项很重要的,如果为0,则audit就不工作了,看不到任何审计日志,哪怕是系统日志messages。所有的规则都不会生效,连没有设定规则时,su提权这样的操作也不会记录。无论是使用auditctl临设配置规则,还是用/etc/audit/audit.rules文件永久配置规则,所有规则设定都要在enabled为1时才可以生效。

当enabled为2时,则表示规则锁定,所有设置都不起作用,只有当系统重启后,enabled不为2了才可以。

服务是服务,enable是enable,这两者并没有关系,服务启动或停止是针对auditd这个守护进程。auditctl -s查询的enabled的状态为audit内核模块的状态。内核模块主要用来获取审计信息,用户态的守护进程主要用来收集信息和记录日志。enabled为1,服务停止,日志会记录在messages中;enable为0,服务启动,没有任何审计信息,不会记录日志。也就是auditd服务是否启动,决定日志记录在哪里,启动了,日志记录在配置文件指定的路径,没有启动,记录在messages日志中。enable决定内核是否开始审计,为0,不启动,为1,启动。

可以通过auditctl -e改变状态,0 不使能,1 使能,2 锁定配置。如果在/boot/grub2/grub.cfg里配置的audit=1,当系统重启后,enable默认为1,如果没有配置audit,则enable为0。

当然了,如果audit的内核模块不加载(即在/boot/grub2/grub.cfg中配置为audit=0),与内核模块交互的auditctl也就无法工作了,状态当然也无法查询。

linux-xdYUnA:~ # auditctl -s
Error - audit support not in kernel
Cannot open netlink audit socket

配置audit只用修改两个配置文件(/etc/audit/audit.rules 和/etc/audit/auditd.conf ),然后通过aureport和ausearch生成和分析数据。要使用安全审计系统可采用下面的步骤:内核选项勾选和安装软件包(上篇文章已介绍)。添加审计规则,修改配置文件,然后启用 audit 守护进程进行日志记录,最后生成审计日志来分析数据。

auditd进程的配置文件是保存在/etc/audit/auditd.conf里,默认文件可满足大多数环境的要求:

local_events = yes
write_logs = yes
log_file = /var/log/audit/audit.log
log_group = root
log_format = RAW
flush = INCREMENTAL_ASYNC
freq = 50
max_log_file = 8
num_logs = 5
priority_boost = 4
disp_qos = lossy
dispatcher = /sbin/audispd
name_format = NONE
##name = mydomain
max_log_file_action = ROTATE
space_left = 75
space_left_action = SYSLOG
action_mail_acct = root
admin_space_left = 50
admin_space_left_action = SUSPEND
disk_full_action = SUSPEND
disk_error_action = SUSPEND
use_libwrap = yes
##tcp_listen_port =
tcp_listen_queue = 5
tcp_max_per_addr = 1
##tcp_client_ports = 1024-65535
tcp_client_max_idle = 0
enable_krb5 = no
krb5_principal = auditd
##krb5_key_file = /etc/audit/audit.key
distribute_network = no

参数说明:

1. log_file 
审计日志文件的完整路径。如果您配置守护进程向除默认/var/log/audit/外的目录中写日志文件时,一定要修改它上面的文件权限,使得只有根用户有读、写和执行权限。所有其他用户都不能访问这个目录或这个目录中的日志文件。
2. log_format 
写日志时要使用的格式。当设置为RAW时,数据会以从内核中检索到的格式写到日志文件中。当设置为NOLOG时,数据不会写到日志文件中,但是如果用dispatcher选项指定了一个,则数据仍然会发送到审计事件调度程序中。
3. priority_boost 
审计应采用多少优先级推进守护进程。必须是非负数。0表示没有变化。
4. flush 
多长时间向日志文件中写一次数据。这个参数与freq联合使用,freq表示的是在与硬件驱动强制同步前,有多少个记录可以发送到磁盘。这个确保audit数据与磁盘中的log文件保持同步。保持默认值即可。值可以是NONE、INCREMENTAL、DATA和SYNC之一。如果设置为NONE,则不需要做特殊努力来将数据刷新到日志文件中。如果设置为INCREMENTAL,则用freq选项的值确定多长时间发生一次向磁盘的刷新。如果设置为DATA,则审计数据和日志文件一直是同步的。如果设置为SYNC,则每次写到日志文件时,数据和元数据是同步的。
5. freq 
如果flush设置为INCREMETNAL,审计守护进程在写到日志文件中前从内核中接收的记录数。
6. num_logs 
max_log_file_action设置为ROTATE时要保存的日志文件数目。必须是0~99之间的数。如果设置为小于2,则不会循环日志。如果递增了日志文件的数目,就可能有必要递增/etc/audit/audit.rules中的内核backlog设置值,以便留出日志循环的时间。如果没有设置num_logs值,它就默认为0,意味着从来不循环日志文件。
7. dispatcher 
当启动这个守护进程时,由审计守护进程自动启动程序。所有守护进程都传递给这个程序。可以用它来进一步定制报表或者以与您的自定义分析程序兼容的不同格式产生它们。自定义程序的示例代码可以在/usr/share/doc/audit- <version>/skeleton.c中找到。由于调度程序用根用户特权运行,因此使用这个选项时要极其小心。这个选项不是必需的。
8. disp_qos 
控制调度程序与审计守护进程之间的通信类型。有效值为lossy和lossless。如果设置为lossy,若审计守护进程与调度程序之间的缓冲区已满 (缓冲区为128千字节),则发送给调度程序的引入事件会被丢弃。然而,只要log_format没有设置为nolog,事件就仍然会写到磁盘中。如果设置为lossless,则在向调度程序发送事件之前和将日志写到磁盘之前,调度程序会等待缓冲区有足够的空间。
9. max_log_file 
以兆字节表示的最大日志文件容量。当达到这个容量时,会执行max_log_file _action指定的动作。
10. max_log_file_action 
当达到max_log_file的日志文件大小时采取的动作。值必须是IGNORE、SYSLOG、SUSPEND、ROTATE和KEEP_LOGS之一。如果设置为IGNORE,则在日志文件达到max_log_file后不采取动作。如果设置为SYSLOG,则当达到文件容量时会向系统日志/var/log/messages中写入一条警告。如果设置为SUSPEND,则当达到文件容量后不会向日志文件写入审计消息。如果设置为ROTATE,则当达到指定文件容量后会循环日志文件,但是只会保存一定数目的老文件,这个数目由num_logs参数指定。老文件的文件名将为audit.log.N,其中 N是一个数字。这个数字越大,则文件越老。如果设置为KEEP_LOGS,则会循环日志文件,但是会忽略num_logs参数,因此不会删除日志文件。
11. space_left 
以兆字节表示的磁盘空间数量。明确出磁盘剩余多少空间时,执行space_left_action指定的动作,这个值的设定需要保证,管理员有足够的时间响应并且清理磁盘空间,这个值的设定依赖于audit日志产生的速率。默认为75M。
12. space_left_action 
当磁盘空间量达到space_left中的值时,采取这个动作。有效值为IGNORE、SYSLOG、EMAIL、SUSPEND、SINGLE和 HALT。如果设置为IGNORE,则不采取动作。如果设置为SYSLOG,则向系统日志/var/log/messages写一条警告消息。如果设置为 EMAIL,则从action_mail_acct向这个地址发送一封电子邮件,并向/var/log/messages中写一条警告消息。如果设置为 SUSPEND,则不再向审计日志文件中写警告消息。如果设置为SINGLE,则系统将在单用户模式下。如果设置为SALT,则系统会关闭。
13. action_mail_acct 
负责维护审计守护进程和日志的管理员的电子邮件地址。如果地址没有主机名,则假定主机名为本地地址,比如root。必须安装sendmail并配置为向指定电子邮件地址发送电子邮件。
14. admin_space_left 
以兆字节表示的磁盘空间数量,指出最低的磁盘剩余空间大小,当到达这个值时,执行admin_space_left_action指定的动作。用这个选项设置比space_left_action更多的主动性动作,以防万一space_left_action没有让管理员释放任何磁盘空间。这个值应小于space_left_action。如果达到这个水平,则会采取admin_space_left_action所指定的动作。
15. admin_space_left_action 
当自由磁盘空间量达到admin_space_left指定的值时,则采取动作。有效值为IGNORE、SYSLOG、EMAIL、SUSPEND、SINGLE和HALT。与这些值关联的动作与space_left_action中的相同。可以设置为single,使系统成为single-user mode,然后让管理员释放磁盘空间。按照默认的来设置比较好,达到space_left时,执行syslog上报warning,达到admin_space_left时,停止记录日志。
16. disk_full_action 
如果含有这个审计文件的分区已满无多余空间,则采取这个动作,默认为suspend。可能值为IGNORE、SYSLOG、SUSPEND、SINGLE和HALT。与这些值关联的动作与space_left_action中的相同。 
提示: 
如果不循环审计日志文件,则含有/var/log/audit/的分区可能变满并引起系统错误。因此,建议让/var/log/audit/位于一个单独的专用分区。
17. disk_error_action 
当分区出现error时,执行的动作。这些动作都依据你所需要的安全规则。在写审计日志或循环日志文件时检测到错误时值必须是IGNORE、SYSLOG、SUSPEND、SINGLE和HALT之一。与这些值关的动作与space_left_action中的相同。 
/etc/sysconfig/auditd文件可以用来设置带EXTRAOPTIONS参数的auditd的命令行选项。唯一的命令行选项-f以调试模式安排守护进程。如果启用了调试模式,则会出现标准错误消息而不是日志文件。AUDITD_LANG设置值可以用来修改守护进程的位置。如果设置为 none,则所有位置信息会从审计环境中删除。如果AUDITD_CLEAN _STOP选项设置为yes,则当用service auditd stop命令停止守护进程时,会删除审计规则与观察器。
18. tcp_listen_port
指定Audit进程监听的端口区间(1~65535)
19. tcp_listen_queue
设置暂时挂起连接的最大值,不要设置太小的值,因为在某些情况下,例如断电后,挂起连接的数量可能会很高。
20. tcp_client_ports
设置允许的客户端端口号范围。
21. tcp_client_max_idle
指定客户端最大挂起次数在一定的时间内。
22. tcp_max_per_addr
表示允许来自一个IP地址的并发连接数的数值。

如果你的环境需要满足严格的安全规则,如下的一些配置可以参考:

log_file:audit 日志放置的路径。这里放置日志的地方最好是一个独立的分区(mount point),这样可以避免其他进程消耗掉这个路径的空间,并且可以为auditd提供精确的剩余空间。

max_log_file:指定每一个单独的audit log文件的最大的size,单位为M,必须设置为充分利用保存着审计日志文件所在分区的可用空间。默认为8M。

max_log_file_action:当达到了日志的最大size后,需要执行的动作,设置为KEEP_LOGS时,可以避免日志被重写。

我们先看下如下的记录:

linux-xdYUnA:/var/log/audit # ll
total 36496
-rw------- 1 root root 3780142 Mar 31 09:32 audit.log
-r-------- 1 root root 8388893 Mar 30 17:40 audit.log.1
-r-------- 1 root root 8388625 Mar 30 17:39 audit.log.2
-r-------- 1 root root 8388806 Mar 30 17:39 audit.log.3
-r-------- 1 root root 8388670 Mar 30 17:39 audit.log.4
linux-xdYUnA:/var/log/audit # ll
total 32828
-rw------- 1 root root   27948 Mar 31 09:34 audit.log
-r-------- 1 root root 8388809 Mar 31 09:34 audit.log.1
-r-------- 1 root root 8388893 Mar 30 17:40 audit.log.2
-r-------- 1 root root 8388625 Mar 30 17:39 audit.log.3
-r-------- 1 root root 8388806 Mar 30 17:39 audit.log.4

第一次查询时,audit.log还没有写满到8M,第二次查询时应该是已经到了8M了,重新写的audit.log。那么之前的audit.log去哪里了呢,我们仔细看每个日志文件的大小,不难发现。第一次查询到的audit.log.4已经没有了,系统认为这个是最老的日志,因为我们设置的num_logs为5,所以这个最老的日志就被删除了,或者理解为新日志把最老的日志给覆盖了。如果我们不想让日志被覆盖,我们可以设置为KEEP_LOGS。如下所示,一直增长的audit的日志,最后无论num_logs设置为多少,日志都在继续增加,这样,最好要保证存放audit日志的空间是一个独立分区,不然会影响其他系统日志的记录。

linux-xdYUnA:/var/log/audit # ll
total 61104
-rw------- 1 root root 3791866 Mar 31 10:01 audit.log
-r-------- 1 root root 8388849 Mar 31 10:01 audit.log.1
-r-------- 1 root root 8388772 Mar 31 09:59 audit.log.2
-r-------- 1 root root 8388776 Mar 31 09:59 audit.log.3
-r-------- 1 root root 8388809 Mar 31 09:34 audit.log.4
-r-------- 1 root root 8388893 Mar 30 17:40 audit.log.5
-r-------- 1 root root 8388625 Mar 30 17:39 audit.log.6
-r-------- 1 root root 8388806 Mar 30 17:39 audit.log.7

4、audit控制命令

1. auditctl 

auditctl命令语法:

auditctl [选项] filter,action   -S syscall   -F condition   -k label

auditctl命令选项:

项目 可选参数 説明
filter user,exit,task,exclude filter 详细说明哪个内核规则匹配过滤器应用在事件中。以下是其中之一的与规则匹配的过
滤器: task、exit、user 以及 exclude
action always, never 是否审核事件(always 表示是)(never 表示否)
syscall all, 2, open 等 所有的系统调用都可以在/usr/include/asm/unistd_64.h 文件中找到。许多系统调用都能形成一个规则
condition euid=0, arch=b64 详细说明其他选项,进一步修改规则来与以特定架构、组 ID、进程 ID 和其他内容为基础的事件相匹配
label 任意文字 标记审核事件并检索日志

-S 表示系统调用号或名字

-F 表示规则域。 

-k 表示设置审计规则上的过滤关键

audit 审计规则分成三个部分:

  • 控制规则:这些规则用于更改审计系统本身的配置和设置。
  • 文件系统规则:这些是文件或目录监视。 使用这些规则,我们可以审核对特定文件或目录的任何类型的访问。
  • 系统调用规则:这些规则用于监视由任何进程或特定用户进行的系统调用。

控制规则

控制规则可以在/etc/audit/audit.rules 中设置,主要包括:

-D #删除所有当前装载的审核规则#
-b 8192 #在内核中设定最大数量的已存在的审核缓冲区为 8Mb#
-e 2 #锁定审核配置#

文件系统规则

可以通过 auditctl 命令设置。监控文件系统行为(依靠文件、目录的权限属性来识别)

规则格式:

-w 路径
-p 权限
-k 关键字
其中-p 权限的动作分为四种
r — 读取文件或者目录。
w — 写入文件或者目录。
x — 运行文件或者目录。
a — 改变在文件或者目录中的属性。

系统调用规则

监控系统调用可能会引起高负荷的日志活动,这会让内核承受更大的负荷。所以要慎重衡量哪些系统调用需要放到 audit.rules 中。如果审计的是目录的话,只能对该目录本身的属性进行审计。如果想审计下面的文件,需要一一列出。

系统调用的监控:

-a 添加一条系统调用监控规则
-S 显示需要监测的系统调用的名称

显示规则和删除规则:

-D 删除所有规则
-d 删除一条规则和-a 对应
-w 写入文件或者目录。
-W 删除一条规则和-w 对应
-l 列出所有规则

定义系统调用规则:

auditctl -a action,filter -S system_call -F field=value -k key_name

action和filter:明确一个事件被记录。action可以为always或者never,filter明确出对应的匹配过滤,filter可以为:task,exit,user,exclude。

system_call:明确出系统调用的名字,几个系统调用可以写在一个规则里,如-S xxx -S xxx。系统调用的名字可以在/usr/include/asm/unistd_64.h文件中找到。

field=value:作为附加选项,修改规则以匹配特定架构、GroupID,ProcessID等的事件。具体有哪些字段。

定义一个规则,当每次使用系统调用adjtimex或者settimeofday时,并且为64位架构,记录审计日志,命令可以输入如下:

auditctl -a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time_change

一个文件被user ID为1000或者更大的用户删除,或重命名,记录审计,命令如下:

auditctl -a always,exit -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete

注意,-F auid!=4294967295 这个是为了排除login UID没有被设置的用户。

也可以通过系统调用规则,来定义文件系统规则,如下的系统调用规则,与-w /etc/shadow -p wa的文件系统规则等同:

auditctl -a always,exit -F path=/etc/shadow -F perm=wa

注意:auditctl添加的规则每次audit服务重启后就消失了,为了让他们在重新启动后有效的,可以将其添加到文件/etc/audit/rules.d/audit.rules 中。

查看当前生效的audit规则:

auditctl -l

 -w 对某个文件、目录进行监控:

Auditctl -w /home/zxy -p wxra

-p后面跟着是规则 w 写入 、r 读 、x 执行、 a修改属性。

auditctl -w /etc/passwd -p war -k password_file
auditctl -w /tmp -p e -k webserver_watch_tmp

-k 筛选字符串,用于查询监控日志。

auditctl -a exit,never -S mount
auditctl -a entry,always -S all -F pid=1005

-S 监控系统调用;-F 给出更多监控条件(pid/path/egid/euid等) 

对某个文件、目录取消监控:

auditctl -W /home/zxy

 定义特定用户(这里假设是 UID 为 10001)访问日志和标签的日志条目的规则:

auditctl -a always,exit -F arch=b64 -F auid=10001 -S open -k userfile

userfile 是用户自己设置的一个规则名字。

 控制Audit功能的开关:

“auditctl -e” 

设置错误级别[0..2] 0=silent, 1=printk, 2=panic:

 “auditctl -f” 

控制Audit消息的速率:

“auditctl -r” 

设置Audit服务的最大缓存空间,如果缓存空间满了,指定的错误级别动作会被触发:

“auditctl -b” 

查看Audit进程当前的状态:

“auditctl -s” 

AUDIT_STATUS:

enabled=1 flag=2 pid=3105 rate_limit=0 backlog_limit=8192 lost=0(丢失的Audit消息数) backlog=0(未输出的Audit缓冲区大小)

2. audit rules 规则

auditctl 添加的规则也可以写入到/etc/audit/rules.d/audit.rules 文件最尾巴上,它可以保证每次audit服务重启后,规则还有效。

#Record all file opens from user 501 
#Use with caution since this can quickly 
#produce a large quantity of records 
-a exit,always -S open -F uid=501 -F key=501open 
#Record file permission changes 
-a entry,always -S chmod

要添加审计规则,可在/etc/audit/audit.rules文件中用下面的语法: 

-a <list>,<action> <options>

如果在运行守护进程时添加规则/etc/audit/audit.rules,则一定要以根用户身份用service auditd restart命令启用修改。也可以使用service auditd reload命令,但是这种方法不会提供配置文件错误的消息。 

list列表名必须是下列名称之一:

task: 
每个任务的列表。只有当创建任务时才使用。只有在创建时就已知的字段(比如UID)才可以用在这个列表中。 
entry:  
系统调用条目列表。当进入系统调用确定是否应创建审计时使用。 
exit:  
系统调用退出列表。当退出系统调用以确定是否应创建审计时使用。 
user:  
用户消息过滤器列表。内核在将用户空间事件传递给审计守护进程之前使用这个列表过滤用户空间事件。有效的字段只有uid、auid、gid和pid。 
exclude:  
事件类型排除过滤器列表。用于过滤管理员不想看到的事件。用msgtype字段指定您不想记录到日志中的消息。 

action动作必须下面的动作之一: 

never:  
不生成审计记录。 
always: 
分配审计上下文,总是把它填充在系统调用条目中,总是在系统调用退出时写一个审计记录。 

<options>可以包括下面几个选项中的一个或多个:

-s <syscall> 
根据名称或数字指定一个系统。要指定所有系统调用,可使用all作为系统调用名称。如果程序使用了这个系统调用,则开始一个审计记录。可以为相同的规则指定多个系统调用,每个系统调用必须用-S启动。在相同的规则中指定多个系统,而不是列出单独的规则,这样可以导致更好的性能,因为只需要评价一个规则。 
- F <name[=,!=,<,>,<=]value> 
指定一个规则字段。如果为一个规则指定了多个字段,则只有所有字段都为真才能启动一个审计记录。每个规则都必须用-F启动,最多可以指定64个规则。如果用用户名和组名作为字段,而不是用UID和GID,则会将它们解析为UID和GID以进行匹配。下面是有效的字段名: 
pid 
进程ID。 
ppid 
父进程的进程ID。 
uid 
用户ID。 
euid 
有效用户ID。 
suid 
设置用户ID。 
fsuid 
文件系统用户ID。 
gid 
组ID。 
egid 
有效组ID。 
sgid 
设置组ID。 
fsgid 
文件系统组ID。 
auid 
审计ID,或者用户登录时使用的原始ID。 
msgtype 
消息类型号。只应用在排除过滤器列表上。 
pers 
OS Personality Number。 
arch 
系统调用的处理器体系结构。指定精确的体系结构,比如i686(可以通过uname -m命令检索)或者指定b32来使用32位系统调用表,或指定b64来使用64位系统调用表。 
devmajor 
Device Major Number。 
devminor 
Device Minor Number。 
inode 
Inode Number。 
exit 
从系统调用中退出值。 
success 
系统调用的成功值。1表是真/是,0表示假/否。 
a0,a1,a2,a3 
分别表示系统调用的前4个参数。只能用数字值。 
key 
设置用来标记事件的审计日志事件消息的过滤键。参见程序清单25-2和程序清单25-3中的示例。当添加观察器时,类似于使用-k选项。参见“编写审计规则与观察器”了解关于-k选项的详细信息。 
obj_user 
资源的SELinux用户。 
obj_role 
资源的SELinux角色。 
obj_type 
资源的SELinux类型。 
obj_lev_low 
资源的SELinux低级别。 
obj_lev_high 
资源的SELinux高级别。 
subj_role 
程序的SELinux角色。 
subj_type 
程序的SELinux类型。 
subj_sen 
程序的SELinux敏感性。 
subj_clr 
程序的SELinux安全级别(clearance)。 

添加一条audit规则,记录maj用户的所用open系统调用:

auditctl-a entry,always -S open -F uid=500

open表示:要查看某一特定用户打开的文件,在另一个终端以maj用户登录,登录后执行一个ls命令即可。

删除这条audit规则:

auditctl-d entry,always -S open -F uid=500

向列表开头添加规则,可用-A替换-a。删除语法相同的规则,用-d替换-a。要删除所有规则,可指定-D选项。 

如不想看到用户登陆类型的消息,可以如下添加规则:

auditctl -a exclude,always -F msgtype=USER_LOGIN

这里过滤是以“消息类型”为对象的。

监视/etc/passwd文件被读、写、执行、修改文件属性的操作记录:

auditctl -w /etc/passwd -p rwax

-a表示在末尾添加动作,查看程序所有的系统调用:

auditctl -a entry,always-S all -F pid=1005

查看指定用户打开的文件:

auditctl -a exit,always-S open -F auid=510

查看不成功的open系统调用:

auditctl-a exit,always -S open -F success!=0

如果与-w结合起来使用-k <key>选项,则由观察器产生的所有记录会含有一个警报词(限制为31个字节),因此可以将该观察器的记录轻松地从日志文件中过滤出来:

#Watch for changes to sysconfig files 
-w /etc/sysconfig -k SYSCONFIG 
#Watch for changes to audit config files 
-w /etc/audit/audit.rules -k AUDIT_RULES 
-w /etc/audit/auditd.conf -k AUDIT_CONF 
-w /var/log/audit/ -k LOG_AUDIT 
#Watch to see who tries to start the VPN client 
-w /usr/bin/vpnc -k VPNC -p x 
#Watch password files 
-w /etc/group -k PASSWD 
-w /etc/passwd -k PASSWD 
-w /etc/shadow -k PASSWD 

删除一个用户后/var/log/audit /audit.log中的日志项,它会修改正在观察的这些口令文件。正如程序清单25-3中带过滤键的规则的示例,这个键被添加到日志项的末尾,因此可以轻松地将它从日志项的其余部分过滤出来:

type=SYSCALL msg=audit(1168227741.656:17915): arch=c000003e syscall=82 
success=yes exit=0 a0=7fff00975dd0 a1=60a700 a2=0 a3=22 items=5 ppid=26575 
pid=4147 auid=501 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 
tty=pts4 comm="userdel" exe="/usr/sbin/userdel" key="PASSWD" 

 使用关键字( key)搜索审计事件记录:

ausearch -k PASSWD | less

 记录uid为root的用户调用mkdir系统调用的情况:

auditctl -a entry,always -F UID=root -S mkdir 

上面的是系统调用入口监视(entry链表) 该规则在进入系统调用的时候触发,记录此时的执行上下文 。 

系统调用出口(exit链表) 同系统调用入口规则,不同的是在退出系统调用的时候被触发。

在调用fork() 或者clone()产生新进程的时候触发:

auditctl -a task,always -F uid=root

该规则适用的“域”仅仅是此时可见的,例如uid gid pid 等等。

5、audit log 日志

 让我们先来构造一条audit日志。在home目录下新建一个目录,然后配置一条audit规则,对这个目录的wrax,都记录审计日志:

auditctl -w /home/audit_test -p wrax -k audit_test

root用户访问audit_test目录时,即在这个目录下ls,审计日志如下:

type=SYSCALL msg=audit(1523501721.433:4172989307): arch=c000003e syscall=257 success=yes exit=3 a0=ffffffffffffff9c a1=21e0550 a2=90800 a3=0 items=1 ppid=13329 pid=18721 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts2 ses=10711 comm="ls" exe="/usr/bin/ls" key="audit_test"type=CWD msg=audit(1523501721.433:4172989307):  cwd="/home/audit_test"type=PATH msg=audit(1523501721.433:4172989307): item=0 name="." inode=99213313 dev=08:11 mode=040755 ouid=0 ogid=0 rdev=00:00 objtype=NORMAL

使用ausearch命令可以看到这条日志的解释,使日志中的一些我们看不懂的参数转换为可读形式:

type=SYSCALL msg=audit(04/12/2018 10:55:21.433:4172989307) : arch=x86_64 syscall=openat success=yes exit=3 a0=0xffffffffffffff9c a1=0x21e0550 a2=O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC a3=0x0 items=1 ppid=13329 pid=18721
auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts2 ses=10711 comm=ls exe=/usr/bin/ls key=audit_test
type=CWD msg=audit(04/12/2018 10:55:21.433:4172989307) : cwd=/home/audit_test
type=PATH msg=audit(04/12/2018 10:55:21.433:4172989307) : item=0 name=. inode=99213313 dev=08:11 mode=dir,755 ouid=root ogid=root rdev=00:00 objtype=NORMAL

参数说明:

Time:审计时间
name:审计对象	
type: audit消息类型, 消息类型有100多种,可以查看https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/sec-audit_record_types
msg: 消息的ID, 它有两个部分组成, 分号之前的是Unix的时间戳,分号之后的是真正的event ID, 同一个应用程序的相同system call拥有相同的event ID, 同一个应用的不同system call则不同。
arch: 调用system call的CPU构架, 可以通过ausearch -i来指定搜索相关的log。
syscall: system call的类型, 发起访问的系统调用号。可以查看https://github.com/torvalds/linux/blob/master/arch/sh/include/asm/unistd.h。
success: system call是成功或者失败。
exit: system call的返回值。
a0 to a3: 系统调用的前四个参数的数字化,可以通过ausearch解码查看。
items: 传递到应用程序的字符串数量。
ppid: 父进程的PID。
pid: 该进程的PID。
auid: audit ID, 针对某一用户一个进程会被分配一个audit ID, 该audit ID会被传递给子进程,尽管在系统中用户切换,该audit ID将始终保持一致。 这样我们可以针对对某一用户进行trace。
uid: user ID。
gid: group ID。
euid, suid, fsuid: Effective user ID, set user ID, and file system user ID.
egid, sgid, fsgid: Effective group ID, set group ID, and file system group ID.
tty: 应用程序开启的终端,这种情况下pseudo-terminal used in an SSH session. 
ses: 用户登录的session ID.
comm: 出现在任务列表中,应用程序的名称。
exe: 二进制程序的解析路径。
subj: 进程执行时selinux上下文
key: 如果audit了很多的目录文件,分配一个key string方便后面我们通过ausearch去过滤这类log。
cwd: 进程的执行目录.
另一种audit log格式:
inode: 指出了与文件或目录相对应的inode number,可以通过下面的命令查看inode对应的文件或目录:find/ -inum <inode number> -print.
dev: 指出文件或目录对应的device ID,在例子中,对应/dev/fd/0这个设备.
mode: 对应文件或目录的权限,这里0100600被解析为-rw-------.
ouid: 对应文件的owner’s user ID.
ogid: 对应文件的owner’s group ID.

其他用户访问audit_test时,审计日志如下:

type=SYSCALL msg=audit(1523501777.709:4172989316): arch=c000003e syscall=257 success=yes exit=3 a0=ffffffffffffff9c a1=10ce550 a2=90800 a3=0 items=1 ppid=2354 pid=30729 auid=0 uid=1001 gid=1001 euid=1001 suid=1001 fsuid=1001 egid=1001 sgid=1001 fsgid=1001 tty=pts1 ses=9870 comm="ls" exe="/usr/bin/ls" key="audit_test"type=CWD msg=audit(1523501777.709:4172989316):  cwd="/home/audit_test"type=PATH msg=audit(1523501777.709:4172989316): item=0 name="." inode=99213313 dev=08:11 mode=040755 ouid=0 ogid=0 rdev=00:00 objtype=NORMAL
type=SYSCALL msg=audit(04/12/2018 10:56:17.709:4172989316) : arch=x86_64 syscall=openat success=yes exit=3 a0=0xffffffffffffff9c a1=0x10ce550 a2=O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC a3=0x0 items=1 ppid=2354 pid=30729 
auid=root uid=lbh gid=lbh euid=lbh suid=lbh fsuid=lbh egid=lbh sgid=lbh fsgid=lbh tty=pts1 ses=9870 comm=ls exe=/usr/bin/ls key=audit_test
type=CWD msg=audit(04/12/2018 10:56:17.709:4172989316) : cwd=/home/audit_test
type=PATH msg=audit(04/12/2018 10:56:17.709:4172989316) : item=0 name=. inode=99213313 dev=08:11 mode=dir,755 ouid=root ogid=root rdev=00:00 objtype=NORMAL

日志解释:

type=SYSCALL
每条记录都是以type=”keyword“开头,SYSCALL表示这条记录是向内核的系统调用触发产生的。
msg=audit(1523501777.709:4172989316)
在audit(time_stamp:ID)格式中,记录时间戳,从1970年1月1日00:00:00到现在的时间,ID为记录中唯一的ID标识,同一个事件产生的ID是相同的,如上访问audit_test目录会触发产生三条日志,但是事件ID是相同的。
arch=c000003e
表示系统的CPU架构,这个十六进制表示”x86_64“,使用命令ausearch -i --arch c000003e可以打印出有这部分内容的audit.log中日志的解释。需要注意的是,使用ausearch来查询时,需要保证audit log中有这样的日志记录。
syscall=257
向内核的系统调用的类型,类型值为257,在/usr/include/asm/unistd_64.h中有定义,这里257表示openat,可以使用命令ausyscall来查询不同的数字对应的系统调用名称。或者使用ausyscall --dump命令来显示所有的系统调用。
……
# ausyscall 257
openat
# ausyscall --dump
Using x86_64 syscall table:
0 read
1 write
2 open
……
success=yes
表示系统调用成功与否
exit=3
系统调用结束时的返回码,可以使用如下命令来查看返回值为3的日志解释,不同的系统调用,返回值不同。
……
#ausearch --interpret --exit 3
……
a0=ffffffffffffff9c a1=21e0550 a2=90800 a3=0
为系统调用时的前四个arguments,这些arguments依赖于使用的系统调用,可以使用ausearch来查看解释(部分参数可以打印出数值具体的解释)。
items=1
表示跟在系统调用后,补充记录的个数。
ppid=2354
父进程ID,如bash的ID。
pid=30729
进程Id,即为ls进程的ID。我们通过ps来查询,可以看到bash的进程与ppid是对应的
……
linux-xdYUnA:/home/audit_test # ps -aux | grep bash
lbh       2354  0.0  0.0 115376  2100 pts/1    S+   Apr11   0:00 bash
root     12478  0.0  0.0 115888  2608 pts/0    Ss   Apr11   0:00 -bash
root     13329  0.1  0.0 115888  2612 pts/2    Ss   11:15   0:00 -bash
root     15531  0.0  0.0 112652   972 pts/2    S+   11:15   0:00 grep --color=auto bash
root     30707  0.0  0.0 115888  2632 pts/1    Ss   Apr11   0:00 -bash
​……

6、aureport 工具

AW类型的audit log会存放在/var/log/audit目录下,这些log体量大而且比较难懂,用aureport可以轻易的统计量化日志报告。

aureport 没带任何参数,仅用-if指定一个audit log文件, 统计出它的总体的log报告, 如何不指定文件,显示当前audit的统计:

aureport -if myfile          

Summary Report
======================
Range of time in logs: 03/02/09 14:13:38.225 - 17/02/09 14:52:27.971
Selected time for report: 03/02/09 14:13:38 - 17/02/09 14:52:27.971
Number of changes in configuration: 13
Number of changes to accounts, groups, or roles: 0
Number of logins: 6
Number of failed logins: 13
Number of authentications: 7
Number of failed authentications: 573
Number of users: 1
Number of terminals: 9
Number of host names: 4
Number of executables: 17
Number of files: 279
Number of AVC's: 0
Number of MAC events: 0
Number of failed syscalls: 994
Number of anomaly events: 0
Number of responses to anomaly events: 0
Number of crypto events: 0
Number of keys: 2
Number of process IDs: 1211
Number of events: 5320

对于myfile的log文件,统计出从14:00到15:00的用户登录信息:

aureport -l -ts 14:00 -te 15:00 -if myfile    

Login Report
============================================
# date time auid host term exe success event
============================================
1. 17/02/09 14:21:09 root: 192.168.2.100 sshd /usr/sbin/sshd no 7718
2. 17/02/09 14:21:15 0 jupiter /dev/pts/3 /usr/sbin/sshd yes 7724

aureport --failed/success针对失败的event的统计,如果统计成功的用aureport --success:

aureport --failed    

Failed Summary Report
======================
Range of time in logs: 03/02/09 14:13:38.225 - 17/02/09 14:57:35.183
Selected time for report: 03/02/09 14:13:38 - 17/02/09 14:57:35.183
Number of changes in configuration: 0
Number of changes to accounts, groups, or roles: 0
Number of logins: 0
Number of failed logins: 13
Number of authentications: 0
Number of failed authentications: 574
Number of users: 1
Number of terminals: 5
Number of host names: 4
Number of executables: 11
Number of files: 77
Number of AVC's: 0
Number of MAC events: 0
Number of failed syscalls: 994
Number of anomaly events: 0
Number of responses to anomaly events: 0
Number of crypto events: 0
Number of keys: 2
Number of process IDs: 708
Number of events: 1583

对用户的event进行总体统计:

aureport -u -i --summary 

User Summary Report
===========================
total  auid
===========================
5640  root
13  tux
3  wilber

从14:00到14:21的event事件列表:

aureport -e -ts 14:00 -te 14:21  

Event Report
===================================
# date time event type auid success
===================================
1. 17/02/09 14:20:27 7462 DAEMON_START 0 yes
2. 17/02/09 14:20:27 7715 CONFIG_CHANGE 0 yes
3. 17/02/09 14:20:57 7716 USER_END 0 yes
4. 17/02/09 14:20:57 7717 CRED_DISP 0 yes
5. 17/02/09 14:21:09 7718 USER_LOGIN -1 no
6. 17/02/09 14:21:15 7719 USER_AUTH -1 yes
7. 17/02/09 14:21:15 7720 USER_ACCT -1 yes
8. 17/02/09 14:21:15 7721 CRED_ACQ -1 yes
9. 17/02/09 14:21:15 7722 LOGIN 0 yes
10. 17/02/09 14:21:15 7723 USER_START 0 yes
11. 17/02/09 14:21:15 7724 USER_LOGIN 0 yes
12. 17/02/09 14:21:15 7725 CRED_REFR 0 yes

分类统计事件数量:

aureport -e -i --summary   

Event Summary Report
======================
total  type
======================
2434  SYSCALL
816  USER_START
816  USER_ACCT
814  CRED_ACQ
810  LOGIN
806  CRED_DISP
779  USER_END
99  CONFIG_CHANGE
52  USER_LOGIN

分类统计事件数量,并画出图表:

aureport -e -i --summary  | mkbar events

对于进程所有event的信息:

aureport -p   

Process ID Report
======================================
# date time pid exe syscall auid event
======================================
1. 13/02/09 15:30:01 32742 /usr/sbin/cron 0 0 35
2. 13/02/09 15:30:01 32742 /usr/sbin/cron 0 0 36
3. 13/02/09 15:38:34 32734 /usr/lib/gdm/gdm-session-worker 0 -1 37

system call的报告:

aureport -s   

Syscall Report
=======================================
# date time syscall pid comm auid event
=======================================
1. 16/02/09 17:45:01 2 20343 cron -1 2279
2. 16/02/09 17:45:02 83 20350 mktemp 0 2284
3. 16/02/09 17:45:02 83 20351 mkdir 0 2285

从可执行的角度去查看audit log:

aureport -x   

Executable Report
====================================
# date time exe term host auid event
====================================
1. 13/02/09 15:08:26 /usr/sbin/sshd sshd 192.168.2.100 -1 12
2. 13/02/09 15:08:28 /usr/lib/gdm/gdm-session-worker :0 ? -1 13
3. 13/02/09 15:08:28 /usr/sbin/sshd ssh 192.168.2.100 -1 14

生成一个文件相关event的日志报告:

aureport -f    

File Report
===============================================
# date time file syscall success exe auid event
===============================================
1. 16/02/09 17:45:01 /etc/shadow 2 yes /usr/sbin/cron -1 2279
2. 16/02/09 17:45:02 /tmp/ 83 yes /bin/mktemp 0 2284
3. 16/02/09 17:45:02 /var 83 no /bin/mkdir 0 2285

对于用户在系统运行命令的生成的报告:

aureport -u     

User ID Report
====================================
# date time auid term host exe event
====================================
1. 13/02/09 15:08:26 -1 sshd 192.168.2.100 /usr/sbin/sshd 12
2. 13/02/09 15:08:28 -1 :0 ? /usr/lib/gdm/gdm-session-worker 13
3. 14/02/09 08:25:39 -1 ssh 192.168.2.101 /usr/sbin/sshd 14

用户登录事件生成的报告:

Login Report
============================================
# date time auid host term exe success event
============================================
1. 13/02/09 15:08:31 tux: 192.168.2.100 sshd /usr/sbin/sshd no 19
2. 16/02/09 12:39:05 root: 192.168.2.101 sshd /usr/sbin/sshd no 2108
3. 17/02/09 15:29:07 geeko: ? tty3 /bin/login yes 7809

查看audit log文件包含日志的起止时间:

aureport -t   

Log Time Range Report
=====================
/var/log/audit/audit.log: 03/02/09 14:13:38.225 - 17/02/09 15:30:01.636

7、ausearch 工具

设置了监控后,会在/var/log/audit/audit.log里出现日志。正常情况下audit启动后会出现大量的监控日志,可以使用ausearch 对日志进行过滤只显示感兴趣的项目:

ausearch - option -if myfile 

在日志中过滤出所有和zxy.txt相关的项目:

Ausearch -f zxy.txt

它可以指定特定的日志文件进行分析, 通过加上"-i"可以将数据格式的,转化成可读的文本格式,比如user ID 和ASCII 码形式的cmd:

ausearch -a 5207    #搜寻当期audit服务中event ID等于5207的log
----
time->Tue Feb 17 13:43:58 2009
type=PATH msg=audit(1234874638.599:5207): item=0 name="/var/log/audit/audit.log" inode=1219041 dev=08:06 mode=0100644 ouid=0 ogid=0 rdev=00:00
type=CWD msg=audit(1234874638.599:5207):  cwd="/root"

 ausearch –f /etc/group:

 

输出结果: 

time : 审计时间。
name : 审计对象
cwd : 当前路径
syscall : 相关的系统调用
auid : 审计用户 ID
uid 和 gid : 访问文件的用户 ID 和用户组 ID
comm : 用户访问文件的命令
exe : 上面命令的可执行文件路径

-k  利用auditctl指定的key查询;-x  执行程序:

ausearch -f /etc/group -x rm

-ts 指定时间后的log (start time);-te 指定时间前的log (end time) :

ausearch -ts today -k password-file
ausearch -ts 3/12/07 -k password-file

搜索系统登录失败,使用如下命令:

ausearch --messag e USER _LO G IN --success no --i nterpret

搜索所有的账户,群组,角色变更,使用以下命令:

ausearch -m ADD _USER -m DEL_USER -m ADD _GROUP -m USER _CHAUT HTOK -m D EL_GROUP -m CHGRP_ID -m ROLE_ASSIGN -m ROLE_REMOVE -i

搜寻从制定时间段的失败的系统调用,使用以下命令:

ausearch --start 02/07/2017 --end 02/21/2017 no w -m SYSCALL -sv no –i

按消息类型查找:

ausearch -m

按登陆ID查找:

ausearch -ul

按uid和euid查找:

ausearch -ua

按uid查找:

ausearch -ui

按euid查找:

ausearch -ue

按gid和egid查找:

ausearch -ga

按gid查找:

ausearch -gi

按egid查找:

ausearch -ge

按cmd查找:

ausearch -c

按exe查找:

ausearch -x

按syscall查找:

ausearch -sc

按pid查找:

ausearch -p

按syscall的返回值查找(yes/no):

ausearch -sv

按文件名查找:

ausearch -f

按连接终端查找(term/ssh/tty):

ausearch -tm

按主机名查找:

ausearch -hn

按特定的key值查找:

ausearch -k

按在audit rule设定的字符串查找:

ausearch -w

8、autrace 工具

为了跟踪设置的rule有没有生效,我们经常会追踪指定的进程,autrace生成的log会存放在/var/log/audit/audit.log。 当用autrace去跟踪一个进程时,为了保证避免autrace与之前audit rule生成的日志冲突,使用auditctl -D去停止所有的audit log, 当autrace结束后,使用systemctl restart auditd重启audit服务。

auditctl -D:

o rules

autrace /usr/bin/less

Waiting to execute: /usr/bin/less
Cleaning up...
No rules
Trace complete. You can locate the records with 'ausearch -i -p 7642'

9、audit日志切割

audit的规则配置稍微不当,就会短时间内产生大量日志,所以这个规则配置一定要当心。当audit日志写满后,可以看到如下场景:

-r-------- 1 root root 8388609 Mar 31 11:47 audit.log.997
-r-------- 1 root root 8388780 Mar 31 11:47 audit.log.998
-r-------- 1 root root 8388621 Mar 31 11:47 audit.log.999

然后在messages日志中有一大堆的warning,之后可能还会影响rsyslog的正常工作。

auditd本身有日志切分的功能,auditd使用fprintf函数来记录log,累计每次写log的size,每次写完后都会去检查log的大小,当这个size达到用户配置的max_log_file的大小时,就会shift_logs(这个是对于KEEP_LOGS这种模式而言的),新的达到切分值的日志命名为audit.log.1,之前的日志audit.log.(num+1)。

检查日志时,隔几次还会去查看一下磁盘空间是否充足,使用的函数是fstatfs,来获取audit.log文件所在的mount分区的空间信息,当达到space_left的值或者admin_space_left,或者磁盘不足时就会执行相应的action。

那么既然auditd本身有log切分的功能,那如果和rsyslog一起使用,会出现什么问题呢?

对于使用syslog函数来记录日志的话,日志的切分是很准确的,但是auditd是使用的fprintf来记录的log,这样的话,还能按照rsyslog中的配置来切分吗?答案是可以的,我们可以这样处理,在/etc/rsyslog.conf配置文件中,按照如下方式来配置:

outchannel audit,/var/log/audit/audit.log.tmp,2097152,xx_log_dump.sh param1 param2

audit表示是outchannel的名称(不是日志文件的名称),/var/log/audit/audit.log.tmp是日志输出的目的文件的名称,即rsyslog要检查大小的文件,2097152表示日志文件的大小阈值,xx_log_dump.sh表示日志文件到达阈值后执行的脚本,一般为转储脚本,参数和程序之间通过空格隔开。这样配置后,rsyslog就会从/var/log/audit/audit.log文件中读取日志,然后一条一条的以syslog的方式写入到audit.log.tmp中,因为audit.log.tmp中加入了日期信息,所以audit.log.tmp会比audit.log文件稍大些,当audit.log.tmp达到2097152这个大小时,就把audit.log切分为audit.log.1并且转储处理。

但是要保证/etc/audit/auditd.conf中配置的max_log_file的值要大于/etc/rsyslog.conf配置的切分转储的值。否则audit要切分,rsyslog也过来切分,就乱了,要在audit切分前,rsyslog先完成切分和转储。

10、配置audit的日志文件到远程主机

假设 audit 服务器名称是 cyq1 ,ip 地址 192.168.0.1 ;audit 客户端名称是 cyq2 ,ip 地址 192.168.0.2 。

首先修改服务器端配置文件:

vi /etc/audit/auditd.conf
#修改第 25 行设置监听端口为 60
tcp_listen_port =60
#然后重启服务
service auditd restart

然后在客户端安装相关软件包并且配置文件:

yum -y install audispd-plugins
#修改配置文件
vi /etc/audisp/plugins.d/au-remote.conf
# 修改第 6 行,把审核日志发送到日志服务器
active =yes
vi /etc/audisp/audisp-remote.conf
#修改第 6 行
remote_server =cyq1
#修改第 7 行设置监听端口为 60
port = 60
vi /etc/audit/auditd.conf
#修改第 6 行
log_format =NOLOG
#然后重启服务
service auditd restart

11、开启audit对系统性能的影响

 我们使用测试性能的工具,unixbench,它有一下几项测试项目:

Execl Throughput                每秒钟执行 execl 系统调用的次数
Pipe Throughput                 一秒钟内一个进程向一个管道写 512 字节数据然后再读回的次数
Pipe-based Context Switching    两个进程(每秒钟)通过一个管道交换一个不断增长的整数的次数
Process Creation                每秒钟一个进程可以创建子进程然后收回子进程的次数(子进程一定立即退出)
Shell Scripts (1 concurrent)    一秒钟一个进程可以并发地开始一个 shell 脚本的 1 个拷贝的次数
Shell Scripts (8 concurrent)    一秒钟内一个进程可以并发地开始一个 shell 脚本的 8 个拷贝的次数
System Call Overhead            进入和离开操作系统内核的代价

测试结果类似如下:

Benchmark Run: Wed Apr 18 2018 14:54:55 - 15:23:15
16 CPUs in system; running 1 parallel copy of tests

Dhrystone 2 using register variables       24249307.1 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     2867.3 MWIPS (10.0 s, 7 samples)
Execl Throughput                               2447.9 lps   (29.9 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks        547726.0 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks          149186.7 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks       1297448.0 KBps  (30.0 s, 2 samples)
Pipe Throughput                              946343.5 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                 186950.1 lps   (10.0 s, 7 samples)
Process Creation                               7092.8 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   5631.6 lpm   (60.0 s, 2 samples)
Shell Scripts (8 concurrent)                   2726.4 lpm   (60.0 s, 2 samples)
System Call Overhead                         905666.4 lps   (10.0 s, 7 samples)

测试了/boot/grub2/grub.cfg 中audit=0,和去除audit=0,以及开启auditd服务等的性能数据:

1、内核参数去掉audit=0,auditd服务默认不启动:这种情况性能没有太大变化;

2、服务开启,auditctl -D删除所有可配置规则:这种情况Pipe Throughput下降近20%,System Call Overhead下降35%,其他下降%2-10%左右;

3、删除所有规则,配置 -a never,task取消系统调用的审计:性能没有太大变化;

4、配置-a never,task,配置audit目录访问,提权,账户变更等基本规则:性能变化不大;

5、audit服务开启,配置pci-dss规则,没有取消系统调用审计:Pipe Throughput下降近30%,System Call Overhead下降近50%,Pipe-based Context Switching下降10%,其他下降%2-10%左右;

从性能结果可以看到,开启内核参数,这个对性能影响不大,但是开启auditd服务后对性能影响就比较明显。

这里需要注意的是,如果auditd服务开启后,再服务停止,auditctl –e 0,性能也没有上升,依然比较差,是因为在audit内核处理中,会判断是否曾经开启过即auditctl -s查询的enabled项,只要开启了,即使后面设置auditctl –e 0后,系统调用依然会走audit流程,这就会影响系统性能。具体代码在arch/x86/kernel/entry_64.S,copy_process()中 ,int audit_alloc函数。

另外,如果配置 -a never,task后,所有的审计 type类型为SYSCALL的都不会记录了,一般情况下是要对系统调用进行审计的。

12、 seaudit 图形化工具

seaudit 是 SElinux 故障诊断工具包(setools-gui)的组件。seaudit 允许用户查看和过滤日志文件的内容。它支持 syslog 和 auditd 两种日志格式,并提供查询以检查基于 SELinux 的策略日志消息。打开 seaudit 工具可以看到审计信息。从"工具"菜单中选择"监控日志",或单击"切换"监视器按钮打开和关闭实时日志监视功能。当此功能开启时,seaudit 会定期检查新消息间隔,默认为每秒。还可以配置间隔首选项对话框。
使用 seaudit 工具可以生成报表方法是从 tools 菜单选择"Creat Report",在"Input"选项你可以选择输出所有 audit 的日志文件或者当前的视图文件。在"Output"选项你可以选择输出 HTML 或者 txt 格式两种报告格式。然后点击"create Report"按钮保存报表文件即可。

下载地址:setools3/seaudit at master · TresysTechnology/setools3 · GitHub 。

七、kdump分析系统Crash故障

1、服务器出现卡顿OOM排查过程

如果Linux服务器突然访问卡顿变慢,负载暴增,具体现象就是输入命令时,输的命令不能立即显示,要过一会儿才显示,按tab键补全也不好使。

如何在最短时间内找出Linux性能问题所在?

1分钟内对系统资源使用情况有个大致的了解:

uptime Or w
dmesg | tail
vmstat 1
mpstat -P ALL 1
pidstat 1
iostat -xz 1
iotop
free -m
sar -n DEV 1
sar -n TCP,ETCP 1
top

1. 使用w或uptime命令查看系统负载,发现系统负载很高:(该服务器只有一个CPU,load average值的意义是单位时间段内CPU活动进程数,这个值越大就说明服务器压力越大,一般情况下这个值只要不超过服务器的cpu数量就没有关系)。

$ uptime
23:51:26 up 21:31,  1 user,  load average: 30.02, 26.43, 19.02

这个命令可以快速查看机器的负载情况。在Linux系统中,这些数据表示等待CPU资源的进程和阻塞在不可中断IO进程(进程状态为D)的数量。这些数据可以让我们对系统资源使用有一个宏观的了解。

命令的输出分别表示1分钟、5分钟、15分钟的平均负载情况。通过这三个数据,可以了解服务器负载是在趋于紧张还是趋于缓解。如果1分钟平均负载很高,而15分钟平均负载很低,说明服务器正在命令高负载情况,需要进一步排查CPU资源都消耗在了哪里。反之,如果15分钟平均负载很高,1分钟平均负载较低,则有可能是CPU资源紧张时刻已经过去。

上面例子中的输出,可以看见最近1分钟的平均负载非常高,且远高于最近15分钟负载,因此我们需要继续排查当前系统中有什么进程消耗了大量的资源。

2. 输出系统日志的最后10行:

dmesg | tail$ dmesg | tail
[1880957.563150] perl invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0
[...]
[1880957.563400] Out of memory: Kill process 18694 (perl) score 246 or sacrifice child
[1880957.563408] Killed process 18694 (perl) total-vm:1972392kB, anon-rss:1953348kB, file-rss:0kB
[2320864.954447] TCP: Possible SYN flooding on port 7001. Dropping request.  Check SNMP counters.

可以看见一次内核的oom kill和一次TCP丢包。这些日志可以帮助排查性能问题。千万不要忘了这一步。

3. vmstat(8) 命令:

$ vmstat 1
procs ---------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r  b swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
34  0    0 200889792  73708 591828    0    0     0     5    6   10 96  1  3  0  0
32  0    0 200889920  73708 591860    0    0     0   592 13284 4282 98  1  1  0  0
32  0    0 200890112  73708 591860    0    0     0     0 9501 2154 99  1  0  0  0
32  0    0 200889568  73712 591856    0    0     0    48 11900 2459 99  0  0  0  0
32  0    0 200890208  73712 591860    0    0     0     0 15898 4840 98  1  1  0  0
^C

每行会输出一些系统核心指标,这些指标可以让我们更详细的了解系统状态。后面跟的参数1,表示每秒输出一次统计信息,表头提示了每一列的含义,这几介绍一些和性能调优相关的列:

  • r:等待在CPU资源的进程数。这个数据比平均负载更加能够体现CPU负载情况,数据中不包含等待IO的进程。如果这个数值大于机器CPU核数,那么机器的CPU资源已经饱和。

  • free:系统可用内存数(以千字节为单位),如果剩余内存不足,也会导致系统性能问题。下文介绍到的free命令,可以更详细的了解系统内存的使用情况。

  • si,so:交换区写入和读取的数量。如果这个数据不为0,说明系统已经在使用交换区(swap),机器物理内存已经不足。

  • us, sy, id, wa, st:这些都代表了CPU时间的消耗,它们分别表示用户时间(user)、系统(内核)时间(sys)、空闲时间(idle)、IO等待时间(wait)和被偷走的时间(stolen,一般被其他虚拟机消耗)

上述这些CPU时间,可以让我们很快了解CPU是否出于繁忙状态。一般情况下,如果用户时间和系统时间相加非常大,CPU出于忙于执行指令。如果IO等待时间很长,那么系统的瓶颈可能在磁盘IO。

示例命令的输出可以看见,大量CPU时间消耗在用户态,也就是用户应用程序消耗了CPU时间。这不一定是性能问题,需要结合r队列,一起分析。

4. mpstat:

$ mpstat -P ALL 1
Linux 3.13.0-49-generic (titanclusters-xxxxx)  07/14/2015  _x86_64_ (32 CPU)
07:38:49 PM  CPU   %usr  %nice   %sys %iowait   %irq  %soft  %steal  %guest  %gnice  %idle
07:38:50 PM  all  98.47   0.00   0.75    0.00   0.00   0.00    0.00    0.00    0.00   0.78
07:38:50 PM    0  96.04   0.00   2.97    0.00   0.00   0.00    0.00    0.00    0.00   0.99
07:38:50 PM    1  97.00   0.00   1.00    0.00   0.00   0.00    0.00    0.00    0.00   2.00
07:38:50 PM    2  98.00   0.00   1.00    0.00   0.00   0.00    0.00    0.00    0.00   1.00
07:38:50 PM    3  96.97   0.00   0.00    0.00   0.00   0.00    0.00    0.00    0.00   3.03
[...]

该命令可以显示每个CPU的占用情况,如果有一个CPU占用率特别高,那么有可能是一个单线程应用程序引起的。

5. pidstat:

$ pidstat 1

Linux 3.13.0-49-generic (titanclusters-xxxxx)  07/14/2015    _x86_64_    (32 CPU)
07:41:02 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
07:41:03 PM     0         9    0.00    0.94    0.00    0.94     1  rcuos/0
07:41:03 PM     0      4214    5.66    5.66    0.00   11.32    15  mesos-slave
07:41:03 PM     0      4354    0.94    0.94    0.00    1.89     8  java
07:41:03 PM     0      6521 1596.23    1.89    0.00 1598.11    27  java
07:41:03 PM     0      6564 1571.70    7.55    0.00 1579.25    28  java
07:41:03 PM 60004     60154    0.94    4.72    0.00    5.66     9  pidstat
07:41:03 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
07:41:04 PM     0      4214    6.00    2.00    0.00    8.00    15  mesos-slave
07:41:04 PM     0      6521 1590.00    1.00    0.00 1591.00    27  java07:41:04 PM     0      6564 1573.00   10.00    0.00 1583.00    28  java
07:41:04 PM   108      6718    1.00    0.00    0.00    1.00     0  snmp-pass
07:41:04 PM 60004     60154    1.00    4.00    0.00    5.00     9  pidstat

pidstat命令输出进程的CPU占用率,该命令会持续输出,并且不会覆盖之前的数据,可以方便观察系统动态。如上的输出,可以看见两个JAVA进程占用了将近1600%的CPU时间,既消耗了大约16个CPU核心的运算资源。

6. iostat -x参数告诉iostata打印出更详尽的报告:

$ iostat -xz 1
Linux 3.13.0-49-generic (titanclusters-xxxxx)  07/14/2015  _x86_64_ (32 CPU)
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
73.96    0.00    3.73    0.03    0.06   22.21
Device:   rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
xvda        0.00     0.23    0.21    0.18     4.52     2.08    34.37     0.00    9.98   13.80    5.42   2.44   0.09
xvdb        0.01     0.00    1.02    8.94   127.97   598.53   145.79     0.00    0.43    1.78    0.28   0.25   0.25
xvdc        0.01     0.00    1.02    8.86   127.79   595.94   146.50     0.00    0.45    1.82    0.30   0.27   0.26
dm-0        0.00     0.00    0.69    2.32    10.47    31.69    28.01     0.01    3.23    0.71    3.98   0.13   0.04
dm-1        0.00     0.00    0.00    0.94     0.01     3.78     8.00     0.33  345.84    0.04  346.81   0.01   0.00
dm-2        0.00     0.00    0.09    0.07     1.35     0.36    22.50     0.00    2.55    0.23    5.62   1.78   0.03
[...]

iostat命令主要用于查看机器磁盘IO情况。该命令输出的列,主要含义是:

  • r/s, w/s, rkB/s, wkB/s:分别表示每秒读写次数和每秒读写数据量(千字节)。读写量过大,可能会引起性能问题。

  • await:IO操作的平均等待时间,单位是毫秒。这是应用程序在和磁盘交互时,需要消耗的时间,包括IO等待和实际操作的耗时。如果这个数值过大,可能是硬件设备遇到了瓶颈或者出现故障。

  • avgqu-sz:向设备发出的请求平均数量。如果这个数值大于1,可能是硬件设备已经饱和(部分前端硬件设备支持并行写入)。

  • %util:设备利用率。这个数值表示设备的繁忙程度,经验值是如果超过60,可能会影响IO性能(可以参照IO操作平均等待时间)。如果到达100%,说明硬件设备已经饱和。

iostat打印出的第1个报告,数值是基于最后一次系统启动的时间统计的,即每个子报告都是基于上1次的报告,因此第一个报告应该被忽略。在这个例子中,第2份报告就是从第1份报告开始后的硬盘数据,第3份报告基于第2份,依此类推。

如果显示的是逻辑设备的数据,那么设备利用率不代表后端实际的硬件设备已经饱和。值得注意的是,即使IO性能不理想,也不一定意味这应用程序性能会不好,可以利用诸如预读取、写缓存等策略提升应用性能。

如果xvda盘的%util数值达到了103.63%,这表示引起I/O慢的进程在写入xvda盘。

7. 使用iotop或者ps查找导致高I/O的进程:

查看哪个进程使用硬盘最多的最简单的方法就是使用iotop命令,虽然iotop好用,但默认主流的linux发行版中是没有安装的,可以使用yum provides */iotop 查看iotop命令是由那个rpm包提供的,使用yum安装下即可。如果无法在短时间内完成iotop的安装,还可以使用ps命令来大致确定具体是那个进程导致的I/O过高。

ps命令能打印出内存,cpu的情况但没办法打印出硬盘I/O的情况。虽然ps没办法打印出I/O的情况,但可以显示出进程是否在等待I/O。等待I/O的进程通常处于uninterruptible、sleep或D状态,通过这些信息可以大致查找出处在wait状态的进程。

for x in `seq 1 10`;do ps -eo state,pid,cmd|grep "^D";echo "---";sleep 5;done

根据命令的打印结果可以看出,进程号为123424的进程每次都会出现,说明很有可能是该进程导致的I/O过高。

为了进一步确认是否是该进程导致的I/O过高,可以在/proc中找到该进程,查看它的I/O。

read_bytes和write_bytes就这个进程读写硬盘的字节数。可以看到123424这个进程已经读了2GB,写了235MB的数据。

接下来的操作,可以使用kill命令杀掉导致I/O飙高的进程(临时)。

8. free:

$ free -m
total       used       free     shared    buffers     cached
Mem:        245998      24545     221453         83         59        541
-/+ buffers/cache:      23944     222053
Swap:            0          0          0

free命令可以查看系统内存的使用情况,-m参数表示按照兆字节展示。最后两列分别表示用于IO缓存的内存数,和用于文件系统页缓存的内存数。需要注意的是,第二行-/+ buffers/cache,看上去缓存占用了大量内存空间。

这是Linux系统的内存使用策略,尽可能的利用内存,如果应用程序需要内存,这部分内存会立即被回收并分配给应用程序。因此,这部分内存一般也被当成是可用内存。

如果可用内存非常少,系统可能会动用交换区(如果配置了的话),这样会增加IO开销(可以在iostat命令中提现),降低系统性能。

9. sar:

$ sar -n DEV 1
 
Linux 3.13.0-49-generic (titanclusters-xxxxx)  07/14/2015     _x86_64_    (32 CPU)
12:16:48 AM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
12:16:49 AM      eth0  18763.00   5032.00  20686.42    478.30      0.00      0.00      0.00      0.00
12:16:49 AM        lo     14.00     14.00      1.36      1.36      0.00      0.00      0.00      0.00
12:16:49 AM   docker0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
12:16:49 AM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
12:16:50 AM      eth0  19763.00   5101.00  21999.10    482.56      0.00      0.00      0.00      0.00
12:16:50 AM        lo     20.00     20.00      3.25      3.25      0.00      0.00      0.00      0.00
12:16:50 AM   docker0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00

sar命令在这里可以查看网络设备的吞吐率。在排查性能问题时,可以通过网络设备的吞吐量,判断网络设备是否已经饱和。如示例输出中,eth0网卡设备,吞吐率大概在22 Mbytes/s,既176 Mbits/sec,没有达到1Gbit/sec的硬件上限。

sar -n TCP,ETCP 1
 
$ sar -n TCP,ETCP 1
Linux 3.13.0-49-generic (titanclusters-xxxxx)  07/14/2015    _x86_64_    (32 CPU)
12:17:19 AM  active/s passive/s    iseg/s    oseg/s
12:17:20 AM      1.00      0.00  10233.00  18846.00
12:17:19 AM  atmptf/s  estres/s retrans/s isegerr/s   orsts/s
12:17:20 AM      0.00      0.00      0.00      0.00      0.00
12:17:20 AM  active/s passive/s    iseg/s    oseg/s
12:17:21 AM      1.00      0.00   8359.00   6039.00
12:17:20 AM  atmptf/s  estres/s retrans/s isegerr/s   orsts/s
12:17:21 AM      0.00      0.00      0.00      0.00      0.00

sar命令在这里用于查看TCP连接状态,其中包括:

  • active/s:每秒本地发起的TCP连接数,既通过connect调用创建的TCP连接;

  • passive/s:每秒远程发起的TCP连接数,即通过accept调用创建的TCP连接;

  • retrans/s:每秒TCP重传数量;

TCP连接数可以用来判断性能问题是否由于建立了过多的连接,进一步可以判断是主动发起的连接,还是被动接受的连接。TCP重传可能是因为网络环境恶劣。

10. top:

$ top
 
top - 00:15:40 up 21:56,  1 user,  load average: 31.09, 29.87, 29.92
Tasks: 871 total,   1 running, 868 sleeping,   0 stopped,   2 zombie
%Cpu(s): 96.8 us,  0.4 sy,  0.0 ni,  2.7 id,  0.1 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:  25190241+total, 24921688 used, 22698073+free,    60448 buffers
KiB Swap:        0 total,        0 used,        0 free.   554208 cached Mem
PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
20248 root      20   0  0.227t 0.012t  18748 S  3090  5.2  29812:58 java
4213 root      20   0 2722544  64640  44232 S  23.5  0.0 233:35.37 mesos-slave
66128 titancl+  20   0   24344   2332   1172 R   1.0  0.0   0:00.07 top
5235 root      20   0 38.227g 547004  49996 S   0.7  0.2   2:02.74 java
4299 root      20   0 20.015g 2.682g  16836 S   0.3  1.1  33:14.42 java     1 root      20   0   33620   2920   1496 S   0.0  0.0   0:03.82 init
2 root      20   0       0      0      0 S   0.0  0.0   0:00.02 kthreadd
3 root      20   0       0      0      0 S   0.0  0.0   0:05.35 ksoftirqd/0
5 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H
6 root      20   0       0      0      0 S   0.0  0.0   0:06.94 kworker/u256:0
8 root      20   0       0      0      0 S   0.0  0.0   2:38.05 rcu_sched

top命令包含了前面好几个命令的检查的内容。比如系统负载情况(uptime)、系统内存使用情况(free)、IO等待(wa)、系统CPU使用情况(vmstat)等。因此通过这个命令,可以相对全面的查看系统负载的来源。

例如执行top命令后,发现CPU这一列wa的数值很高,说明CPU资源在等待I/O,由此可以判断是因为I/O的原因导致了系统负载过高,操作卡顿。top命令从系统面大体展示了I/O Wait,但无法确定具体是哪个磁盘正在被影响。

同时,top命令支持排序,可以按照不同的列排序,方便查找出诸如内存占用最多的进程、CPU占用率最高的进程等。但是,top命令相对于前面一些命令,输出是一个瞬间值,如果不持续盯着,可能会错过一些线索。这时可能需要暂停top命令刷新,来记录和比对数据。

2、使用Crash工具分析Linux dump文件

Linux 内核(以下简称内核)是一个不与特定进程相关的功能集合,内核的代码很难轻易的在调试器中执行和跟踪。开发者认为,内核如果发生了错误,就不应该继续运行。因此内核发生错误时,它的行为通常被设定为系统崩溃,机器重启。基于动态存储器的电气特性,机器重启后,上次错误发生时的现场会遭到破坏,这使得查找内核的错误变得异常困难。

内核社区和一些商业公司为此开发了很多种调试技术和工具,希望可以让内核的调试变得简单。其中一种是单步跟踪调试方法,即使用代码调试器,一步步的跟踪执行的代码,通过查看变量和寄存器的值来分析错误发生的原因。这一类的调试器有 gdb,kdb, kgdb。另一种方法是在系统崩溃时,将内存保存起来,供事后进行分析。多数情况下,单步调式跟踪可以满足需求,但是单步跟踪调试也有缺点。如遇到如下几种情况时:

  • 错误发生在客户的机器上。
  • 错误发生在很关键的生产机器上。
  • 错误很难重现。

单步调试跟踪方法将无能为力。对于这几种情况,在内核发生错误并崩溃的时候,将内存转储起来供事后分析就显得尤为重要。本文接下来将介绍内核的内存转储机制以及如何对其进行分析。

内核的内存转储机制

由于 Linux 的开放性的缘故,在 Linux 下有好几种内存转储机制。下面将对它们分别做简要的介绍。

LKCD

LKCD(Linux Kernel Crash Dump) 是 Linux 下第一个内核崩溃内存转储项目,它最初由 SGI 的工程师开发和维护。它提供了一种可靠的方法来发现、保存和检查系统的崩溃。LKCD 作为 Linux 内核的一个补丁,它一直以来都没有被接收进入内核的主线。目前该项目已经完全停止开发。

Diskdump

Diskdump 是另外一个内核崩溃内存转储的内核补丁,它由塔高 (Takao Indoh) 在 2004 年开发出来。与 LKCD 相比,Diskdump 更加简单。当系统崩溃时,Diskdump 对系统有完全的控制。为避免混乱,它首先关闭所有的中断;在 SMP 系统上,它还会把其他的 CPU 停掉。然后它校验它自己的代码,如果代码与初始化时不一样。它会认为它已经被破坏,并拒绝继续运行。然后 Diskdump 选择一个位置来存放内存转储。Diskdump 作为一个内核的补丁,也没有被接收进入内核的主线。在众多的发行版中,它也只得到了 RedHat 的支持。

Netdump

RedHat 在它的 Linux 高级服务器 2.1 的版本中,提供了它自己的第一个内核崩溃内存转储机制:Netdump。 与 LKCD 和 Diskdump 将内存转储保存在本地磁盘不同,当系统崩溃时,Netdump 将内存转储文件通过网络保存到远程机器中。RedHat 认为采用网络方式比采用磁盘保的方式要简单,因为当系统崩溃时,可以在没有中断的情况下使用网卡的论询模式来进行网络数据传送。同时,网络方式对内存转储文件提供了更好的管理支持。与 Diskdump 一样,Netdump 没有被接收进入内核的主线,目前也只有 RedHat 的发行版对 Netdump 提供支持。

Kdump

Kdump 是一种基于 kexec 的内存转储工具,目前它已经被内核主线接收,成为了内核的一部分,它也由此获得了绝大多数 Linux 发行版的支持。与传统的内存转储机制不同不同,基于 Kdump 的系统工作的时候需要两个内核,一个称为系统内核,即系统正常工作时运行的内核;另外一个称为捕获内核,即正常内核崩溃时,用来进行内存转储的内核。 在本文稍后的内容中,将会介绍如何设置 kump。

MKdump

MKdump(mini kernel dump) 是 NTT 数据和 VA Linux 开发另一个内核内存转储工具,它与 Kdump 类似,都是基于 kexec,都需要使用两个内核来工作。其中一个是系统内核;另外一个是 mini 内核,用来进行内存转储。与 Kdump 相比,它有以下特点:

  • 将内存保存到磁盘。
  • 可以将内存转储镜像转换到 lcrash 支持格式。
  • 通过 kexec 启动时,mini 内核覆盖第一个内核。

各种内存转储分析工具

与具有众多的内存转储机制一样,Linux 下也有众多的内存转储分析工具,下面将会逐一做简单介绍。

Lcrash

Lcrash 是随 LKCD 一起发布的一个内内存储分析工具。随着 LKCD 开发的停止,lcrash 的开发也同时停止了。目前它的代码已经被合并进入 Crash 工具中。

Alicia

Alicia (Advanced Linux Crash-dump Interactive Analyzer,高级 Linux 崩溃内存转储交互分析器 ) 是一个建立在 lcrash 和 Crash 工具之上的一个内存转储分析工具。它使用 Perl 语言封装了 Lcrash 和 Crash 的底层命令,向用户提供了一个更加友好的交互方式和界面。Alicia 目前的开发也已经停滞。

Crash

Crash 是由 Dave Anderson 开发和维护的一个内存转储分析工具,目前它的最新版本是 5.0.0。 在没有统一标准的内存转储文件的格式的情况下,Crash 工具支持众多的内存转储文件格式,包括:

  • Live linux 系统
  • kdump 产生的正常的和压缩的内存转储文件
  • 由 makedumpfile 命令生成的压缩的内存转储文件
  • 由 Netdump 生成的内存转储文件
  • 由 Diskdump 生成的内存转储文件
  • 由 Kdump 生成的 Xen 的内存转储文件
  • IBM 的 390/390x 的内存转储文件
  • LKCD 生成的内存转储文件
  • Mcore 生成的内存转储文件

Kdump原理

kdump简介

kdump是2.6.16之后,内核引入的一种新的内核崩溃现场信息收集工具。当一个内核崩溃后(我们称之为panic),内核会使用kexec(类似于进程的exec,把当前内核换掉)进入到一个干净的备份内核(只使用少量内存,由第一个内核预留放在一块内存中),干净的内核启动后,仍旧是用户态服务初始化,这时会使用kdump工具会从内核读出需要的信息,再写到磁盘上的一个vmcore的文件中。之后就可以使用crash工具来分析vmcore文件了(就像gdb分析用户态崩溃现场core文件一样)。

当系统崩溃时,kdump 使用 kexec 启动到第二个内核。第二个内核通常叫做捕获内核,以很小内存启动以捕获转储镜像。第一个内核保留了内存的一部分给第二内核启动用。由于 kdump 利用 kexec 启动捕获内核,绕过了 BIOS,所以第一个内核的内存得以保留。这是内核崩溃转储的本质。kdump 需要两个不同目的的内核,生产内核和捕获内核。生产内核是捕获内核服务的对像。捕获内核会在生产内核崩溃时启动起来,与相应的 ramdisk 一起组建一个微环境,用以对生产内核下的内存进行收集和转存。

kdump配置文件存放在/etc/kdump.conf 配置文件中配置了一些相关信息,包括系统崩溃时,dump的路径,默认情况下是放在/var/crash目录下面。可以通过sysrq强制让系统产生一个vmcore。

echo c > /proc/sysrq-trigger

这造成内核崩溃,如配置有效,系统将重启进入 kdump 内核,当系统进程进入到启动 kdump 服务的点时,vmcore 将会拷贝到你在 kdump 配置文件中设置的位置。RHEL 的缺省目录是 : /var/crash;SLES 的缺省目录是 : /var/log/dump。然后系统重启进入到正常的内核。一旦回复到正常的内核,就可以在上述的目录下发现 vmcore 文件,即内存转储文件。可以使用之前安装的 kernel-debuginfo 中的 crash 工具来进行分析。

kdump原理

kexec是kdump机制的关键,包含两部分:

1)内核空间的系统调用kexec_load:负责在生产内核启动时将捕获内核加载到指定地址。

2)用户空间的工具kexec-tools:将捕获内核的地址传递给生产内核,从而在系统崩溃的时候找到捕获内核的地址并运行。

kdump是一种基于kexec的内核崩溃转储机制。当系统崩溃时,kdump使用kexec启动到第二个内核。第二个内核通常叫做捕获内核,以很小内存启动以捕获转储镜像。

第一个内核保留了内存的一部分给第二个内核启动使用,由于kdump利用kexec启动捕获内核,绕过了BIOS,所以第一个内核的内存得以保留,这是内存崩溃转储的本质。

捕获内核启动后,会像一般内核一样,去运行为它创建的ramdisk上的init程序。而各种转储机制都可以事先在init中实现。为了在生产内核崩溃时能顺利启动捕获内核,捕获内核以及它的ramdisk是事先放到生产内核的内存中的。

生产内核的内存是通过/proc/vmcore这个文件交给捕获内核的。为了生成它,用户工具在生产内核中分析出内存的使用和分布等情况,然后把这些信息综合起来生成一个ELF头文件保存起来。捕获内核被引导时会被同时传递这个ELF文件头的地址,通过分析它,捕获内核就可以生成出/proc/vmcore。有了/proc/vmcore这个文件,捕获内核的ramdisk中的脚本就可以通过通常的文件读写和网络来实现各种策略了。

Crash原理

当系统崩溃时,通过kdump可以获得当时的内存转储文件vmcore,但是该如何分析vmcore呢?

crash是一个用于分析内核转储文件的工具,一般和kdump搭配使用。使用crash时,要求调试内核vmlinux在编译时带有-g选项,即带有调试信息,如果没有指定vmcore,则默认使用实时系统的内存来分析。

值得一提的是,crash也可以用来分析实时的系统内存,是一个很强大的调试工具。

crash使用gdb作为内部引擎,语法类似于gdb,命令的使用说明可以用<cmd> help来查看。

使用crash需要安装crash工具包和内核调试信息包:

crash
kernel-debuginfo-common
kernel-debuginfo

crash语法:

crash [OPTION] NAMELIST MEMORY-IMAGE      (dumpfile form)
crash [OPTION] [NAMELIST]                                   (live system form)

使用crash来调试vmcore,至少需要两个参数:

NAMELIST:未压缩的内核映像文件vmlinux,默认位于/usr/lib/debug/lib/modules/$(uname -r)/vmlinux,由内核调试信息包提供。
MEMORY-IMAGE:内存转储文件vmcore,默认位于/var/crash/%HOST-%DATE/vmcore,由kdump生成。

例如:

# crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux   /var/crash/%HOST-%DATE/vmcore

(1) 错误类型

首先可以在vmcore-dmesg.txt中先查看错误类型,如:

1. divide error: 0000 [#1] SMP,除数为0造成内核崩溃,由1号CPU触发。

2. BUG: unable to handle kernel NULL pointer dereference at 000000000000012c,引用空指针。

这样一来就能知道引发内核崩溃的错误类型。

(2) 错误地点

RIP为造成内核崩溃的指令,Call Trace为函数调用栈,通过RIP和Call Trace可以确定函数的调用路径,以及在哪个函数中的哪条指令引发了错误。

例如RIP为:

[<ffffffff812cdb54>] ? tcp_enter_loss+0x1d3/0x23b

[<ffffffff812cdb54>]是指令在内存中的虚拟地址。

tcp_enter_loss是函数名(symbol)。

0x1d3是这条指令相对于tcp_enter_loss入口的偏移,0x23b是函数编译成机器码后的长度。

这样一来就能确定在哪个函数中引发了错误,以及错误的大概位置。

Call Trace为函数的调用栈,是从下往上看的,可以用来分析函数的调用关系。

(3) crash基本输出

crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux   /var/crash/%HOST-%DATE/vmcore
      KERNEL: /usr/lib/debug/lib/modules/2.6.32-358.el6.x86_64/vmlinux
    DUMPFILE: vmcore  [PARTIAL DUMP]
        CPUS: 12
        DATE: Fri Sep 19 16:47:01 2014
      UPTIME: 7 days, 06:37:46
LOAD AVERAGE: 0.19, 0.05, 0.01
       TASKS: 282
    NODENAME: localhost.localdomain
     RELEASE: 2.6.32-358.el6.x86_64
     VERSION: #1 SMP Tue Oct 29 10:18:21 CST 2013
     MACHINE: x86_64  (1999 Mhz)
      MEMORY: 48 GB
       PANIC: "Oops: 0002 [#1] SMP " (check log for details)
         PID: 0
     COMMAND: "swapper"
        TASK: ffffffff81a8d020  (1 of 12)  [THREAD_INFO: ffffffff81a00000]
         CPU: 0
       STATE: TASK_RUNNING (PANIC)

这些基本输出信息简单明了,可由sys命令触发。

(4) crash常用命令

bt:打印函数调用栈,displays a task's kernel-stack backtrace,可以指定进程号bt <pid>。

log:打印系统消息缓冲区,displays the kernel log_buf contents,如log | tail -n 30。

ps:显示进程的状态,>表示活跃的进程,如ps | grep RU。

sys:显示系统概况。

kmem -i:显示内存使用信息。

dis <addr>:对给定地址进行反汇编。

exception RIP即为造成错误的指令。

关于log命令:

内核首先把消息打印到内核态的ring buffer,用户态的klogd负责读取并转发给syslogd,让它记录到磁盘。

在内核崩溃时,可能无法把消息记录到磁盘,但是ring buffer中一般会有记录。所以log命令有时候能查看

到系统日志中所缺失的信息。

(5) 结构体和变量

查看结构体中所有成员的值,例如:

ps | grep RU
> 0 0 0 ffffffff81a8d020 RU 0.0 0 0 [swapper]
struct task_struct ffffffff81a8d020

struct task_struct {
  state = 0, 
  stack = 0xffffffff81a00000, 
  usage = {
    counter = 2
  }, 
  flags = 2097408, 

显示整个结构体的定义:

struct task_struct

struct task_struct {
    volatile long int state;
    void *stack;
    atomic_t usage;
    unsigned int flags;

显示整个结构体的定义,以及每个成员的偏移:

struct -o task_struct

struct task_struct {
     [0] volatile long int state;
     [8] void *stack;
    [16] atomic_t usage;
    [20] unsigned int flags;
    ...

显示结构体中的成员定义,以及它的偏移:

struct task_struct.pid

struct task_struct {
  [1192] pid_t pid;
}

显示结构体中成员的值:

struct task_struct.pid ffffffff81a8d020

pid = 0

查看全局变量的值:

p sysctl_tcp_rmem

sysctl_tcp_rmem = $4 = 
 {40960, 873800, 41943040}

查看percpu全局变量(加前缀per_cpu_):

p per_cpu__irq_stat

PER-CPU DATA TYPE:
  irq_cpustat_t per_cpu__irq_stat; // 变量类型的声明
PER-CPU ADDRESSES:
  [0]: ffff880028216540 // 0号CPU对应变量的地址
  [1]: ffff880645416540
  ...

查看0号CPU对应变量的值:

struct irq_cpustat_t ffff880028216540

struct irq_cpustat_t {
  __softirq_pending = 0, 
  __nmi_count = 4780195, 
  irq0_irqs = 148, 
  ...

(6) 反汇编和源码行

反汇编:

dis ffffffffa021ba91 // 反汇编一条指令
dis -l probe_2093+497 10 // 反汇编从某个地址开始的10条指令
对于内核中的符号:
sym tcp_v4_do_rcv // 通过symbol,显示虚拟地址和源码位置
sym ffffffff8149f930 // 通过虚拟地址,显示symbol和源码位置

对于模块中的符号,需要先加载相应的模块进来,才能显示符号对应的源码:

mod // 查看模块
mod -s module /path/to/module.ko // 加载模块
sym symbol // 显示符号对应的模块源码,也可以用virtual address

(7) 修改内存

提供动态的修改运行中内核的功能,以供调试,但是RHEL和CentOS上不允许。

wr:modifies the contents of memory.
wr [-u | -k | -p] [-8 | -16 | -32 | -64] [address | symbol] value

使用例子:

p sysctl_tcp_timestamps

sysctl_tcp_timestamps = $3 = 1
wr sysctl_tcp_timestamps 0

wr: cannot write to /dev/crash!

/dev/crash的文件属性是rw,但是crash_fops中并没有提供写函数,所以还是只读的。

这个功能很有用,但被RHEL和CentOS禁止了,所以如需动态修改运行内核还是用systemtap吧。

程序崩溃生成 /var/crash/xxxxxx.crash 文件,如何分析

当主机发生宕机后,crash会在/var/crash这个目录下生成vmcore(内核crash时内存转储文件),也就是dump。

在该目录中,除了生成vmcore,还会生成vmcore-dmesg.txt(内核crash时当时的dmesg信息)

如何分析这个dump来定位宕机的原因呢?

可以执行crash /usr/lib/debug/usr/lib/modules/3.10.0-327.el7.x86_64/vmlinux /var/crash/127.0.0.1-2021-05-07-11\:38\:33/vmcore 进入分析模式(wnlinux这里要指定的)

 注意:kdump服务必须为启动状态:

chkconfig kdump on
systemctl enable kdump.service
service kdump status

想要crash分析core-dump,必须要安装三个包:

kernel-debuginfo-common
kernel-debuginfo
crash-debuginfo

http://debuginfo.centos.org/5/x86_64//Index of /7/x86_64中找与uname -r 找相同相同内核版本的common:

安装kernel-debuginfo-common 和 kernel-debuginfo: 

#wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-common-x86_64-3.10.0-327.el7.x86_64.rpm
# wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-3.10.0-327.el7.x86_64.rpm

安装crash-debuginfo:

yum install -y crash

然后我们执行crash vmlinux 产生的core路径进入分析模式,分析dump原因:

字段说明:

KERNEL∶系统崩溃时运行的kernel文件
DUMPFILE∶内核转储文件
CPUS∶所在机器的CPU数量
DATE∶系统崩溃的时间
TASKS∶系统崩溃时内存中的任务数
NODENAME∶崩溃的系统主机名
RELEASE∶和VERSION∶内核版本号
MACHINE∶CPU架构
MEMORY∶崩溃主机的物理内存
PANIC∶崩溃类型,常见的崩溃类型包括∶
SysRq(System Request)∶通过魔法组合键导致的系统崩溃,通常是测试使用。通过 echo c >/proc/sysrq-trigger,就可以触发系统崩溃。
oops∶可以看成是内核级的Segmentation Fault。应用程序如果进行了非法内存访问或执行了非法指令,会得到 Segfault 信号,一般行为是coredump,应用程序也可以自己截获 Segfault 信号,行处理。如果内核自己犯了这自样的错误,则会弹出oops 信息。
Segmentation fault(core dumped)一般是对内存操作不当造成的,常见的有∶
(1)数组超出范围。
(2)修改了只读内存。
(3)修改了只读内存。

其实 vmcore-dmesg.txt也能看出当时系统的宕机原因,一般在文件最后面:

pid为337的khungtaskd进程触发的,触发原因是进程死锁。

crash模式下,执行执行swap查看宕机时的swap值:

 可以查看当时的负载状态:

 也可以查看宕机时的系统进程状态:

PANIC原因分析

可以通过help查看可用指令:

1)bt命令

acktrace打印内核栈回溯信息,bt pid 打印指定进程栈信息。可以查看内核指令:

bt是分析crash的很好的工具,以"# 数字"开头的行为调用堆栈,即系统崩溃前内核依次调用的一系列函数,通过这个可以迅速推断内核在何处崩溃。

比如这里的#1 crash_kexec at ffffff81035b7b,我们再可以利用dis -I 加内存地址来反汇编出内容:

可以明显看到:

 

 说明系统crash是因为收到了c的sysrq才宕机的。

最重要的信息:[exception RIP: my_openat+36],指出发生异常的指令信息。

RIP: ffffffffc07c5024,可以得知,发生crash的函数是my_openat中,偏移36字节处的指令。

对应x86-64汇编,应用层下来的系统调用对应的6个参数存放的寄存器依次对应:rdi、rsi、rdx、rcx、r8、r9。对于多于6个参数的,仍存储在栈上。

2)log命令

打印vmcore的系统内核日志信息。按时间顺序分析core内的log:

可以分析出当时,内核启动的各项配置,内核最后崩溃时异常日志信息。

3)rd memory命令

读取内存内容。

4)struct命令

显示结构体定义及指定地址的结构体内容。

5)irq命令

查看中断信息。

6)vtop命令

查看地址页表信息等等。

7)dis命令

dis 命令用于对给定地址的内容进行反汇编。

dis -l (function+offset) 10 反汇编出指令所在代码开始,10行代码。

幸运的话,反汇编出来会直接对应源码,我们这里只能看出执行mov 0x70(%rdi),%r13时系统崩溃,如下:

 crash> dis -l c000000000255900 
 /usr/src/debug/kernel-ppc64-3.0.8/linux-3.0/fs/proc/mmu.c: 47 
 0xc000000000255900 <.get_vmalloc_info+112>:     ld      r10,8(r11) 
 5.5 struct – view data struct 
 struct 命令用于查看数据结构的定义原型。命令截图如下:
 crash> struct -o vm_struct 
 struct vm_struct { 
   [0] struct vm_struct *next; 
   [8] void *addr; 
  [16] long unsigned int size; 
  [24] long unsigned int flags; 
  [32] struct page **pages; 
  [40] unsigned int nr_pages; 
  [48] phys_addr_t phys_addr; 
  [56] void *caller; 
 } 
 SIZE: 64

8)mod命令

mod 查看当时内核加载的所有内核模块信息。

 

重装加载进改内核模块: 

crash> mod -s my_test_lkm /mnt/hgfs/test_ko/lkm-test05/my_test_lkm.ko
     MODULE       NAME                            SIZE  OBJECT FILE
ffffffffc07c7000  my_test_lkm                    12740  /mnt/hgfs/test_ko/lkm-test05/my_test_lkm.ko

9)sym命令

sym 转换指定符号为其虚拟地址,显示系统中符号信息。

如上面bt打印的RIP: ffffffffc07c5024,使用sym转换查看系统符号信息。

crash> sym ffffffffc07c5024
ffffffffc07c5024 (t) my_openat+36 [my_test_lkm] /mnt/hgfs/test_ko/lkm-test05/my_lkm.c: 25

这时就可以看出对应到my_test_lkm模块的源码,/mnt/hgfs/test_ko/lkm-test05/my_lkm.c文件里第25行,查看代码可以发现:

这种hook写法在centos8.x上的最新系统调用约定,是内核版本4.17及之后采用的调用约定。而我当前环境是centos7.6,内核版本为3.10。0,其调用约定并不是这样的,所以这样取参数是有问题的。

10)ps命令

打印内核崩溃时,正常的进程信息。

带 > 标识代表是活跃的进程,ps pid打印某指定进程的状态信息:

crash> ps 27005
   PID    PPID  CPU       TASK        ST  %MEM     VSZ    RSS  COMM
> 27005   7783   1  ffff997b388ae180  RU   0.2   91732   4124  pickup

11)FILES命令

files pid 打印指定进程所打开的文件信息。

12)vm命令

vm pid 打印某指定进程当时虚拟内存基本信息。

13)task命令

 task 查看当前进程或指定进程task_struct和thread_info的信息。

14)kmen 命令

kmem查看当时系统内存使用信息。 

kmem [-f|-F|-c|-C|-i|-v|-V|-n|-z|-o|-h] [-p | -m member[,member]]

       [[-s|-S] [slab] [-I slab[,slab]]] [-g [flags]] [[-P] address]]

我们是要kmem -i查看:

crash宕机案例

1)panic为空

bt结果:

 

log结果: 

 载入完内核模块后定位原因在pid0上,根据log及bt定位,问题在pid0和swapper造成的。

问题出现在这里:

 

红帽官网查询故障原因及解决方案:

 2)机器重启分析

可以看到主机宕机的原因是因为软件的bug,系统panic时指向错误的是oracle进程。 

 

可以看到oracle用户的一个进程在内存中被以外中断导致系统panic,通过bt看的到,该进程号为3502。 

通过ps看到内存标记了与两个oracle进程异常。 

3)coredump不完整

[root@bondlp1 2012-02-02-01:37]# crash /usr/lib/debug/lib/modules/2.6.18-305.el5/vmlinux vmcore 

 crash 5.1.8-1.el5 
 Copyright (C) 2002-2011  Red Hat, Inc. 
 Copyright (C) 2004, 2005, 2006  IBM Corporation 
 Copyright (C) 1999-2006  Hewlett-Packard Co 
 Copyright (C) 2005, 2006  Fujitsu Limited 
 Copyright (C) 2006, 2007  VA Linux Systems Japan K.K. 
 Copyright (C) 2005  NEC Corporation 
 Copyright (C) 1999, 2002, 2007  Silicon Graphics, Inc. 
 Copyright (C) 1999, 2000, 2001, 2002  Mission Critical Linux, Inc. 
 This program is free software, covered by the GNU General Public License, 
 and you are welcome to change it and/or distribute copies of it under 
 certain conditions.  Enter "help copying" to see the conditions. 
 This program has absolutely no warranty.  Enter "help warranty" for details. 

 WARNING: vmcore: may be truncated or incomplete 
         PT_LOAD p_offset: 1610681124 
                 p_filesz: 234881024 
           bytes required: 1845562148 
            dumpfile size: 1638400000

vmocre为:

出现的coredump为不完整的,或者在dump收集的过程被打断或者毁坏,导致coredump为incomplete的情况,这种时候利用crash直接分析会报错∶

 只能利用crash的minimal模式来分析:

vmcore 文件不完整,导致这个问题的原因可能有多种,硬盘空间不足,网络 dump 时网络中断等等。对于这种情况,我们需要重新 dump 一个完整的 vmcore 进行分析调试。 

4) panic为空且机器重启

 问题指向系统的python程序。

bt结果指向一个PID为12181的进程。 

利用ps查看进程,确实在宕机前出现异常:

log中信息有具体的说明:

 综上考虑,panic为空且bt调试结果为:

 系统发行版本号为6.1,很像rhel6.0-6.2的一个内核清算bug:

此故障是由于cpu繁忙时调度cpu工作算法出现错误,在除法运算时分母或分子中出现0,导致错误产生,需要升级内核。 

5)Oops: Kernel access of bad area, sig: 11 [#1]

测试工作中发现的 SLES 系统发生系统崩溃定位。

首先启动 crash:

 # crash vmlinux-3.0.8-0.11-ppc64 vmcore 

 crash 5.1.9 
 Copyright (C) 2002-2011  Red Hat, Inc. 
 Copyright (C) 2004, 2005, 2006  IBM Corporation 
 Copyright (C) 1999-2006  Hewlett-Packard Co 
 Copyright (C) 2005, 2006  Fujitsu Limited 
 Copyright (C) 2006, 2007  VA Linux Systems Japan K.K. 
 Copyright (C) 2005  NEC Corporation 
 Copyright (C) 1999, 2002, 2007  Silicon Graphics, Inc. 
 Copyright (C) 1999, 2000, 2001, 2002  Mission Critical Linux, Inc. 
 This program is free software, covered by the GNU General Public License, 
 and you are welcome to change it and/or distribute copies of it under 
 certain conditions.  Enter "help copying" to see the conditions. 
 This program has absolutely no warranty.  Enter "help warranty" for details. 

 GNU gdb (GDB) 7.0 
 Copyright (C) 2009 Free Software Foundation, Inc. 
 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
 This is free software: you are free to change and redistribute it. 
 There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
 and "show warranty" for details. 
 This GDB was configured as "powerpc64-unknown-linux-gnu"... 
      KERNEL: vmlinux-3.0.8-0.11-ppc64          
    DUMPFILE: vmcore 
        CPUS: 40 
        DATE: Wed Nov 16 20:17:11 2011 
      UPTIME: 10:37:23 
 LOAD AVERAGE: 60.00, 60.00, 60.00 
       TASKS: 811 
    NODENAME: eellp1 
     RELEASE: 3.0.8-0.11-ppc64 
     VERSION: #1 SMP Thu Nov 10 16:28:46 UTC 2011 (3cea58b) 
     MACHINE: ppc64  (3550 Mhz) 
      MEMORY: 4 GB 
       PANIC: "Oops: Kernel access of bad area, sig: 11 [#1]" (check log for details) 
         PID: 5563 
     COMMAND: "sh"
        TASK: c0000000faac3700  [THREAD_INFO: c0000000f8ce0000] 
         CPU: 36 
       STATE: TASK_RUNNING (PANIC) 

 crash>

可以看到内核版本是 3.0.8-0.11-ppc64,这是一个 sles11sp2 的开发版本。

接下来,我们用 bt 命令来看一下堆栈:

crash> bt 
 PID: 5563   TASK: c0000000faac3700  CPU: 36  COMMAND: "sh"
 #0 [c0000000f8ce31b0] .crash_kexec at c0000000001039f8 
 #1 [c0000000f8ce33b0] .die at c000000000020158 
 #2 [c0000000f8ce3450] .bad_page_fault at c000000000045004 
 #3 [c0000000f8ce34d0] handle_page_fault at c000000000005ec8 
 Data Access error  [300] exception frame: 
 R0:  0000000000130000    R1:  c0000000f8ce37c0    R2:  c000000000f876d8   
 R3:  c000000001224dc8    R4:  0000000000000001    R5:  0000000000000000   
 R6:  cfffffffffffffff    R7:  0000000002220000    R8:  2ffffffff1f10000   
 R9:  d00000000e0f0000    R10: 0000000000000000    R11: 0000000100000000   
 R12: 0000000082002424    R13: c000000001f06c00    R14: 000000001003e270   
 R15: 0000000000000001    R16: 0000000000000001    R17: 0000000000000000   
 R18: 0000000000000000    R19: c0000000f820b4b8    R20: c0000000f8ce3df8   
 R21: c000000000fe2400    R22: 00000fffb53d0000    R23: fffffffffffff000   
 R24: 0000000000000400    R25: 000000000000ed99    R26: 0000000000002000   
 R27: 0000000000002e58    R28: c000000001224dc8    R29: c000000001224dc0   
 R30: c000000000ef2658    R31: c0000000f8ce39a0   
 NIP: c000000000255900    MSR: 8000000000009032    OR3: c000000000005278 
 CTR: c000000000263a08    LR:  c0000000002558dc    XER: 0000000000000001 
 CCR: 0000000022002444    MQ:  0000000000000001    DAR: 0000000100000008 
 DSISR: 0000000040000000     Syscall Result: 0000000000000000 
 ..... 
 #4 [c0000000f8ce37c0] .get_vmalloc_info at c000000000255900 
 [Link Register ]  [c0000000f8ce37c0] .get_vmalloc_info at c0000000002558dc  (un 
 reliable) 
 #5 [c0000000f8ce3850] .meminfo_proc_show at c000000000263ad8 
 #6 [c0000000f8ce3b40] .seq_read at c00000000020aa44 
 #7 [c0000000f8ce3c30] .proc_reg_read at c000000000258ccc 
 #8 [c0000000f8ce3ce0] .vfs_read at c0000000001dee60 
 #9 [c0000000f8ce3d80] .sys_read at c0000000001df06c 
 #10 [c0000000f8ce3e30] syscall_exit at c0000000000097ec 
 syscall  [c01] exception frame: 
 R0:  0000000000000003    R1:  00000ffff3cceb60    R2:  00000fffb5305c40   
 R3:  0000000000000008    R4:  00000fffb53d0000    R5:  0000000000000400   
 R6:  0000000000000001    R7:  00000fffb5249f88    R8:  800000000200f032   
 R9:  0000000000000000    R10: 0000000000000000    R11: 0000000000000000   
 R12: 0000000000000000    R13: 00000fffb50b8110   
 NIP: 00000fffb523d0c4    MSR: 800000000200f032    OR3: 0000000000000008 
 CTR: 00000fffb51dae70    LR:  00000fffb51daeac    XER: 0000000000000001 
 CCR: 0000000044002422    MQ:  0000000000000001    DAR: 00000fffb51dcd60 
 DSISR: 0000000040000000     Syscall Result: 00000fffb53d0000 
 Crash>

们看到系统崩溃前的最后一个调用是“#4 [c0000000f8ce37c0] .get_vmalloc_info at c000000000255900”,现在用 dis 命令来看一下该地址的反汇编结果:

crash> dis -l c000000000255900 
 /usr/src/debug/kernel-ppc64-3.0.8/linux-3.0/fs/proc/mmu.c: 47 
 0xc000000000255900 <.get_vmalloc_info+112>:     ld      r10,8(r11)

从上面的反汇编结果中,我们看到问题出在 mmu.c 第 47 行代码,翻开 linux 源码的相应位置:

 21 void get_vmalloc_info(struct vmalloc_info *vmi) 
 22 { 
 23         struct vm_struct *vma; 
……
 46 for (vma = vmlist; vma; vma = vma->next) { 
 47                       unsigned long addr = (unsigned long) vma->addr;

用 struct 命令查看数据结构:

crash> struct -o vm_struct 
 struct vm_struct { 
   [0] struct vm_struct *next; 
   [8] void *addr; 
  [16] long unsigned int size; 
  [24] long unsigned int flags; 
  [32] struct page **pages; 
  [40] unsigned int nr_pages; 
  [48] phys_addr_t phys_addr; 
  [56] void *caller; 
 } 
 SIZE: 64 
 crash>

对照源码和反汇编代码,我们发现第 47 行的源码,实际对应的就是反汇编的代码

ld r10,8(r11) # 将寄存器 r11 的第 8 个 byte 后的内容,load 到寄存器 r10。

那么 r11 中应该是 vm_struct 结构,我们再用 struct 来看看:

 crash> struct vm_struct 0000000100000000 
 struct: invalid kernel virtual address: 0000000100000000 
 crash>

说明 r11 的内容已经被破坏,并不是指向一个 vm_struct 结构了。

经过上面的层层分析,我们推测问题的产生过程如下:mmu.c 第 46 行, vma = vma->next 取到了一个错误的地址,导致第 47 行 addr = (unsigned long) vma->addr 产生了内核错误。

6)Oops: 0000 [#1] SMP

crash vmcore /usr/lib/debug/lib/modules/3.10.0-514.el7.x86_64/vmlinux
[16280.734352] BUG: unable to handle kernel NULL pointer dereference at 00000000000000b8
[16280.735299] IP: [] raid10_sync_request+0x579/0x1a90 [raid10]
[16280.735299] PGD 0
[16280.735299] Oops: 0000 [#1] SMP
[16280.735299] Modules linked in: raid10 ext4 mbcache jbd2 raid1 loop nfsv3 rpcsec_gss_krb5 nfsv4 dns_resolver nfs fscache snd_hda_codec_realtek snd_hda_codec_generic snd_hda_intel snd_hda_codec coretemp snd_hda_core iTCO_wdt hp_wmi ppdev sg sparse_keymap gpio_ich iTCO_vendor_support snd_hwdep snd_seq kvm i5000_edac edac_core rfkill snd_seq_device snd_pcm irqbypass pcspkr lpc_ich snd_timer i5k_amb snd parport_pc shpchp parport soundcore dm_multipath nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs libcrc32c sd_mod crc_t10dif crct10dif_generic sr_mod cdrom crct10dif_common ata_generic pata_acpi nouveau video mxm_wmi drm_kms_helper syscopyarea sysfillrect ahci sysimgblt ata_piix fb_sys_fops libahci ttm libata serio_raw igb drm mptsas dca scsi_transport_sas tg3 i2c_algo_bit mptscsih i2c_core ptp
[16280.735299]  mptbase pps_core wmi floppy fjes dm_mirror dm_region_hash dm_log dm_mod
[16280.735299] CPU: 3 PID: 26188 Comm: md0_resync Not tainted 3.10.0-514.el7.x86_64 #1
[16280.735299] Hardware name: Hewlett-Packard HP xw6400 Workstation/0A04h, BIOS 786D4 v02.38 10/25/2010
[16280.735299] task: ffff88003559bec0 ti: ffff8800591e8000 task.ti: ffff8800591e8000
[16280.735299] RIP: 0010:[]  [] raid10_sync_request+0x579/0x1a90 [raid10]
[16280.735299] RSP: 0018:ffff8800591ebbc8  EFLAGS: 00010202
[16280.735299] RAX: 00000000002b3780 RBX: ffff88006f8e0b00 RCX: 0000000000000002
[16280.735299] RDX: ffff880053665860 RSI: ffff88006fb58800 RDI: 00000000002b3380
[16280.735299] RBP: ffff8800591ebca0 R08: 0000000000000000 R09: 0000000000000007
[16280.735299] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
[16280.735299] R13: ffff880053665840 R14: 0000000000000000 R15: ffff880053fbd400
[16280.735299] FS:  0000000000000000(0000) GS:ffff88007fcc0000(0000) knlGS:0000000000000000
[16280.735299] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[16280.735299] CR2: 00000000000000b8 CR3: 0000000078f19000 CR4: 00000000000007e0
[16280.735299] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[16280.735299] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[16280.735299] Stack:
[16280.735299]  ffff8800591ebd14 00000000000003ff 0000000000000000 00000000810d2f4f
[16280.735299]  00000000002b3800 0000000000000000 0000000000000000 ffff880000000007
[16280.735299]  ffff88006fb58800 0000000000000000 00000000002b3780 ffff880000000080
[16280.735299] Call Trace:
[16280.735299]  [] ? sysfs_notify_dirent+0x50/0x60
[16280.735299]  [] md_do_sync+0xabb/0x1000
[16280.735299]  [] ? wake_up_atomic_t+0x30/0x30
[16280.735299]  [] md_thread+0x155/0x1a0
[16280.735299]  [] ? find_pers+0x80/0x80
[16280.735299]  [] kthread+0xcf/0xe0
[16280.735299]  [] ? end_buffer_async_read+0x130/0x130
[16280.735299]  [] ? kthread_create_on_node+0x140/0x140
[16280.735299]  [] ret_from_fork+0x58/0x90
[16280.735299]  [] ? kthread_create_on_node+0x140/0x140
[16280.735299] Code: ff 31 c0 0f 1f 80 00 00 00 00 48 98 48 c1 e0 05 49 8b 44 05 58 45 89 4d 60 49 89 7d 58 45 89 a5 80 00 00 00 49 89 45 78 4c 8b 33 <49> 8b 96 b8 00 00 00 83 e2 02 0f 84 0f 02 00 00 49 8b 55 68 48
[16280.735299] RIP  [] raid10_sync_request+0x579/0x1a90 [raid10]
[16280.735299]  RSP 
[16280.735299] CR2: 00000000000000b8

set 命令:

rash> set 26188
    PID: 26188
COMMAND: "md0_resync"
   TASK: ffff88003559bec0  [THREAD_INFO: ffff8800591e8000]
    CPU: 3
  STATE: TASK_RUNNING (PANIC)

bt命令:

crash> bt
PID: 26188  TASK: ffff88003559bec0  CPU: 3   COMMAND: "md0_resync"
 #0 [ffff8800591eb868] machine_kexec at ffffffff81059cdb
 #1 [ffff8800591eb8c8] __crash_kexec at ffffffff81105182
 #2 [ffff8800591eb998] crash_kexec at ffffffff81105270
 #3 [ffff8800591eb9b0] oops_end at ffffffff8168ed88
 #4 [ffff8800591eb9d8] no_context at ffffffff8167e993
 #5 [ffff8800591eba28] __bad_area_nosemaphore at ffffffff8167ea29
 #6 [ffff8800591eba70] bad_area_nosemaphore at ffffffff8167eb93
 #7 [ffff8800591eba80] __do_page_fault at ffffffff81691b1e
 #8 [ffff8800591ebae0] do_page_fault at ffffffff81691cc5
 #9 [ffff8800591ebb10] page_fault at ffffffff8168df88
    [exception RIP: raid10_sync_request+1401]
    RIP: ffffffffa09b09e9  RSP: ffff8800591ebbc8  RFLAGS: 00010202                    #RIP 是函数中panic时的地址
    RAX: 00000000002b3780  RBX: ffff88006f8e0b00  RCX: 0000000000000002
    RDX: ffff880053665860  RSI: ffff88006fb58800  RDI: 00000000002b3380
    RBP: ffff8800591ebca0   R8: 0000000000000000   R9: 0000000000000007
    R10: 0000000000000000  R11: 0000000000000000  R12: 0000000000000000
    R13: ffff880053665840  R14: 0000000000000000  R15: ffff880053fbd400
    ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
#10 [ffff8800591ebca8] md_do_sync at ffffffff814fe94b
#11 [ffff8800591ebe50] md_thread at ffffffff814fab65
#12 [ffff8800591ebec8] kthread at ffffffff810b052f
#13 [ffff8800591ebf50] ret_from_fork at ffffffff81696418

反汇编:

crash> mod -s raid10
     MODULE       NAME                      SIZE  OBJECT FILE
ffffffffa09b62e0  raid10                   48005  /lib/modules/3.10.0-514.el7.x86_64/kernel/drivers/md/raid10.ko 
crash> dis -l raid10_sync_request | grep -C 6 ffffffffa09b09e9
0xffffffffa09b09db :    mov    %r12d,0x80(%r13)
/usr/src/debug/kernel-3.10.0-514.el7/linux-3.10.0-514.el7.x86_64/drivers/md/raid10.c: 3204
0xffffffffa09b09e2 :    mov    %rax,0x78(%r13)
/usr/src/debug/kernel-3.10.0-514.el7/linux-3.10.0-514.el7.x86_64/drivers/md/raid10.c: 3206
0xffffffffa09b09e6 :    mov    (%rbx),%r14
/usr/src/debug/kernel-3.10.0-514.el7/linux-3.10.0-514.el7.x86_64/arch/x86/include/asm/bitops.h: 319
0xffffffffa09b09e9 :    mov    0xb8(%r14),%rdx
/usr/src/debug/kernel-3.10.0-514.el7/linux-3.10.0-514.el7.x86_64/drivers/md/raid10.c: 3207
0xffffffffa09b09f0 :    and    $0x2,%edx
0xffffffffa09b09f3 :    je     0xffffffffa09b0c08 
/usr/src/debug/kernel-3.10.0-514.el7/linux-3.10.0-514.el7.x86_64/drivers/md/raid10.c: 3220
0xffffffffa09b09f9 :    mov    0x68(%r13),%rdx
/usr/src/debug/kernel-3.10.0-514.el7/linux-3.10.0-514.el7.x86_64/drivers/md/raid10.c: 3186

发现是一个位操作,在3207行:

3206                                 rdev = mirror->rdev;
3207                                 if (!test_bit(In_sync, &rdev->flags)) {
   
   

可以知道是mirror->rdev 为空指针。

7)缺少调试信息包

 [root@bondlp1 2012-02-02-01:37]# crash 

 crash 5.1.8-1.el5 
 Copyright (C) 2002-2011  Red Hat, Inc. 
 Copyright (C) 2004, 2005, 2006  IBM Corporation 
 Copyright (C) 1999-2006  Hewlett-Packard Co 
 Copyright (C) 2005, 2006  Fujitsu Limited 
 Copyright (C) 2006, 2007  VA Linux Systems Japan K.K. 
 Copyright (C) 2005  NEC Corporation 
 Copyright (C) 1999, 2002, 2007  Silicon Graphics, Inc. 
 Copyright (C) 1999, 2000, 2001, 2002  Mission Critical Linux, Inc. 
 This program is free software, covered by the GNU General Public License, 
 and you are welcome to change it and/or distribute copies of it under 
 certain conditions.  Enter "help copying" to see the conditions. 
 This program has absolutely no warranty.  Enter "help warranty" for details. 

 crash: /boot/vmlinuz-2.6.18-307.el5: no debugging data available 
 crash: vmlinuz-2.6.18-307.el5.debug: debuginfo file not found 

 crash: either install the appropriate kernel debuginfo package, or 
       copy vmlinuz-2.6.18-307.el5.debug to this machine

遇到这种问题时,需要安装内核调试信息包,再重新运行 crash 命令。

8)vmlinux 和 vmcore 版本不匹配

[root@bondlp1 2012-02-02-01:37]# crash /usr/lib/debug/lib/modules/2.6.18-305.el5/vmlinux vmcore 

 crash 5.1.8-1.el5 
 Copyright (C) 2002-2011  Red Hat, Inc. 
 Copyright (C) 2004, 2005, 2006  IBM Corporation 
 Copyright (C) 1999-2006  Hewlett-Packard Co 
 Copyright (C) 2005, 2006  Fujitsu Limited 
 Copyright (C) 2006, 2007  VA Linux Systems Japan K.K. 
 Copyright (C) 2005  NEC Corporation 
 Copyright (C) 1999, 2002, 2007  Silicon Graphics, Inc. 
 Copyright (C) 1999, 2000, 2001, 2002  Mission Critical Linux, Inc. 
 This program is free software, covered by the GNU General Public License, 
 and you are welcome to change it and/or distribute copies of it under 
 certain conditions.  Enter "help copying" to see the conditions. 
 This program has absolutely no warranty.  Enter "help warranty" for details. 

 GNU gdb (GDB) 7.0 
 Copyright (C) 2009 Free Software Foundation, Inc. 
 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
 This is free software: you are free to change and redistribute it. 
 There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
 and "show warranty" for details. 
 This GDB was configured as "powerpc64-unknown-linux-gnu"... 

 WARNING: kernel version inconsistency between vmlinux and dumpfile 

 please wait... (gathering module symbol data) 
 WARNING: cannot access vmalloc'd module memory 

 crash: invalid kernel virtual address: 8000000000b663c8  type: "runqueues entry (per_cpu)"

这种情况说明你所使用的 vmlinux 与产生 vmcore 的内核版本不一致,需要使用相同版本的内核来调试 vmcore 文件。

最后:

如果我们确定是某个内核模块导致的问题,可以反汇编出该模块的源代码:

objdump -S -D my_test_lkm.ko > lkm.S

然后vim查看lkm.S文件,查看对应的源码,我们上面调试的bt信息中**[exception RIP: my_openat+36]**,也即是my_openat中偏移量为0x24的地方,如下图:

如果崩溃处对应有c代码的话,这样排查起来就简单多了。

猜你喜欢

转载自blog.csdn.net/qq_35029061/article/details/126210085
今日推荐