IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Rsyslog 的 mmnormalize 模块用法

    陈子 (rao.chenlin@gmail.com)发表于 2015-11-25 00:00:00
    love 0

    mmnormalize 是 Rsyslog 内置的一种数据解析的方案,甚至有自己的官网:http://www.liblognorm.com可以阅读相关用法细节。它既不像 Rsyslog 的 rainerscript 那样采用 ERE 类型的简单正则,也不像 Logstash的 Grok 那样采用 PCRE 类型的复杂正则(一度通过添加 regex parser 引入过 PCRE,后来又删了),而是自己设计了一套方式,其最核心的匹配语法就是 %char-to: 这种“向后匹配直到*为止”。下面是一段解析 nginx 访问日志的 mmnormalize 配置,相信大家第一眼看上去都会晕:

    rule=:"%client_ip:char-to:"%" %tcp_peer_ip:ipv4% - [%req_time:char-to:]%] "%verb:word% %url:word% %protocol:char-to:"%" %status:interpret:int:number% %latency:interpret:float:word% %bytes_sent:interpret:int:number% "%referrer:char-to:"%" "%user_agent:char-to:"%" %upstream_addrs:tokenized:, :tokenized: \x3a :regex:[^ ,]+% %upstream_response_times:tokenized:, :tokenized: \x3a :interpret:float:regex:[^ ,]+% %pipe:word% \t %host:word% cache_%cache:word%
    

    不过上个月 liblognorm 做了一次重大版本更新,新的 v2 语法,添加了一个 user-defined types 的设计,这就有点类似 Grok 的预定义正则的意思啦。

    所以,本文来详细说说,从 v1.1.0 开始,新增的一些 liblognorm 的 type 给我们处理 Rsyslog 数据带来的便利。

    normalize 的匹配规则叫做 rulebase,所以可以看到有些 rsyslog 介绍中,mmnormallize 配置文件的后缀名是 *.rb,可不要以为是用 Ruby 解析啊。

    version=2
    type=@TIMESTAMP:%date:date-iso% %time:time-24hr%Z
    type=@TIMESTAMP:%datetime:date-rfc5424%
    type=@TIME:%resptime:float%
    type=@TIME:-
    rule=:%timestamp:@TIMESTAMP% %clientip:ipv4% %resptime:@TIME% %urlpath:string% %reqbody:json% %referer:quoted-string%
    
    

    这行 rule 在 v2 中还可以写的更美观一些:

    rule=:%[ {"type":"@TIMESTAMP", "name":"timestamp"},
             {"type":"literal", "text:" "},
             {"type":"ipv4", "name":"clientip"},
             {"type":"literal", "text:" "},
             {"type":"@TIME", "name":"resptime"},
             {"type":"literal", "text:" "},
             {"type":"string", "name":"urlpath"},
             {"type":"literal", "text:" "},
             {"type":"quoted-string", "name":"referer"},
             {"type":"literal", "text:" "},
             {"type":"json", "name":"reqbody"}
           ]%
    

    Rsyslog 的 mmjsonparse 模块只能解析 CEE 格式,如果 msg 本身是纯 JSON 的,反而不能解析,这时候就可以用上 mmnormalize 的 json parser 了。

    和 json 一样也是 v1.1 以后才加入的,还有 char-sep 和 rest,char-sep 和 char-to 的区别是前者是0到多个,后者是1到多个;rest 则用来收集当前位置到本行结尾的全部数据。

    也就是说:%capturename:char-sep:\x20 等于 %capturename:char-sep: % 等于 %{"type":"char-sep","name":"capturename","extradata":" "}% 等于 %capturename:char-sep{"extradata":" "}。相当于 Grok 里的 [^ ]*?。其他类似。

    如果觉得上面那种预定义太麻烦,毕竟响应时间无非就是数值或者横杆而已,那么这行还可以这么写:

             {"type":"alternative",
              "parser": [
                {"name":"resptime", "type":"float"},
                {"type":"literal", "text":"-"}
              ]
             }
    

    还有类似 logstash-filter-kv 插件的功能,比如把

    a:2,b:4, c:6, d:8
    

    这段数据做切割处理的配置:

    %{"name":"obj", "type":"repeat",
      "parser":[
        {"type":"string", "name":"key"},
        {"type":"literal", "text":":"},
        {"type":"number", "name":"val"}
      ],
      "while": {
        "type":"alternative", "parser": [
          {"type":"literal", "text":", "},
          {"type":"literal", "text":","}
        ]
      } 
    }%
    

    会解析得到下面这样的 JSON 结果:

    { "obj": [
        { "val": "2", "key": "a" },
        { "val": "4", "key": "b" },
        { "val": "6", "key": "c" },
        { "val": "8", "key": "d" }
      ]
    }
    

    看起来似乎不是很 kv 的样子,不过对于写入 Elasticsearch 来说,却刚刚好符合 nested object 的设计!

    不过目前,还有些匹配模式在 v2 中不支持的,还得继续使用 v1 模式:

    rule=:%filesize:interpert:float:number%
    

    有时候,明明你这个数据中是整形,但是因为 ES 的 mapping 问题或者其他原因,需要强制转换成浮点型。Rsyslog 本身的 rainerscript 只提供了 cnum() 函数,没有 cfloat(),那么我们只能在 mmnormalize 里做 interpert 转换了。而这个操作目前在 v2 版本中还不支持。

    目前 liblognorm 所支持的所有匹配格式说明,见https://github.com/rsyslog/liblognorm/blob/master/doc/configuration.rst



沪ICP备19023445号-2号
友情链接