Testing MultilineParser Log Format Handling in Fluentd
This test suite validates the MultilineParser plugin functionality in Fluentd, focusing on parsing multi-line log entries with configurable patterns. It ensures robust handling of various log formats and configuration scenarios.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
fluent/fluentd
test/plugin/test_parser_multiline.rb
require_relative '../helper'
require 'fluent/test/driver/parser'
require 'fluent/plugin/parser'
class MultilineParserTest < ::Test::Unit::TestCase
def setup
Fluent::Test.setup
end
def create_parser(conf)
parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::MultilineParser).configure(conf)
parser
end
def test_configure_with_invalid_params
[{'format100' => '/(?<msg>.*)/'}, {'format1' => '/(?<msg>.*)/', 'format3' => '/(?<msg>.*)/'}, 'format1' => '/(?<msg>.*)'].each { |config|
assert_raise(Fluent::ConfigError) {
create_parser(config)
}
}
end
def test_parse
parser = create_parser('format1' => '/^(?<time>\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}) \[(?<thread>.*)\] (?<level>[^\s]+)(?<message>.*)/')
parser.instance.parse(<<EOS.chomp) { |time, record|
2013-3-03 14:27:33 [main] ERROR Main - Exception
javax.management.RuntimeErrorException: null
\tat Main.main(Main.java:16) ~[bin/:na]
EOS
assert_equal(event_time('2013-3-03 14:27:33').to_i, time)
assert_equal({
"thread" => "main",
"level" => "ERROR",
"message" => " Main - Exception\njavax.management.RuntimeErrorException: null\n\tat Main.main(Main.java:16) ~[bin/:na]"
}, record)
}
end
def test_parse_with_firstline
parser = create_parser('format_firstline' => '/----/', 'format1' => '/time=(?<time>\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}).*message=(?<message>.*)/')
parser.instance.parse(<<EOS.chomp) { |time, record|
----
time=2013-3-03 14:27:33
message=test1
EOS
assert(parser.instance.firstline?('----'))
assert_equal(event_time('2013-3-03 14:27:33').to_i, time)
assert_equal({"message" => "test1"}, record)
}
end
def test_parse_with_multiple_formats
parser = create_parser('format_firstline' => '/^Started/',
'format1' => '/Started (?<method>[^ ]+) "(?<path>[^"]+)" for (?<host>[^ ]+) at (?<time>[^ ]+ [^ ]+ [^ ]+)\n/',
'format2' => '/Processing by (?<controller>[^\u0023]+)\u0023(?<controller_method>[^ ]+) as (?<format>[^ ]+?)\n/',
'format3' => '/( Parameters: (?<parameters>[^ ]+)\n)?/',
'format4' => '/ Rendered (?<template>[^ ]+) within (?<layout>.+) \([\d\.]+ms\)\n/',
'format5' => '/Completed (?<code>[^ ]+) [^ ]+ in (?<runtime>[\d\.]+)ms \(Views: (?<view_runtime>[\d\.]+)ms \| ActiveRecord: (?<ar_runtime>[\d\.]+)ms\)/'
)
parser.instance.parse(<<EOS.chomp) { |time, record|
Started GET "/users/123/" for 127.0.0.1 at 2013-06-14 12:00:11 +0900
Processing by UsersController#show as HTML
Parameters: {"user_id"=>"123"}
Rendered users/show.html.erb within layouts/application (0.3ms)
Completed 200 OK in 4ms (Views: 3.2ms | ActiveRecord: 0.0ms)
EOS
assert(parser.instance.firstline?('Started GET "/users/123/" for 127.0.0.1...'))
assert_equal(event_time('2013-06-14 12:00:11 +0900').to_i, time)
assert_equal({
"method" => "GET",
"path" => "/users/123/",
"host" => "127.0.0.1",
"controller" => "UsersController",
"controller_method" => "show",
"format" => "HTML",
"parameters" => "{\"user_id\"=>\"123\"}",
"template" => "users/show.html.erb",
"layout" => "layouts/application",
"code" => "200",
"runtime" => "4",
"view_runtime" => "3.2",
"ar_runtime" => "0.0"
}, record)
}
end
def test_parse_with_keep_time_key
parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::MultilineParser).configure(
'format1' => '/^(?<time>\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2})/',
'keep_time_key' => 'true'
)
text = '2013-3-03 14:27:33'
parser.instance.parse(text) { |time, record|
assert_equal text, record['time']
}
end
def test_parse_unmatched_lines
parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::MultilineParser).configure(
'format1' => '/^message (?<message_id>\d)/',
'unmatched_lines' => true,
)
text = "message 1\nmessage a"
r = []
parser.instance.parse(text) { |_, record| r << record }
assert_equal [{ 'message_id' => '1' }, { 'unmatched_line' => 'message a'}], r
end
end