require_relative '../helper' require 'fluent/plugin/filter_grep' require 'fluent/test/driver/filter' class GrepFilterTest < Test::Unit::TestCase include Fluent setup do Fluent::Test.setup @time = event_time end def create_driver(conf = '') Fluent::Test::Driver::Filter.new(Fluent::Plugin::GrepFilter).configure(conf) end sub_test_case 'configure' do test 'check default' do d = create_driver assert_empty(d.instance.regexps) assert_empty(d.instance.excludes) end test "regexpN can contain a space" do d = create_driver(%[regexp1 message foo]) d.instance._regexp_and_conditions.each { |value| assert_equal(Regexp.compile(/ foo/), value.pattern) } end test "excludeN can contain a space" do d = create_driver(%[exclude1 message foo]) d.instance._exclude_or_conditions.each { |value| assert_equal(Regexp.compile(/ foo/), value.pattern) } end sub_test_case "duplicate key" do test "flat" do conf = %[ regexp1 message test regexp2 message test2 ] assert_raise(Fluent::ConfigError) do create_driver(conf) end end test "section" do conf = %[ key message pattern test key message pattern test2 ] assert_raise(Fluent::ConfigError) do create_driver(conf) end end test "mix" do conf = %[ regexp1 message test key message pattern test ] assert_raise(Fluent::ConfigError) do create_driver(conf) end end test "and/regexp" do conf = %[ key message pattern test key message pattern test ] assert_raise(Fluent::ConfigError) do create_driver(conf) end end test "and/regexp, and/regexp" do conf = %[ key message pattern test key message pattern test ] assert_raise(Fluent::ConfigError) do create_driver(conf) end end test "regexp, and/regexp" do conf = %[ key message pattern test key message pattern test ] assert_raise(Fluent::ConfigError) do create_driver(conf) end end test "and/exclude" do conf = %[ key message pattern test key message pattern test ] assert_raise(Fluent::ConfigError) do create_driver(conf) end end test "and/exclude, and/exclude" do conf = %[ key message pattern test key message pattern test ] assert_raise(Fluent::ConfigError) do create_driver(conf) end end test "exclude, or/exclude" do conf = %[ key message pattern test key message pattern test ] assert_raise(Fluent::ConfigError) do create_driver(conf) end end end sub_test_case "pattern with slashes" do test "start with character classes" do conf = %[ key message pattern /[a-z]test/ key message pattern /[A-Z]test/ ] d = create_driver(conf) assert_equal(/[a-z]test/, d.instance.regexps.first.pattern) assert_equal(/[A-Z]test/, d.instance.excludes.first.pattern) end end sub_test_case "and/or section" do test " section cannot include both and " do conf = %[ key message pattern /test/ key level pattern /debug/ ] assert_raise(Fluent::ConfigError) do create_driver(conf) end end test " section cannot include both and " do conf = %[ key message pattern /test/ key level pattern /debug/ ] assert_raise(Fluent::ConfigError) do create_driver(conf) end end end end sub_test_case 'filter_stream' do def messages [ "2013/01/13T07:02:11.124202 INFO GET /ping", "2013/01/13T07:02:13.232645 WARN POST /auth", "2013/01/13T07:02:21.542145 WARN GET /favicon.ico", "2013/01/13T07:02:43.632145 WARN POST /login", ] end def filter(config, msgs) d = create_driver(config) d.run { msgs.each { |msg| d.feed("filter.test", @time, {'foo' => 'bar', 'message' => msg}) } } d.filtered_records end test 'empty config' do filtered_records = filter('', messages) assert_equal(4, filtered_records.size) end test 'regexpN' do filtered_records = filter('regexp1 message WARN', messages) assert_equal(3, filtered_records.size) assert_block('only WARN logs') do filtered_records.all? { |r| !r['message'].include?('INFO') } end end test 'excludeN' do filtered_records = filter('exclude1 message favicon', messages) assert_equal(3, filtered_records.size) assert_block('remove favicon logs') do filtered_records.all? { |r| !r['message'].include?('favicon') } end end test 'regexps' do conf = %[ key message pattern WARN ] filtered_records = filter(conf, messages) assert_equal(3, filtered_records.size) assert_block('only WARN logs') do filtered_records.all? { |r| !r['message'].include?('INFO') } end end test 'excludes' do conf = %[ key message pattern favicon ] filtered_records = filter(conf, messages) assert_equal(3, filtered_records.size) assert_block('remove favicon logs') do filtered_records.all? { |r| !r['message'].include?('favicon') } end end sub_test_case 'with invalid sequence' do def messages [ "\xff".force_encoding('UTF-8'), ] end test "don't raise an exception" do assert_nothing_raised { filter(%[regexp1 message WARN], ["\xff".force_encoding('UTF-8')]) } end end sub_test_case "and/or section" do def records [ { "time" => "2013/01/13T07:02:11.124202", "level" => "INFO", "method" => "GET", "path" => "/ping" }, { "time" => "2013/01/13T07:02:13.232645", "level" => "WARN", "method" => "POST", "path" => "/auth" }, { "time" => "2013/01/13T07:02:21.542145", "level" => "WARN", "method" => "GET", "path" => "/favicon.ico" }, { "time" => "2013/01/13T07:02:43.632145", "level" => "WARN", "method" => "POST", "path" => "/login" }, ] end def filter(conf, records) d = create_driver(conf) d.run do records.each do |record| d.feed("filter.test", @time, record) end end d.filtered_records end test "basic and/regexp" do conf = %[ key level pattern ^INFO$ key method pattern ^GET$ ] filtered_records = filter(conf, records) assert_equal(records.values_at(0), filtered_records) end test "basic or/exclude" do conf = %[ key level pattern ^INFO$ key method pattern ^GET$ ] filtered_records = filter(conf, records) assert_equal(records.values_at(1, 3), filtered_records) end test "basic or/regexp" do conf = %[ key level pattern ^INFO$ key method pattern ^GET$ ] filtered_records = filter(conf, records) assert_equal(records.values_at(0, 2), filtered_records) end test "basic and/exclude" do conf = %[ key level pattern ^INFO$ key method pattern ^GET$ ] filtered_records = filter(conf, records) assert_equal(records.values_at(1, 2, 3), filtered_records) end sub_test_case "and/or combo" do def records [ { "time" => "2013/01/13T07:02:11.124202", "level" => "INFO", "method" => "GET", "path" => "/ping" }, { "time" => "2013/01/13T07:02:13.232645", "level" => "WARN", "method" => "POST", "path" => "/auth" }, { "time" => "2013/01/13T07:02:21.542145", "level" => "WARN", "method" => "GET", "path" => "/favicon.ico" }, { "time" => "2013/01/13T07:02:43.632145", "level" => "WARN", "method" => "POST", "path" => "/login" }, { "time" => "2013/01/13T07:02:44.959307", "level" => "ERROR", "method" => "POST", "path" => "/login" }, { "time" => "2013/01/13T07:02:45.444992", "level" => "ERROR", "method" => "GET", "path" => "/ping" }, { "time" => "2013/01/13T07:02:51.247941", "level" => "WARN", "method" => "GET", "path" => "/info" }, { "time" => "2013/01/13T07:02:53.108366", "level" => "WARN", "method" => "POST", "path" => "/ban" }, ] end test "and/regexp, or/exclude" do conf = %[ key level pattern ^ERROR|WARN$ key method pattern ^GET|POST$ key level pattern ^WARN$ key method pattern ^GET$ ] filtered_records = filter(conf, records) assert_equal(records.values_at(4), filtered_records) end test "and/regexp, and/exclude" do conf = %[ key level pattern ^ERROR|WARN$ key method pattern ^GET|POST$ key level pattern ^WARN$ key method pattern ^GET$ ] filtered_records = filter(conf, records) assert_equal(records.values_at(1, 3, 4, 5, 7), filtered_records) end test "or/regexp, and/exclude" do conf = %[ key level pattern ^ERROR|WARN$ key method pattern ^GET|POST$ key level pattern ^WARN$ key method pattern ^GET$ ] filtered_records = filter(conf, records) assert_equal(records.values_at(0, 1, 3, 4, 5, 7), filtered_records) end test "or/regexp, or/exclude" do conf = %[ key level pattern ^ERROR|WARN$ key method pattern ^GET|POST$ key level pattern ^WARN$ key method pattern ^GET$ ] filtered_records = filter(conf, records) assert_equal(records.values_at(4), filtered_records) end test "regexp, and/regexp" do conf = %[ key level pattern ^ERROR|WARN$ key method pattern ^GET|POST$ key path pattern ^/login$ ] filtered_records = filter(conf, records) assert_equal(records.values_at(3, 4), filtered_records) end test "regexp, or/exclude" do conf = %[ key level pattern ^ERROR|WARN$ key method pattern ^GET|POST$ key level pattern ^WARN$ key method pattern ^GET$ ] filtered_records = filter(conf, records) assert_equal(records.values_at(4), filtered_records) end test "regexp, and/exclude" do conf = %[ key level pattern ^ERROR|WARN$ key method pattern ^GET|POST$ key level pattern ^WARN$ key method pattern ^GET$ ] filtered_records = filter(conf, records) assert_equal(records.values_at(1, 3, 4, 5, 7), filtered_records) end end end end sub_test_case 'nested keys' do def messages [ {"nest1" => {"nest2" => "INFO"}}, {"nest1" => {"nest2" => "WARN"}}, {"nest1" => {"nest2" => "WARN"}} ] end def filter(config, msgs) d = create_driver(config) d.run { msgs.each { |msg| d.feed("filter.test", @time, {'foo' => 'bar', 'message' => msg}) } } d.filtered_records end test 'regexps' do conf = %[ key $.message.nest1.nest2 pattern WARN ] filtered_records = filter(conf, messages) assert_equal(2, filtered_records.size) assert_block('only 2 nested logs') do filtered_records.all? { |r| r['message']['nest1']['nest2'] == 'WARN' } end end test 'excludes' do conf = %[ key $.message.nest1.nest2 pattern WARN ] filtered_records = filter(conf, messages) assert_equal(1, filtered_records.size) assert_block('only 2 nested logs') do filtered_records.all? { |r| r['message']['nest1']['nest2'] == 'INFO' } end end end sub_test_case 'grep non-string jsonable values' do def filter(msg, config = 'regexp1 message 0') d = create_driver(config) d.run do d.feed("filter.test", @time, {'foo' => 'bar', 'message' => msg}) end d.filtered_records end data( 'array' => ["0"], 'hash' => ["0" => "0"], 'integer' => 0, 'float' => 0.1) test "value" do |data| filtered_records = filter(data) assert_equal(1, filtered_records.size) end test "value boolean" do filtered_records = filter(true, %[regexp1 message true]) assert_equal(1, filtered_records.size) end end end