require 'fluent/test' require 'fluent/parser' require 'fluent/plugin/parser_grok' require 'tempfile' include Fluent def str2time(str_time, format = nil) if format Time.strptime(str_time, format).to_i else Time.parse(str_time).to_i end end class GrokParserTest < ::Test::Unit::TestCase class Timestamp < self def test_timestamp_iso8601 internal_test_grok_pattern('%{TIMESTAMP_ISO8601:time}', 'Some stuff at 2014-01-01T00:00:00+0900', str2time('2014-01-01T00:00:00+0900'), {}) end def test_datestamp_rfc822_with_zone internal_test_grok_pattern('%{DATESTAMP_RFC822:time}', 'Some stuff at Mon Aug 15 2005 15:52:01 UTC', str2time('Mon Aug 15 2005 15:52:01 UTC'), {}) end def test_datestamp_rfc822_with_numeric_zone internal_test_grok_pattern('%{DATESTAMP_RFC2822:time}', 'Some stuff at Mon, 15 Aug 2005 15:52:01 +0000', str2time('Mon, 15 Aug 2005 15:52:01 +0000'), {}) end def test_syslogtimestamp internal_test_grok_pattern('%{SYSLOGTIMESTAMP:time}', 'Some stuff at Aug 01 00:00:00', str2time('Aug 01 00:00:00'), {}) end end def test_call_for_grok_pattern_not_found assert_raise Grok::GrokPatternNotFoundError do internal_test_grok_pattern('%{THIS_PATTERN_DOESNT_EXIST}', 'Some stuff at somewhere', nil, {}) end end def test_call_for_multiple_fields internal_test_grok_pattern('%{MAC:mac_address} %{IP:ip_address}', 'this.wont.match DEAD.BEEF.1234 127.0.0.1', nil, {"mac_address" => "DEAD.BEEF.1234", "ip_address" => "127.0.0.1"}) end def test_call_for_complex_pattern internal_test_grok_pattern('%{COMBINEDAPACHELOG}', '127.0.0.1 192.168.0.1 - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777 "-" "Opera/12.0"', str2time('28/Feb/2013:12:00:00 +0900', '%d/%b/%Y:%H:%M:%S %z'), { "clientip" => "127.0.0.1", "ident" => "192.168.0.1", "auth" => "-", "verb" => "GET", "request" => "/", "httpversion" => "1.1", "response" => "200", "bytes" => "777", "referrer" => "\"-\"", "agent" => "\"Opera/12.0\"" }, "time_format" => "%d/%b/%Y:%H:%M:%S %z" ) end def test_call_for_custom_pattern pattern_file = File.new(File.expand_path("../my_pattern", __FILE__), "w") pattern_file.write("MY_AWESOME_PATTERN %{GREEDYDATA:message}\n") pattern_file.close begin internal_test_grok_pattern('%{MY_AWESOME_PATTERN:message}', 'this is awesome', nil, {"message" => "this is awesome"}, "custom_pattern_path" => pattern_file.path ) ensure File.delete(pattern_file.path) end end class OptionalType < self def test_simple internal_test_grok_pattern('%{INT:user_id:integer} paid %{NUMBER:paid_amount:float}', '12345 paid 6789.10', nil, {"user_id" => 12345, "paid_amount" => 6789.1 }) end def test_array internal_test_grok_pattern('%{GREEDYDATA:message:array}', 'a,b,c,d', nil, {"message" => %w(a b c d)}) end def test_array_with_delimiter internal_test_grok_pattern('%{GREEDYDATA:message:array:|}', 'a|b|c|d', nil, {"message" => %w(a b c d)}) end def test_timestamp_iso8601 internal_test_grok_pattern('%{TIMESTAMP_ISO8601:stamp:time}', 'Some stuff at 2014-01-01T00:00:00+0900', nil, {"stamp" => str2time('2014-01-01T00:00:00+0900')}) end def test_datestamp_rfc822_with_zone internal_test_grok_pattern('%{DATESTAMP_RFC822:stamp:time}', 'Some stuff at Mon Aug 15 2005 15:52:01 UTC', nil, {"stamp" => str2time('Mon Aug 15 2005 15:52:01 UTC')}) end def test_datestamp_rfc822_with_numeric_zone internal_test_grok_pattern('%{DATESTAMP_RFC2822:stamp:time}', 'Some stuff at Mon, 15 Aug 2005 15:52:01 +0000', nil, {"stamp" => str2time('Mon, 15 Aug 2005 15:52:01 +0000')}) end def test_syslogtimestamp internal_test_grok_pattern('%{SYSLOGTIMESTAMP:stamp:time}', 'Some stuff at Aug 01 00:00:00', nil, {"stamp" => str2time('Aug 01 00:00:00')}) end def test_timestamp_with_format internal_test_grok_pattern('%{TIMESTAMP_ISO8601:stamp:time:%Y-%m-%d %H%M}', 'Some stuff at 2014-01-01 1000', nil, {"stamp" => str2time('2014-01-01 10:00')}) end end private def internal_test_grok_pattern(grok_pattern, text, expected_time, expected_record, options = {}) parser = Fluent::Test::ParserTestDriver.new(TextParser::GrokParser).configure({"grok_pattern" => grok_pattern}.merge(options)) # for the old, return based API time, record = parser.parse(text) assert_equal(expected_time, time) if expected_time assert_equal(expected_record, record) # for the new API parser.parse(text) {|time, record| assert_equal(expected_time, time) if expected_time assert_equal(expected_record, record) } end end