Home » Code » Linux » 使用rsyslog进行远程日志记录的简易教程

使用rsyslog进行远程日志记录的简易教程

你们为什么要记录数据?对于我有两个明确的原因:统计和调试。对于第一种情况,一段时间内无法访问得到数据并不是什么大问题,统计只有在收集很长一段时间后才有意义。但当某台服务器完全故障,服务一个接一个不可用,你想马上确定发生了什么,你必须通过ssh访问你的日志,然而服务已经不可用。这时日志记录在远程就很有必要了。

我们可以依靠操作系统提供一个方案来解决这个问题。从2004年开始,Rainer Gerhanrds开始编写rsyslog,这是一个提供了远程记录和强大过滤功能的守护进程。本文会介绍如何进行设置实现远程记录功能,并展示一些可能的日常使用示例,包括标准的系统日志和apache的访问和错误日志。

免责声明

如果你要开始更改你们的日志设置,请小心操作,记得备份相关数据并在之后检查新设置是否正确的工作。本文只是一个简单的介绍,不是完美的参考。如果你不知道一些操作是什么意思或有什么作用,请先查阅一下。另外,备份配置文件迟早会派上用场的。如果你发现我范了什么错误,也请通知我。

linux上记录日志小而陋的历史

回到当年,在《帝国反击战》被视为绝无仅有的特效电影的时代,Eric Allman为邮件发送创造了一个日志记录标准。很快这个标准被其他程序采纳并成为unix系统事实上的日志记录标准。20年后,syslog-ng,一个开源的syslog实现出现了,在过滤和配置方面带来了巨大改进。最后几乎到现代(2004)上边提到的Rainer Gerhanrds开始编写rsyslog作为syslog-ng的竞争对手,因为他认为竞争对手的存在是很有必要的

起步

很简单,毕竟我们是在linux上,执行“aptitude install rsyslog”就足够了。你还要做的就是检查是否有其他日志记录守护进程在你的系统上运行(或者你已经有rsyslog在运行了),比如sysklogd或其他。你不需要它们了因为我们要开始远程日志记录。如果你能在/etc/下边看到rsyslog.conf,表明已经设置好本地日志记录了。现在,清除文件中所有的规则,实测最少需要保留这么两行:

$ModLoad imuxsock
*.* @1.2.3.4:514

这时候如果你重启rsyslog,所有设施所有级别的错误都会通过UDP发送到IP为1.2.3.4的服务器上。通过在第一个@前边添加第二个并更改端口你就能通过TCP来发送,不过现在我不介意日志丢失因此使用UDP就足够了。使用*.*日志可能有点多,如果你清楚在接收服务器上哪些日志是要被抛弃的,你可以直接在发送服务器上抛弃掉以节省带宽。继续往下看该如何操作。

以上就是实现系统日志记录这个目标所要做的全部工作,但我们不仅于此,我们还要让apache使用系统日志而不是监听它自己本身的命令。对于错误日志,非常简单,我们告诉它使用系统日志来处理即可。对于访问日志则有些不同。在httpd.conf主配置文件中,将以下配置项注释掉原来的新增如下:

ErrorLog syslog
CustomLog "|/usr/bin/logger -t apache -i -p local6.notice" combinediod

正如你看到的,错误日志并不是难事,访问日志则需要使用CustomLog做一些特殊的事情。每条访问日志通过管道传输到能被rsyslog接收的/usr/bin/logger中去,设施(local6)和级别(notice)是单独传传输的。最后,选择一种特定的日志格式,默认apache带了common和combined两种,以及需要开启mod_logio.c的combinedio,我这里的combinediod是在combinedio最后再加一项%D,表示服务器处理本请求所需时间,单位微秒。更多信息参见官方文档

关于“local6.notice”,前者是facility,中文可译为设施。一般有以下几种:

facility
编号 名称 说明
0 kern 内核相关
1 user 用户相关
2 mail 邮件相关
3 daemon 守护进程相关
4 auth 权限相关
5 syslog syslog本身相关
6 lpr 打印服务相关
7 news
8 uucp
9 cron 进程或应用调度
10 authpriv
11 ftp
16~23 local0~local7 用户自定义消息

后者是priority,优先级(严重性),有以下几个等级:

priority
编号 名称 全称 说明
0 emerg Emergency 紧急
1 alert Alerts 报警
2 crit Critimal 关键
3 err Errors 错误
4 warning Warnings 警告
5 notice Notification 通知
6 info Information 消息
7 debug Debugging 调试

到这里,系统日志和apache的访问日志、错误日志都被发送到了1.2.3.4,问题是在1.2.3.4上没有任何人在监听…

设置主机

为了让1.2.3.4开启监听,我们也需要修改它的rsyslog.conf。以下是开启514端口进行UDP监听需要做的(如果你是通过aptitude安装的,配置文件里应该还有一堆其他的东西,你只需要去掉UDP部分的注释就行了)。

$ModLoad imudp
$UDPServerAddress 1.2.3.4
$UDPServerRun 514

上边配置实际干了这三件事:

  1. 加载了一个模块,使我们的rsyslog有的监听UDP包的能力。
  2. 定义一个IP地址,如果这个为空或者使用*,这台服务器知道的所有本地IP都监听了。一般来说并不想如此,在我们的应用场景中,机器只监听特定的本地IP,不会被外界干扰。
  3. 定义rsyslog需要监听的端口

重启rsyslog就能检查你的配置是否生效,使用这个命令: netstat -nlp 能得到类似这样的结果:

udp    0    0 1.2.3.4:514      0.0.0.0:*     16637/rsyslogd

注:译者是使用的公网,没有内网机器可测,上边第2点使用的*。

