Reputation: 21
I tried to get the difference between these two JSON objects coming from JDBC in Logstash.
example JDBC JSON:
before = '{"heroes":[{"id":1,"name":"pudge"},{"id":2,"name":"slark"},{"id":3,"name":"techies"}]}'
after = '{"heroes":[{"id":1,"name":"pudge"},{"id":2,"name":"slark"},{"id":3,"name":"invoker"}]}'
but I'm getting this error:
[ERROR][logstash.filters.ruby][main][88122xx6957217be6831d4e0f72ec6a5e9ec4dccc693227d1256f06b0d14bad03] Ruby exception occurred: undefined method `deep_diff' for #<Hash:0x5480e379> {:class=>"NoMethodError", :backtrace=>["(ruby filter code):30:in `block in filter_method'", "/usr/share/logstash/vendor/bundle/jruby/2.6.0/gems/logstash-filter-ruby-3.1.8/lib/logstash/filters/ruby.rb:96:in `inline_script'", "/usr/share/logstash/vendor/bundle/jruby/2.6.0/gems/logstash-filter-ruby-3.1.8/lib/logstash/filters/ruby.rb:89:in `filter'", "/usr/share/logstash/logstash-core/lib/logstash/filters/base.rb:159:in `do_filter'", "/usr/share/logstash/logstash-core/lib/logstash/filters/base.rb:178:in `block in multi_filter'", "org/jruby/RubyArray.java:1865:in `each'", "/usr/share/logstash/logstash-core/lib/logstash/filters/base.rb:175:in `multi_filter'", "org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java:134:in `multi_filter'", "/usr/share/logstash/logstash-core/lib/logstash/java_pipeline.rb:300:in `block in start_workers'"]}
my Logstash .conf file:
input {
jdbc {
jdbc_driver_library => "/etc/elasticsearch-jdbc-2.3.4.1/lib/mysql-connector-java-5.1.38.jar"
jdbc_driver_class => "com.mysql.jdbc.Driver"
jdbc_connection_string => "foo"
jdbc_user => "bar"
jdbc_password => "foo"
schedule => "*/5 * * * *"
statement => "SELECT * FROM foo WHERE id > :sql_last_value LIMIT 1000"
use_column_value => true
tracking_column => "id"
last_run_metadata_path => ".../configs/foo-jdbc-int-sql_last_value.yml"
clean_run => false
type => "foo"
}
}
filter {
ruby {
code => '
require "json"
class Hash
def deep_diff(other)
(self.keys | other.keys).inject({}) do |diff, key|
next diff if self[key] == other[key]
if self[key].is_a?(Hash) && other[key].is_a?(Hash)
diff[key] = self[key].deep_diff(other[key])
else
diff[key] = [self[key], other[key]]
end
diff
end
end
end
before = event.get("before")
after = event.get("after")
if before.nil? || after.nil? || before.empty? || after.empty?
event.set("before_after_diff", nil)
else
hash1 = JSON.parse(before)
hash2 = JSON.parse(after)
diff = hash1.deep_diff(hash2)
event.set("before_after_diff", diff.to_json)
'
}
}
output {
elasticsearch {
# ...
}
}
If I use the Hash class in ruby compilers like I mentioned, it works. But it doesn't work in Logstash.
for example if I delete the Hash class in Logstash .conf filter scope and I use only function, like:
def deep_diff(hash1, hash2)
(hash1.keys | hash2.keys).inject({}) do |diff, key|
next diff if hash1[key] == hash2[key]
if hash1[key].is_a?(Hash) && hash2[key].is_a?(Hash)
diff[key] = deep_diff(hash1[key], hash2[key])
else
diff[key] = [hash1[key], hash2[key]]
end
diff
end
end
diff = deep_diff(hash1, hash2)
it works!
Is this normal? Should I use without Hash class or not?
example code working in Ruby compilers:
require 'json'
class Hash
def deep_diff(other)
(keys | other.keys).each_with_object({}) do |key, diff|
next diff if self[key] == other[key]
diff[key] = if self[key].is_a?(Hash) && other[key].is_a?(Hash)
self[key].deep_diff(other[key])
else
[self[key], other[key]]
end
end
end
end
before = '{"heroes":[{"id":1,"name":"pudge"},{"id":2,"name":"slark"},{"id":3,"name":"techies"}]}'
after = '{"heroes":[{"id":1,"name":"pudge"},{"id":2,"name":"slark"},{"id":3,"name":"invoker"}]}'
if before.nil? || after.nil? || before.empty? || after.empty?
return
else
hash1 = JSON.parse(before)
hash2 = JSON.parse(after)
diff = hash1.deep_diff(hash2)
puts diff.to_json
end
Upvotes: 1
Views: 152