fluentd 1.11.3-x86-mingw32 → 1.12.2-x86-mingw32

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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/.deepsource.toml +13 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  4. data/.github/ISSUE_TEMPLATE/config.yml +5 -0
  5. data/.github/workflows/linux-test.yaml +36 -0
  6. data/.github/workflows/macos-test.yaml +30 -0
  7. data/.github/workflows/stale-actions.yml +22 -0
  8. data/.github/workflows/windows-test.yaml +30 -0
  9. data/CHANGELOG.md +138 -0
  10. data/MAINTAINERS.md +5 -2
  11. data/README.md +2 -2
  12. data/bin/fluent-cap-ctl +7 -0
  13. data/bin/fluent-ctl +7 -0
  14. data/fluentd.gemspec +4 -3
  15. data/lib/fluent/capability.rb +87 -0
  16. data/lib/fluent/command/bundler_injection.rb +1 -1
  17. data/lib/fluent/command/ca_generate.rb +6 -3
  18. data/lib/fluent/command/cap_ctl.rb +174 -0
  19. data/lib/fluent/command/cat.rb +0 -1
  20. data/lib/fluent/command/ctl.rb +177 -0
  21. data/lib/fluent/command/fluentd.rb +4 -0
  22. data/lib/fluent/command/plugin_config_formatter.rb +18 -2
  23. data/lib/fluent/compat/parser.rb +2 -2
  24. data/lib/fluent/config/section.rb +2 -2
  25. data/lib/fluent/config/types.rb +2 -2
  26. data/lib/fluent/env.rb +4 -0
  27. data/lib/fluent/event.rb +3 -13
  28. data/lib/fluent/load.rb +0 -1
  29. data/lib/fluent/plugin.rb +5 -0
  30. data/lib/fluent/plugin/buffer.rb +2 -21
  31. data/lib/fluent/plugin/formatter.rb +24 -0
  32. data/lib/fluent/plugin/formatter_csv.rb +1 -1
  33. data/lib/fluent/plugin/formatter_hash.rb +3 -1
  34. data/lib/fluent/plugin/formatter_json.rb +3 -1
  35. data/lib/fluent/plugin/formatter_ltsv.rb +7 -5
  36. data/lib/fluent/plugin/formatter_out_file.rb +6 -4
  37. data/lib/fluent/plugin/formatter_single_value.rb +4 -2
  38. data/lib/fluent/plugin/formatter_tsv.rb +4 -2
  39. data/lib/fluent/plugin/in_http.rb +24 -3
  40. data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
  41. data/lib/fluent/plugin/in_tail.rb +128 -41
  42. data/lib/fluent/plugin/in_tail/position_file.rb +39 -14
  43. data/lib/fluent/plugin/in_tcp.rb +1 -0
  44. data/lib/fluent/plugin/out_copy.rb +18 -5
  45. data/lib/fluent/plugin/out_exec_filter.rb +3 -3
  46. data/lib/fluent/plugin/out_forward.rb +61 -28
  47. data/lib/fluent/plugin/out_http.rb +29 -4
  48. data/lib/fluent/plugin/output.rb +14 -6
  49. data/lib/fluent/plugin/storage_local.rb +3 -3
  50. data/lib/fluent/plugin_helper/http_server/compat/server.rb +1 -1
  51. data/lib/fluent/plugin_helper/inject.rb +4 -1
  52. data/lib/fluent/plugin_helper/retry_state.rb +4 -0
  53. data/lib/fluent/supervisor.rb +153 -48
  54. data/lib/fluent/system_config.rb +2 -1
  55. data/lib/fluent/time.rb +58 -1
  56. data/lib/fluent/version.rb +1 -1
  57. data/lib/fluent/winsvc.rb +22 -4
  58. data/templates/plugin_config_formatter/param.md-table.erb +10 -0
  59. data/test/command/test_binlog_reader.rb +22 -6
  60. data/test/command/test_cap_ctl.rb +100 -0
  61. data/test/command/test_ctl.rb +57 -0
  62. data/test/command/test_fluentd.rb +38 -0
  63. data/test/command/test_plugin_config_formatter.rb +124 -2
  64. data/test/config/test_configurable.rb +1 -1
  65. data/test/plugin/in_tail/test_position_file.rb +46 -26
  66. data/test/plugin/out_forward/test_connection_manager.rb +6 -0
  67. data/test/plugin/test_filter_stdout.rb +6 -1
  68. data/test/plugin/test_formatter_hash.rb +6 -3
  69. data/test/plugin/test_formatter_json.rb +14 -4
  70. data/test/plugin/test_formatter_ltsv.rb +13 -5
  71. data/test/plugin/test_formatter_out_file.rb +35 -14
  72. data/test/plugin/test_formatter_single_value.rb +12 -6
  73. data/test/plugin/test_formatter_tsv.rb +12 -4
  74. data/test/plugin/test_in_exec.rb +1 -1
  75. data/test/plugin/test_in_http.rb +25 -0
  76. data/test/plugin/test_in_tail.rb +470 -32
  77. data/test/plugin/test_out_copy.rb +87 -0
  78. data/test/plugin/test_out_file.rb +23 -18
  79. data/test/plugin/test_out_forward.rb +74 -0
  80. data/test/plugin/test_out_http.rb +20 -1
  81. data/test/plugin/test_output.rb +12 -0
  82. data/test/plugin/test_parser_syslog.rb +2 -2
  83. data/test/plugin/test_sd_file.rb +1 -1
  84. data/test/plugin_helper/test_child_process.rb +5 -2
  85. data/test/plugin_helper/test_compat_parameters.rb +7 -2
  86. data/test/plugin_helper/test_http_server_helper.rb +3 -1
  87. data/test/plugin_helper/test_inject.rb +42 -0
  88. data/test/plugin_helper/test_server.rb +18 -5
  89. data/test/test_capability.rb +74 -0
  90. data/test/test_event.rb +16 -0
  91. data/test/test_formatter.rb +64 -10
  92. data/test/test_output.rb +6 -1
  93. data/test/test_supervisor.rb +150 -1
  94. data/test/test_time_parser.rb +109 -0
  95. metadata +61 -29
  96. data/.travis.yml +0 -57
  97. data/appveyor.yml +0 -28
