fluentd 0.14.0 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/example/copy_roundrobin.conf +39 -0
  3. data/example/filter_stdout.conf +5 -5
  4. data/example/in_forward.conf +2 -2
  5. data/example/in_http.conf +2 -2
  6. data/example/in_syslog.conf +2 -2
  7. data/example/in_tail.conf +2 -2
  8. data/example/in_tcp.conf +2 -2
  9. data/example/in_udp.conf +2 -2
  10. data/example/out_buffered_null.conf +32 -0
  11. data/example/out_copy.conf +4 -4
  12. data/example/out_file.conf +2 -2
  13. data/example/out_forward.conf +2 -2
  14. data/example/v0_12_filter.conf +8 -8
  15. data/fluentd.gemspec +1 -1
  16. data/lib/fluent/command/fluentd.rb +6 -1
  17. data/lib/fluent/compat/handle_tag_name_mixin.rb +53 -0
  18. data/lib/fluent/compat/input.rb +1 -0
  19. data/lib/fluent/compat/output.rb +1 -0
  20. data/lib/fluent/compat/record_filter_mixin.rb +34 -0
  21. data/lib/fluent/compat/set_tag_key_mixin.rb +50 -0
  22. data/lib/fluent/compat/set_time_key_mixin.rb +69 -0
  23. data/lib/fluent/compat/type_converter.rb +90 -0
  24. data/lib/fluent/config/configure_proxy.rb +24 -4
  25. data/lib/fluent/config/dsl.rb +18 -1
  26. data/lib/fluent/config/v1_parser.rb +3 -2
  27. data/lib/fluent/configurable.rb +1 -1
  28. data/lib/fluent/event.rb +37 -9
  29. data/lib/fluent/mixin.rb +12 -286
  30. data/lib/fluent/plugin/buffer.rb +2 -2
  31. data/lib/fluent/plugin/in_dummy.rb +5 -1
  32. data/lib/fluent/plugin/in_gc_stat.rb +7 -37
  33. data/lib/fluent/plugin/in_http.rb +2 -0
  34. data/lib/fluent/plugin/{in_stream.rb → in_unix.rb} +0 -0
  35. data/lib/fluent/plugin/out_buffered_stdout.rb +60 -0
  36. data/lib/fluent/plugin/out_copy.rb +8 -51
  37. data/lib/fluent/plugin/out_null.rb +5 -5
  38. data/lib/fluent/plugin/out_relabel.rb +5 -5
  39. data/lib/fluent/plugin/out_roundrobin.rb +13 -40
  40. data/lib/fluent/plugin/output.rb +9 -0
  41. data/lib/fluent/plugin_helper.rb +2 -0
  42. data/lib/fluent/plugin_helper/formatter.rb +138 -0
  43. data/lib/fluent/plugin_helper/inject.rb +112 -0
  44. data/lib/fluent/plugin_helper/parser.rb +138 -0
  45. data/lib/fluent/plugin_helper/storage.rb +64 -50
  46. data/lib/fluent/process.rb +6 -1
  47. data/lib/fluent/registry.rb +1 -1
  48. data/lib/fluent/supervisor.rb +20 -2
  49. data/lib/fluent/test.rb +30 -5
  50. data/lib/fluent/test/base.rb +2 -66
  51. data/lib/fluent/test/driver/base.rb +3 -0
  52. data/lib/fluent/test/driver/base_owned.rb +106 -0
  53. data/lib/fluent/test/driver/formatter.rb +30 -0
  54. data/lib/fluent/test/driver/multi_output.rb +52 -0
  55. data/lib/fluent/test/driver/owner.rb +32 -0
  56. data/lib/fluent/test/driver/parser.rb +30 -0
  57. data/lib/fluent/test/helpers.rb +54 -0
  58. data/lib/fluent/test/log.rb +73 -0
  59. data/lib/fluent/time.rb +71 -0
  60. data/lib/fluent/version.rb +1 -1
  61. data/test/compat/test_parser.rb +82 -0
  62. data/test/config/test_configure_proxy.rb +15 -0
  63. data/test/config/test_dsl.rb +180 -2
  64. data/test/helper.rb +2 -24
  65. data/test/plugin/test_in_gc_stat.rb +6 -6
  66. data/test/plugin/test_in_http.rb +49 -32
  67. data/test/plugin/{test_in_stream.rb → test_in_unix.rb} +1 -1
  68. data/test/plugin/test_out_buffered_stdout.rb +108 -0
  69. data/test/plugin/test_out_copy.rb +88 -127
  70. data/test/plugin/test_out_null.rb +29 -0
  71. data/test/plugin/test_out_relabel.rb +28 -0
  72. data/test/plugin/test_out_roundrobin.rb +35 -29
  73. data/test/plugin/test_out_stdout.rb +4 -4
  74. data/test/plugin/test_output_as_buffered.rb +51 -0
  75. data/test/plugin/test_output_as_buffered_secondary.rb +13 -0
  76. data/test/plugin/test_parser_apache.rb +38 -0
  77. data/test/plugin/test_parser_apache2.rb +38 -0
  78. data/test/plugin/test_parser_apache_error.rb +40 -0
  79. data/test/plugin/test_parser_base.rb +32 -0
  80. data/test/plugin/test_parser_csv.rb +94 -0
  81. data/test/plugin/test_parser_json.rb +107 -0
  82. data/test/plugin/test_parser_labeled_tsv.rb +129 -0
  83. data/test/plugin/test_parser_multiline.rb +100 -0
  84. data/test/plugin/test_parser_nginx.rb +42 -0
  85. data/test/plugin/test_parser_none.rb +53 -0
  86. data/test/plugin/test_parser_regexp.rb +110 -0
  87. data/test/plugin/test_parser_syslog.rb +66 -0
  88. data/test/plugin/test_parser_time.rb +46 -0
  89. data/test/plugin/test_parser_tsv.rb +125 -0
  90. data/test/plugin_helper/test_child_process.rb +11 -2
  91. data/test/plugin_helper/test_formatter.rb +212 -0
  92. data/test/plugin_helper/test_inject.rb +388 -0
  93. data/test/plugin_helper/test_parser.rb +223 -0
  94. data/test/plugin_helper/test_retry_state.rb +40 -40
  95. data/test/plugin_helper/test_storage.rb +77 -10
  96. data/test/scripts/fluent/plugin/out_test.rb +22 -17
  97. data/test/scripts/fluent/plugin/out_test2.rb +80 -0
  98. data/test/test_event.rb +57 -0
  99. data/test/test_formatter.rb +0 -178
  100. data/test/test_output.rb +2 -152
  101. data/test/test_root_agent.rb +3 -2
  102. data/test/test_supervisor.rb +93 -26
  103. data/test/test_time_formatter.rb +186 -0
  104. metadata +69 -7
  105. data/test/test_parser.rb +0 -1087
