fluentd 0.14.9 → 0.14.10

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/ChangeLog +44 -0
  4. data/appveyor.yml +1 -0
  5. data/code-of-conduct.md +3 -0
  6. data/fluentd.gemspec +1 -1
  7. data/lib/fluent/command/cat.rb +11 -3
  8. data/lib/fluent/compat/output.rb +6 -3
  9. data/lib/fluent/compat/parser.rb +2 -0
  10. data/lib/fluent/config/section.rb +1 -1
  11. data/lib/fluent/env.rb +1 -1
  12. data/lib/fluent/plugin/filter_record_transformer.rb +12 -30
  13. data/lib/fluent/plugin/in_forward.rb +50 -169
  14. data/lib/fluent/plugin/in_monitor_agent.rb +8 -4
  15. data/lib/fluent/plugin/in_syslog.rb +13 -7
  16. data/lib/fluent/plugin/in_tail.rb +29 -14
  17. data/lib/fluent/plugin/in_tcp.rb +54 -14
  18. data/lib/fluent/plugin/in_udp.rb +49 -13
  19. data/lib/fluent/plugin/out_file.rb +30 -14
  20. data/lib/fluent/plugin/out_forward.rb +199 -173
  21. data/lib/fluent/plugin/output.rb +71 -46
  22. data/lib/fluent/plugin/parser_json.rb +1 -1
  23. data/lib/fluent/plugin_helper.rb +2 -0
  24. data/lib/fluent/plugin_helper/event_loop.rb +24 -6
  25. data/lib/fluent/plugin_helper/inject.rb +12 -1
  26. data/lib/fluent/plugin_helper/server.rb +494 -0
  27. data/lib/fluent/plugin_helper/socket.rb +101 -0
  28. data/lib/fluent/plugin_helper/socket_option.rb +84 -0
  29. data/lib/fluent/plugin_helper/timer.rb +1 -0
  30. data/lib/fluent/test/driver/base.rb +45 -13
  31. data/lib/fluent/version.rb +1 -1
  32. data/lib/fluent/winsvc.rb +1 -1
  33. data/test/compat/test_parser.rb +10 -0
  34. data/test/config/test_configurable.rb +20 -0
  35. data/test/helper.rb +36 -1
  36. data/test/plugin/test_filter_record_transformer.rb +31 -103
  37. data/test/plugin/test_in_forward.rb +13 -75
  38. data/test/plugin/test_in_monitor_agent.rb +65 -35
  39. data/test/plugin/test_in_syslog.rb +39 -3
  40. data/test/plugin/test_in_tcp.rb +78 -62
  41. data/test/plugin/test_in_udp.rb +101 -80
  42. data/test/plugin/test_out_file.rb +17 -0
  43. data/test/plugin/test_out_forward.rb +155 -125
  44. data/test/plugin/test_output_as_buffered.rb +4 -2
  45. data/test/plugin_helper/test_inject.rb +21 -0
  46. data/test/plugin_helper/test_server.rb +905 -0
  47. data/test/test_event_time.rb +3 -1
  48. data/test/test_output.rb +30 -1
  49. data/test/test_test_drivers.rb +5 -2
  50. metadata +19 -6
