1110.4
syslog:系统事件的日志程序
syslog最初是由Eric Allman编写的,它是一个综合的日志记录系统。syslog有两个主要的功能有两项重要的功能:使程序员从繁重、机械的编写日志文件代码的工作中解脱来,使管理员更好地控制日志的记录过程。在出现syslog之前,每个程序都有自己的日志记录策略。系统管理员对保存什么信息或是信息保存在哪儿没有控制权。
syslog相当灵活,它能让消息按照其来源和重要性(“严重性级别”)来排序,也能把消息送到各种目的地:日志文件、用户的终端、或者甚至是别的计算机。syslog集中管理网络日志的功能是它最有价值的特性之一。
10.4.1 syslog的其他替代方案
|
|
虽然syslog已经长期主导UNIX和Linux的日志系统,但是人们已经开发出了替代它的几种方案,试图解决它的一些缺点。syslog-ng(下一代syslog)就是这其中之一,它现在成为SUSE系统上默认采用的日志工具。从配置的观点来看,它和标准的syslog有很大的不同,我们在本书里就不详细介绍它了。如果想在非SUSE的系统上试试,可以从www.balabit.com获得它。 |
One of these, syslog-ng
(syslog, next generation), is now used on SUSE systems
by default. From a configuration standpoint it is quite different from the standard
syslog, and we will not describe it in detail in this book. It’s available from
www.balabit.com if you would like to try it on a non-SUSE
system.
syslog-ng增加了更多的配置功能、能基于消息内容进行过滤,确保了消息一致性,以及在消息通过网络转发时针对防火墙的限制提供了更好的支持。
(圣地亚哥超级计算中心的)SDSC Secure Syslog也叫做高性能syslog。它通过实现RFC 3195的规范,提供了一种“达到举证水平”的审计系统。它的设计考虑到了大流量站点的需要,包含了大量性能优化措施。您可以从sourceforge.net/projects/sdscsyslog获得它的源代码。
10.4.2 syslog的体系结构
syslog包括3个部分:
syslogd,日志守护进程(及其配置文件/etc/syslog.conf);
openlog等,将消息提交给syslogd的库例程;
logger,一条从shell提交日志记录项的用户级命令。
在下面的讨论中,我们先介绍syslogd的配置,然后简要说明如何从Perl脚本中使用syslog。
syslogd在系统引导时启动并连续运行,它不能用inetd来管理它。懂得syslog的程序把日志项(使用syslog库例程)写到专门的文件/dev/log中,这是一个UNIX的域套接口。syslogd从这个文件中读取消息,参考其配置文件,并将各条信息分发到合适的目的地。
内核执行日志功能的守护进程klogd负责从内核的内部日志缓冲区检索消息,并把它们发送给syslogd。
挂起信号(HUP,信号1)可以让syslogd关闭它的日志文件,重新读取它的配置文件,并再度开始日志记录。如果用户修改了/etc/syslog.conf,那么必须向syslogd发送一个挂起信号来使修改生效。TERM信号将使syslogd退出。
syslogd将它的进程ID写入到文件/var/run/syslogd.pid里。这一约定使得从一个脚本向syslogd发送信号变得比较容易。例如,下面的命令将发送一个挂起信号:
# kill-HUP ‘/bin/cat /var/run/syslogd.pid‘
试图压缩或者修改一个已经由syslogd打开以供写入信息的日志文件是不太安全的,可能会导致不可知的结果。恰当的步骤是把老的日志移到别处,重新创建日志,所有权关系和权限都保持不变权属关系和权限都保持不变,然后向syslogd发送一个HUP信号。这个过程用logrotate很容易就能实现,参考1110.3节的例子。
1110.4.1
3 配置syslogd
配置文件/etc/syslog.conf控制着syslogd的行为。这是一个格式相当简单的文本文件。空白行和以字符“#”开始的行都被忽略。基本格式为:
selector <Tab> action
例如,下面的一行:
mail.info /var/log/maillog
将把来自电子邮件系统的信息保存在文件/var/log/maillog中。
selector用语法facility.level指明正在发送日志消息的程序(即“设备[facility]”)和消息的严重性级别。设备的名称和严重性级别必须从已定义值的一个简短列表中选择,程序不能使用自己定义的值。设备分别为内核、常用应用程序组、以及本地编写的程序进行定义。任何其他程序则归为普通设备“用户(user)”一类。
selector可以包含特殊的关键字*和none,其含义分别为“所有的”或“什么都没有”。selector可以包括多个用逗号分开的设备。多个selector可以用分号组合起来。
通常情况下一般而言,selector相互之间为“或(OR)”的关系,和某个selector匹配的消息将由同一行的action处理。但是,不管同一行中其他的selector是如何定义的,只要有一个带有none级别的selector就会排除列出的设备。
这里有几个格式化和组合selector的例子:

