Logstash ruby filter hash class exception

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 as 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 it without the Hash class or not?

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.