我们在做日志处理时,往往会从多个源服务器收集日志,然后在一个(或一组)中心服务器做日志聚合分析。源服务器上的日志可能属于同一应用类型,也可能属于不同应用类型。
我们可能需要在聚合服务器上对这些不同类型的日志分类处理,一个实现方法就是在Fluentd内部重新给这些日志打tag,然后重新路由到合适的output插件进行输出。
rewrite_tag_filter就是一个提供这种给日志重新打tag的插件。
需要说明的是,从其命名来看,rewrite_tag_filter是一个filter,而实际上它是一个output插件。因为Fluentd的filter插件并不允许重写tag。
【基本原理】
rewrite_tag_filter可通过定义一系列的规则(rule)来实现日志的匹配和tag重写。
这些规则会按照其定义顺序逐一对日志进行匹配,一旦日志符合某个规则,插件会使用该规则定义的方法重写日志的tag,并将重写后的日志事件再次发送到Fluentd路由中,从而实现对输入日志的分类处理。
举一个简单的例子:
# Configuration
<match app.component>
@type rewrite_tag_filter
<rule>
key message
pattern /^(w+)$/
tag $1.${tag}
</rule>
</match>
在这个例子中,日志的原tag为app.component。
rewrite_tag_filter会对日志记录的message字段进行匹配测试,pattern定义了匹配规则,这里是匹配message中的每个单词,然后去第一个单词,将其插入到原tag之前。
重写效果如下所示:
+------------------------------------------+ +------------------------------------------------+
| original record | | rewritten tag record |
|------------------------------------------| |------------------------------------------------|
| app.component {"message":"[info]: ..."} | +----> | info.app.component {"message":"[info]: ..."} |
| app.component {"message":"[warn]: ..."} | +----> | warn.app.component {"message":"[warn]: ..."} |
| app.component {"message":"[crit]: ..."} | +----> | crit.app.component {"message":"[crit]: ..."} |
| app.component {"message":"[alert]: ..."} | +----> | alert.app.component {"message":"[alert]: ..."} |
+------------------------------------------+ +------------------------------------------------+
【安装说明】
td-agent v3.0.1或更高版本已经内置了rewrite_tag_filter。
较低版本的td-agent可以通过以下命令进行安装:
# for td-agent2 (with fluentd v0.12)
$ sudo td-agent-gem install fluent-plugin-rewrite-tag-filter -v 1.6.0
# for td-agent3 (with fluentd v0.14)
$ sudo td-agent-gem install fluent-plugin-rewrite-tag-filter
【配置示例】
一个好的配置设计原则是:先过滤掉不需要的日志,然后再处理需要重写的日志。
我们看一个例子。
<source>
@type tail
path /var/log/httpd/access_log
<parse>
@type apache2
</parse>
tag td.apache.access
pos_file /var/log/td-agent/apache_access.pos
</source>
<match td.apache.access>
@type rewrite_tag_filter
capitalize_regex_backreference yes
<rule>
key path
pattern /\.(gif|jpe?g|png|pdf|zip)$/
tag clear
</rule>
<rule>
key status
pattern /^200$/
tag clear
invert true
</rule>
<rule>
key domain
pattern /^.+\.com$/
tag clear
invert true
</rule>
<rule>
key domain
pattern /^maps\.example\.com$/
tag site.ExampleMaps
</rule>
<rule>
key domain
pattern /^news\.example\.com$/
tag site.ExampleNews
</rule>
# it is also supported regexp back reference.
<rule>
key domain
pattern /^(mail)\.(example)\.com$/
tag site.$2$1
</rule>
<rule>
key domain
pattern /.+/
tag site.unmatched
</rule>
</match>
<match site.*>
@type mongo
host localhost
database apache_access
remove_tag_prefix site
tag_mapped
capped
capped_size 100m
</match>
<match clear>
@type null
</match>
这个例子中,rewrite_tag_filter首先过滤掉了Apache中图片、压缩包等静态文件的请求日志,然后对日志中的path、status、domain这些字段依次进行正则匹配:
第二个rule用于匹配响应代码为200的记录,通过invert将非200的请求记录过滤掉;
第三个rule用于匹配.com结尾的域名,通过invert将非.com域名请求记录过滤掉;
第四五六个rule用于分类处理不同前缀的域名,分别重写其tag为site.ExampleMaps、site.ExampleNews、site.ExampleMail;
最后一个rule用于处理其他域名,统一重写tag为site.unmatched。
被过滤掉的日志,其tag被重写为clear,并最后丢弃(输出到null)。
其他被重写tag的日志会按照其tag名称被分别写入MongoDB的不同collections中。
【参数说明】
【场景举例】
我们再举一个应用示例。
# built-in TCP input
<source>
@type forward
</source>
# Filter record like mod_rewrite with fluent-plugin-rewrite-tag-filter
<match apache.access>
@type rewrite_tag_filter
<rule>
key status
pattern /^(?!404)$/
tag clear
</rule>
<rule>
key path
pattern /.+/
tag mongo.apache.access.error404
</rule>
</match>
# Store deadlinks log into mongoDB
<match mongo.apache.access.error404>
@type mongo
host 10.100.1.30
database apache
collection deadlinks
capped
capped_size 50m
</match>
# Clear tag
<match clear>
@type null
</match>
这个配置使用in_forward收集Apache的访问日志。
通过设置两个rule,提取日志中的http 404请求记录,将这些请求的url写入MongoDB,这样就可以方便地统计网站中存在的死链。
【常见问题】
使用rewrite_tag_filter经常遇到的情况是,重写tag导致日志无法输出。
比如:
<match app.**>
@type rewrite_tag_filter
<rule>
key level
pattern /(.+)/
tag app.$1
</rule>
</match>
<match app.**>
@type forward
# ...
</match>
这个片段就会导致日志无法输出。
仔细看重写规则可以发现,以app开头的tag被重写后仍然是以app为开头。这导致了新事件重新进入第一个<match>,发生了死循环。
所以重新tag时需要谨慎一些,避免发生此类情况。