@@ -0,0 +1,53 @@
1
+ require_relative '../helper'
2
+ require 'fluent/test/driver/parser'
3
+ require 'fluent/plugin/parser'
4
+
5
+ class NoneParserTest < ::Test::Unit::TestCase
6
+ def setup
7
+ Fluent::Test.setup
8
+ end
9
+
10
+ def test_config_params
11
+ parser = Fluent::Test::Driver::Parser.new(Fluent::TextParser::NoneParser)
12
+ parser.configure({})
13
+ assert_equal "message", parser.instance.message_key
14
+
15
+ parser.configure('message_key' => 'foobar')
16
+ assert_equal "foobar", parser.instance.message_key
17
+ end
18
+
19
+ def test_parse
20
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin.new_parser('none'))
21
+ parser.configure({})
22
+ parser.instance.parse('log message!') { |time, record|
23
+ assert_equal({'message' => 'log message!'}, record)
24
+ }
25
+ end
26
+
27
+ def test_parse_with_message_key
28
+ parser = Fluent::Test::Driver::Parser.new(Fluent::TextParser::NoneParser)
29
+ parser.configure('message_key' => 'foobar')
30
+ parser.instance.parse('log message!') { |time, record|
31
+ assert_equal({'foobar' => 'log message!'}, record)
32
+ }
33
+ end
34
+
35
+ def test_parse_without_default_time
36
+ time_at_start = Time.now.to_i
37
+
38
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin.new_parser('none'))
39
+ parser.configure({})
40
+ parser.instance.parse('log message!') { |time, record|
41
+ assert time && time >= time_at_start, "parser puts current time without time input"
42
+ assert_equal({'message' => 'log message!'}, record)
43
+ }
44
+
45
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin.new_parser('none'))
46
+ parser.instance.estimate_current_event = false
47
+ parser.configure({})
48
+ parser.instance.parse('log message!') { |time, record|
49
+ assert_equal({'message' => 'log message!'}, record)
50
+ assert_nil time, "parser returns nil w/o time if configured so"
51
+ }
52
+ end
53
+ end
@@ -0,0 +1,110 @@
1
+ require_relative '../helper'
2
+ require 'fluent/test/driver/parser'
3
+ require 'fluent/plugin/parser'
4
+
5
+ class RegexpParserTest < ::Test::Unit::TestCase
6
+ def setup
7
+ Fluent::Test.setup
8
+ end
9
+
10
+ def internal_test_case(parser)
11
+ text = '192.168.0.1 - - [28/Feb/2013:12:00:00 +0900] [14/Feb/2013:12:00:00 +0900] "true /,/user HTTP/1.1" 200 777'
12
+ parser.parse(text) { |time, record|
13
+ assert_equal(event_time('28/Feb/2013:12:00:00 +0900', format: '%d/%b/%Y:%H:%M:%S %z'), time)
14
+ assert_equal({
15
+ 'user' => '-',
16
+ 'flag' => true,
17
+ 'code' => 200.0,
18
+ 'size' => 777,
19
+ 'date' => event_time('14/Feb/2013:12:00:00 +0900', format: '%d/%b/%Y:%H:%M:%S %z'),
20
+ 'host' => '192.168.0.1',
21
+ 'path' => ['/', '/user']
22
+ }, record)
23
+ }
24
+ end
25
+
26
+ def test_parse_with_typed
27
+ # Use Regexp.new instead of // literal to avoid different parser behaviour in 1.9 and 2.0
28
+ internal_test_case(Fluent::Plugin::RegexpParser.new(Regexp.new(%q!^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] \[(?<date>[^\]]*)\] "(?<flag>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)$!), 'time_format'=>"%d/%b/%Y:%H:%M:%S %z", 'types'=>'user:string,date:time:%d/%b/%Y:%H:%M:%S %z,flag:bool,path:array,code:float,size:integer'))
29
+ end
30
+
31
+ def test_parse_with_configure
32
+ # Specify conf by configure method instaed of intializer
33
+ regexp = Regexp.new(%q!^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] \[(?<date>[^\]]*)\] "(?<flag>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)$!)
34
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::RegexpParser.new(regexp))
35
+ parser.configure('time_format'=>"%d/%b/%Y:%H:%M:%S %z", 'types'=>'user:string,date:time:%d/%b/%Y:%H:%M:%S %z,flag:bool,path:array,code:float,size:integer')
36
+ internal_test_case(parser.instance)
37
+ assert_equal(regexp, parser.instance.patterns['format'])
38
+ assert_equal("%d/%b/%Y:%H:%M:%S %z", parser.instance.patterns['time_format'])
39
+ end
40
+
41
+ def test_parse_with_typed_and_name_separator
42
+ internal_test_case(Fluent::Test::Driver::Parser.new(Fluent::Plugin::RegexpParser.new(Regexp.new(%q!^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] \[(?<date>[^\]]*)\] "(?<flag>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)$!), 'time_format'=>"%d/%b/%Y:%H:%M:%S %z", 'types'=>'user|string,date|time|%d/%b/%Y:%H:%M:%S %z,flag|bool,path|array,code|float,size|integer', 'types_label_delimiter'=>'|')).instance)
43
+ end
44
+
45
+ def test_parse_with_time_key
46
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::RegexpParser.new(/(?<logtime>[^\]]*)/))
47
+ parser.instance.configure(
48
+ 'time_format'=>"%Y-%m-%d %H:%M:%S %z",
49
+ 'time_key'=>'logtime',
50
+ )
51
+ text = '2013-02-28 12:00:00 +0900'
52
+ parser.instance.parse(text) do |time, record|
53
+ assert_equal Fluent::EventTime.parse(text), time
54
+ end
55
+ end
56
+
57
+ def test_parse_without_time
58
+ time_at_start = Time.now.to_i
59
+ text = "tagomori_satoshi tagomoris 34\n"
60
+
61
+ parser = Fluent::Plugin::RegexpParser.new(Regexp.new(%q!^(?<name>[^ ]*) (?<user>[^ ]*) (?<age>\d*)$!))
62
+ parser.configure('types'=>'name:string,user:string,age:integer')
63
+
64
+ parser.parse(text) { |time, record|
65
+ assert time && time >= time_at_start, "parser puts current time without time input"
66
+ assert_equal "tagomori_satoshi", record["name"]
67
+ assert_equal "tagomoris", record["user"]
68
+ assert_equal 34, record["age"]
69
+ }
70
+
71
+ parser2 = Fluent::Test::Driver::Parser.new(Fluent::Plugin::RegexpParser.new(Regexp.new(%q!^(?<name>[^ ]*) (?<user>[^ ]*) (?<age>\d*)$!)))
72
+ parser2.configure('types'=>'name:string,user:string,age:integer')
73
+ parser2.instance.estimate_current_event = false
74
+
75
+ parser2.instance.parse(text) { |time, record|
76
+ assert_equal "tagomori_satoshi", record["name"]
77
+ assert_equal "tagomoris", record["user"]
78
+ assert_equal 34, record["age"]
79
+
80
+ assert_nil time, "parser returns nil if configured so"
81
+ }
82
+ end
83
+
84
+ def test_parse_with_keep_time_key
85
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::RegexpParser.new(
86
+ Regexp.new(%q!(?<time>.*)!),
87
+ 'time_format'=>"%d/%b/%Y:%H:%M:%S %z",
88
+ 'keep_time_key'=>'true',
89
+ )
90
+ )
91
+ text = '28/Feb/2013:12:00:00 +0900'
92
+ parser.instance.parse(text) do |time, record|
93
+ assert_equal text, record['time']
94
+ end
95
+ end
96
+
97
+ def test_parse_with_keep_time_key_with_typecast
98
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::RegexpParser.new(
99
+ Regexp.new(%q!(?<time>.*)!),
100
+ 'time_format'=>"%d/%b/%Y:%H:%M:%S %z",
101
+ 'keep_time_key'=>'true',
102
+ 'types'=>'time:time:%d/%b/%Y:%H:%M:%S %z',
103
+ )
104
+ )
105
+ text = '28/Feb/2013:12:00:00 +0900'
106
+ parser.instance.parse(text) do |time, record|
107
+ assert_equal 1362020400, record['time']
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,66 @@
1
+ require_relative '../helper'
2
+ require 'fluent/test/driver/parser'
3
+ require 'fluent/plugin/parser'
4
+
5
+ class SyslogParserTest < ::Test::Unit::TestCase
6
+ def setup
7
+ Fluent::Test.setup
8
+ @parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::SyslogParser)
9
+ @expected = {
10
+ 'host' => '192.168.0.1',
11
+ 'ident' => 'fluentd',
12
+ 'pid' => '11111',
13
+ 'message' => '[error] Syslog test'
14
+ }
15
+ end
16
+
17
+ def test_parse
18
+ @parser.configure({})
19
+ @parser.instance.parse('Feb 28 12:00:00 192.168.0.1 fluentd[11111]: [error] Syslog test') { |time, record|
20
+ assert_equal(event_time('Feb 28 12:00:00', format: '%b %d %H:%M:%S'), time)
21
+ assert_equal(@expected, record)
22
+ }
23
+ assert_equal(Fluent::Plugin::SyslogParser::REGEXP, @parser.instance.patterns['format'])
24
+ assert_equal("%b %d %H:%M:%S", @parser.instance.patterns['time_format'])
25
+ end
26
+
27
+ def test_parse_with_time_format
28
+ @parser.configure('time_format' => '%b %d %M:%S:%H')
29
+ @parser.instance.parse('Feb 28 00:00:12 192.168.0.1 fluentd[11111]: [error] Syslog test') { |time, record|
30
+ assert_equal(event_time('Feb 28 12:00:00', format: '%b %d %H:%M:%S'), time)
31
+ assert_equal(@expected, record)
32
+ }
33
+ assert_equal('%b %d %M:%S:%H', @parser.instance.patterns['time_format'])
34
+ end
35
+
36
+ def test_parse_with_priority
37
+ @parser.configure('with_priority' => true)
38
+ @parser.instance.parse('<6>Feb 28 12:00:00 192.168.0.1 fluentd[11111]: [error] Syslog test') { |time, record|
39
+ assert_equal(event_time('Feb 28 12:00:00', format: '%b %d %H:%M:%S'), time)
40
+ assert_equal(@expected.merge('pri' => 6), record)
41
+ }
42
+ assert_equal(Fluent::Plugin::SyslogParser::REGEXP_WITH_PRI, @parser.instance.patterns['format'])
43
+ assert_equal("%b %d %H:%M:%S", @parser.instance.patterns['time_format'])
44
+ end
45
+
46
+ def test_parse_without_colon
47
+ @parser.configure({})
48
+ @parser.instance.parse('Feb 28 12:00:00 192.168.0.1 fluentd[11111] [error] Syslog test') { |time, record|
49
+ assert_equal(event_time('Feb 28 12:00:00', format: '%b %d %H:%M:%S'), time)
50
+ assert_equal(@expected, record)
51
+ }
52
+ assert_equal(Fluent::Plugin::SyslogParser::REGEXP, @parser.instance.patterns['format'])
53
+ assert_equal("%b %d %H:%M:%S", @parser.instance.patterns['time_format'])
54
+ end
55
+
56
+ def test_parse_with_keep_time_key
57
+ @parser.configure(
58
+ 'time_format' => '%b %d %M:%S:%H',
59
+ 'keep_time_key'=>'true',
60
+ )
61
+ text = 'Feb 28 00:00:12 192.168.0.1 fluentd[11111]: [error] Syslog test'
62
+ @parser.instance.parse(text) do |time, record|
63
+ assert_equal "Feb 28 00:00:12", record['time']
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,46 @@
1
+ require_relative '../helper'
2
+ require 'fluent/test/driver/parser'
3
+ require 'fluent/plugin/parser'
4
+
5
+ class TimeParserTest < ::Test::Unit::TestCase
6
+ def setup
7
+ Fluent::Test.setup
8
+ end
9
+
10
+ def test_call_with_parse
11
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::Parser::TimeParser.new(nil))
12
+
13
+ assert(parser.instance.parse('2013-09-18 12:00:00 +0900').is_a?(Fluent::EventTime))
14
+
15
+ time = event_time('2013-09-18 12:00:00 +0900')
16
+ assert_equal(time, parser.instance.parse('2013-09-18 12:00:00 +0900'))
17
+ end
18
+
19
+ def test_parse_with_strptime
20
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::Parser::TimeParser.new('%d/%b/%Y:%H:%M:%S %z'))
21
+
22
+ assert(parser.instance.parse('28/Feb/2013:12:00:00 +0900').is_a?(Fluent::EventTime))
23
+
24
+ time = event_time('28/Feb/2013:12:00:00 +0900', format: '%d/%b/%Y:%H:%M:%S %z')
25
+ assert_equal(time, parser.instance.parse('28/Feb/2013:12:00:00 +0900'))
26
+ end
27
+
28
+ def test_parse_nsec_with_strptime
29
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::Parser::TimeParser.new('%d/%b/%Y:%H:%M:%S:%N %z'))
30
+
31
+ assert(parser.instance.parse('28/Feb/2013:12:00:00:123456789 +0900').is_a?(Fluent::EventTime))
32
+
33
+ time = event_time('28/Feb/2013:12:00:00:123456789 +0900', format: '%d/%b/%Y:%H:%M:%S:%N %z')
34
+ assert_equal_event_time(time, parser.instance.parse('28/Feb/2013:12:00:00:123456789 +0900'))
35
+ end
36
+
37
+ def test_parse_with_invalid_argument
38
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::Parser::TimeParser.new(nil))
39
+
40
+ [[], {}, nil, true, 10000, //, ->{}, '', :symbol].each { |v|
41
+ assert_raise Fluent::ParserError do
42
+ parser.instance.parse(v)
43
+ end
44
+ }
45
+ end
46
+ end
@@ -0,0 +1,125 @@
1
+ require_relative '../helper'
2
+ require 'fluent/test/driver/parser'
3
+ require 'fluent/plugin/parser'
4
+
5
+ class TSVParserTest < ::Test::Unit::TestCase
6
+ def setup
7
+ Fluent::Test.setup
8
+ end
9
+
10
+ data('array param' => '["a","b"]', 'string param' => 'a,b')
11
+ def test_config_params(param)
12
+ parser = Fluent::Test::Driver::Parser.new(Fluent::TextParser::TSVParser)
13
+
14
+ assert_equal "\t", parser.instance.delimiter
15
+
16
+ parser.configure(
17
+ 'keys' => param,
18
+ 'delimiter' => ',',
19
+ )
20
+
21
+ assert_equal ['a', 'b'], parser.instance.keys
22
+ assert_equal ",", parser.instance.delimiter
23
+ end
24
+
25
+ data('array param' => '["time","a","b"]', 'string param' => 'time,a,b')
26
+ def test_parse(param)
27
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::TSVParser)
28
+ parser.configure('keys' => param, 'time_key' => 'time')
29
+ parser.instance.parse("2013/02/28 12:00:00\t192.168.0.1\t111") { |time, record|
30
+ assert_equal(event_time('2013/02/28 12:00:00', format: '%Y/%m/%d %H:%M:%S'), time)
31
+ assert_equal({
32
+ 'a' => '192.168.0.1',
33
+ 'b' => '111',
34
+ }, record)
35
+ }
36
+ end
37
+
38
+ def test_parse_with_time
39
+ time_at_start = Time.now.to_i
40
+
41
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::TSVParser)
42
+ parser.configure('keys' => 'a,b')
43
+ parser.instance.parse("192.168.0.1\t111") { |time, record|
44
+ assert time && time >= time_at_start, "parser puts current time without time input"
45
+ assert_equal({
46
+ 'a' => '192.168.0.1',
47
+ 'b' => '111',
48
+ }, record)
49
+ }
50
+
51
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::TSVParser)
52
+ parser.instance.estimate_current_event = false
53
+ parser.configure('keys' => 'a,b', 'time_key' => 'time')
54
+ parser.instance.parse("192.168.0.1\t111") { |time, record|
55
+ assert_equal({
56
+ 'a' => '192.168.0.1',
57
+ 'b' => '111',
58
+ }, record)
59
+ assert_nil time, "parser returns nil w/o time and if configured so"
60
+ }
61
+ end
62
+
63
+ data(
64
+ 'left blank column' => ["\t@\t@", {"1" => "","2" => "@","3" => "@"}],
65
+ 'center blank column' => ["@\t\t@", {"1" => "@","2" => "","3" => "@"}],
66
+ 'right blank column' => ["@\t@\t", {"1" => "@","2" => "@","3" => ""}],
67
+ '2 right blank columns' => ["@\t\t", {"1" => "@","2" => "","3" => ""}],
68
+ 'left blank columns' => ["\t\t@", {"1" => "","2" => "","3" => "@"}],
69
+ 'all blank columns' => ["\t\t", {"1" => "","2" => "","3" => ""}])
70
+ def test_black_column(data)
71
+ line, expected = data
72
+
73
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::TSVParser)
74
+ parser.configure('keys' => '1,2,3')
75
+ parser.instance.parse(line) { |time, record|
76
+ assert_equal(expected, record)
77
+ }
78
+ end
79
+
80
+ def test_parse_with_keep_time_key
81
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::TSVParser)
82
+ parser.configure(
83
+ 'keys'=>'time',
84
+ 'time_key'=>'time',
85
+ 'time_format'=>"%d/%b/%Y:%H:%M:%S %z",
86
+ 'keep_time_key'=>'true',
87
+ )
88
+ text = '28/Feb/2013:12:00:00 +0900'
89
+ parser.instance.parse(text) do |time, record|
90
+ assert_equal text, record['time']
91
+ end
92
+ end
93
+
94
+ data('array param' => '["a","b","c","d","e","f"]', 'string param' => 'a,b,c,d,e,f')
95
+ def test_parse_with_null_value_pattern
96
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::TSVParser)
97
+ parser.configure(
98
+ 'keys'=>param,
99
+ 'time_key'=>'time',
100
+ 'null_value_pattern'=>'^(-|null|NULL)$'
101
+ )
102
+ parser.instance.parse("-\tnull\tNULL\t\t--\tnuLL") do |time, record|
103
+ assert_nil record['a']
104
+ assert_nil record['b']
105
+ assert_nil record['c']
106
+ assert_equal record['d'], ''
107
+ assert_equal record['e'], '--'
108
+ assert_equal record['f'], 'nuLL'
109
+ end
110
+ end
111
+
112
+ data('array param' => '["a","b"]', 'string param' => 'a,b')
113
+ def test_parse_with_null_empty_string
114
+ parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::TSVParser)
115
+ parser.configure(
116
+ 'keys'=>param,
117
+ 'time_key'=>'time',
118
+ 'null_empty_string'=>true
119
+ )
120
+ parser.instance.parse("\t ") do |time, record|
121
+ assert_nil record['a']
122
+ assert_equal record['b'], ' '
123
+ end
124
+ end
125
+ end
@@ -312,6 +312,14 @@ class ChildProcessTest < Test::Unit::TestCase
312
312
  ary = []
