Caution:目前RFC3164已经被RFC5424所取代,具体可以参考rfc5424
关于syslog协议的描述,现在主要有两个规范:一个是RFC3164,另外一个是RFC3195。而这两个协议在内容上,并不一样,或者说相差很大。
RFC3164主要讲的是关于syslog协议的格式以及在网络中传输的各种规则,但是其并没有很严格的规定,很多都是建议、约定之类的术语。这是因为RFC3164出来的比较晚,很多实际中已经应用了,所以目前该协议比较混乱,并没有很严格的要求。
RFC3195主要说的是保证syslog消息可靠传输的规范。因为RFC3164依靠UDP协议是无法提供可靠的传输的。为了保证其安全性,此规范定义了使用tcp协议来实现可靠传输,但是目前这个协议应用并不多,所以接下来的讨论也并不会涉及到此方面。
关于syslog的历史:
Syslog 最早约在1980年代由 Sendmail project 的 Eric Allman 所发展,最初单纯只为了 Sendmail。由于 syslog 显示出了他的价值,所以后来慢慢的成为 unix 及 unix-like 系统的标准记录方式,直到演进成为大部分网路设备厂所支援的情况。可是奇妙的是,syslog 和大部分的网路协定标准不同,他一直没有任何标准去规定他的记录格式,造成许多的syslog判读及分析困难。直到2001年由 Internet Engineering Task Force (IETF) 才制定了 RFC3164 - The BSD Syslog Protocol 作为 syslog 第一个标准,这个标准一直到 2009年的 RFC 5424 - The Syslog Protocol 出现后才被废止,而 RFC 5424 也成为今日 syslog 的标准,但是此标准非常的新,只有非常少的系统会去支援RFC 5424,现存设备仍以RFC 3164为基准。由以上提到的 syslog 的历史可知,syslog 并没有一个大家共同的标准规范,也就造成了各式各样 syslog 格式的出现。但是只要目的是514端口的udp封包,我们就要当他是syslog 的封包,且受限于udp,一个syslog的封包最大是1024个bytes。
关于syslog包格式(RFC3164):
Syslog包分为3个部分,PRI, HEADER,以及MSG,总长度不能超过1024个字节。其中PRI代表了facility以及severity,即代表消息来源以及消息的严重程度,因该字段只存在于syslog报文包头部分,在log中并不可见,因此我们在此不加以讨论。
HEADER部分包含一个时间戳以及发送方的主机名或者ip地址,并且HEADER部分必须是一些可打印字符。时间戳部分是格式为”Mmm dd hh:mm:ss”的本地时间,其中Mmm是3个字母的英文缩写,如果日期小于10,必须用空格代替缺少的一个数字。主机名部分一般使用主机名,如果没有的话可以使用IPv4或者IPv6的地址。需要注意的是主机名中不能包含任何空格。时间戳和主机名后面都各自跟一个空格。
MSG部分一般包含生成消息的进程信息(TAG field)以及消息正文(CONTENT field)。TAG部分主要是包含生成消息的进程信息,不能超过32个字符。消息体必须是一些可见字符,这部分就是消息的正文。TAG与CONTENT之间的间隔用非字母表字母隔开,一般用”[“,”:”或者空格隔开。
需要注意的是虽然RFC3164规定了syslog报文的大小不得超过1024字节,但是在实际情况中,会经常发现有大于该大小的报文(尤其是H3C的设备),至于原因在前面已经说过了。另sysklogd和rsyslog两种程序对syslog报文的解析也不是完全相同,例如sysklogd就无法正确解析这样的时间戳:%May 2 19:07:49:225 2013;而rsyslog则会误将2013解析为header的hostname等等。
接下来再说下配置文件/etc/syslog.conf的规则:
facility.level(selector) action 设备.优先级(选择符) 动作 |
其中 facility 的取值如下表所示:
Numerical Code | Facility | Reference |
0 | kernel messages | [RFC3164] |
1 | user-level messages | [RFC3164] |
2 | mail system | [RFC3164] |
3 | system daemons | [RFC3164] |
4 | security/authorization messages [1] | [RFC3164] |
5 | messages generated internally by syslogd | [RFC3164] |
6 | line printer subsystem | [RFC3164] |
7 | network news subsystem | [RFC3164] |
8 | UUCP subsystem | [RFC3164] |
9 | clock daemon [2] | [RFC3164] |
10 | security/authorization messages [1] | [RFC3164] |
11 | FTP daemon | [RFC3164] |
12 | NTP subsystem | [RFC3164] |
13 | log audit [1] | [RFC3164] |
14 | log alert [1] | [RFC3164] |
15 | clock daemon [2] | [RFC3164] |
16 | local use 0 (local0) | [RFC3164] |
17 | local use 1 (local1) | [RFC3164] |
18 | local use 2 (local2) | [RFC3164] |
19 | local use 3 (local3) | [RFC3164] |
20 | local use 4 (local4) | [RFC3164] |
21 | local use 5 (local5) | [RFC3164] |
22 | local use 6 (local6) | [RFC3164] |
23 | local use 7 (local7) | [RFC3164] |
注:facility的取值只能是上表中的24个,如果取local8则会报错“unknown facility name”。其中local[0-7]由程序自定义使用,*通配符代表除了mark以外的所有信息
level 的取值如下表所示:
Numerical Code | Severity | Reference |
0 | Emergency: system is unusable | [RFC3164] |
1 | Alert: action must be taken immediately | [RFC3164] |
2 | Critical: critical conditions | [RFC3164] |
3 | Error: error conditions | [RFC3164] |
4 | Warning: warning conditions | [RFC3164] |
5 | Notice: normal but significant condition | [RFC3164] |
6 | Informational: informational messages | [RFC3164] |
7 | Debug: debug-level messages | [RFC3164] |
注: 1. 优先级是由应用程序在编程的时候决定的,除非修改源码再编译,否则不能改变消息的优先级;
2. 低的优先级包含高优先级。如定义了warning日志,则其涵盖emerg、alert、critical、error等消息(除非使用“=”号定义)
3. *匹配所有级别,除了none(none:没有重要级,通常用于通常用于排错)
Selector:
通过小数点符号“.”把 facility和level 连接在一起则成为selector(选择符)。这两个部分都不区分大小写,并且可以使用上表中定义的数字来代替字符。可以使用分号“;”同时定义多个选择符,其支持以下修饰符:
* :匹配所有日志信息。可以代表任何facility和severity,根据在“.”之前或之后判断
, :可以分割facility,这样可以把几个facility合并。但是severity不能这样合并
; :可以指定多个选择符。处理的顺序是按照从前往后的顺序匹配选择符,并且后面的选择符可以覆盖前面的,因此可以使用这一特性来排除一些特殊的等级
= :加在severity之前,表示仅包含本优先级的日志信息
! :表示忽略掉这种facility或severity的日志信息
Action:
由前面选择符定义的日志信息,可以执行下面的动作:
file :指定日志文件的绝对路径,默认直接写入磁盘;可以在路径前添加“-”,表示不立即写入而是先放到缓存里,等达到一定的数量后再写入磁盘,这样可以提高性能;但若期间机器出现问题,这些日志数据可能会丢失;因此,只建议用于数量大但非必要的日志,如:mail等
@host :指定远程主机名/IP地址即可
user :发送信息直接到指定用户的终端上,但该用户必须已经登录到系统中。以“,”分割多个用户
terminal :发送到指定串行或并行设备标识符上,如:/dev/tty2
named pipe :发送到预先用mkfifo命令创建的FIFO文件,如:|/tmp/message.fifo(路径前添加“|”,注意:不能通过“ | /var/xxx.sh ”的方式将日志导向到其他脚本中处理!)
* :表示把信息发送到所有已登录用户的终端上
举例:
...
# 把除邮件、新闻组、计划任务等外的所有通知性消息都写入messages文件中
*.info;mail.none;news.none;cron.none /var/log/messages
# 把邮件、新闻组中仅通知性消息写入info文件,其他信息不写入;并且先放到缓存中,累积到一定程度后再写入文件(“-”:表示使用异步的方式记录)
mail,news.=info -/var/adm/info
# 把邮件的除通知性消息外都写入mail文件中
mail.*;mail.!=info /var/adm/mail
# 仅把邮件的通知性消息发送到tty12终端设备
mail.=info /dev/tty12
# 如果root和joey用户已经登陆到系统,则把所有紧急信息通知他们
*.alert root,joey
# 把所有信息都导向到probe主机(通过/etc/hosts或dns解析其IP地址)
*.* @probe
...
注:每条消息均会经过所有规则的,并不是唯一匹配的(也就是说,假设mail.=info信息通过上面范例中定义的规则时,/var/adm/info、/dev/tty12,甚至probe主机都会收到相同的信息。这样看上去比较烦琐,但可以带来的好处就是保证了信息的完整性,可供不同地方进行分析)