@@ -81,7 +81,7 @@ module Fluent
81
81
 
82
82
  def build_handler
83
83
  @methods.group_by(&:first).each do |(path, rest)|
84
- klass = Fluent::PluginHelper::HttpServer::Compat::WebrickHandler.build(Hash[rest.map { |e| [e[1], e[2]] }])
84
+ klass = Fluent::PluginHelper::HttpServer::Compat::WebrickHandler.build(**Hash[rest.map { |e| [e[1], e[2]] }])
85
85
  @server.mount(path, klass)
86
86
  end
87
87
  end
@@ -76,7 +76,7 @@ module Fluent
76
76
  config_param :time_key, :string, default: nil
77
77
 
78
78
  # To avoid defining :time_type twice
79
- config_param :time_type, :enum, list: [:float, :unixtime, :string], default: :float
79
+ config_param :time_type, :enum, list: [:float, :unixtime, :unixtime_millis, :unixtime_micros, :unixtime_nanos, :string], default: :float
80
80
 
81
81
  Fluent::TimeMixin::TIME_PARAMETERS.each do |name, type, opts|
82
82
  config_param(name, type, **opts)
@@ -132,6 +132,9 @@ module Fluent
132
132
  if @_inject_time_key
133
133
  @_inject_time_formatter = case @inject_config.time_type
134
134
  when :float then ->(time){ time.to_r.truncate(+6).to_f } # microsecond floating point value
135
+ when :unixtime_millis then ->(time) { time.respond_to?(:nsec) ? time.to_i * 1_000 + time.nsec / 1_000_000 : (time * 1_000).floor }
136
+ when :unixtime_micros then ->(time) { time.respond_to?(:nsec) ? time.to_i * 1_000_000 + time.nsec / 1_000 : (time * 1_000_000).floor }
137
+ when :unixtime_nanos then ->(time) { time.respond_to?(:nsec) ? time.to_i * 1_000_000_000 + time.nsec : (time * 1_000_000_000).floor }
135
138
  when :unixtime then ->(time){ time.to_i }
136
139
  else
137
140
  localtime = @inject_config.localtime && !@inject_config.utc
@@ -127,6 +127,10 @@ module Fluent
127
127
  nil
128
128
  end
129
129
 
130
+ def recalc_next_time
131
+ @next_time = calc_next_time
132
+ end
133
+
130
134
  def limit?
131
135
  if @forever
132
136
  false
@@ -45,6 +45,7 @@ module Fluent
45
45
  module ServerModule
