【问题标题】:Manipulating JSON messages from Kafka topic using Logstash filter使用 Logstash 过滤器处理来自 Kafka 主题的 JSON 消息
【发布时间】:2017-03-01 02:12:44
【问题描述】:

我正在使用 Logstash 2.4 从 Kafka 主题读取 JSON 消息并将它们发送到 Elasticsearch 索引。

JSON格式如下--

{
   "schema":
             {
            "type": "struct",
        "fields": [
                    {
                   "type":"string",
                   "optional":false,
                   "field":"reloadID"
                },
                {
                   "type":"string",
                   "optional":false,
                   "field":"externalAccountID"
                },
                {
                   "type":"int64",
                   "optional":false,
                   "name":"org.apache.kafka.connect.data.Timestamp",
                   "version":1,
                   "field":"reloadDate"
                },
                {
                   "type":"int32",
                   "optional":false,
                   "field":"reloadAmount"
                },
                {
                   "type":"string",
                   "optional":true,
                   "field":"reloadChannel"
                }
              ],
        "optional":false,
        "name":"reload"
         },
   "payload":
             {
            "reloadID":"328424295",
        "externalAccountID":"9831200013",
        "reloadDate":1446242463000,
        "reloadAmount":240,
        "reloadChannel":"C1"
         }
}

在我的配置文件中没有任何过滤器,来自 ES 索引的目标文档如下所示--

{
  "_index" : "kafka_reloads",
  "_type" : "logs",
  "_id" : "AVfcyTU4SyCFNFP2z5-l",
  "_score" : 1.0,
  "_source" : {
    "schema" : {
      "type" : "struct",
      "fields" : [ {
        "type" : "string",
        "optional" : false,
        "field" : "reloadID"
      }, {
        "type" : "string",
        "optional" : false,
        "field" : "externalAccountID"
      }, {
        "type" : "int64",
        "optional" : false,
        "name" : "org.apache.kafka.connect.data.Timestamp",
        "version" : 1,
        "field" : "reloadDate"
      }, {
        "type" : "int32",
        "optional" : false,
        "field" : "reloadAmount"
      }, {
        "type" : "string",
        "optional" : true,
        "field" : "reloadChannel"
      } ],
      "optional" : false,
      "name" : "reload"
    },
    "payload" : {
      "reloadID" : "155559213",
      "externalAccountID" : "9831200014",
      "reloadDate" : 1449529746000,
      "reloadAmount" : 140,
      "reloadChannel" : "C1"
    },
    "@version" : "1",
    "@timestamp" : "2016-10-19T11:56:09.973Z",
  }
}

但是,我只希望“有效负载”字段的值部分作为目标 JSON 正文移动到我的 ES 索引。所以我尝试在配置文件中使用'mutate'过滤器,如下所示--

input {
   kafka {
            zk_connect => "zksrv-1:2181,zksrv-2:2181,zksrv-4:2181"
            group_id => "logstash"
            topic_id => "reload"
            consumer_threads => 3
   }
}
filter {
  mutate {
     remove_field => [ "schema","@version","@timestamp" ]
  }
}
output {
   elasticsearch {
                    hosts => ["datanode-6:9200","datanode-2:9200"]
                    index => "kafka_reloads"
   }
}

使用此过滤器,ES 文档现在如下所示 --

{
      "_index" : "kafka_reloads",
      "_type" : "logs",
      "_id" : "AVfch0yhSyCFNFP2z59f",
      "_score" : 1.0,
      "_source" : {
        "payload" : {
          "reloadID" : "850846698",
          "externalAccountID" : "9831200013",
          "reloadDate" : 1449356706000,
          "reloadAmount" : 30,
          "reloadChannel" : "C1"
        }
      }
}

但实际上应该是下图——

{
      "_index" : "kafka_reloads",
      "_type" : "logs",
      "_id" : "AVfch0yhSyCFNFP2z59f",
      "_score" : 1.0,
      "_source" : {
          "reloadID" : "850846698",
          "externalAccountID" : "9831200013",
          "reloadDate" : 1449356706000,
          "reloadAmount" : 30,
          "reloadChannel" : "C1"
      }
}

有没有办法做到这一点?谁能帮我解决这个问题?

我也试过下面的过滤器——

filter {
   json {
      source => "payload"
   }
}

但这给了我这样的错误——

解析 json 时出错 {:source=>"payload", :raw=>{"reloadID"=>"572584696", "externalAccountID"=>"9831200011", "reloadDate"=>1449093851000, "reloadAmount"=> 180, "reloadChannel"=>"C1"}, :exception=>java.lang.ClassCastException: org.jruby.RubyHash 不能转换为 org.jruby.RubyIO, :level=>:warn}

任何帮助将不胜感激。

谢谢 高塔姆·戈什

【问题讨论】:

    标签: json elasticsearch filter apache-kafka logstash


    【解决方案1】:

    您可以使用以下ruby 过滤器实现您想要的:

      ruby {
         code => "
            event.to_hash.delete_if {|k, v| k != 'payload'}
            event.to_hash.update(event['payload'].to_hash)
            event.to_hash.delete_if {|k, v| k == 'payload'}
         "
      }
    

    它的作用是:

    1. 删除除payload 之外的所有字段
    2. 在根级别复制所有payload 内部字段
    3. 删除payload 字段本身

    你最终会得到你需要的东西。

    【讨论】:

    • 太棒了!!效果很好..非常感谢哥们!!
    • 太棒了,很高兴它有帮助!
    • 好东西,谢谢@Val。这对使用 Oracle GoldenGate -> Kafka -> Logstash -> 的任何人都有很大用处
    • @RobinMoffatt 如果这对您有用,我很高兴。由于我一直在多个上下文中使用此代码,因此我正在考虑从中创建一个 logstash 过滤器。每当我这样做时,我都会更新此线程。我只是还不知道怎么称呼它。有什么想法吗?
    • 或者我可以简单地用另一个extract 操作修改现有的mutate 过滤器。虽然不确定该操作的名称...
    【解决方案2】:

    已经有一段时间了,但是here 有一个有效的解决方法,希望它有用。

    json_encode {
      source => "json"
      target => "json_string"
    }
    
    json {
      source => "json_string"
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-15
    • 1970-01-01
    • 2021-02-05
    • 1970-01-01
    相关资源
    最近更新 更多