@@ -0,0 +1,101 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'socket'
18
+ require 'ipaddr'
19
+
20
+ require_relative 'socket_option'
21
+
22
+ module Fluent
23
+ module PluginHelper
24
+ module Socket
25
+ # stop : [-]
26
+ # shutdown : [-]
27
+ # close : [-]
28
+ # terminate: [-]
29
+
30
+ include Fluent::PluginHelper::SocketOption
31
+
32
+ attr_reader :_sockets # for tests
33
+
34
+ # TODO: implement connection pool for specified host
35
+
36
+ def socket_create(proto, host, port, **kwargs, &block)
37
+ case proto
38
+ when :tcp
39
+ socket_create_tcp(host, port, **kwargs, &block)
40
+ when :udp
41
+ socket_create_udp(host, port, **kwargs, &block)
42
+ when :tls
43
+ socket_create_tls(host, port, **kwargs, &block)
44
+ when :unix
45
+ raise "not implemented yet"
46
+ else
47
+ raise ArgumentError, "invalid protocol: #{proto}"
48
+ end
49
+ end
50
+
51
+ def socket_create_tcp(host, port, resolve_name: false, **kwargs, &block)
52
+ sock = TCPSocket.new(host, port)
53
+ socket_option_set(sock, resolve_name: resolve_name, **kwargs)
54
+ if block
55
+ begin
56
+ block.call(sock)
57
+ ensure
58
+ sock.close_write rescue nil
59
+ sock.close rescue nil
60
+ end
61
+ else
62
+ sock
63
+ end
64
+ end
65
+
66
+ def socket_create_udp(host, port, resolve_name: false, connect: false, **kwargs, &block)
67
+ family = IPAddr.new(IPSocket.getaddress(host)).ipv4? ? ::Socket::AF_INET : ::Socket::AF_INET6
68
+ sock = UDPSocket.new(family)
69
+ socket_option_set(sock, resolve_name: resolve_name, **kwargs)
70
+ sock.connect(host, port) if connect
71
+ if block
72
+ begin
73
+ block.call(sock)
74
+ ensure
75
+ sock.close rescue nil
76
+ end
77
+ else
78
+ sock
79
+ end
80
+ end
81
+
82
+ def socket_create_tls(host, port, resolve_name: false, certopts: {}, &block)
83
+ raise "not implemented yet"
84
+ end
85
+
86
+ # socket_create_socks ?
87
+
88
+ def initialize
89
+ super
90
+ # @_sockets = [] # for keepalived sockets / connection pool
91
+ end
92
+
93
+ # def close
94
+ # @_sockets.each do |sock|
95
+ # sock.close
96
+ # end
97
+ # super
98
+ # end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,84 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'socket'
18
+ require 'fcntl'
19
+
20
+ # this module is only for Socket/Server plugin helpers
21
+ module Fluent
22
+ module PluginHelper
23
+ module SocketOption
24
+ FORMAT_STRUCT_LINGER = 'I!I!' # { int l_onoff; int l_linger; }
25
+ FORMAT_STRUCT_TIMEVAL = 'L!L!' # { time_t tv_sec; suseconds_t tv_usec; }
26
+
27
+ def socket_option_validate!(protocol, resolve_name: nil, linger_timeout: nil, recv_timeout: nil, send_timeout: nil, certopts: nil)
28
+ unless resolve_name.nil?
29
+ if protocol != :tcp && protocol != :udp && protocol != :tls
30
+ raise ArgumentError, "BUG: resolve_name in available for tcp/udp/tls"
31
+ end
32
+ end
33
+ if linger_timeout
34
+ if protocol != :tcp && protocol != :tls
35
+ raise ArgumentError, "BUG: linger_timeout is available for tcp/tls"
36
+ end
37
+ end
38
+ if certopts
39
+ if protocol != :tls
40
+ raise ArgumentError, "BUG: certopts is available only for tls"
41
+ end
42
+ else
43
+ if protocol == :tls
44
+ raise ArgumentError, "BUG: certopts (certificate options) not specified for TLS"
45
+ socket_option_certopts_validate!(certopts)
46
+ end
47
+ end
48
+ end
49
+
50
+ def socket_option_certopts_validate!(certopts)
51
+ raise "not implemented yet"
52
+ end
53
+
54
+ def socket_option_set(sock, resolve_name: nil, nonblock: false, linger_timeout: nil, recv_timeout: nil, send_timeout: nil, certopts: nil)
55
+ unless resolve_name.nil?
56
+ sock.do_not_reverse_lookup = !resolve_name
57
+ end
58
+ if nonblock
59
+ sock.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
60
+ end
61
+ if linger_timeout
62
+ optval = [1, linger_timeout.to_i].pack(FORMAT_STRUCT_LINGER)
63
+ socket_option_set_one(sock, :SO_LINGER, optval)
64
+ end
65
+ if recv_timeout
66
+ optval = [recv_timeout.to_i, 0].pack(FORMAT_STRUCT_TIMEVAL)
67
+ socket_option_set_one(sock, :SO_RCVTIMEO, optval)
68
+ end
69
+ if send_timeout
70
+ optval = [send_timeout.to_i, 0].pack(FORMAT_STRUCT_TIMEVAL)
71
+ socket_option_set_one(sock, :SO_SNDTIMEO, optval)
72
+ end
73
+ # TODO: certopts for TLS
74
+ sock
75
+ end
76
+
77
+ def socket_option_set_one(sock, option, value)
78
+ sock.setsockopt(::Socket::SOL_SOCKET, option, value)
79
+ rescue => e
80
+ log.warn "failed to set socket option", sock: sock.class, option: option, value: value, error: e
81
+ end
82
+ end
83
+ end
84
+ end
@@ -36,6 +36,7 @@ module Fluent
36
36
  timer = TimerWatcher.new(title, interval, repeat, log, checker, &block)