保存进来的日志

每台服务器上的日志都会被1.2.3.4接收,如果你想把它们都放到一个文件中,你需要做的只是在rsyslog.conf中添加这么一行并重启它:

*.* /var/log/oneGiantHeapOfLogs.log

当然,如果你不想这么做,我们就要使用过滤器。开始这么做之前我先给你们介绍另一个概念——模板。

模板

由于很多服务器都往同一台机器发送日志,经上边这么简单配置它不能智能的把local6.notice日志过滤出来并保存到/var/log/apache-access.log。我们需要一个方案来动态的把相同设施的日志放到不同的文件中。为了实现这个目标,模板就派上用场了。以下是我使用的一些例子:

$template syslog, "/var/log/external/%fromhost%/syslog.log"
$template apacheError, "/var/log/external/%fromhost%/apache/error.log"
$template apacheAccess, "/var/log/external/%fromhost%/apache/%msg:R,ERE,1,ZERO:imp:([a-zA-Z0-9\-]+)\.--end%-access.log"
$template mailError, "/var/log/external/%fromhost%/mail/error.log"
$template position, "/var/log/external/test/position-%$now%.log"

这里边做了两件事。首先你应该注意到了%fromhost%,这是一个属性占位符,将会动态的被日志来源机器名经DNS解析后的值替换掉。其他更多的属性占位符可以参考这里。记住:带$符合($now,系统当前时间)的是系统属性,不带$(fromhost,日志来源主机)的是日志属性。

第二个占位符%msg%那里有点晦涩难懂,但在最后它只不过是一个正则表达式。由于我们的服务器机器会重复部署每个部署都非常容易产生访问日志,因此我们在发送机器上的日志格式上添加一些信息然后在这里解析出来。关于模板中的正则表达式可以查看这里

上边的例子中只是动态生成的文件名,有时候还需要动态添加一些内容,比如在日志最开始添加时间,在最末尾添加换行符等。做法一样的使用这个模板语法,只是右边的路径换成日志内容。

$template test1,"%timestamp:1:26:date-rfc3339% %rawmsg:1:5%\n"

上边的意思,是将时间使用rfc3339格式化后截取第1到第26位,将原始日志内容截取第1到第5位。以下日志中,最上是完整的rfc3339格式时间,中间是将时间进行截取,最下是将信息截取。

2017-02-24T23:21:19.127083+08:00 test from local !
2017-02-24T23:21:20.351050+08:00 test from local !
2017-02-24T23:21:21.112482+08:00 test from local !
2017-02-24T23:32:14.674547 test from local !
2017-02-24T23:32:14.824273 test from local !
2017-02-24T23:32:15.131581 test from local !
2017-02-24T23:32:15.323076 test from local !
2017-02-24T23:32:15.471818 test from local !
2017-02-24T23:33:21.831590 test 
2017-02-24T23:33:24.948113 test 
2017-02-24T23:33:25.417399 test 

真实过滤

有了模板的动态文件名的结果,可以开始真实的过滤了。首先,过滤出apache日志:

local7.* ?apacheError
& ~
 
local6.notice ?apacheAccess
& ~

我会解释这里每一行所做的事。对于错误日志,我们只是设置使用syslog来处理,它默认使用的设施编号是local7,这可以从官方文档中得知(打开文档地址,搜索”local7″)。访问日志则是主动使用local6.notice。在这里,问号(?)的作用是告诉rsyslog使用哪个模板。对于错误日志模板,如果一条日志来自v004,那么它将被存储到/var/log/external/v004/apache/error.log,如果它来自v027,则被存储到/var/log/external/v027/apache/error.log。在指定了模板的下一行,有一个“&”和“~”,“~”的作用告诉rsyslog删除由前一条命令过滤出来的所有志,“&”则仅仅是连接这两行。

由于我们的邮件服务器也进行远程日志记录,如果我们也能从一个指定文件获得邮件相关的错误日志那是极好的。若我只对真实邮件服务器的错误日志感觉兴趣,我并不需要那些随机虚拟机的带有特定后缀的日志,该如何过滤呢?这个需求看起来有点棘手,下边这个方案我不知道是否完美,但至少在我这是可行的:

if $syslogfacility-text == 'mail' and $syslogseverity-text == 'info' and $fromhost startswith 'mail' then ?mailError
& ~

if-and-then结构也能用上占位符,同时还能和预定义的数值进行比较运算(如isequal, startswith等等)。如果所有条件都满足这条记录会使用一个模板进行保存然后删除。注意:全部的“&”,“~”必须单独一行,其他信息也是每条要单独一行(比如$template整个定义,整个if-and-then)。

上边这个if-and-then后只是通过?指定了位置模板,如果也需要同时指定信息模板呢?这时就需要使用到action语法。

if $rawmsg startswith "test" then {
    action(type="omfile" DynaFile="position" template="test1")
    stop
}

现在我们的apache日志和错误日志都分开存储到不同文件中了,邮件服务器的错误日志也是如此。剩下的就放到系统日志中:

*.* ?syslog

这是配置文件中最后一个过滤器,所有未被前边过滤器捕获的日志都将用syslog模板存储到指定位置。

写在最后

上边的配置行来自我们真实配置中的代码码片段,当然不是全部都展示出来了。如果你想自己实现远程日志记录,注意多思考,并考虑自己的实际情况。希望这篇文章在你进行远程日志记录时能帮到你。

参考自:http://www.freeklijten.nl/2011/08/16/A-tutorial-on-remote-logging-with-rsyslog。略有修改,并有额外信息整理自网络。

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Time limit is exhausted. Please reload CAPTCHA.