46
46
  def before_run
47
47
  @fluentd_conf = config[:fluentd_conf]
48
+ @rpc_endpoint = nil
48
49
  @rpc_server = nil
49
50
  @counter = nil
50
51
 
@@ -53,23 +54,28 @@ module Fluent
53
54
  @enable_get_dump = config[:enable_get_dump]
54
55
  run_rpc_server
55
56
  end
56
- install_supervisor_signal_handlers
57
57
 
58
- if config[:signame]
59
- @signame = config[:signame]
58
+ if Fluent.windows?
60
59
  install_windows_event_handler
60
+ else
61
+ install_supervisor_signal_handlers
61
62
  end
62
63
 
63
64
  if counter = config[:counter_server]
64
65
  run_counter_server(counter)
65
66
  end
66
67
 
67
- socket_manager_path = ServerEngine::SocketManager::Server.generate_path
68
- ServerEngine::SocketManager::Server.open(socket_manager_path)
69
- ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = socket_manager_path.to_s
68
+ if config[:disable_shared_socket]
69
+ $log.info "shared socket for multiple workers is disabled"
70
+ else
71
+ socket_manager_path = ServerEngine::SocketManager::Server.generate_path
72
+ ServerEngine::SocketManager::Server.open(socket_manager_path)
73
+ ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = socket_manager_path.to_s
74
+ end
70
75
  end
71
76
 
72
77
  def after_run
78
+ stop_windows_event_thread if Fluent.windows?
73
79
  stop_rpc_server if @rpc_endpoint
74
80
  stop_counter_server if @counter
75
81
  Fluent::Supervisor.cleanup_resources
@@ -92,7 +98,8 @@ module Fluent
92
98
  @rpc_server.mount_proc('/api/processes.flushBuffersAndKillWorkers') { |req, res|
93
99
  $log.debug "fluentd RPC got /api/processes.flushBuffersAndKillWorkers request"
94
100
  if Fluent.windows?
95
- $log.warn "operation 'flushBuffersAndKillWorkers' is not supported on Windows now."
101
+ supervisor_sigusr1_handler
102
+ stop(true)
96
103
  else
97
104
  Process.kill :USR1, $$
98
105
  Process.kill :TERM, $$
@@ -101,7 +108,9 @@ module Fluent
101
108
  }
