Log Agent - Fluent Bit Parser元件

Fluent bit回顾
Log Agent - Fluent Bit 简介
Log Agent - Fluent Bit 安装与常见架构模式
Log Agent - Fluent Bit Service配置与内建 API
Log Agent - Fluent Bit Input元件 与 Tail浅谈

Parsers

Parser主要功能就是把从Input收到的非结构化资料转换成Structured Log

主要的Parser类型有

  • JSON
  • Regular Expression
  • Logfmt
  • Decorders
  • LTSV
[PARSER]
    Name parser自定义名称
    Format parser类型名称
    Time_Key    time的栏位名称, 会将这栏位的值转成log的时间戳记
    Time_Format 使用strptime格式

JSON Parser

JSON格是最简单了, 本来就是Structured, Object的话都依订有key,
如果有必要, 有栏位就是代表log time时, 需要特别指定Time_Key跟Time_Format

"{"logTime":"2021-10-12 18:31:01","message":"ithome"}"

Parser示范

[PARSER]
    Name demoJson
    Format json
    Time_Key    logTime
    Time_Format %Y-%m-%d %H:%M:%S

Logfmt Parser

Logfmt format 其实就是之前提过的KVP
一样本来就是Structured

logTime=2021-10-12 18:31:01 message=ithome
[PARSER]    
    Name        demologfmt    
    Format      logfmt

Regular Expression Parser

这Regex Parser才是重点中的重点, 太多Log资料并非是Structured, 而是Flat Log.
我们需要用Regex来捕捉哪些内容是属於哪些key/label

input元件读进这一行, 给了parser

47.29.201.179 - - [28/Feb/2019:13:17:10 +0000] "GET /?p=1 HTTP/2.0" 200 5316 "https://domain1.com/?p=1" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36"

定义Regex如下

/^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")/

剖析结果

{
    "remote": "47.29.201.179",
    "host": "-",
    "user": "-",
    "method": "GET",
    "path": "/?p=1",
    "code": "200",
    "size": "5316",
    "referer": "https://domain1.com/?p=1",
    "agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36"
}

我来慢慢说明那Regex

  • 开头跟结尾的/
    • 使用两个/ regexx /来包裹regex
  • (?<remote>[^ ]*)
    • (?<Name> regex pattern)用pattern来捕捉内容塞给对应命名的key
      • (?[^ ]) 把[^] 匹配到的字串都赋值给remote
    • [^ ]*这regex pattern就是一直匹配不是空格的字元
      • [^ ] ^在[]内表示except後面的字, 後面接的是space
  • \[(?<time>[^\]]*)\]
    • \[\]只是因为[]是特殊符号, 但这里要表示就是[]这字, 就要透过\做Escaping转义
  • (?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?
    • 拆两段(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?
      • (?\S+)的\S也是用来表示任意的非空白字元, 跟上面的[^ ]*一样
        • 用来捕捉到GET
      • (?: +(?[^"]?)(?: +\S)?)?
        • 先讲解(?: +) , 这代表non-capturing groups, 就表示(?: )这里面的字元不会被捕捉出来, 这里面其实是+, 就是至少一个空格space
          • 用来比对/?p=1这里/之前的那空格
        • 再来(?<path>[^\"]*?), 这就一直匹配不是"的字元, 并捕捉赋值给path
          • 用来捕捉到/?p=1
        • 最後是(?: +\S*)?
          • ()? 表示前面匹配到的字元出现0-1次
          • (?: +\S*)
            • 跟之前一样有non-capturing groups匹配空格,然後持续匹配任意个非空格字元

https://ithelp.ithome.com.tw/upload/images/20211012/20104930uDM6TnZss4.png
後面字串的剖析方式大同小异

另一个范例, Apache HTTP Server log

192.168.2.20 - - [29/Jul/2015:10:27:10 -0300] "GET /cgi-bin/try/ HTTP/1.0" 200 3395
[PARSER]    
    Name   apache    
    Format regex    
    Regex  ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$    
    Time_Key time    
    Time_Format %d/%b/%Y:%H:%M:%S %z    
    Types code:integer size:integer

结果如下,
时间段29/Jul/2015:10:27:10 -0300被Time_Format给解析成时间
以timestamp1438176430呈现

Oct 12 23:55:23 nathan td-agent-bit[256618]: [0] demo: [1438176430.000000000, {"host"=>"192.168.2.20", "user"=>"-", "method"=>"GET", "path"=>"/cgi-bin/try/", "code"=>"200", "size"=>"3395"}]

成功的透过Regex Parser将flat log转成Structured Log

本日小结

官网其实还有提供LTSV, 但我没用过,
还有提供一些Decorder, 这些日後有机会在分享
但Regex在Parser这里真的非常非常非常地重要

---参考文件
strptime参考
Non-Capturing Groups
Fluentd - regexp
Rubular - Ruby regex editor
Calyptia - Regex

---新增自定义parser

IIS Log Parser

rubular
Regex key的命名规则

[PARSER]
    Name iislog
    Format regex
    Regex ^(?<time>[^ ]+ [^ ]+) (?<s_ip>[^ ]+) (?<cs_method>[^ ]+) (?<cs_uri_stem>[^ ]+) (?<cs_uri_query>[^ ]+) (?<s_port>[^ ]+) (?<cs_username>[^ ]+) (?<c_ip>[^ ]+) (?<user_agent>[^ ]+) (?<sc_status>[^ ]+) (?<sc_substatus>[^ ]+) (?<sc_win32_status>[^ ]+) (?<sc_bytes>[^ ]+) (?<cs_bytes>[^ ]+) (?<time_taken>[^ ]+)$
    Time_Key time
    Time_Format %Y-%m-%d %H:%M:%S

顺便也新增一组filter, 用上modify功能, 动态加上一组key_value

[FILTER]
    Name modify
    match IIS_*
    Add server serverid_1

看看结果, 这就是我要的XD
https://ithelp.ithome.com.tw/upload/images/20220311/20104930bgI0NkiaZH.png


<<:  Day28 Let's ODOO: ODOO.sh

>>:  认识强大的Python套件:Pandas(上)

Day 6 : 数学运算与逻辑判断

今天将会介绍程序中的数学运算,并且学习python的逻辑判断。 数学运算 Python也可以拿来当计...

Day14 - 【概念篇】OAuth flows: Implicit (Legacy)

本系列文之後也会置於个人网站 +----------+ | Resource | | Owner ...

[D05] 数位影像处理

在了解完基本的影像概念後,我们来看看实际操作时该用什麽套件、函式等等来处理程序会更加方便吧! 常用的...

[Day05] TS:如何把物件型别的所有属性值取出变成 union type?试试 Indexed Access Types

昨天我们知道可以使用 keyof 的方式取出物件属性 key,那麽如果我们是想要取出物件型别中属性值...

Day25 跟着官方文件学习Laravel-Service Container

Service Container 是管理类别依赖和执行依赖注入的一个容器。 官方文件告诉我们可以利...