CLS组合解析实战手册:关键日志信息,精准提取解析

2022-04-19 17:27:15 浏览数 (1)

作者: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及以上版本,即将发布。

代码语言:javascript复制
{
  "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

千万级日活量,斗鱼如何基于日志实现秒级监控告警?

0 人点赞