37
37
  @_timers << title
38
38
  event_loop_attach(timer)
39
+ timer
39
40
  end
40
41
 
41
42
  def timer_running?
@@ -18,6 +18,8 @@ require 'fluent/config'
18
18
  require 'fluent/config/element'
19
19
  require 'fluent/log'
20
20
 
21
+ require 'serverengine/socket_manager'
22
+ require 'fileutils'
21
23
  require 'timeout'
22
24
 
23
25
  module Fluent
@@ -32,20 +34,18 @@ module Fluent
32
34
 
33
35
  def initialize(klass, opts: {}, &block)
34
36
  if klass.is_a?(Class)
37
+ @instance = klass.new
35
38
  if block
36
- # Create new class for test w/ overwritten methods
37
- # klass.dup is worse because its ancestors does NOT include original class name
38
- klass_name = klass.name
39
- klass = Class.new(klass)
40
- klass.define_singleton_method("name") { klass_name }
41
- klass.module_eval(&block)
39
+ @instance.singleton_class.module_eval(&block)
40
+ @instance.send(:initialize)
42
41
  end
43
- @instance = klass.new
44
42
  else
45
43
  @instance = klass
46
44
  end
47
45
  @instance.under_plugin_development = true
48
46
 
47
+ @socket_manager_server = nil
48
+
49
49
  @logs = []
50
50
 
51
51
  @test_clock_id = Process::CLOCK_MONOTONIC_RAW rescue Process::CLOCK_MONOTONIC
@@ -101,6 +101,15 @@ module Fluent
101
101
  end
102
102
 
103
103
  def instance_start
104
+ if @instance.respond_to?(:server_wait_until_start)
105
+ @socket_manager_path = ServerEngine::SocketManager::Server.generate_path
106
+ if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
107
+ FileUtils.rm_f @socket_manager_path
108
+ end
109
+ @socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
110
+ ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @socket_manager_path.to_s
111
+ end
112
+
104
113
  unless @instance.started?
105
114
  @instance.start
106
115
  end
@@ -130,22 +139,45 @@ module Fluent
130
139
  def instance_shutdown
131
140
  instance_hook_before_stopped
132
141
 
133
- @instance.stop unless @instance.stopped?
134
- @instance.before_shutdown unless @instance.before_shutdown?
135
- @instance.shutdown unless @instance.shutdown?
142
+ unless @instance.stopped?
143
+ @instance.stop rescue nil
144
+ end
145
+ unless @instance.before_shutdown?
146
+ @instance.before_shutdown rescue nil
147
+ end
148
+ unless @instance.shutdown?
149
+ @instance.shutdown rescue nil
150
+ end
136
151
 
137
152
  if @instance.respond_to?(:event_loop_wait_until_stop)
138
153
  @instance.event_loop_wait_until_stop
139
154
  end
140
155
 
141
- @instance.after_shutdown unless @instance.after_shutdown?
142
- @instance.close unless @instance.closed?
156
+ unless @instance.after_shutdown?
157
+ @instance.after_shutdown rescue nil
158
+ end
159
+ unless @instance.closed?
160
+ @instance.close rescue nil
161
+ end
143
162
 
144
163
  if @instance.respond_to?(:thread_wait_until_stop)
145
164
  @instance.thread_wait_until_stop
146
165
  end
147
166
 
148
- @instance.terminate unless @instance.terminated?
167
+ if @instance.respond_to?(:server_wait_until_stop)
168
+ @instance.server_wait_until_stop
169
+ end
170
+
171
+ unless @instance.terminated?
172
+ @instance.terminate rescue nil
173
+ end
174
+
175
+ if @socket_manager_server
176
+ @socket_manager_server.close
177
+ if @socket_manager_server.is_a?(String) && File.exist?(@socket_manager_path)
178
+ FileUtils.rm_f @socket_manager_path
179
+ end
180
+ end
149
181
  end
150
182
 
151
183
  def run_actual(timeout: DEFAULT_TIMEOUT, &block)
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '0.14.9'
19
+ VERSION = '0.14.10'
20
20
 
21
21
  end
@@ -58,7 +58,7 @@ begin
58
58
  ev.set
59
59
  ev.close
60
60
  if @pid > 0
61
- Porcess.waitpid(@pid)
61
+ Process.waitpid(@pid)
62
62
  end
63
63
  end
64
64
  end
