Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use Event#from_json if available #19

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 2.1.0
- Backward compatible support for `Event#from_json` method https://github.com/logstash-plugins/logstash-codec-json_lines/pull/19

## 2.0.5
- Directly use buftok to avoid indirection through the line codec https://github.com/logstash-plugins/logstash-codec-json_lines/pull/18

Expand Down
28 changes: 18 additions & 10 deletions lib/logstash/codecs/json_lines.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,34 @@ def register
@converter.logger = @logger
end

def decode(data)
def decode(data, &block)
@buffer.extract(data).each do |line|
yield guard(@converter.convert(line))
parse(@converter.convert(line), &block)
end
end # def decode
end

def encode(event)
# Tack on a @delimiter for now because previously most of logstash's JSON
# outputs emitted one per line, and whitespace is OK in json.
@on_event.call(event, "#{event.to_json}#{@delimiter}")
end # def encode
end

private

def guard(data)
begin
LogStash::Event.new(LogStash::Json.load(data))
rescue LogStash::Json::ParserError => e
LogStash::Event.new("message" => data, "tags" => ["_jsonparsefailure"])
end
# from_json_parse uses the Event#from_json method to deserialize and directly produce events
def from_json_parse(json, &block)
LogStash::Event.from_json(json).each { |event| yield event }
rescue LogStash::Json::ParserError
yield LogStash::Event.new("message" => json, "tags" => ["_jsonparsefailure"])
end

# legacy_parse uses the LogStash::Json class to deserialize json
def legacy_parse(json, &block)
yield LogStash::Event.new(LogStash::Json.load(json))
rescue LogStash::Json::ParserError
yield LogStash::Event.new("message" => json, "tags" => ["_jsonparsefailure"])
end

alias_method :parse, LogStash::Event.respond_to?(:from_json) ? :from_json_parse : :legacy_parse

end # class LogStash::Codecs::JSONLines
4 changes: 2 additions & 2 deletions logstash-codec-json_lines.gemspec
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
Gem::Specification.new do |s|

s.name = 'logstash-codec-json_lines'
s.version = '2.0.5'
s.version = '2.1.0'
s.licenses = ['Apache License (2.0)']
s.summary = "This codec will decode streamed JSON that is newline delimited."
s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
s.authors = ["Elastic"]
s.email = 'info@elastic.co'
s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
s.require_paths = ["lib"]
s.require_paths = ["lib"]

# Files
s.files = Dir['lib/**/*','spec/**/*','*.gemspec','*.md','CONTRIBUTORS','Gemfile','LICENSE','NOTICE.TXT']
Expand Down
46 changes: 37 additions & 9 deletions spec/codecs/json_lines_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
require "insist"

describe LogStash::Codecs::JSONLines do
subject do
next LogStash::Codecs::JSONLines.new
end

let(:codec_options) { {} }

shared_examples :codec do

context "#decode" do
it "should return an event from json data" do
Expand Down Expand Up @@ -37,9 +38,7 @@
context "when using custom delimiter" do
let(:delimiter) { "|" }
let(:line) { "{\"hey\":1}|{\"hey\":2}|{\"hey\":3}|" }
subject do
next LogStash::Codecs::JSONLines.new("delimiter" => delimiter)
end
let(:codec_options) { { "delimiter" => delimiter } }

it "should decode multiple lines separated by the delimiter" do
result = []
Expand Down Expand Up @@ -122,9 +121,7 @@

context "when using custom delimiter" do
let(:delimiter) { "|" }
subject do
next LogStash::Codecs::JSONLines.new("delimiter" => delimiter)
end
let(:codec_options) { { "delimiter" => delimiter } }

it "should decode multiple lines separated by the delimiter" do
subject.on_event do |e, d|
Expand Down Expand Up @@ -170,4 +167,35 @@
expect(collector.last['field']).to eq('value2')
end
end

end

context "forcing legacy parsing" do
it_behaves_like :codec do
subject do
# register method is called in the constructor
LogStash::Codecs::JSONLines.new(codec_options)
end

before(:each) do
# stub codec parse method to force use of the legacy parser.
# this is very implementation specific but I am not sure how
# this can be tested otherwise.
allow(subject).to receive(:parse) do |line, &block|
subject.send(:legacy_parse, line, &block)
end
end
end
end

context "default parser choice" do
# here we cannot force the use of the Event#from_json since if this test is run in the
# legacy context (no Java Event) it will fail but if in the new context, it will be picked up.
it_behaves_like :codec do
subject do
# register method is called in the constructor
LogStash::Codecs::JSONLines.new(codec_options)
end
end
end
end