表10.3列出了有效的设备名。目前的设备有21种。
syslogd本身可以产生时间戳消息,如果syslog.conf中出现了“mark”设备(facility)为其指定的一个目的地,那么会记录这些消息。时间戳可以帮助用户确定机器是在早上3:00和3:20之间崩溃的,而不仅仅是“昨天晚上的某个时间”。这个信息在调试有规律发生的问题时有很大用处。例如,许多站点都经历过当清洁工在深夜插上吸尘器电源时发生跳闸而导致神秘崩溃的事。
表1110.3 syslog的设备名
|
设备(facility) |
使用该设备的程序 |
|
* |
除了“mark”之外的所有设备 |
|
auth |
与安全和授权有关的命令 |
|
authpriv |
敏感/保密的授权消息a |
|
cron |
守护进程cron |
续表
|
设备(facility) |
使用该设备的程序 |
|
|
daemon |
系统守护进程 |
|
|
ftp |
FTP守护进程,ftpd |
|
|
kern |
内核 |
|
|
local0-7 |
本地消息的8种类型 |
|
|
lpr |
行式打印机的假脱机系统 |
|
|
|
sendmail以及其他与电子邮件相关的软件 |
|
|
mark |
定期产生的时间戳 |
|
|
news |
Usenet新闻系统 |
|
|
syslog |
syslogd内部消息 |
|
|
user |
用户进程(如果没有指定,这将是默认值) |
|
|
uucp |
为UUCP保留,并未使用 |
|
续表
a.所有与授权有关的消息都敏感。authpriv消息和auth消息不应该让任何人都能读取。
syslogd本身可以产生时间戳消息,如果syslog.conf中出现了“mark”设备(facility)为其指定的一个目的地,那么会记录这些消息。时间戳可以帮助用户确定机器是在早上3:00和3:20之间崩溃的,而不仅仅是“昨天晚上的某个时间”。这个信息在调试有规律发生的问题时有很大用处。例如,许多站点都经历过当清洁工在深夜插上吸尘器电源时发生跳闸而导致神秘崩溃的事。
如果系统十分繁忙,其他日志消息通常可以提供充分的时间戳信息。但在凌晨的几个小时并不总是这种情况。
syslog的严重性级别按照重要性递减的顺序在表1110.4中列出:。
消息的严重性级别指明了它的重要性。各个级别间的区别有时候显得比较模糊。在notice和warning之间(以及在warning和err之间)有一条清晰的界限,但是alert和crit相比,在所表达的含义上准确的细微差别则有点要靠猜测。表10.7列出了各种常用软件程序采用的特定级别。
表1110.4 syslog的严重性级别(降序)
|
级 别 |
大 致 含 义 |
级 别 |
大 致 含 义 |
|
emerg |
恐慌状态 |
warning |
警告消息 |
|
alert |
紧急状态 |
notice |
需要调查的事项 |
|
crit |
临界状态 |
info |
提供信息的消息 |
|
err |
其他错误情况 |
debug |
仅供调试 |
消息的严重性级别指明了它的重要性。在syslog.conf文件中,这些级别指定了最低程度的重要性,只有重要性大于(包括)它的消息才会被记录下来。例如,来自电子邮件系统的一条警告级消息和mail.warning匹配,也同样和mail.notice、mail.info、mail.debug、*.warning、*.notice、*.info和*.debug匹配。如果syslog.conf文件指定了mail.info消息应该被记录到某个日志文件中,那么mail.warning消息也将被记录到该文件中。在syslog.conf文件中,这些级别指定了最低程度的重要性,只有重要性大于(包括)它的消息才会被记录下来。例如,来自电子邮件系统的一条警告级消息和mail.warning匹配,也同样和mail.notice、mail.info、mail.debug、*.warning、*.notice、*.info和*.debug匹配。如果syslog.conf文件指定了mail.info消息应该被记录到某个日志文件中,那么mail.warning消息也将被记录到该文件中。
Linux版的syslog对基本语法做了改进,它也允许在优先级前面加上字符=和!,分别表示“仅此优先级”和“除此优先级及其以上级别”的意思。表1110.5给出了一些例子。
表1110.5 在syslog.conf中限定优先级的例子
|
选 择 符 |
含 义 |
|
mail.info |
选择与邮件相关的、优先级为info或者更高的消息 |
|
mail.=info |
只选择优先级为info的消息 |
|
mail.info;mail.!err |
只选择优先级为info、notice和warning的消息 |
|
mail.debug;mail.!=warning |
选择除warning之外的所有优先级 |
action字段说明如何处理一则消息。表1110.6列出了可以选择的处理方法。
表1110.6 syslog的动作
|
动作(Action) |
含 义 |
|
filename |
把消息写入本地机器上的一个文件里 |
|
@hostname |
把消息转发给主机hostname上的syslogd |
|
@ipaddress |
把消息转发给IP地址为ipaddress的主机 |
|
| fifoname |
把消息写入有名管道fifonamea |
|
user1,user2,… |
如果用户登录到了系统上,那么就把消息写在用户的屏幕上 |
|
* |
把消息写给目前已经登录的所有用户 |
续表
a. 参考info mkfifo了解更多的信息。
如果采取了filename(或者fifoname)这样的动作,那么文件名应该用绝对路径。如果您指定了一个不存在的文件名,那么在首次有消息送到这个文件的时候,syslod会创建它[2]。您可以在filename动作之前加一个短划线“-”,表示在写完每条日志记录项后,不应该对文件系统执行sync。执行sync有助于在发生崩溃的时候尽可能多地保留日志信息,但是从磁盘吞吐上来看,代价又太大。
如果用的是hostname而不是IP地址,那么主机名必须能通过DNS或者NIS这样的转换机制解析出来。有关主机名如何转换为IP地址的更多信息,可参考18.3.2节。
虽然一个selector可以包含多个设备(facility)和级别,但是却不能提供多个动作。为了把一则消息发送到两个地方(比如,到本地文件和到中央日志主机),您可以在配置文件中包含具有相同Selector的两行。
因为syslog消息能够用来实施拒绝服务攻击,所以除非syslogd以-r标志启动,否则它不会接受来自其他机器的日志消息。默认情况下,syslogd也会拒绝充当第三方消息转发器,从一台网络主机来的消息不会再被发给另一台网络主机。使用-h标志能够取消这一功能。(如果您想让这些选项始终都被启用,那么对于Red HatRHEL和Fedora,可以在脚本/etc/rc.d/init.d/syslog中加上这些标志,对于Debian和Ubuntu,可以在脚本/etc/init.d/sysklogd里加上这些标志。SuSE Linux提供了更好的语法,只要您修改/etc/rc.config里定义的变量SYSLOGD_PARAMS就行了。)
1110.4.4
设计站点日志方案
配置日志记录以便把重要的系统错误和警告保存在每台计算机上的一个文件中,在一个小型站点中这样做足够了,就像前面我们用syslog做的那样。syslog.conf文件可以针对每台主机进行定制。
在一个大型网络中,必须有中央日志记录。它使得大量信息保持在可管理的状态,而且运气好的话,破坏网络计算机安全的人可能无法访问到审计数据。黑客常常通过修改系统日志来擦去他们留下的痕迹。如果日志消息刚一产生就被转移到别的位置,那么想要破坏它就更难了。站点级的防火墙不应该让外部站点向syslogd提交消息。但要清楚一点,任何人都可以调用syslog,并且可以伪造从任何守护进程或者应用程序来的日志项。syslog也使用UDP协议,而这个协议并不保证是可靠的;消息可能会丢失。您的防火墙应该不允许外部站点向您的syslogd提交消息。
但要清楚一点,任何人都可以调用syslog,并且可以伪造从任何守护进程或者应用程序来的日志项。syslog也使用UDP协议,而这个协议并不保证是可靠的,消息可能会丢失。
选择一台稳定的计算机作为日志记录服务器,最好是有很好的安全措施而且登录用户不多的一台机器。其他计算机可以使用保存在中央主机上的一个通用配置文件。因此,只需要维护两个版本的syslog.conf文件。这样可以保持日志记录的完整性,但同时对于管理员来说又不再是个恶梦。有关在网络上分布文件的更多信息,请参见第1817章。
为了达到最好的安全性,syslog服务器应该通过防火墙与网络的其余部分隔离开,只能让连到syslog端口的网络连接通过,另外只能让得到允许可以向syslog记录日志的主机访问syslog服务器。根据周边的风险程度不同,可以从系统管理员的工作站用SSH连接,让管理员更方便地检查日志。
某些非常大的站点可能还需要给日志记录体系添加几个级别。遗憾的是,syslog的当前版本只能为最后一跳(hop)保留原来的主机名称。如果主机“client”将某些日志项发送到主机“server”,“server”又将它们发送到“master”,“master”只能知道消息来自“server”,而不知道是来自“client”的。
1110.4.2
5 配置文件举例
在syslog的配置上,不同的Linux发行版本变化非常大。因为读懂syslog.conf文件并不困难,所以就不详细看我们举例的发行版本中使用的配置文件了,它们都很直观易懂。我们转而要看一些常见的方法,如果您做出了不同于系统默认的选择,那么可能想要以这些方法来设置日志功能。
下面有3个syslog.conf文件的实例,分别对应于小型网络上的一台单机、较大网络中的一台客户机和一台中央日志记录主机。中央日志记录主机称为“netloghost”[3]。
一、单机
下面是单机的基本配置:

第1个非注释行把紧急(emergency)消息写到所有当前在线用户的屏幕上。在系统即将关闭时,shutdown所产生的消息就是一个紧急级别消息的例子。
第2行把重要(important)消息写入/var/log/messages文件。info级别比warning级别低,因此daemon,auth.info子句又包含了来自passwd、su和守护进程的日志记录消息。第三行把打印机错误信息写入到/var/log/lpd-errs。
二、网络客户机
网络客户机通常把重要的消息转发给中央日志记录主机:

这样的配置并没有在本地保存太多日志消息。值得一提的是,如果netloghost已经关闭或者不可达,日志消息将会不可避免地丢失。用户可以在本地机器上保存某些重要消息的额外副本来应付这种可能发生的情况。
在安装了许多本地软件的站点中,许多消息可能会被不恰当地记录到user设备(facility)的emerg级别里。在本例中,第一行用user.none子句专门把user/emerg排除在外。
第2和第3行把所有重要消息转发到中央日志记录主机,从打印系统和全校刷卡访问系统(local1)来的信息都被排除在外。第4行把本地日志消息也传送到netloghost。第5行把插卡访问记录信息传送到校园的日志主机。最后两3行项将保存打印机错误和、sudo日志消息和内核消息的本地备份。有关sudo的更多信息,请参见3.4.22节。
三、中央日志记录主机
本例针对netloghost,它是由大约7000台主机构成的一个中等规模网络上的中央安全日志主机。