@@ -79,4 +79,14 @@ class TextParserTest < ::Test::Unit::TestCase
79
79
  p2.configure('format' => 'none')
80
80
  assert_equal false, p2.parser.estimate_current_event
81
81
  end
82
+
83
+ data(ignorecase: Regexp::IGNORECASE,
84
+ multiline: Regexp::MULTILINE,
85
+ both: Regexp::IGNORECASE & Regexp::MULTILINE)
86
+ def test_regexp_parser_config(options)
87
+ source = "a"
88
+ parser = Fluent::TextParser::RegexpParser.new(Regexp.new(source, options), { "dummy" => "dummy" })
89
+ regexp = parser.instance_variable_get("@regexp")
90
+ assert_equal(options, regexp.options)
91
+ end
82
92
  end
@@ -1295,6 +1295,26 @@ module Fluent::Config
1295
1295
  assert_raise Fluent::ObsoletedParameterError.new("'key2' parameter is already removed: key2 has been removed.") do
1296
1296
  obj.configure(config_element('ROOT', '', {'key2' => 'yay'}, []))
1297
1297
  end
1298
+ first_log = obj.log.logs.first
1299
+ assert{ first_log && first_log.include?("[error]") && first_log.include?("config error in:\n<ROOT>\n key2 yay\n</ROOT>") }
1300
+ end
1301
+
1302
+ sub_test_case 'logger is nil' do
1303
+ test 'nothing raised if deprecated parameter is configured' do
1304
+ obj = ConfigurableSpec::UnRecommended.new
1305
+ obj.log = nil
1306
+ obj.configure(config_element('ROOT', '', {'key1' => 'yay'}, []))
1307
+ assert_nil(obj.log)
1308
+ end
1309
+
1310
+ test 'NoMethodError is not raised if obsoleted parameter is configured' do
1311
+ obj = ConfigurableSpec::UnRecommended.new
1312
+ obj.log = nil
1313
+ assert_raise Fluent::ObsoletedParameterError.new("'key2' parameter is already removed: key2 has been removed.") do
1314
+ obj.configure(config_element('ROOT', '', {'key2' => 'yay'}, []))
1315
+ end
1316
+ assert_nil(obj.log)
1317
+ end
1298
1318
  end
1299
1319
  end
1300
1320
 
@@ -69,7 +69,18 @@ end
69
69
 
70
70
  include Fluent::Test::Helpers
71
71
 
72
- def unused_port(num = 1)
72
+ def unused_port(num = 1, protocol: :tcp, bind: "0.0.0.0")
73
+ case protocol
74
+ when :tcp
75
+ unused_port_tcp(num)
76
+ when :udp
77
+ unused_port_udp(num, bind: bind)
78
+ else
79
+ raise ArgumentError, "unknown protocol: #{protocol}"
80
+ end
81
+ end
82
+
83
+ def unused_port_tcp(num = 1)
73
84
  ports = []
74
85
  sockets = []
75
86
  num.times do
@@ -85,6 +96,30 @@ def unused_port(num = 1)
85
96
  end
86
97
  end
87
98
 
99
+ PORT_RANGE_AVAILABLE = (1024...65535)
100
+
101
+ def unused_port_udp(num = 1, bind: "0.0.0.0")
102
+ family = IPAddr.new(IPSocket.getaddress(bind)).ipv4? ? ::Socket::AF_INET : ::Socket::AF_INET6
103
+ ports = []
104
+ sockets = []
105
+ while ports.size < num
106
+ port = rand(PORT_RANGE_AVAILABLE)
107
+ u = UDPSocket.new(family)
108
+ if (u.bind(bind, port) rescue nil)
109
+ ports << port
110
+ sockets << u
111
+ else
112
+ u.close
113
+ end
114
+ end
115
+ sockets.each{|s| s.close }
116
+ if num == 1
117
+ return ports.first
118
+ else
119
+ return *ports
120
+ end
121
+ end
122
+
88
123
  def waiting(seconds, logs: nil, plugin: nil)
89
124
  begin
90
125
  Timeout.timeout(seconds) do
@@ -2,9 +2,11 @@ require_relative '../helper'
2
2
  require 'timecop'
3
3
  require 'fluent/test/driver/filter'
4
4
  require 'fluent/plugin/filter_record_transformer'
5
+ require 'flexmock/test_unit'
5
6
 
6
7
  class RecordTransformerFilterTest < Test::Unit::TestCase
7
8
  include Fluent
9
+ include FlexMock::TestCase
8
10
 