313
313
  arguments = ["-e", "10.times{ puts 'okay'; STDOUT.flush rescue nil; sleep #{TEST_WAIT_INTERVAL_FOR_LOOP} }"] # 0.5 * 10
314
314
  Timeout.timeout(TEST_DEADLOCK_TIMEOUT) do
315
+ assert_equal [], @d.log.out.logs
316
+ @d.log.out.singleton_class.module_eval do
317
+ define_method(:write){|message|
318
+ raise "boo" if message.include?('test: {"test":"test"}') || message.include?('test: {"test"=>"test"}')
319
+ @logs.push message
320
+ }
321
+ end
322
+
315
323
  @d.child_process_execute(:t7, "ruby", arguments: arguments, interval: 2, immediate: true, mode: [:read]) do |io|
316
324
  ary << io.read.split("\n").map(&:chomp).join
317
325
  end
@@ -319,8 +327,9 @@ class ChildProcessTest < Test::Unit::TestCase
319
327
  assert_equal 1, @d._child_process_processes.size
320
328
  @d.stop
321
329
  warn_msg = '[warn]: previous child process is still running. skipped. title=:t7 command="ruby" arguments=["-e", "10.times{ puts \'okay\'; STDOUT.flush rescue nil; sleep 0.5 }"] interval=2 parallel=false' + "\n"
