chenpengcong / blog

14 stars 3 forks source link

使用rsyslog进行日志收集 #23

Open chenpengcong opened 6 years ago

chenpengcong commented 6 years ago

最近完成了这样一个需求:采集各个服务器上的业务日志(文件格式存储)到一台中央服务器上

出于性能和资源占用两个方面我选择了rsyslog来完成这个任务,在此记录下rsyslog的使用心得

配置的模板大致如下

业务服务器

input(type="imrelp" port="20514" ruleset="RemoteLogProcess")

module(load="omrelp")
module(load="imfile")
module(load="impstats"
       interval="600"
       severity="7"
       log.syslog="off"
       # need to turn log stream logging off!
       log.file="/var/spool/rsyslog/stats.log") # 每隔600秒输出运行信息

/**
 * action.resumeRetryCount="-1": action失败时无限重试
 * action.resumeInterval="10": action重试时间为(numRetries / 10 + 1) * action.resumeInterval
 * queue.filename="q_sendToLogServer": 队列文件名前缀为q_sendToLogServer
 * queue.spoolDirectory="/var/spool/rsyslog": 设置队列文件存储目录
 * queue.size="50000": 内存队列最多存储50000条消息
 * queue.highwatermark="45000", queue.lowwatermark="30000": 当内存队列存储超过45000条消息时,开始写将内存队列里的消息写入磁盘,直到减至30000
 * queue.maxdiskspace="10g": 所有队列文件最多在磁盘上占用10g
 * queue.saveonshutdown="on": 当rsyslog关闭时未发送的消息被写入磁盘
 **/
ruleset(name="Log2LogServer"){
    action(type="omrelp" Target="1.1.1.1" Port="20514" Template="RSYSLOG_ForwardFormat"\
    action.resumeRetryCount="-1" action.resumeInterval="10"\
    queue.filename="q_sendToLogServer" queue.spoolDirectory="/var/spool/rsyslog" queue.type="LinkedList" queue.size="50000" queue.highwatermark="45000" queue.lowwatermark="30000" queue.maxdiskspace="10g" queue.saveonshutdown="on")
}

input(type="imfile" addMetadata="on" File="/path/to/your/file" Tag="tomcat_access" Ruleset="Log2LogServer")

要理解上面的配置,还需要认识disk-assisted queue

中央服务器

module(load="imrelp")
module(load="impstats"
       interval="600"
       severity="7"
       log.syslog="off"
       # need to turn log stream logging off!
       log.file="/var/spool/rsyslog/stats.log")

template(name="TomcatAccessLogFormat" type="string" string="%fromhost-ip% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n")

/**
 * asyncWriting="on", ioBufferSize="64k": 开启异步写,当缓冲的数据达到64k才进行写文件
 * flushInterval="1": 每秒将已缓冲但未写的数据进行写操作
 **/
ruleset(name="RemoteLogProcess"){
    if ($syslogtag startswith "tomcat_access") then {
        action(type="omfile" File="/data/log/access.log" template="TomcatAccessLogFormat"  asyncWriting="on" flushInterval="1" ioBufferSize="64k" flushOnTXEnd="off")
    } 
}

input(type="imrelp" port="20514" ruleset="RemoteLogProcess")

如何在消息中额外添加数据再进行转发

由于rsyslog是根据一定格式解析消息, 所以如果我们的消息转发使用了自定义的模板(template),中央服务器的rsyslog可能会解析消息错误,解决方法是将要添加的信息作为消息中msg的一部分,中央服务器的rsyslog再从msg中截取我们想要的数据

比如我们经过一系列逻辑处理得到一个变量$.mydata,现在需要将该变量的值传递到远程rsyslog,并且远程rsyslog可以获取该值,如果我修改上面的配置,使用以下模板进行转发

template(name="myT" type="string" string="<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %$.mydata% $.mydata% %syslogtag%%msg%")

那么远程rsyslog解析消息后%syslogtag%的值是变量$.mydata的值而不是指定的Tag="tomcat_access"

原因是rsyslog解析不了我们自定义的模板,内置模板RSYSLOG_ForwardFormat的格式是<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag:1:32% %msg:::sp-if-no-1st-sp%%msg%,和自定义模板myT的区别是在%syslogtag%之前多了个%$.mydata%,因此该位置的值被解析为属性syslogtag

正确做法是将变量放在%msg%前面(不要空格),整体作为msg传递到远程rsyslog

ruleset(name="TrimMsg"){
    set $.trimed_msg=ltrim($msg);
}

远程rsyslog先去除可能存在的前置空格,然后可以在string template中截取出变量mydata的内容%$.trimed_msg:1:3%

注意点

定位问题手段

工具

官网提供了几个蛮有用的工具

消息乱序

rsyslog使用disk-assisted queue可能会出现消息乱序问题 Confirmation on disk assisted queue functionality rsyslog reorders log file content

resources

references