作者:timothy
导语:云原生日志服务(Cloud Log Service,CLS)是腾讯云提供的一站式日志数据解决平台,提供了从日志采集、日志存储到日志检索,图表分析、监控告警、日志投递等多项服务,协助用户通过日志来解决业务运维、服务监控、日志审计等场景问题。
背景
随着用户业务版图的不断扩张,新业务数据不断写入,再加上老业务数据的长时间沉淀,用户的日志数据量会呈现倍数级持续性增长。在日常运维过程中,往往面临着日志格式复杂的问题,不能通过单一功能处理将日志结构化为理想的格式。
日志服务CLS是腾讯云提供的一站式日志数据解决方案,支持200 数据分析函数和70 数据加工函数,具备强大的数据处理能力;而LogListener是日志服务提供的日志采集客户端,通过安装部署LogListener,可以方便快速地接入日志服务。在上述使用场景里,可以通过LogListener的组合解析模式,在采集端就使用不同组合的插件来定义解析方式,完美应对海量数据处理工作,大大降低日志运维门槛,提高了日志的应用价值。
详细信息请参考官网文档:
CLS:
https://cloud.tencent.com/product/cls
LogListener:
https://cloud.tencent.com/document/product/614/33495
解析流程详解
组合解析主要功能是在采集端结构化复杂格式的日志,在应用场景上,此类格式日志通常需要的处理分为下面3种:
- 结合多种解析方式处理日志:往往一条日志的格式同时包含多种解析模式,不同段落需要对应的提取方法。比如在第一层解析(分隔符)后得到的某个字段内容是JSON对象,还需要再使用JSON将里面的多对KV再逐个解析出来;
- 对日志内容特定字段的再加工:包括通过丢弃、重命名、增加等功能来处理日志正文内容,比如日志内容解析后想去除不关键的字段就可以使用Drop插件丢弃;
- 组合上面两种情况,更为灵活地处理一整条日志。
LogListener的组合解析模式支持用户在控制台输入代码(JSON格式)来定义日志解析的流水线逻辑。用户可添加一个或多个LogListener插件处理配置,LogListener会根据处理配置顺序逐一执行,从而实现对于上文各种场景的日志解析需求。
我们来看一下具体的解析流程 :
从上面的流程可以看出,解析的过程主要分为以下3步:
- 使用分割符将日志区分成ABCD四段;
- 按照解析要求,使用不同插件分别对每段的内容做下一层解析,提取出需要的内容;
- 将解析后输出的内容拼接成想要的理想输出内容。
解析场景实操演示
目前LogListener的组合解析模式可支持的插件及其功能如下表:
经典场景案例展示
场景1:丢弃字段
日志内容中解析后有些字段内容不进行上报,可以用「丢弃字段」插件缩减日志长度,以减少使用成本。
示例:原始日志中一共有三组KV对,我们关心的是中间的有效数据key2,可以使用processor_drop插件丢弃日志中的key1字段和key3字段。
日志原文如下:
代码语言:javascript复制key1:value1
key2:value2
key3:value3
LogListener组合解析processor_drop插件示例:
代码语言:javascript复制{
"processors":[
{
"type":"processor_drop",
"detail": {
"Sourcekey": ["key1","key3"]
}
}
]
}
处理结果如下:
代码语言:javascript复制key2:value2
场景2:增加字段
在很多日志分析的场景下,用户希望能够新增一些额外的信息到日志正文中,比如元数据信息或者其他相关的标签信息。
示例:用户希望抽取日志路径内的信息,将其补充到日志中,用来展示该条日志的归属。比如希望提取文件路径/home/admin/userA/serviceA/access.log中的user和service作为补充信息,就可以使用插件对元数据filename进行处理,处理结果为 TAG.user:xxx;TAG.service_:xxx。
日志原文及文件路径如下:
代码语言:javascript复制value1,value2
路径:/usr/local/loglistener-2.7.4/testdir/test.log
LogListener组合解析示例:
注:meta_processor插件需要loglistener 2.7.4及以上版本,即将发布。
{
"processors": [
{
"type": "processor_split_delimiter",
"detail":{
"Delimiter": ",",
"ExtractKeys": ["msg1","msg2"]
}
},
{
"type": "meta_processor",
"detail": {
"ExtractKeys": ["FILENAME"]
},
"processors": [
{
"type": "processor_fullregex",
"detail": {
"KeepSource":false,
"SourceKey": "FILENAME",
"ExtractRegex": "/\w /\w /(\w )-([^/] )/(\w )/(\w ). *",
"ExtractKeys": ["app","ver","logdir","logname"]
}
}
]
}
]
}
处理结果如下:
代码语言:javascript复制msg1:value1
msg2:value2
__TAG__.app:loglistener
__TAG__.ver:2.7.4
__TAG__.logname:test
__TAG__.logdir:testdir
场景3:自定义插件
使用特定解析格式,展开具体字段内的内容,并对不同的内容分别处理。我们先看一个简单的展示。
假设一条日志的原始数据为:
代码语言:javascript复制1571394459,http://127.0.0.1/my/course/4|10.135.46.111|200,status:DEAD,
自定义插件内容如下:
代码语言:javascript复制"processors": [
{
"type": "processor_split_delimiter",
"detail": {
"Delimiter": ",",
"ExtractKeys": [ "time", "msg1","msg2"]
},
"processors": [
{
"type": "processor_timeformat",
"detail": {
"KeepSource": true,
"TimeFormat": "%s",
"SourceKey": "time"
}
},
{
"type": "processor_split_delimiter",
"detail": {
"KeepSource": false,
"Delimiter": "|",
"SourceKey": "msg1",
"ExtractKeys": [ "submsg1","submsg2","submsg3"]
}
},
{
"type": "processor_split_key_value",
"detail": {
"KeepSource": false,
"Delimiter": ":",
"SourceKey": "msg2"
}
}
]
}
]
}
经过日志服务结构化处理后,该条日志的处理结果为:
代码语言:javascript复制time: 1571394459
submsg1: http://127.0.0.1/my/course/4
submsg2: 10.135.46.111
submsg3: 200
status: DEAD
我们再来看一个真实的复杂案例。原始日志如下:
代码语言:javascript复制2016-01-02 12:59:59/log_start/{"remote_ip":"10.135.46.111","body_sent":23,"responsetime":0.232,"upstreamtime":"0.232","upstreamhost":"unix:/tmp/php-cgi.sock","http_host":"127.0.0.1","method":"POST","url":"/event/dispatch","request":"POST /event/dispatch HTTP/1.1","xff":"-","referer":"http://127.0.0.1/my/course/4","agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0","response_code":"200"}/log_end/
期望输出:JSON数组展开,并去掉头尾start及end内容。
根据Loglistener的组合解析流程,实现路径一共包含3个Step。
Step1. 利用“/”分隔符解析日志为五部分:
[a]
代码语言:javascript复制2016/01/02 12:59:59
[b]
代码语言:javascript复制log_start
[c]
代码语言:javascript复制{"remote_ip":"10.135.46.111","body_sent":23,"responsetime":0.232,"upstreamtime":"0.232","upstreamhost":"unix:/tmp/php-cgi.sock","http_host":"127.0.0.1","method":"POST","url":"/event/dispatch","request":"POST /event/dispatch HTTP/1.1","xff":"-","referer":"http://127.0.0.1/my/course/4","agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0","response_code":"200"}
[d]
代码语言:javascript复制log_end
[e] 空
Step2. 分别对a、b、c、d、e使用插件处理:
- a在分隔符第一层解析时设定key值为time;
- b、d、e使用插件去除字段处理,不再保留内容;
- c使用JSON展开。
Step3. 对c使用JSON展开。
代码语言:javascript复制{
"processors": [
{
"type": "processor_split_delimiter",
"detail": {
"KeepSource": false,
"Delimiter": "/",
"ExtractKeys": [
"time",
"msg2",
"msg3",
"msg4",
"msg5"
]
},
"processors": [
{
"type": "processor_drop",
"detail": {
"SourceKey": "msg2"
}
},
{
"type": "processor_json",
"detail": {
"KeepSource": false,
"SourceKey": "msg3"
}
},
{
"type": "processor_drop",
"detail": {
"SourceKey": "msg4"
}
},
{
"type": "processor_drop",
"detail": {
"SourceKey": "msg5"
}
}
]
}
]
}
最终输出结果如下图:
代码语言:javascript复制time:2016/01/02 12:59:59
agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0
body_sent: 23
http_host: 127.0.0.1
method: POST
referer: http://127.0.0.1/my/course/4
remote_ip: 10.135.46.111
request: POST /event/dispatch HTTP/1.1
response_code: 200
responsetime: 0.232
upstreamhost: unix:/tmp/php-cgi.sock
upstreamtime: 0.232
url: /event/dispatch
xff: -
更多场景实战案例请参考官网文档:
https://cloud.tencent.com/document/product/614/61310
结语
当业务日志结构太过复杂,涉及多种解析模式,单种解析模式(如 Nginx 模式、完整正则模式、JSON 模式等)无法满足日志解析需求时,LogListener的组合解析模式,支持用户通过CLS控制台添加一个或多个LogListener插件处理配置,满足复合型日志解析需求,精准覆盖日志解析全场景,大大降低运维成本,释放人力压力,最大程度发挥日志价值。
在未来,CLS会继续打磨日志服务的细节,帮助用户在日志运维、运营、合规审计等业务方面实现跨越式发展,造福更多的运维团队与开发团队。
以上就是关于CLS应用组合解析模式将复杂日志结构化的应用实践,感谢阅读!
加入「腾讯云日志服务CLS技术交流群」,获取更多资讯,掌握最新动态!
往期文章:
IEG Global x CLS:「游戏出海 -日志合规」史上最全案例教程
【腾讯云应用性能观测x日志服务】:链路日志关联,加速故障定位
【日志服务CLS】全新Grafana数据源,一键安装,功能升级
日志服务Grafana可视化实践——从自建ELK到使用CLS
千万级日活量,斗鱼如何基于日志实现秒级监控告警?