logstash-plugins/logstash-input-beats

If the input event contains nested JSON in the "message" field, it gets converted to a string

andrei-kalach opened this issue · 0 comments

  • Logstash version 8.0.0, built from source
  • logstash-input-beats Plugin 6.1.5, built from source

We are ingesting JSON log files with FileBeat and are forwarding them to a LogStash Instance.

The FileBeat configuration is trivial:

filebeat.inputs:
- type: log
  enabled: true
  json.keys_under_root: true
  json.add_error_key: true
  paths:
    - C:\Samples\*

In LogStash a FileBeat input is configured with the default plain codec:

input { beats { port => 5044 } }

In JSON documents in log files the "message" field contains a nested JSON, example:

{"thread": "http-nio-127.0.0.1-10080-exec-1", "level": "INFO", "message": {"mykey": "panel2", "duration": 92, "user": "anonym"}, "loggerFqcn": "org.apache.logging.log4j.spi.AbstractLogger", "contextMap": {"APP": "Racy10", "BROWSER": "curl/7.58.0"},"timestamp": "2021-06-11T15:25:08.842+0200"}

We are expecting that the "message" will be available as a Hash in LogStash for filtering / transformation, but in reality it comes in LogStash as a string representation of a Ruby Hash and cannot be processed as JSON:
{"user"=>"anonym", "mykey"=>"panel2", "duration"=>92}

The cause seems to be here: https://github.com/logstash-plugins/logstash-input-beats/blob/master/lib/logstash/inputs/beats/message_listener.rb#L184

        hash.delete(FILEBEAT_LOG_LINE_FIELD).to_s

The target field ("message") is extracted here from the input event and converted to a string.

The problem can be easily reproduced with tests, in spec/inputs/beats/message_listener_spec.rb add following test and run it:

    context "when the message contains nested JSON" do
      let(:message) { MockMessage.new("abc", { "message" => Hash["a" => "test", "b" => 200], "@metadata" => {} }) }

      it "extract the event" do
        subject.onNewMessage(ctx, message)
        event = queue.pop
        expect(event.get("message")).to eq(Hash["a" => "test", "b" => 200])
      end
    end

The test fails than with the error:

bundle exec rspec spec/inputs/beats/message_listener_spec.rb

...

   ←[31m  expected: {"a"=>"test", "b"=>200}←[0m
     ←[31m       got: "{\"a\"=>\"test\", \"b\"=>200}"←[0m