主要内容
Linux日志系统
Linux操作系统中比较重要的日志管理程序有两个,分别是Rsyslogd和Journald,在本文中主要讲述的是Rsyslogd日志系统。日志管理是系统管理中重要的一环,因为日志中包含大量的系统运行信息:例如系统内核、服务、应用程序等记录,都被写入到日志当中,日志为我们管理系统,解决问题提供重要的信息。
Rsyslogd和Journald两个日志系统并不是完全独立的,它们可以互相协作,原因在于,journald每次产生的日志并不保存在硬盘中,每次系统重启的时候,journald就会丢弃之前的日志,新的日志是系统重启后重新生成的,这样,journald就要通过把日志传递到rsyslogd,rsyslogd负责日志的持久化。
另一个问题是,Journald只能管理本地的日志,也就是说,如果有多台服务器需要管理,那么建立一台中心化的日志管理服务器,是一个很好的解决方案,而Journald做不到;Rsyslogd这个时候就可以派上用场,Rsyslogd的一个重要功能是,可以把日志转发到指定的服务器中,达到中心化管理日志的目的。Journald则可以先把日志传递给rsyslogd,通过rsyslogd把日志发送到日志服务器。
它们之间还有一个不同的地方,就是rsyslogd产生的日志是基于文本的,而journald的日志是二进制格式的,也就是说,journald的日志不能使用普通的文本处理工具查看,只能通过journalctl命令查看。
Rsyslogd基本配置
rsyslogd的配置文件保存在/etc/rsyslog.conf
。默认,rsyslogd的日志写入到/var/log目录下(可以通过配置文件更改),在这个目录,可以找到很多相关的日志记录,例如,系统启动日志,定期任务日志等等,还有一些日志以时间结尾,这些日志已经被rotate过,logrotate的其中一个作用是防止单个日志文件过大。
在rsyslog.conf配置文件中,可以看到类似下面的配置:
1 |
cron.* /var/log/cron |
意思是:所有关于cron的日志(不管警告还是错误等),都保存到/var/log/cron文件中。
配置文件基本语法
配置文件主要有三个部分,包括全局指令(global directives)、模块(modules)和规则(rules)。其中规则由过滤器(filter)和动作(action)组成。像上面的cron.*
就是一个过滤器,/var/log/cron
就是动作。过滤器用于指定日志的类型,而动作则决定如何处理这些类型的日志,例如保存到硬盘的某个地方。
过滤器(filters)
过滤器有时候被称为选择器(selector),rsyslog可以配置三种形式的过滤器:
- Facility/Priority-based filter
- Property-based filter
- Expression-based filter
Facility/Priority-based 过滤器
例如前面的cron.*
就是这种类型的过滤器。
Facility指定了产生日志的子系统,这些子系统包括:kern(内核)、user、mail、daemon、auth(授权)、syslog、lpr、news、uucp、cron、authpriv、ftp、local0~local7,常用的就应该是kern、mail、auth、cron、ftp这些。
Priority则指定日志的类型,包括:emerg、alert、crit、err、warning、notice、info、debug。
通配符*
的意思是任何类型。例如*.*
,即所有的Facility和Priority。
举个例子:cron.alert
的意思是:cron定期任务所产生的警告日志,任何等于alert或者高于alert等级的日志(crit、err、warning等)都会被指定的动作处理。
如果希望只处理定义等级的日志,而不处理高于这个等级的日志,可以使用等号(=),例如:
1 |
cron.=alert /var/log/cron |
有一些子系统产生的日志可能没有Priority,那么可以使用关键字none
,例如
1 |
news.none /var/log/messages |
除了星号和等号,过滤器中还可以使用逗号(,)和感叹号(!),逗号用于分隔多个Priority,而感叹号的作用是取反,例如:
1 |
cron.!info,!debug /var/log/cron |
意思是除了info和debug等级的日志外,都写入到/var/log/cron中。
Property-based 过滤器
基于属性的过滤器,使我们可以根据不同的属性值进行日志处理。配置文件中常用的属性有:msg、hostname、fromhost、programname、timegenerated等,想知道更多的属性,可以查看rsyslog.conf的manpage,也可以通过下面的链接查看更多:
基本语法:
1 |
:PROPERTY,[!]COMPARE_OPERATION,"VALUE" |
属性过滤器可用的操作符如下:
- contains 检查属性值是否包含指定的字符串(大小写敏感)
- contains_i 和上面一样,但忽略大小写
- isequal 属性值是否等于目标字符串
- startswith 属性值是否以某字符串开头(大小写敏感)
- startswith_i 如上,但忽略大小写
- regex 正则表达式匹配
- ereregex 使用扩展正则表达式匹配
- isempty 属性值是否为空
属性过滤器例子:
1 2 3 4 5 |
#日志信息中是否包含“error”字符串 :msg, contains, "error" #主机名称是否相等 :hostname, isequal, "host1" |
Expression-based 过滤器
基于表达式的过滤器,这个表达式是一个条件表达式,即当满足特定条件的时候,执行指定的操作。
一般来说,表达式过滤器需要结合Rsyslogd中的属性来使用。
基本语法:
1 |
if expression_true then action else action |
else后续部分并不是必须的,它可以指定不满足条件的时候所执行的操作。
表达式中可用的操作符有:
- and、or、not
- ==、!=、<>、<、>、<=、>= (!=和<>的作用基本相等)
- contains
- startswith、startswith_i(case-insensitive)
更多的可查看官方文档,一般来说,上面这些操作符基本满足日常维护的作用。
一些例子:
1 2 3 4 5 6 7 |
#日志中包含error,保存到/var/log/errlog中 if $msg contains 'error' then /var/log/errlog #如果要同时满足多个条件,使用and连接这些条件,整个表达式需要写在一行中 if $syslogfacility-text == 'local0' and $msg startswith 'DEVNAME' and ($msg contains 'error1' or $msg contains 'error0') then /var/log/somelog if $syslogfacility-text == 'local0' and $msg startswith 'DEVNAME' and not ($msg contains 'error1' or $msg contains 'error0') then /var/log/somelog |
目前正则表达式不能使用在表达式过滤器中。
动作(action)
前面已经说过,一条完整的规则(rule)应该由过滤器和动作构成,过滤器用于选择日志类型,而动作决定日志应该如何处理。过滤器上面已经讲完,接下来谈一谈动作部分。
Rsyslog系统常用的动作有下面几个:
- 写入普通文件
- 转发到远程日志服务器
- 发送给某个系统用户
- 插入到数据库
- 丢弃日志(discard)
不常用的动作如下:
- 发送到终端
- 输出到管道
- 执行指定程序
写入普通文件
这个应该是最常用的动作了,例如rsyslog.conf中的cron配置:
1 2 |
*.info;mail.none;authpriv.none;cron.none /var/log/messages mail.* -/var/log/maillog |
第二行的动作前面有一个(-)横杠,表示日志不会马上写入到文件中,而是缓存到内存中,这样可以提高日志系统的性能,但有可能会造成日志的丢失。默认情况下,产生日志是同步写入到文件系统中去的,如果不希望同步写入,只需要在文件路径前面添加这个-
。
发送给系统用户
当用户登录的时候,用户就可以收到系统发送的日志,例如rsyslog.conf中的紧急类型日志:
1 |
*.emerg :omusrmsg:* |
同样,动作后面的星号表示所有的用户。如果要指定接收日志的用户,可以使用逗号分隔每一个用户,例如:
1 |
*.emerg :omusrmsg:root,user1,user2 |
发送到远程日志服务器
日志发送到远程服务器之前,服务器需要先把相关模块打开,例如rsyslog.conf中的:
1 2 3 4 5 6 7 |
# Provides UDP syslog reception #$ModLoad imudp #$UDPServerRun 514 # Provides TCP syslog reception #$ModLoad imtcp #$InputTCPServerRun 514 |
日志服务器可以使用的协议有两个,一个是udp,另一个是tcp,选择要使用的协议,并打开注释即可。
另一个需要注意的地方是,如果打开注释后发现日志并不能正常转发到服务器,请检查一下防火墙的设置,把相关的端口列入白名单,这里是514端口。
本地服务器也需要做一些设置,下面是rsyslog.conf中的配置:
1 2 3 |
#*.* @@remote-host:514 #把日志转发到ip地址为192.168.0.10的服务器 *.* @@192.168.0.10:514 |
两个@表示使用的是tcp协议,如果使用udp协议,使用一个@即可。
丢弃日志
有时候产生的日志太多,并不是所有的日志都有价值的,这些对我们没有太大意义的日志可以不作处理(丢弃),使用波浪符号(~)处理需要丢弃的日志。
例如:
1 |
mail.notice ~ |
直接把等级为notice的mail日志丢弃。
设置多个动作
可以为过滤器设置多个动作,每个动作单独一行,并在后面的动作的行首添加&符号。例如:
1 2 3 |
cron.* /var/log/cron & :omusrmsg:* & @@192.168.0.10:514 |
使用模板(template)
使用模板可以在运行时决定日志文件的保存路径和文件名称,通常配合Rsyslog的属性来使用。模板在使用前必须先通过$template指令定义。
定义模板的基本语法:
1 |
$template template_name,file_path |
例如,日志服务器希望根据客户端的hostname来分别保存它们的日志,可以这样设置:
1 2 |
$template SimpleTemplate,"/var/log/%hostname%/messages-%$now%.log" if $fromhost-ip != '127.0.0.1' then ?SimpleTemplate |
第一行定义了一个模板,这个模板根据日志中的主机名称和当前的时间共同决定日志的保存路径。然后第二行使用了一个表达式过滤器,意思是当产生日志的主机ip不是本机的话,就使用定义好的模板。
可以在任意过滤器中使用模板,例如Facility/Priority-based 过滤器
1 |
cron.* ?SimpleTemplate |
使用Ruleset
顾名思义,Ruleset就是多个规则的集合,rsyslogd从ruleset的第一条规则开始处理,直到这个ruleset的最后一条规则。rsyslogd有一个默认的Ruleset,名为RSYSLOG_DefaultRuleset。可以这样理解,rsyslog.conf中的所有规则都是RSYSLOG_DefaultRuleset中的成员。
自定义Ruleset
使用$RuleSet指定,可以创建自定义的Ruleset,一旦创建了新的Ruleset,后续的所有规则都被归类到这个Ruleset中,除非有新的Ruleset被创建,或者显式切换回默认的Ruleset(RSYSLOG_DefaultRuleset)。
下面是一个简单的例子:
1 2 3 4 5 6 7 |
$template Centos7Server,"/var/log/%hostname%/messages-%$now%.log" #创建一个名为remote的Ruleset $RuleSet remote *.* ?Centos7Server #switch back to the default ruleset $RuleSet RSYSLOG_DefaultRuleset |
这个例子创建了一个名叫remote的Ruleset,虽然集合里面只有一条规则。规则中使用了一个预先定义的模板。最后切换回默认的Ruleset,如果不这样做,后面所有的规则都会被归类到新定义的Ruleset中。
使用自定义Ruleset
Ruleset的使用分两种情况,第一种是本地日志记录,另一种是远程日志记录。定义好Ruleset后,并不会马上生效,它需要被绑定,无论是什么情况。
先说一下第二种情况:只给远程日志绑定Ruleset。这种情况比较简单,它的绑定指令是$InputTCPServerBindRuleset
,例如:
1 2 3 4 |
# Provides TCP syslog reception $ModLoad imtcp $InputTCPServerBindRuleset remote #绑定自定以的Ruleset $InputTCPServerRun 514 |
这个指令只影响使用TCP协议作为输入的日志,本地服务器的日志不会受到影响,因此本地日志依然使用默认的RSYSLOG_DefaultRuleset。
接着反过来说第一种情况:本地绑定Ruleset。准确来说,本地使用Ruleset不能称为绑定,它只能通过设置为默认来被使用,使用$DefaultRuleset
指令。还是使用前面定义的名为remote的Ruleset作为例子:
1 |
$DefaultRuleset remote |
在没有使用$InputTCPServerBindRuleset
的前提下,当使用这个指令把remote变为默认,它不但影响本地的日志,也影响到使用TCP协议的日志。当然,如果希望TCP协议的日志使用不同的Ruleset,可以使用$InputTCPServerBindRuleset
指令覆盖这个行为,因为后定义的规则会覆盖前面的规则。
也可以同时使用多个Ruleset,例如为不同的端口绑定不同的Ruleset:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# process remote messages #define rulesets first $RuleSet remote10514 *.* /var/log/remote10514 $RuleSet remote10515 *.* /var/log/remote10515 $RuleSet remote10516 mail.* /var/log/mail10516 & ~ # note that the discard-action will prevent this messag from # being written to the remote10516 file - as usual... *.* /var/log/remote10516 # and now define listners bound to the relevant ruleset $InputTCPServerBindRuleset remote10514 $InputTCPServerRun 10514 $InputTCPServerBindRuleset remote10515 $InputTCPServerRun 10515 $InputTCPServerBindRuleset remote10516 $InputTCPServerRun 10516 Note that the "mail.*" ru |
这是关于Rsyslog的第一篇文章,由于Rsyslog涉及的东西太多,如果在一篇文章中把主要的东西都列出来,会造成文章太长,阅读体验不佳,因此把它们拆分为几篇文章,剩下的内容会在后面的文章中继续分析。
转载请注明:Pure nonsense » Linux日志管理Rsyslog之基础