102
109
  @rpc_server.mount_proc('/api/plugins.flushBuffers') { |req, res|
103
110
  $log.debug "fluentd RPC got /api/plugins.flushBuffers request"
104
- unless Fluent.windows?
111
+ if Fluent.windows?
112
+ supervisor_sigusr1_handler
113
+ else
105
114
  Process.kill :USR1, $$
106
115
  end
107
116
  nil
@@ -125,7 +134,9 @@ module Fluent
125
134
 
126
135
  @rpc_server.mount_proc('/api/config.gracefulReload') { |req, res|
127
136
  $log.debug "fluentd RPC got /api/config.gracefulReload request"
128
- unless Fluent.windows?
137
+ if Fluent.windows?
138
+ supervisor_sigusr2_handler
139
+ else
129
140
  Process.kill :USR2, $$
130
141
  end
131
142
 
@@ -159,38 +170,101 @@ module Fluent
159
170
  end
160
171
 
161
172
  def install_supervisor_signal_handlers
173
+ return if Fluent.windows?
174
+
162
175
  trap :HUP do
163
176
  $log.debug "fluentd supervisor process get SIGHUP"
164
177
  supervisor_sighup_handler
165
- end unless Fluent.windows?
178
+ end
166
179
 
167
180
  trap :USR1 do
168
181
  $log.debug "fluentd supervisor process get SIGUSR1"
169
182
  supervisor_sigusr1_handler
170
- end unless Fluent.windows?
183
+ end
171
184
 
172
185
  trap :USR2 do
173
186
  $log.debug 'fluentd supervisor process got SIGUSR2'
174
187
  supervisor_sigusr2_handler
175
- end unless Fluent.windows?
188
+ end
189
+ end
190
+
191
+ if Fluent.windows?
192
+ # Override some methods of ServerEngine::MultiSpawnWorker
193
+ # Since Fluentd's Supervisor doesn't use ServerEngine's HUP, USR1 and USR2
194
+ # handlers (see install_supervisor_signal_handlers), they should be
195
+ # disabled also on Windows, just send commands to workers instead.
196
+ def restart(graceful)
197
+ @monitors.each do |m|
198
+ m.send_command(graceful ? "GRACEFUL_RESTART\n" : "IMMEDIATE_RESTART\n")
199
+ end
200
+ end
201
+
202
+ def reload
203
+ @monitors.each do |m|
204
+ m.send_command("RELOAD\n")
205
+ end
206
+ end
176
207
  end
177
208
 
178
209
  def install_windows_event_handler
210
+ return unless Fluent.windows?
211
+
212
+ @pid_signame = "fluentd_#{$$}"
213
+ @signame = config[:signame]
214
+
179
215
  Thread.new do
180
- ev = Win32::Event.new(@signame)
216
+ ipc = Win32::Ipc.new(nil)
217
+ events = [
218
+ Win32::Event.new("#{@pid_signame}_STOP_EVENT_THREAD"),
219
+ Win32::Event.new("#{@pid_signame}"),
220
+ Win32::Event.new("#{@pid_signame}_HUP"),
221
+ Win32::Event.new("#{@pid_signame}_USR1"),
222
+ Win32::Event.new("#{@pid_signame}_USR2"),
223
+ ]
224
+ if @signame
225
+ signame_events = [
226
+ Win32::Event.new("#{@signame}"),
227
+ Win32::Event.new("#{@signame}_HUP"),
228
+ Win32::Event.new("#{@signame}_USR1"),
229
+ Win32::Event.new("#{@signame}_USR2"),
230
+ ]
231
+ events.concat(signame_events)
232
+ end
181
233
  begin
182
- ev.reset
183
- until WaitForSingleObject(ev.handle, 0) == WAIT_OBJECT_0
184
- sleep 1
234
+ loop do
235
+ idx = ipc.wait_any(events, Windows::Synchronize::INFINITE)
236
+ if idx > 0 && idx <= events.length
237
+ $log.debug("Got Win32 event \"#{events[idx - 1].name}\"")
238
+ else
239
+ $log.warn("Unexpected reutrn value of Win32::Ipc#wait_any: #{idx}")
240
+ end
241
+ case idx
242
+ when 2, 6
243
+ stop(true)
244
+ when 3, 7
245
+ supervisor_sighup_handler
246
+ when 4, 8
247
+ supervisor_sigusr1_handler
248
+ when 5, 9
249
+ supervisor_sigusr2_handler
250
+ when 1
251
+ break
252
+ end
185
253
  end
186
- kill_worker
187
- stop(true)
188
254
  ensure
189
- ev.close
255
+ events.each { |event| event.close }
190
256
  end
191
257
  end
192
258
  end
193
259
 
260
+ def stop_windows_event_thread
261
+ if Fluent.windows?
262
+ ev = Win32::Event.open("#{@pid_signame}_STOP_EVENT_THREAD")
263
+ ev.set
264
+ ev.close
265
+ end
266
+ end
267
+
194
268
  def supervisor_sighup_handler
195
269
  kill_worker
196
270
  end
@@ -265,9 +339,25 @@ module Fluent
265
339
  def send_signal_to_workers(signal)
266
340
  return unless config[:worker_pid]
267
341
 
268
- config[:worker_pid].each_value do |pid|
269
- # don't rescue Errno::ESRCH here (invalid status)
270
- Process.kill(signal, pid)
342
+ if Fluent.windows?
343
+ send_command_to_workers(signal)
344
+ else
345
+ config[:worker_pid].each_value do |pid|
346
+ # don't rescue Errno::ESRCH here (invalid status)
347
+ Process.kill(signal, pid)
348
+ end
349
+ end
350
+ end
351
+
352
+ def send_command_to_workers(signal)
353
+ # Use SeverEngine's CommandSender on Windows
354
+ case signal
355
+ when :HUP
356
+ restart(false)
357
+ when :USR1
358
+ restart(true)
359
+ when :USR2
360
+ reload
271
361
  end
272
362
  end
273
363
  end
@@ -295,7 +385,7 @@ module Fluent
295
385
  config_mtime = File.mtime(path)
296
386
 
297
387
  # reuse previous config if last load time is within 5 seconds and mtime of the config file is not changed
298
- if Time.now - Time.at(pre_loadtime) < 5 and config_mtime == pre_config_mtime
388
+ if (Time.now - Time.at(pre_loadtime) < 5) && (config_mtime == pre_config_mtime)
299
389
  return params['pre_conf']
300
390
  end
301
391
 
@@ -367,6 +457,7 @@ module Fluent
367
457
  config_path: path,
368
458
  main_cmd: params['main_cmd'],
369
459
  signame: params['signame'],
460
+ disable_shared_socket: params['disable_shared_socket']
370
461
  }
371
462
  if daemonize
372
463
  se_config[:pid_path] = pid_path
@@ -482,7 +573,8 @@ module Fluent
482
573
  supervise: true,
483
574
  standalone_worker: false,
484
575
  signame: nil,
485
- conf_encoding: 'utf-8'
576
+ conf_encoding: 'utf-8',
577
+ disable_shared_socket: nil
486
578
  }