从本地程序和网络上的syslogd来的日志记录数据被写入到文件。在某些情况下,每种设备(facility)的输出结果都保存在它自己的文件中。
中央日志记录主机在写入每条消息时都为其生成一个时间戳。时间戳并不反映原来主机上的时间。如果用户拥有位于不同时区的主机,或者系统时钟不同步,那么时间戳就会有点儿误导性。
1110.4.3
6 syslog输出的样本
下面的日志文件片段取自科罗拉多大学计算机系主控syslog主机中的日志文件之一。
![]()


大约有200台计算机将日志记录到这台主机上。
这个例子包含的记录项源自不同的主机(av18、proxy-1、mroe和coyote)和不同的程序:sbatchd、pop-proxy、pingem以及PAM(Pluggable Authentication Module,可插入式身份验证模块)库。
请注意节录的最后一行,它抱怨说有一条消息重复了100遍。为了使日志更加简短,syslog通常会合并重复的消息,并用这样的总结来替换它们。但是,取得这个日志示例的主机还可以接受来自许多其他主机的日志记录,因此这条特别的消息就有一点儿误导性。在这一混合的日志中,这条消息实际上指的是前面来自av18的日志记录,而不是紧接在它前面的那条日志记录。
定期细读日志文件是个不错的想法。确切知道什么是正常的,以便在发生异常时可以很容易地发现它。还有一个更好的方法,安装一个日志的事后处理程序(例如swatch)来自动捕获异常情况。请参阅1110.5节。
1110.4.5
7 使用syslog的软件
表1110.7中列出了使用syslog的一些程序,还包括了这些程序的日志记录的设备(facility)和重要程度的级别,以及对每个程序的简短描述。有些行加了阴影是为了便于阅读。
表10.7 使用syslog的软件
|
程 序 |
设 备 |
级 别 |
描 述 |
|
cron |
cron,daemon |
info |
系统任务调用守护进程 |
|
cups |
lpr |
info-err |
常用的UNIX打印系统 |
|
ftpd |
ftp |
debug-crit |
FTP守护进程(wu-ftpd) |
|
inetd |
daemon |
err,warning |
Internet超级守护进程(Debian) |
|
imapd |
|
info-alert |
IMAP邮件服务器 |
|
login |
authpriv |
info-err |
登录程序 |
|
lpd |
lpr |
info-err |
单行打印机守护进程 |
|
named |
daemon |
info-err |
名字服务器(DNS) |
|
ntpd |
daemon,user |
info-crit |
网络时间守护进程 |
|
passwd |
auth |
notice,warning |
口令设置程序 |
|
popper |
local0 |
debug,notice |
POP3邮件服务器 |
|
sendmail |
|
debug-alert |
邮件传输系统 |
|
ssh |
auth |
|
|
|
su |
auth |
notice,crit |
切换UID |
|
sudo |
local2 |
notice,alert |
受限的su程序 |
|
syslogd |
syslog,mark |
info-err |
内部错误、时间戳 |
|
tcpd |
local7 |
debug-err |
inetd的TCP封装程序 |
|
vmlinuz |
kern |
所有级别 |
内核 |
|
xinetd |
|
info (默认) |
inetd的变体(Red Hat、SUSE) |
有了所有这些信息,用户应该非常清楚哪些消息应该保留、哪些应该删除了,不是吗?但是,可能不是这样的可能未必如此。实际上,用户必须知道什么样的日志级别对自己的系统有用。最好的方式是首先让日志记录超过需要,然后去掉那些不想要的内容。等到产生数据的平均速率令您满意时就可以了。
1110.4.6
8 调试syslog
$ logger -p
local5.warning "test message"
logger命令用于从shell脚本提交日志项。用户也可以用它来检测syslogd的配置文件的变化。例如,如果已经添加了一行:
local5.warning /tmp/evi.log
而且想看看它是否起了作用,则运行:
$ logger -p local5.warning "test message"
含有“test message”的一行记录项应该写到/tmp/evi.log文件中。如果没有写入,那么可能是忘记了给syslogd发送挂起信号。
把日志记录发给控制台设备/dev/console、任何虚拟终端或支持流控的端口的时候应该小心。如果有人在控制台是一台老式的VT100终端,而且又有人无意中键入了<Control-S>,那么控制台的输出将会停止。所有对syslog的调用都将受阻,系统将变得非常缓慢。检查这种性能下降情况有一个好方法,即通过logger向控制台发送一条syslog消息。如果logger挂起了,则用户需要找到出了问题的控制台则用户需要找到出了问题的端口,键入<Control-Q>,然后重新考虑日志记录的策略。
在控制台上做日志记录的另外一个缺点是,由一个大问题产生的大量消息可以使控制台变得不稳定,而此时正是最需要它的时候。如果没有优化过控制台驱动程序,又采用某种帧缓冲类型的话,大量的消息确实会让整个系统无法使用。根据控制台的设置和管理情况不同(例如,通过一台控制台服务器),控制台的日志记录也应该有一些安全措施。
根据控制台的设置和管理情况不同(例如,通过一台控制台服务器),控制台的日志记录也应该有一些安全措施。
1110.4.7
9 在程序中使用syslog
库例程openlog、syslog和closelog能够让程序使用syslog系统。这些库例程有C和、Perl、Python和PHP的版本,这里只讨论Perl的接口。
在Perl脚本的开始处加上下面的一行,就可以引入库例程的定义:
use Sys::Syslog;
openlog例程使用指定的设备(facility)名称初始化日志记录:
openlog(ident, logopt, facility);
消息按照logopt指定的选项被记录下来,并以标识字符串ident开头。如果没有用过openlog,那么默认ident为当前用户名,logopt为一个空字符串,而facility为“user”。logopt字符串应该包含一个由逗号隔开的选项清单,这些选项在表1110.8中列出。
表1110.8 例程的日志记录选项
|
选 项 |
含 义 |
|
pid |
在每条日志消息上包含当前进程的PID |
|
ndelay |
立即连接到syslogd(不用等到要发消息的时候再连接) |
|
cons |
如果syslogd不可达,就把消息发送到系统控制台 |
|
nowait |
不用等待(wait(3))派生子进程来写控制台消息 |
例如,合理的openlog调用可以是:
openlog("adminscript", "pid,cons", "local4");
syslog例程发送一个消息至syslogd,将其以指定的优先级记录:
syslog(priority, message, ...);
来自openlog调用的日期、时间、主机名称和ident字符串都预先加入到日志文件的消息中。message后面可跟各种其他参数,以形成一个printf风格的输出格式,包括文本和其他变量的列表,例如:
syslog("info","Delivery to'%s'failed after %d attempts.", $user, $nAttempts);
特殊符号%m把errno的当前值(最新的错误代码)扩展为一条错误消息。
形如“level | facility”的优先级字符串既设置了严重性级别,也设置了设备名称。如果没有调用openlog并指定一个ident字符串,syslog例程还会检查message是否具有一条标准UNIX错误消息的形式,例如:
adminscript: User "nobody" not found in /etc/passwd file.
如果符合这个格式,冒号之前的那一部分就被秘密地采用为ident字符串。这些有用(但没有在文档中正式说明)的特性使得调用openlog并不是必不可少的了,但调用openlog仍然是个不错的想法。在一个地方(调用openlog时)指定设备的名称,比在整个代码中不断重复设备名称要好。
closelog例程将关闭日志记录通道:
closelog();
如果想以不同的选项重新打开日志记录通道,就必须调用这个例程。在程序退出时调用closelog是一个很好的形式,但是这样做并不是非确实必不可少的。
下面有一个完整的例子:

这一小段脚本将产生下面的日志记录(191是admincript的PID):
Dec 28 22:56:24 moet.colorado.edu adminscript[191]: Those whom the gods
would destroy, they first teach Basic.