322
- assert{ @d.log.out.logs.first.end_with?(warn_msg) }
323
- assert{ @d.log.out.logs.all?{|line| line.end_with?(warn_msg) } }
330
+ logs = @d.log.out.logs
331
+ assert{ logs.first.end_with?(warn_msg) }
332
+ assert{ logs.all?{|line| line.end_with?(warn_msg) } }
324
333
  @d.shutdown; @d.close; @d.terminate
325
334
  assert_equal [], @d.log.out.logs
326
335
  end
@@ -0,0 +1,212 @@
1
+ require_relative '../helper'
2
+ require 'fluent/plugin_helper/formatter'
3
+ require 'fluent/plugin/base'
4
+
5
+ class FormatterHelperTest < Test::Unit::TestCase
6
+ class ExampleFormatter < Fluent::Plugin::Formatter
7
+ Fluent::Plugin.register_formatter('example', self)
8
+ def format(tag, time, record)
9
+ "#{tag},#{time.to_i},#{record.keys.sort.join(',')}" # hey, you miss values! :P
10
+ end
11
+ end
12
+ class Example2Formatter < Fluent::Plugin::Formatter
13
+ Fluent::Plugin.register_formatter('example2', self)
14
+ def format(tag, time, record)
15
+ "#{tag},#{time.to_i},#{record.values.sort.join(',')}" # key...
16
+ end
17
+ end
18
+ class Dummy < Fluent::Plugin::TestBase
19
+ helpers :formatter
20
+ end
21
+
22
+ setup do
23
+ @d = nil
24
+ end
25
+
26
+ teardown do
27
+ if @d
28
+ @d.stop unless @d.stopped?
29
+ @d.shutdown unless @d.shutdown?
30
+ @d.close unless @d.closed?
31
+ @d.terminate unless @d.terminated?
32
+ end
33
+ end
34
+
35
+ test 'can be initialized without any formatters at first' do
36
+ d = Dummy.new
37
+ assert_equal 0, d._formatters.size
38
+ end
39
+
40
+ test 'can be configured without format sections' do
41
+ d = Dummy.new
42
+ assert_nothing_raised do
43
+ d.configure(config_element())
44
+ end
45
+ assert_equal 0, d._formatters.size
46
+ end
47
+
48
+ test 'can be configured with a format section' do
49
+ d = Dummy.new
50
+ conf = config_element('ROOT', '', {}, [
51
+ config_element('format', '', {'@type' => 'example'})
52
+ ])
53
+ assert_nothing_raised do
54
+ d.configure(conf)
55
+ end
56
+ assert_equal 1, d._formatters.size
57
+ assert{ d._formatters.values.all?{ |formatter| !formatter.started? } }
58
+ end
59
+
60
+ test 'can be configured with 2 or more format sections with different usages with each other' do
61
+ d = Dummy.new
62
+ conf = config_element('ROOT', '', {}, [
63
+ config_element('format', 'default', {'@type' => 'example'}),
64
+ config_element('format', 'extra', {'@type' => 'example2'}),
65
+ ])
66
+ assert_nothing_raised do
67
+ d.configure(conf)
68
+ end
69
+ assert_equal 2, d._formatters.size
70
+ assert{ d._formatters.values.all?{ |formatter| !formatter.started? } }
71
+ end
72
+
73
+ test 'cannot be configured with 2 format sections with same usage' do
74
+ d = Dummy.new
75
+ conf = config_element('ROOT', '', {}, [
76
+ config_element('format', 'default', {'@type' => 'example'}),
77
+ config_element('format', 'extra', {'@type' => 'example2'}),
78
+ config_element('format', 'extra', {'@type' => 'example2'}),
79
+ ])
80
+ assert_raises Fluent::ConfigError do
81
+ d.configure(conf)
82
+ end
83
+ end
84
+
85
+ test 'creates a format plugin instance which is already configured without usage' do
86
+ @d = d = Dummy.new
87
+ conf = config_element('ROOT', '', {}, [
88
+ config_element('format', '', {'@type' => 'example'})
89
+ ])
90
+ d.configure(conf)
91
+ d.start
92
+
93
+ formatter = d.formatter_create
94
+ assert{ formatter.is_a? ExampleFormatter }
95
+ assert formatter.started?
96
+ end
97
+
98
+ test 'creates a formatter plugin instance which is already configured with usage' do
99
+ @d = d = Dummy.new
100
+ conf = config_element('ROOT', '', {}, [
101
+ config_element('format', 'mydata', {'@type' => 'example'})
102
+ ])
103
+ d.configure(conf)
104
+ d.start
105
+
106
+ formatter = d.formatter_create(usage: 'mydata')
107
+ assert{ formatter.is_a? ExampleFormatter }
108
+ assert formatter.started?
109
+ end
110
+
111
+ test 'creates a formatter plugin without configurations' do
112
+ @d = d = Dummy.new
113
+ d.configure(config_element())
114
+ d.start
115
+
116
+ formatter = d.formatter_create(usage: 'mydata', type: 'example', conf: config_element('format', 'mydata'))
117
+ assert{ formatter.is_a? ExampleFormatter }
118
+ assert formatter.started?
119
+ end
120
+
121
+ test 'creates 2 or more formatter plugin instances' do
122
+ @d = d = Dummy.new
123
+ conf = config_element('ROOT', '', {}, [
124
+ config_element('format', 'mydata', {'@type' => 'example'}),
125
+ config_element('format', 'secret', {'@type' => 'example2'})
126
+ ])
127
+ d.configure(conf)
128
+ d.start
129
+
130
+ p1 = d.formatter_create(usage: 'mydata')
131
+ p2 = d.formatter_create(usage: 'secret')
132
+ assert{ p1.is_a? ExampleFormatter }
133
+ assert p1.started?
134
+ assert{ p2.is_a? Example2Formatter }
135
+ assert p2.started?
136
+ end
137
+
138
+ test 'calls lifecycle methods for all plugin instances via owner plugin' do
139
+ @d = d = Dummy.new
140
+ conf = config_element('ROOT', '', {}, [ config_element('format', '', {'@type' => 'example'}), config_element('format', 'e2', {'@type' => 'example'}) ])
141
+ d.configure(conf)
142
+ d.start
143
+
144
+ i1 = d.formatter_create(usage: '')
145
+ i2 = d.formatter_create(usage: 'e2')
146
+ i3 = d.formatter_create(usage: 'e3', type: 'example2')
147
+
148
+ assert i1.started?
149
+ assert i2.started?
150
+ assert i3.started?
151
+
152
+ assert !i1.stopped?
153
+ assert !i2.stopped?
154
+ assert !i3.stopped?
155
+
156
+ d.stop
157
+
158
+ assert i1.stopped?
159
+ assert i2.stopped?
160
+ assert i3.stopped?
161
+
162
+ assert !i1.before_shutdown?
163
+ assert !i2.before_shutdown?
164
+ assert !i3.before_shutdown?
165
+
166
+ d.before_shutdown
167
+
168
+ assert i1.before_shutdown?
169
+ assert i2.before_shutdown?
170
+ assert i3.before_shutdown?
171
+
172
+ assert !i1.shutdown?
173
+ assert !i2.shutdown?
174
+ assert !i3.shutdown?
175
+
176
+ d.shutdown
177
+
178
+ assert i1.shutdown?
179
+ assert i2.shutdown?
180
+ assert i3.shutdown?
181
+
182
+ assert !i1.after_shutdown?
183
+ assert !i2.after_shutdown?
184
+ assert !i3.after_shutdown?
185
+
186
+ d.after_shutdown
187
+
188
+ assert i1.after_shutdown?
189
+ assert i2.after_shutdown?
190
+ assert i3.after_shutdown?
191
+
192
+ assert !i1.closed?
193
+ assert !i2.closed?
194
+ assert !i3.closed?
195
+
196
+ d.close
197
+
198
+ assert i1.closed?
199
+ assert i2.closed?
200
+ assert i3.closed?
201
+
202
+ assert !i1.terminated?
203
+ assert !i2.terminated?
204
+ assert !i3.terminated?
205
+
206
+ d.terminate
207
+
208
+ assert i1.terminated?
209
+ assert i2.terminated?
210
+ assert i3.terminated?
211
+ end
212
+ end