487
579
  end
488
580
 
@@ -710,6 +802,7 @@ module Fluent
710
802
  'counter_server' => @system_config.counter_server,
711
803
  'log_format' => @system_config.log.format,
712
804
  'log_time_format' => @system_config.log.time_format,
805
+ 'disable_shared_socket' => @system_config.disable_shared_socket
713
806
  }
714
807
 
715
808
  se = ServerEngine.create(ServerModule, WorkerModule){
@@ -746,33 +839,45 @@ module Fluent
746
839
  end
747
840
  end
748
841
 
749
- trap :USR1 do
750
- flush_buffer
751
- end unless Fluent.windows?
842
+ if Fluent.windows?
843
+ install_main_process_command_handlers
844
+ else
845
+ trap :USR1 do
846
+ flush_buffer
847
+ end
752
848
 
753
- trap :USR2 do
754
- reload_config
755
- end unless Fluent.windows?
849
+ trap :USR2 do
850
+ reload_config
851
+ end
852
+ end
853
+ end
756
854
 
757
- if Fluent.windows?
758
- command_pipe = STDIN.dup
759
- STDIN.reopen(File::NULL, "rb")
760
- command_pipe.binmode
761
- command_pipe.sync = true
855
+ def install_main_process_command_handlers
856
+ command_pipe = $stdin.dup
857
+ $stdin.reopen(File::NULL, "rb")
858
+ command_pipe.binmode
859
+ command_pipe.sync = true
762
860
 
763
- Thread.new do
764
- loop do
765
- cmd = command_pipe.gets.chomp
766
- case cmd
767
- when "GRACEFUL_STOP", "IMMEDIATE_STOP"
768
- $log.debug "fluentd main process get #{cmd} command"
769
- @finished = true
770
- $log.debug "getting start to shutdown main process"
771
- Fluent::Engine.stop
772
- break
773
- else
774
- $log.warn "fluentd main process get unknown command [#{cmd}]"
775
- end
861
+ Thread.new do
862
+ loop do
863
+ cmd = command_pipe.gets
864
+ break unless cmd
865
+
866
+ case cmd.chomp!
867
+ when "GRACEFUL_STOP", "IMMEDIATE_STOP"
868
+ $log.debug "fluentd main process get #{cmd} command"
869
+ @finished = true
870
+ $log.debug "getting start to shutdown main process"
871
+ Fluent::Engine.stop
872
+ break
873
+ when "GRACEFUL_RESTART"
874
+ $log.debug "fluentd main process get #{cmd} command"
875
+ flush_buffer
876
+ when "RELOAD"
877
+ $log.debug "fluentd main process get #{cmd} command"
878
+ reload_config
879
+ else
880
+ $log.warn "fluentd main process get unknown command [#{cmd}]"
776
881
  end
777
882
  end
778
883
  end
@@ -27,7 +27,7 @@ module Fluent
27
27
  :log_event_verbose, :ignore_repeated_log_interval, :ignore_same_log_interval,
28
28
  :without_source, :rpc_endpoint, :enable_get_dump, :process_name,
29
29
  :file_permission, :dir_permission, :counter_server, :counter_client,
30
- :strict_config_value, :enable_msgpack_time_support
30
+ :strict_config_value, :enable_msgpack_time_support, :disable_shared_socket
31
31
  ]
32
32
 
33
33
  config_param :workers, :integer, default: 1
@@ -45,6 +45,7 @@ module Fluent
45
45
  config_param :process_name, :string, default: nil
46
46
  config_param :strict_config_value, :bool, default: nil
47
47
  config_param :enable_msgpack_time_support, :bool, default: nil