9
11
  setup do
10
12
  Test.setup
@@ -53,7 +55,7 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
53
55
  hostname ${hostname}
54
56
  tag ${tag}
55
57
  time ${time}
56
- message ${hostname} ${tag_parts[-1]} ${message}
58
+ message ${hostname} ${tag_parts[-1]} ${record["message"]}
57
59
  </record>
58
60
  ]
59
61
 
@@ -119,7 +121,7 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
119
121
  config = %[
120
122
  enable_ruby yes
121
123
  <record>
122
- message ${hostname} ${tag_parts.last} ${"'" + message + "'"}
124
+ message ${hostname} ${tag_parts.last} ${"'" + record["message"] + "'"}
123
125
  </record>
124
126
  ]
125
127
  msgs = ['1', '2']
@@ -263,8 +265,8 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
263
265
  enable_ruby #{enable_ruby}
264
266
  remove_keys eventType0
265
267
  <record>
266
- message bar ${message}
267
- eventtype ${eventType0}
268
+ message bar ${record["message"]}
269
+ eventtype ${record["eventType0"]}
268
270
  </record>
269
271
  ]
270
272
  msgs = ['1', '2']
@@ -360,11 +362,11 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
360
362
  auto_typecast false
361
363
  enable_ruby #{enable_ruby}
362
364
  <record>
363
- single ${source}
364
- multiple ${source}${source}
365
- with_prefix prefix-${source}
366
- with_suffix ${source}-suffix
367
- with_quote source[""]
365
+ single ${record["source"]}
366
+ multiple ${record["source"]}${record["source"]}
367
+ with_prefix prefix-${record["source"]}
368
+ with_suffix ${record["source"]}-suffix
369
+ with_quote record["source"][""]
368
370
  </record>
369
371
  ]
370
372
  msgs = [
@@ -379,27 +381,27 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
379
381
  multiple: "stringstring",
380
382
  with_prefix: "prefix-string",
381
383
  with_suffix: "string-suffix",
382
- with_quote: %Q{source[""]} },
384
+ with_quote: %Q{record["source"][""]} },
383
385
  { single: 123.to_s,
384
386
  multiple: "#{123.to_s}#{123.to_s}",
385
387
  with_prefix: "prefix-#{123.to_s}",
386
388
  with_suffix: "#{123.to_s}-suffix",
387
- with_quote: %Q{source[""]} },
389
+ with_quote: %Q{record["source"][""]} },
388
390
  { single: [1, 2].to_s,
389
391
  multiple: "#{[1, 2].to_s}#{[1, 2].to_s}",
390
392
  with_prefix: "prefix-#{[1, 2].to_s}",
391
393
  with_suffix: "#{[1, 2].to_s}-suffix",
392
- with_quote: %Q{source[""]} },
394
+ with_quote: %Q{record["source"][""]} },
393
395
  { single: {a:1, b:2}.to_s,
394
396
  multiple: "#{{a:1, b:2}.to_s}#{{a:1, b:2}.to_s}",
395
397
  with_prefix: "prefix-#{{a:1, b:2}.to_s}",
396
398
  with_suffix: "#{{a:1, b:2}.to_s}-suffix",
397
- with_quote: %Q{source[""]} },
399
+ with_quote: %Q{record["source"][""]} },
398
400
  { single: nil.to_s,
399
401
  multiple: "#{nil.to_s}#{nil.to_s}",
400
402
  with_prefix: "prefix-#{nil.to_s}",
401
403
  with_suffix: "#{nil.to_s}-suffix",
402
- with_quote: %Q{source[""]} },
404
+ with_quote: %Q{record["source"][""]} },
403
405
  ]
404
406
  actual_results = []
405
407
  filtered = filter(config, msgs)
@@ -420,10 +422,10 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
420
422
  auto_typecast yes
421
423
  enable_ruby #{enable_ruby}
422
424
  <record>
423
- single ${source}
424
- multiple ${source}${source}
425
- with_prefix prefix-${source}
426
- with_suffix ${source}-suffix
425
+ single ${record["source"]}
426
+ multiple ${record["source"]}${record["source"]}
427
+ with_prefix prefix-${record["source"]}
428
+ with_suffix ${record["source"]}-suffix
427
429
  </record>
428
430
  ]
