断更了将近两个月?
五月下旬开始参加实习,工作颇为忙碌,单程一小时的通勤也磨灭了我回到宿舍之后继续学习和输出的热情;然而实习已近两月,所幸稍有所得,不做记录则恐愧对时光矣。
syslog工作流程简述
不管是什么应用,日志机制永是最重要的机制之一,从日志中,维护人员可以排查错误、发现攻击,从而有效地提高应用的可用性。
操作系统也是如此,本文将对Linux日志机制中的一个重要组成部分——syslog/rsyslog——进行一个简要的叙述。
大部分Linux发行版默认的日志守护进程为syslog(或较新版本的rsyslog),位于 /etc/syslog
或 /etc/syslogd
或 /etc/rsyslog.d
,默认配置文件为 /etc/syslog.conf
或 rsyslog.conf
,任何希望生成日志的程序都可以向syslog发送信息。
syslog应该对接收的信息进行某种处理。我们可以从直觉出发,考虑一下syslog收到一条信息后应该做哪些事情:首先,系统中有那么多的信息源,我们会考虑对这些信息源进行分类;之后,每个信息源给出的信息都具有不同的情境,正常运行产生的信息跟报错信息肯定不能一视同仁的,我们会考虑根据信息的严重性对这些信息进行分类;最后,符合筛选条件的信息就触发某种动作,比如把它写进某个日志文件里。
流程图是个好东西。我们假设系统中有若干类信息源,每类信息源产生不同等级的信息,那么syslog应该对这些信息进行分类分级处理,如下图所示:
当然,这一流程图只是为了较为直观地呈现syslog分类分级的机制,以使读者有个初步的印象,接下来,我们将从配置文件出发,介绍syslog(rsyslog)的日志记录细节。
过滤规则
如果你的系统是CentOS,可以打开 /etc/rsyslog.conf
,这是syslog的配置文件,Ubuntu下的配置文件位于 /etc/rsyslog.d/50-default.conf
;在这里,你可以看到不少类似下方的语句:
authpriv.* /var/log/secure
这是syslog日志记录的一条规则,我们将规则拆开来看,实际上只有三个部分:
第一个部分是facility(设备类型),第二个部分是priority(优先级/严重性),第三个部分是action(动作)。
你应该能够想到,这一条规则就描述了上文所说的对消息进行分类分级处理的过程!
仔细看看配置文件吧,每一条规则都是如此的简单而实用:
#### RULES ####
# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.* /dev/console
# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none /var/log/messages
# The authpriv file has restricted access.
authpriv.* /var/log/secure
# Log all the mail messages in one place.
mail.* -/var/log/maillog
# Log cron stuff
cron.* /var/log/cron
# Everybody gets emergency messages
*.emerg :omusrmsg:*
facility
规则的第一部分facility指的是消息源设备的类型。syslog体系中已经将Linux中的大部分进程进行了合理的分类,例如与内核消息相关的 kern
类型、与授权信息相关的 auth/authpriv
类型等等,官方为我们总结出了如下的表格:
priority和selector
将消息源设备进行分类之后,就需要看看这条消息对应的是什么级别,priority(或者叫severity)就用来表示消息的严重性。
facility + priority的形式能够唯一确定一条消息的种类,因此被称为 选择器(selector) 。正如我们所看到的规则那样,使用 facility.priority
的形式来指定一个选择器。其中,在不特别指定的情况下,选中的是 facility
设备类型所产生的 priority
级别及以上的消息,也就是说,一个 kern.info
选择器不仅能选中 kern
类型的 info
级别消息,还能选中 info
以上的所有级别。
例如 kernel
进程产生了一条严重性为 warning
的信息,那么这条信息就将被 kern.info
或 kern.notice
等规则选中。
除了基本的选择器用法,rsyslog在syslog的基础上扩展了一些选择器的语法。例如使用符号 =
可以 严格选中 某一优先级的消息,使用符号 !
可以选中 除了 某一优先级的所有消息,最常用的 *
号表示这一字段的 所有取值 ,字段 none
常常配合 *
号使用,表示不记录某些facility的消息。还有一些使用表达式构造的选择器,在此不加叙述(因为在Linux默认配置中本身就用得不多),读者可以阅读文末给出的参考资料[1]来进行扩展学习。
action
最后,是规则的最后一部分——动作(action)。这一部分的内容可以有较多的玩法,一般来说,我们使用两种操作:
- action字段写上一个文件名。如默认配置文件中的多数规则,这表示将选择器选中的消息记录到目标文件上。
- action字段形如
@<IP>:<端口>
,这表示将选择器选中的消息 转发 到目标服务器的目标端口上。一个@
号表示使用UDP协议发送(默认),两个@
号表示使用TCP协议发送。例如我们配置一条规则*.* @@192.168.0.1:514
表示将所有类型的、所有级别的消息都转发到服务器192.168.0.1
的514
端口。
至此,我们就了解了规则的含义,顺带地,你可以初步读懂Linux日志配置文件里的部分内容了。从这些规则出发,你能够对Linux系统下的一些日志文件有更深入的了解。我们再来看一下这些规则:
*.info;mail.none;authpriv.none;cron.none /var/log/messages
# 这条规则表示将除了 mail、authpriv、cron 的类型之外的所有设备类型的消息记录到 /var/log/messages 文件中
# 因此,你可以在 /var/log/message 文件中找到大部分日志消息
authpriv.* /var/log/secure
# 这条规则表示将 authpriv 类型的所有级别消息记录到 /var/log/secure 文件中
# 因此,你应该在 /var/log/secure 文件中查看与授权信息相关的日志(如sshd登录记录,sudo认证记录等)
mail.* -/var/log/maillog
cron.* /var/log/cron
可以看到,上面三条规则的facility是互补的,把这几个文件综合起来看,相当于使用了 *.*
的选择器(info
级别已经和 *
差不多了),也就是说,你基本可以在上面的四个文件中查看到Linux系统产生的所有消息。
模板Template
阅读至此,我们能够把任何需要的消息用我们希望的办法进行记录或转发,但仅仅采用默认的格式可能还远远不够。
正常情况下,一条Linux日志长成这样:
Jul 2 23:30:03 localhost su: pam_unix(su:session): session opened for user root by xr_g(uid=0)
这一条日志分为几个部分: [时间戳] [主机名] [进程名和进程ID] [消息体]
。
这可不是我瞎说的,因为rsyslog在记录日志的时候使用了默认的 模板 。
如果你使用过Django或者什么其他的后端编程框架,很可能已经了解了模板的概念;如果你没接触过模板,不妨简单地将其看作一种 格式 ,就像你写论文时候的格式要求那样,所有的消息都要按照这种格式进行记录。而与你写论文时相同,论文模板里总是会指定一些较为宽泛的 属性 ,比如开头要写上摘要和关键字,所有人的论文都是相同的结构,但摘要和关键字的具体内容就因人而异了。
日志的模板也正是如此,一条模板指定了日志的大致结构,就像上面提到的那样;而这一结构由一个一个的属性组成,日志守护进程需要根据这些属性往模板里填充数据,从而产生一条具体的日志。
模板的定义
模板的定义办法有新旧两种,我个人比较习惯旧式的模板定义办法:
# $template [模板名] [模板格式]
$template MyTmp,"%timestamp% %hostname% %syslogfacility-text% %syslogseverity-text% %msg%\n"
而新版的模板定义办法有若干个,例如:
template(name="tpl3" type="string"
string="%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n"
)
模板的使用
定义好了自己的模板之后,可以直接将模板应用在action字段上,具体办法就是在action原本的内容后加一个分号 ;
,然后写上自己的模板名。
例如修改 /var/log/message
内容为我们自定义的格式:
# Step1 设置模板,使用模板
[root@localhost log]# cat /etc/rsyslog.conf
···
$template MyTmp,"%timestamp% %hostname% %syslogfacility-text% %syslogseverity-text% %msg%\n"
···
*.info;mail.none;authpriv.none;cron.none /var/log/messages;MyTmp # 注意这里!!!!
# Step2 重启rsyslog服务
[root@localhost log]# systemctl restart rsyslog
# Step3 观察日志内容的变化
[root@localhost log]# tail /var/log/messages
···
Jul 2 23:57:55 localhost daemon info Stopped System Logging Service.
Jul 2 23:57:55 localhost daemon info Starting System Logging Service...
···
rsyslog给出了一些模板中可用的属性,此处列出几个常用的属性,详细信息可以查看参考资料[2]。
属性 | 含义 |
---|---|
%timestamp% | 时间戳,格式为默认为 MMM dd HH:mm:ss |
%syslogtag% | 消息的标签,一般为 进程名[进程ID] 的形式,如 sshd[1234] |
%msg% | 原程序发送的消息内容,这一字段由原始进程自行定义,一般各不相同 |
%fromhost-ip% | 一般用于远程接收日志的服务器上,获取日志发送方的IP |
%syslogfacility-text% | 以文字形式打印出facility |
%syslogseverity-text% | 以文字形式打印出severity |
%hostname% | 主机名 |
我们需要为自定义的模板命名,当然,不能与系统默认保留的一些模板重名,比如下面几个系统自带的模板:
template(name="RSYSLOG_TraditionalForwardFormat" type="string"
string="<%PRI%>%TIMESTAMP% %HOSTNAME% %syslogtag:1:32%%msg:::sp-if-no-1st-sp%%msg%")
template(name="RSYSLOG_ForwardFormat" type="string"
string="<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag:1:32%%msg:::sp-if-no-1st-sp%%msg%")
更多的内容可以阅读参考资料[3]。
注意上面给出的第一个系统模板 RSYSLOG_TraditionalForwardFormat
,这正是Linux系统中默认的日志格式,现在你明白前面我们对系统日志的格式解释是从何而来的了。
小结
在实际工作中,syslog还有一些其他的玩法(如配置远程转发,日志模板的进阶使用等),在此就不予介绍了,之后有时间再开一篇。
本文介绍了Linux日志机制的一个重要依赖——syslog/rsyslog,通过对日志配置文件、规则含义等的简要叙述,相信读者能够对Linux日志的机制有一个初步的理解,通过这些日志,你将能够揭开系统运行状态的面纱,更高效地排除错误,更快乐地生活。
参考资料
[1] Filter Conditions — rsyslog 8.18.0.master documentation