48
+ config_param :disable_shared_socket, :bool, default: nil
48
49
  config_param :file_permission, default: nil do |v|
49
50
  v.to_i(8)
50
51
  end
data/lib/fluent/time.rb CHANGED
@@ -50,6 +50,7 @@ module Fluent
50
50
  def to_int
51
51
  @sec
52
52
  end
53
+ alias :to_i :to_int
53
54
 
54
55
  def to_f
55
56
  @sec + @nsec / 1_000_000_000.0
@@ -131,13 +132,14 @@ module Fluent
131
132
  end
132
133
 
133
134
  module TimeMixin
134
- TIME_TYPES = ['string', 'unixtime', 'float']
135
+ TIME_TYPES = ['string', 'unixtime', 'float', 'mixed']
135
136
 
136
137
  TIME_PARAMETERS = [
137
138
  [:time_format, :string, {default: nil}],
138
139
  [:localtime, :bool, {default: true}], # UTC if :localtime is false and :timezone is nil
139
140
  [:utc, :bool, {default: false}], # to turn :localtime false
140
141
  [:timezone, :string, {default: nil}],
142
+ [:time_format_fallbacks, :array, {default: []}], # try time_format, then try fallbacks
141
143
  ]
142
144
  TIME_FULL_PARAMETERS = [
143
145
  # To avoid to define :time_type twice (in plugin_helper/inject)
@@ -169,6 +171,12 @@ module Fluent
169
171
  raise Fluent::ConfigError, "both of utc and localtime are specified, use only one of them"
170
172
  end
171
173
 
174
+ if conf.has_key?('time_type') and @time_type == :mixed
175
+ if @time_format.nil? and @time_format_fallbacks.empty?
176
+ raise Fluent::ConfigError, "time_type is :mixed but time_format and time_format_fallbacks is empty."
177
+ end
178
+ end
179
+
172
180
  Fluent::Timezone.validate!(@timezone) if @timezone
173
181
  end
174
182
  end
@@ -179,6 +187,7 @@ module Fluent
179
187
  end
180
188
 
181
189
  def time_parser_create(type: @time_type, format: @time_format, timezone: @timezone, force_localtime: false)
190
+ return MixedTimeParser.new(type, format, @localtime, timezone, @utc, force_localtime, @time_format_fallbacks) if type == :mixed
182
191
  return NumericTimeParser.new(type) if type != :string
183
192
  return TimeParser.new(format, true, nil) if force_localtime
184
193
 
@@ -451,4 +460,52 @@ module Fluent
451
460
  end
452
461
  end
453
462
  end
463
+
464
+ # MixedTimeParser is available when time_type is set to :mixed
465
+ #
466
+ # Use Case 1: primary format is specified explicitly in time_format
467
+ # time_type mixed
468
+ # time_format %iso8601
469
+ # time_format_fallbacks unixtime
470
+ # Use Case 2: time_format is omitted
471
+ # time_type mixed
472
+ # time_format_fallbacks %iso8601, unixtime
473
+ #
474
+ class MixedTimeParser < TimeParser # to include TimeParseError
475
+ def initialize(type, format = nil, localtime = nil, timezone = nil, utc = nil, force_localtime = nil, fallbacks = [])
476
+ @parsers = []
477
+ fallbacks.unshift(format).each do |fallback|
478
+ next unless fallback
479
+ case fallback
480
+ when 'unixtime', 'float'
481
+ @parsers << NumericTimeParser.new(fallback, localtime, timezone)
482
+ else
483
+ if force_localtime
484
+ @parsers << TimeParser.new(fallback, true, nil)
485
+ else
486
+ localtime = localtime && (timezone.nil? && !utc)
487
+ @parsers << TimeParser.new(fallback, localtime, timezone)
488
+ end
489
+ end
490
+ end
491
+ end
492
+
493
+ def parse(value)
494
+ @parsers.each do |parser|
495
+ begin
496
+ Float(value) if parser.class == Fluent::NumericTimeParser
497
+ rescue
498
+ next
499
+ end
500
+ begin
501
+ return parser.parse(value)
502
+ rescue
503
+ # skip TimeParseError
504
+ end
505
+ end
506
+ fallback_class = @parsers.collect do |parser| parser.class end.join(",")
507
+ raise TimeParseError, "invalid time format: value = #{value}, even though fallbacks: #{fallback_class}"
508
+ end
509
+ end
510
+
454
511
  end