将压缩的字节串从protobuf转换为通过logstash格式化

时间:2017-12-12 10:46:39

标签: ruby elasticsearch logstash

我有一个protobuf,我试图通过logstash提供。有些值看起来是二进制格式的:

通过rubydebug编解码器

打印时

我得到的价值如下:

rData => '\xD8:\xC9$'

这似乎是因为protobuf模板有:

optional :bytes, :rData, 5

其中......在锡上执行的操作 - 将原始字节传递给logstash,后者假定它们是文本。

因此,rData行将解码为216.58.201.36,这是www.google.com的响应。

如何在弹力搜索中将其转换为有用的格式?

1 个答案:

答案 0 :(得分:0)

为了实现这一目标,你需要自己写一点红宝石。

但不要担心,它比听起来容易,你可以将ruby内联到logstash配置文件中。

首先:

  • 将输出编解码器设置为rubydebug,以便打印数据结构 - 您需要这样来识别您想要的字段。

所以对于我的例子(为了简洁起见):

我们对rData字段感兴趣。

"socketProtocol" => 1,
    "@timestamp" => 2017-12-12T10:26:41.910Z,
   "requestorId" => "",
          "port" => 47788,
      "response" => {
            "rcode" => 0,
              "rrs" => [
        [0] {
             "rType" => 1,
             "rData" => "\xD8:\xC9$",
            "rClass" => 1,
             "rName" => "www.google.com.",
              "rTtl" => 300
        }
    ],

我们还有一些较长rData字段的示例,其中rubydebug中的值为:

"rData" => "*\x00\x14P@\t\b\v\x00\x00\x00\x00\x00\x00 \x04",

最终将其呈现为Elasticsearch:

"rData": "*\u0000\u0014P@\t\b\u000b\u0000\u0000\u0000\u0000\u0000\u0000 \u0004",

因此,我们使用event.get("response")提取此内容,以便我们可以测试存在(必要时,因为在我的用例中会有response字段没有数据):

filter {
  if [response] {
    ruby {
      code => 

        # response rData can be a different things.
        #usually an ipV4 address, or an ipv6. 
        #But they're usually written in different formats - ipv4 is dotted quads,
        #where ipv6 is hex and double-bytes
        #so we look at the (unpacked) string length, and see if there are 4 (or more) 'uint64s' in there. 
        #and substitute accordingly. 
        '
        response = event.get("response")
        if ( response and response["rrs"] and response["rrs"][0] and response["rrs"][0]["rData"] ) 
           rdata = response["rrs"][0]["rData"]
           hex_value = rdata.unpack("H*").join("")
           ip_value =  rdata.unpack("C4").join(".")
           length_rdata =    rdata.unpack("L*").length
           if ( length_rdata >= 4 ) 
             event.set("[response][decoded_rdata]", hex_value )
           else
             event.set("[response][decoded_rdata]", ip_value) 
           end
        end
       '
    }
  }
} 

注意 - 这会测试rData值的长度,如果长度超过"然后假设它是一个ipv6地址并格式化为十六进制,如果它是短的,则假设它的ipv4和格式为传统的“点缀”和#39;四。

然后它添加到一个新的子域response.decoded_rdata,这可能对弹性搜索更有用,而不是嵌套更深。

我们还有一个额外的代码片段来处理'字节' from / to / messageId字段的编码大致相似:

  ruby {
    code =>  
       #take to and from fields, and assume they're packed IP addresses. 
       #take messageId and convert to hex. 
       'event.set("from", event.get("from").unpack("C4").join("."));
        event.set("to", event.get("to").unpack("C4").join("."));
        event.set("messageId", event.get("messageId").unpack("H*").join(""));
       '
  }