429
431
  msgs = [
@@ -467,28 +469,6 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
467
469
  end
468
470
  assert_equal(expected_results, actual_results)
469
471
  end
470
-
471
- test %Q[record["key"] with enable_ruby #{enable_ruby}] do
472
- config = %[
473
- enable_ruby #{enable_ruby}
474
- auto_typecast yes
475
- <record>
476
- _timestamp ${record["@timestamp"]}
477
- _foo_bar ${record["foo.bar"]}
478
- </record>
479
- ]
480
- d = create_driver(config)
481
- record = {
482
- "foo.bar" => "foo.bar",
483
- "@timestamp" => 10,
484
- }
485
- d.run { d.feed(@tag, @time, record) }
486
- filtered = d.filtered
487
- filtered.each do |t, r|
488
- assert { r['_timestamp'] == record['@timestamp'] }
489
- assert { r['_foo_bar'] == record['foo.bar'] }
490
- end
491
- end
492
472
  end
493
473
 
494
474
  test 'unknown placeholder (enable_ruby no)' do
@@ -503,30 +483,11 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
503
483
  }
504
484
  end
505
485
 
506
- data(auto_typecast_yes: ["yes", "unknown['bar']"],
507
- auto_typecast_no: ["no", "%Q[\#{unknown['bar']}]"])
508
- test 'failed to expand (enable_ruby yes)' do |(param, expected_log)|
509
-
510
- config = %[
511
- enable_ruby yes
512
- auto_typecast #{param}
513
- <record>
514
- message ${unknown['bar']}
515
- </record>
516
- ]
517
- filtered = filter(config) { |d|
518
- mock(d.instance.log).warn("failed to expand `#{expected_log}`", anything)
519
- }
520
- filtered.each do |t, r|
521
- assert_nil(r['message'])
522
- end
523
- end
524
-
525
486
  test 'expand fields starting with @ (enable_ruby no)' do
526
487
  config = %[
527
488
  enable_ruby no
528
489
  <record>
529
- foo ${@timestamp}
490
+ foo ${record["@timestamp"]}
530
491
  </record>
531
492
  ]
532
493
  d = create_driver(config)
@@ -555,54 +516,21 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
555
516
  assert_equal([message["@timestamp"]], r['foo'])
556
517
  end
557
518
  end
519
+ end # test placeholders
558
520
 
559
- test 'expand fields starting with @ (enable_ruby yes)' do
560
- config = %[
521
+ sub_test_case 'test error record' do
522
+ test 'invalid record for placeholders' do
523
+ d = create_driver(%[
561
524
  enable_ruby yes
562
525
  <record>
563
- foo ${__send__("@timestamp")}
526
+ foo ${record["unknown"]["key"]}
564
527
  </record>
565
- ]
566
- d = create_driver(config)
567
- message = {"@timestamp" => "foo"}
568
- d.run { d.feed(@tag, @time, message) }
569
- filtered = d.filtered
570
- filtered.each do |t, r|
571
- assert_equal(message["@timestamp"], r['foo'])
528
+ ])
529
+ flexmock(d.instance.router).should_receive(:emit_error_event).
530
+ with(String, Fluent::EventTime, Hash, RuntimeError).once
531
+ d.run do
532
+ d.feed(@tag, Fluent::EventTime.now, {'key' => 'value'})
572
533
  end
573
534
  end
574
- end # test placeholders
575
-
576
- test "compatibility test (enable_ruby yes)" do
577
- config = %[
578
- enable_ruby yes
579
- auto_typecast yes
580
- <record>
581
- _message prefix-${message}-suffix
582
- _time ${Time.at(time)}
583
- _number ${number == '-' ? 0 : number}
584
- _match ${/0x[0-9a-f]+/.match(hex)[0]}
585
- _timestamp ${__send__("@timestamp")}
586
- _foo_bar ${__send__('foo.bar')}
587
- </record>
588
- ]
589
- d = create_driver(config)
590
- record = {
591
- "number" => "-",
592
- "hex" => "0x10",
593
- "foo.bar" => "foo.bar",
594
- "@timestamp" => 10,
595
- "message" => "10",
596
- }
597
- d.run { d.feed(@tag, @time, record) }
598
- filtered = d.filtered
599
- filtered.each do |t, r|
600
- assert { r['_message'] == "prefix-#{record['message']}-suffix" }
601
- assert { r['_time'] == Time.at(@time) }
602
- assert { r['_number'] == 0 }
603
- assert { r['_match'] == record['hex'] }
604
- assert { r['_timestamp'] == record['@timestamp'] }
605
- assert { r['_foo_bar'] == record['foo.bar'] }
606
- end
607
535
  end
608
536
  end