The decode_netflow9 and decode_ipfix methods have rescue blocks that catch parsing errors and log a warning, but the return value of @logger.warn(...) (a LogStash::Logging::Logger object) becomes the method's return value.
The callers expect an array and call .each on the result:
decode_netflow9(flowset, record).each{|event| yield(event)}
This causes:
NoMethodError: undefined method `each' for #<LogStash::Logging::Logger:0x768fa52f>
Stack trace:
[ERROR][logstash.inputs.udp] Exception in inputworker
{"exception"=>#<NoMethodError: undefined method `each' for #<LogStash::Logging::Logger:0x768fa52f>>,
"backtrace"=>[
"/usr/share/logstash/vendor/bundle/jruby/3.1.0/gems/logstash-codec-netflow-4.3.2/lib/logstash/codecs/netflow.rb:100:in `block in decode'",
...
The same issue exists in decode_netflow5, though it manifests differently since the caller yields directly rather than iterating.
Impact: When a BinData::ValidityError or IOError occurs while parsing a record, the NoMethodError exits the flowset.records.each loop, and all remaining records in that packet are lost.
Solution
Remove the rescue blocks from decode_netflow5, decode_netflow9, and decode_ipfix. Add error handling inside the flowset.records.each loops in the decode method instead. This ensures:
- The error is logged
- Processing continues for remaining records in the flowset
The
decode_netflow9anddecode_ipfixmethods have rescue blocks that catch parsing errors and log a warning, but the return value of@logger.warn(...)(aLogStash::Logging::Loggerobject) becomes the method's return value.The callers expect an array and call
.eachon the result:This causes:
Stack trace:
The same issue exists in
decode_netflow5, though it manifests differently since the caller yields directly rather than iterating.Impact: When a
BinData::ValidityErrororIOErroroccurs while parsing a record, theNoMethodErrorexits theflowset.records.eachloop, and all remaining records in that packet are lost.Solution
Remove the rescue blocks from
decode_netflow5,decode_netflow9, anddecode_ipfix. Add error handling inside theflowset.records.eachloops in thedecodemethod instead. This ensures: