fluentd 0.14.7-x86-mingw32 → 0.14.10-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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +2 -0
  4. data/CONTRIBUTING.md +6 -1
  5. data/ChangeLog +95 -0
  6. data/Rakefile +21 -0
  7. data/appveyor.yml +1 -0
  8. data/code-of-conduct.md +3 -0
  9. data/example/out_exec_filter.conf +42 -0
  10. data/fluentd.gemspec +1 -1
  11. data/lib/fluent/agent.rb +2 -2
  12. data/lib/fluent/command/binlog_reader.rb +1 -1
  13. data/lib/fluent/command/cat.rb +15 -4
  14. data/lib/fluent/compat/output.rb +14 -9
  15. data/lib/fluent/compat/parser.rb +141 -11
  16. data/lib/fluent/config/configure_proxy.rb +2 -11
  17. data/lib/fluent/config/section.rb +8 -1
  18. data/lib/fluent/configurable.rb +1 -3
  19. data/lib/fluent/env.rb +1 -1
  20. data/lib/fluent/log.rb +1 -1
  21. data/lib/fluent/plugin/base.rb +17 -0
  22. data/lib/fluent/plugin/filter_parser.rb +108 -0
  23. data/lib/fluent/plugin/filter_record_transformer.rb +14 -35
  24. data/lib/fluent/plugin/filter_stdout.rb +1 -1
  25. data/lib/fluent/plugin/formatter.rb +5 -0
  26. data/lib/fluent/plugin/formatter_msgpack.rb +4 -0
  27. data/lib/fluent/plugin/formatter_stdout.rb +3 -2
  28. data/lib/fluent/plugin/formatter_tsv.rb +34 -0
  29. data/lib/fluent/plugin/in_exec.rb +48 -93
  30. data/lib/fluent/plugin/in_forward.rb +66 -265
  31. data/lib/fluent/plugin/in_http.rb +68 -65
  32. data/lib/fluent/plugin/in_monitor_agent.rb +8 -4
  33. data/lib/fluent/plugin/in_syslog.rb +42 -58
  34. data/lib/fluent/plugin/in_tail.rb +29 -14
  35. data/lib/fluent/plugin/in_tcp.rb +54 -14
  36. data/lib/fluent/plugin/in_udp.rb +49 -13
  37. data/lib/fluent/plugin/multi_output.rb +1 -3
  38. data/lib/fluent/plugin/out_exec.rb +58 -71
  39. data/lib/fluent/plugin/out_exec_filter.rb +199 -279
  40. data/lib/fluent/plugin/out_file.rb +172 -81
  41. data/lib/fluent/plugin/out_forward.rb +229 -206
  42. data/lib/fluent/plugin/out_stdout.rb +6 -21
  43. data/lib/fluent/plugin/output.rb +90 -59
  44. data/lib/fluent/plugin/parser.rb +121 -61
  45. data/lib/fluent/plugin/parser_csv.rb +9 -3
  46. data/lib/fluent/plugin/parser_json.rb +37 -35
  47. data/lib/fluent/plugin/parser_ltsv.rb +11 -19
  48. data/lib/fluent/plugin/parser_msgpack.rb +50 -0
  49. data/lib/fluent/plugin/parser_regexp.rb +15 -42
  50. data/lib/fluent/plugin/parser_tsv.rb +8 -3
  51. data/lib/fluent/plugin_helper.rb +10 -1
  52. data/lib/fluent/plugin_helper/child_process.rb +139 -73
  53. data/lib/fluent/plugin_helper/compat_parameters.rb +93 -4
  54. data/lib/fluent/plugin_helper/event_emitter.rb +14 -1
  55. data/lib/fluent/plugin_helper/event_loop.rb +24 -6
  56. data/lib/fluent/plugin_helper/extract.rb +16 -4
  57. data/lib/fluent/plugin_helper/formatter.rb +9 -11
  58. data/lib/fluent/plugin_helper/inject.rb +16 -1
  59. data/lib/fluent/plugin_helper/parser.rb +3 -3
  60. data/lib/fluent/plugin_helper/server.rb +494 -0
  61. data/lib/fluent/plugin_helper/socket.rb +101 -0
  62. data/lib/fluent/plugin_helper/socket_option.rb +84 -0
  63. data/lib/fluent/plugin_helper/timer.rb +1 -0
  64. data/lib/fluent/root_agent.rb +1 -1
  65. data/lib/fluent/test/driver/base.rb +95 -49
  66. data/lib/fluent/test/driver/base_owner.rb +18 -8
  67. data/lib/fluent/test/driver/multi_output.rb +2 -1
  68. data/lib/fluent/test/driver/output.rb +29 -6
  69. data/lib/fluent/test/helpers.rb +3 -1
  70. data/lib/fluent/test/log.rb +4 -0
  71. data/lib/fluent/test/startup_shutdown.rb +13 -0
  72. data/lib/fluent/time.rb +14 -8
  73. data/lib/fluent/version.rb +1 -1
  74. data/lib/fluent/winsvc.rb +1 -1
  75. data/test/command/test_binlog_reader.rb +5 -1
  76. data/test/compat/test_parser.rb +10 -0
  77. data/test/config/test_configurable.rb +193 -0
  78. data/test/config/test_configure_proxy.rb +0 -43
  79. data/test/helper.rb +36 -1
  80. data/test/plugin/test_base.rb +16 -0
  81. data/test/plugin/test_filter_parser.rb +665 -0
  82. data/test/plugin/test_filter_record_transformer.rb +36 -100
  83. data/test/plugin/test_filter_stdout.rb +18 -27
  84. data/test/plugin/test_in_dummy.rb +1 -1
  85. data/test/plugin/test_in_exec.rb +206 -94
  86. data/test/plugin/test_in_forward.rb +268 -347
  87. data/test/plugin/test_in_http.rb +310 -186
  88. data/test/plugin/test_in_monitor_agent.rb +65 -35
  89. data/test/plugin/test_in_syslog.rb +39 -3
  90. data/test/plugin/test_in_tcp.rb +78 -62
  91. data/test/plugin/test_in_udp.rb +101 -80
  92. data/test/plugin/test_out_exec.rb +223 -68
  93. data/test/plugin/test_out_exec_filter.rb +520 -169
  94. data/test/plugin/test_out_file.rb +637 -177
  95. data/test/plugin/test_out_forward.rb +242 -234
  96. data/test/plugin/test_out_null.rb +1 -1
  97. data/test/plugin/test_out_secondary_file.rb +4 -2
  98. data/test/plugin/test_out_stdout.rb +14 -35
  99. data/test/plugin/test_output_as_buffered.rb +60 -2
  100. data/test/plugin/test_parser.rb +359 -0
  101. data/test/plugin/test_parser_csv.rb +1 -2
  102. data/test/plugin/test_parser_json.rb +3 -4
  103. data/test/plugin/test_parser_labeled_tsv.rb +1 -2
  104. data/test/plugin/test_parser_none.rb +1 -2
  105. data/test/plugin/test_parser_regexp.rb +8 -4
  106. data/test/plugin/test_parser_tsv.rb +4 -3
  107. data/test/plugin_helper/test_child_process.rb +184 -0
  108. data/test/plugin_helper/test_compat_parameters.rb +88 -1
  109. data/test/plugin_helper/test_extract.rb +0 -1
  110. data/test/plugin_helper/test_formatter.rb +5 -2
  111. data/test/plugin_helper/test_inject.rb +21 -0
  112. data/test/plugin_helper/test_parser.rb +6 -5
  113. data/test/plugin_helper/test_server.rb +905 -0
  114. data/test/test_event_time.rb +3 -1
  115. data/test/test_output.rb +53 -2
  116. data/test/test_plugin_classes.rb +20 -0
  117. data/test/test_root_agent.rb +139 -0
  118. data/test/test_test_drivers.rb +135 -0
  119. metadata +28 -8
  120. data/test/plugin/test_parser_base.rb +0 -32
@@ -123,7 +123,7 @@ module Fluent
123
123
  end
124
124
 
125
125
  # configured_in MUST be kept
126
- merged.configured_in_section = self.configured_in_section
126
+ merged.configured_in_section = self.configured_in_section || other.configured_in_section
127
127
 
128
128
  merged.argument = other.argument || self.argument
129
129
  merged.params = other.params.merge(self.params)
@@ -177,7 +177,7 @@ module Fluent
177
177
  self.class.new(@name, options)
178
178
  end
179
179
 
180
- merged.configured_in_section = self.configured_in_section
180
+ merged.configured_in_section = self.configured_in_section || other.configured_in_section
181
181
 
182
182
  merged.argument = self.argument || other.argument
183
183
  merged.params = other.params.merge(self.params)
@@ -339,15 +339,6 @@ module Fluent
339
339
  sub_proxy = ConfigureProxy.new(name, type_lookup: @type_lookup, **kwargs)
340
340
  sub_proxy.instance_exec(&block)
341
341
 
342
- if sub_proxy.init?
343
- if sub_proxy.argument && !sub_proxy.defaults.has_key?(sub_proxy.argument.first)
344
- raise ArgumentError, "#{name}: init is specified, but default value of argument is missing"
345
- end
346
- if sub_proxy.params.keys.any?{|param_name| !sub_proxy.defaults.has_key?(param_name)}
347
- raise ArgumentError, "#{name}: init is specified, but there're parameters without default values"
348
- end
349
- end
350
-
351
342
  @params.delete(name)
352
343
  @sections[name] = sub_proxy
353
344
 
@@ -147,7 +147,7 @@ module Fluent
147
147
  # because they are expected to be removed entirely sometime in the future.
148
148
  # Obsoleted: These obsolete features have been entirely removed from JavaScript and can no longer be used.
149
149
  if opts[:deprecated]
150
- logger.warn "'#{name}' parameter is deprecated: #{opts[:deprecated]}"
150
+ logger.warn "'#{name}' parameter is deprecated: #{opts[:deprecated]}" if logger
151
151
  end
152
152
  if opts[:obsoleted]
153
153
  logger.error "config error in:\n#{conf}" if logger
@@ -166,6 +166,13 @@ module Fluent
166
166
  varname = subproxy.variable_name
167
167
  elements = (conf.respond_to?(:elements) ? conf.elements : []).select{ |e| e.name == subproxy.name.to_s || e.name == subproxy.alias.to_s }
168
168
  if elements.empty? && subproxy.init?
169
+ if subproxy.argument && !subproxy.defaults.has_key?(subproxy.argument.first)
170
+ raise ArgumentError, "#{name}: init is specified, but default value of argument is missing"
171
+ end
172
+ missing_keys = subproxy.params.keys.select{|param_name| !subproxy.defaults.has_key?(param_name)}
173
+ if !missing_keys.empty?
174
+ raise ArgumentError, "#{name}: init is specified, but there're parameters without default values:#{missing_keys.join(',')}"
175
+ end
169
176
  elements << Fluent::Config::Element.new(subproxy.name.to_s, '', {}, [])
170
177
  end
171
178
 
@@ -71,9 +71,7 @@ module Fluent
71
71
  root.instance_eval{ @params.keys }.each do |param_name|
72
72
  next if param_name.to_s.start_with?('@')
73
73
  varname = "@#{param_name}".to_sym
74
- if (! root[param_name].nil?) || (instance_variable_defined?(varname) && instance_variable_get(varname).nil?)
75
- instance_variable_set(varname, root[param_name])
76
- end
74
+ instance_variable_set(varname, root[param_name])
77
75
  end
78
76
 
79
77
  self
@@ -18,7 +18,7 @@ module Fluent
18
18
  DEFAULT_CONFIG_PATH = ENV['FLUENT_CONF'] || '/etc/fluent/fluent.conf'
19
19
  DEFAULT_PLUGIN_DIR = ENV['FLUENT_PLUGIN'] || '/etc/fluent/plugin'
20
20
  DEFAULT_SOCKET_PATH = ENV['FLUENT_SOCKET'] || '/var/run/fluent/fluent.sock'
21
- DEFAULT_OJ_OPTIONS = {bigdecimal_load: :float, mode: :compat}
21
+ DEFAULT_OJ_OPTIONS = {bigdecimal_load: :float, mode: :compat, use_to_json: true}
22
22
  IS_WINDOWS = /mswin|mingw/ === RUBY_PLATFORM
23
23
  private_constant :IS_WINDOWS
24
24
 
@@ -446,7 +446,7 @@ module Fluent
446
446
 
447
447
  # This class delegetes some methods which are used in `Fluent::Logger` to a instance variable(`dev`) in `Logger::LogDevice` class
448
448
  # https://github.com/ruby/ruby/blob/7b2d47132ff8ee950b0f978ab772dee868d9f1b0/lib/logger.rb#L661
449
- class LogDeviceIO < Logger::LogDevice
449
+ class LogDeviceIO < ::Logger::LogDevice
450
450
  def flush
451
451
  if @dev.respond_to?(:flush)
452
452
  @dev.flush
@@ -31,6 +31,7 @@ module Fluent
31
31
  def initialize
32
32
  super
33
33
  @_state = State.new(false, false, false, false, false, false, false, false, false)
34
+ @_context_router = nil
34
35
  @under_plugin_development = false
35
36
  end
36
37
 
@@ -45,6 +46,22 @@ module Fluent
45
46
  self
46
47
  end
47
48
 
49
+ def string_safe_encoding(str)
50
+ unless str.valid_encoding?
51
+ log.info "invalid byte sequence is replaced in `#{str}`" if self.respond_to?(:log)
52
+ str = str.scrub('?')
53
+ end
54
+ yield str
55
+ end
56
+
57
+ def context_router=(router)
58
+ @_context_router = router
59
+ end
60
+
61
+ def context_router
62
+ @_context_router
63
+ end
64
+
48
65
  def start
49
66
  @_state.start = true
50
67
  self
@@ -0,0 +1,108 @@
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 'fluent/time'
18
+ require 'fluent/config/error'
19
+ require 'fluent/plugin/filter'
20
+ require 'fluent/plugin_helper/parser'
21
+ require 'fluent/plugin_helper/compat_parameters'
22
+
23
+ module Fluent::Plugin
24
+ class ParserFilter < Filter
25
+ Fluent::Plugin.register_filter('parser', self)
26
+
27
+ helpers :parser, :compat_parameters
28
+
29
+ config_param :key_name, :string
30
+ config_param :reserve_data, :bool, default: false
31
+ config_param :reserve_time, :bool, default: false
32
+ config_param :inject_key_prefix, :string, default: nil
33
+ config_param :replace_invalid_sequence, :bool, default: false
34
+ config_param :hash_value_field, :string, default: nil
35
+
36
+ attr_reader :parser
37
+
38
+ def configure(conf)
39
+ compat_parameters_convert(conf, :parser)
40
+
41
+ super
42
+
43
+ @parser = parser_create
44
+ end
45
+
46
+ FAILED_RESULT = [nil, nil].freeze # reduce allocation cost
47
+ REPLACE_CHAR = '?'.freeze
48
+
49
+ def filter_with_time(tag, time, record)
50
+ raw_value = record[@key_name]
51
+ if raw_value.nil?
52
+ router.emit_error_event(tag, time, record, ArgumentError.new("#{@key_name} does not exist"))
53
+ if @reserve_data
54
+ return time, handle_parsed(tag, record, time, {})
55
+ else
56
+ return FAILED_RESULT
57
+ end
58
+ end
59
+ begin
60
+ @parser.parse(raw_value) do |t, values|
61
+ if values
62
+ t = if @reserve_time
63
+ time
64
+ else
65
+ t.nil? ? time : t
66
+ end
67
+ r = handle_parsed(tag, record, t, values)
68
+ return t, r
69
+ else
70
+ router.emit_error_event(tag, time, record, Fluent::Plugin::Parser::ParserError.new("pattern not match with data '#{raw_value}'"))
71
+ if @reserve_data
72
+ t = time
73
+ r = handle_parsed(tag, record, time, {})
74
+ return t, r
75
+ else
76
+ return FAILED_RESULT
77
+ end
78
+ end
79
+ end
80
+ rescue Fluent::Plugin::Parser::ParserError => e
81
+ router.emit_error_event(tag, time, record, e)
82
+ return FAILED_RESULT
83
+ rescue ArgumentError => e
84
+ raise unless @replace_invalid_sequence
85
+ raise unless e.message.index("invalid byte sequence in") == 0
86
+
87
+ raw_value = raw_value.scrub(REPLACE_CHAR)
88
+ retry
89
+ rescue => e
90
+ router.emit_error_event(tag, time, record, Fluent::Plugin::Parser::ParserError.new("parse failed #{e.message}"))
91
+ return FAILED_RESULT
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ def handle_parsed(tag, record, t, values)
98
+ if values && @inject_key_prefix
99
+ values = Hash[values.map { |k, v| [@inject_key_prefix + k, v] }]
100
+ end
101
+ r = @hash_value_field ? {@hash_value_field => values} : values
102
+ if @reserve_data
103
+ r = r ? record.merge(r) : record
104
+ end
105
+ r
106
+ end
107
+ end
108
+ end
@@ -38,7 +38,7 @@ module Fluent::Plugin
38
38
  desc 'When set to true, the full Ruby syntax is enabled in the ${...} expression.'
39
39
  config_param :enable_ruby, :bool, default: false
40
40
  desc 'Use original value type.'
41
- config_param :auto_typecast, :bool, default: false # false for lower version compatibility
41
+ config_param :auto_typecast, :bool, default: true
42
42
 
43
43
  def configure(conf)
44
44
  super
@@ -92,24 +92,22 @@ module Fluent::Plugin
92
92
  'tag_suffix' => tag_suffix,
93
93
  'hostname' => @hostname,
94
94
  }
95
- last_record = nil
96
95
  es.each do |time, record|
97
- last_record = record # for debug log
98
- placeholder_values.merge!({
99
- 'time' => @placeholder_expander.time_value(time),
100
- 'record' => record,
101
- })
102
- new_record = reform(record, placeholder_values)
103
- if @renew_time_key && new_record.has_key?(@renew_time_key)
104
- time = Fluent::EventTime.from_time(Time.at(new_record[@renew_time_key].to_f))
96
+ begin
97
+ placeholder_values['time'] = @placeholder_expander.time_value(time)
98
+ placeholder_values['record'] = record
99
+
100
+ new_record = reform(record, placeholder_values)
101
+ if @renew_time_key && new_record.has_key?(@renew_time_key)
102
+ time = Fluent::EventTime.from_time(Time.at(new_record[@renew_time_key].to_f))
103
+ end
104
+ new_es.add(time, new_record)
105
+ rescue => e
106
+ router.emit_error_event(tag, time, record, e)
107
+ log.debug { "map:#{@map} record:#{record} placeholder_values:#{placeholder_values}" }
105
108
  end
106
- new_es.add(time, new_record)
107
109
  end
108
110
  new_es
109
- rescue => e
110
- log.warn "failed to reform records", error: e
111
- log.warn_backtrace
112
- log.debug "map:#{@map} record:#{last_record} placeholder_values:#{placeholder_values}"
113
111
  end
114
112
 
115
113
  private
@@ -204,9 +202,6 @@ module Fluent::Plugin
204
202
  end
205
203
  elsif value.kind_of?(Hash) # record, etc
206
204
  value.each do |k, v|
207
- unless placeholder_values.has_key?(k) # prevent overwriting reserved keys such as tag
208
- placeholders.store("${#{k}}", v) # foo
209
- end
210
205
  placeholders.store(%Q[${#{key}["#{k}"]}], v) # record["foo"]
211
206
  end
212
207
  else # string, interger, float, and others?
@@ -309,30 +304,14 @@ module Fluent::Plugin
309
304
  placeholders['hostname'],
310
305
  )
311
306
  rescue => e
312
- log.warn "failed to expand `#{str}`", error: e
313
- log.warn_backtrace
314
- nil
307
+ raise "failed to expand `#{str}` : error = #{e}"
315
308
  end
316
309
 
317
310
  class CleanroomExpander
318
311
  def expand(__str_to_eval__, tag, time, record, tag_parts, tag_prefix, tag_suffix, hostname)
319
- tags = tag_parts # for old version compatibility
320
- _ = tags # to suppress "unused variable" warning for tags
321
- Thread.current[:record_transformer_record] = record # for old version compatibility
322
312
  instance_eval(__str_to_eval__)
323
313
  end
324
314
 
325
- # for old version compatibility
326
- def method_missing(name)
327
- key = name.to_s
328
- record = Thread.current[:record_transformer_record]
329
- if record.has_key?(key)
330
- record[key]
331
- else
332
- raise NameError, "undefined local variable or method `#{key}'"
333
- end
334
- end
335
-
336
315
  (Object.instance_methods).each do |m|
337
316
  undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
338
317
  end
@@ -34,7 +34,7 @@ module Fluent::Plugin
34
34
  def configure(conf)
35
35
  compat_parameters_convert(conf, :inject, :formatter)
36
36
  super
37
- @formatter = formatter_create(conf: @config.elements('format').first, default_type: DEFAULT_FORMAT_TYPE)
37
+ @formatter = formatter_create
38
38
  end
39
39
 
40
40
  def filter_stream(tag, es)
@@ -26,6 +26,11 @@ module Fluent
26
26
 
27
27
  configured_in :format
28
28
 
29
+ PARSER_TYPES = [:text_per_line, :text, :binary]
30
+ def formatter_type
31
+ :text_per_line
32
+ end
33
+
29
34
  def format(tag, time, record)
30
35
  raise NotImplementedError, "Implement this method in child class"
31
36
  end
@@ -21,6 +21,10 @@ module Fluent
21
21
  class MessagePackFormatter < Formatter
22
22
  Plugin.register_formatter('msgpack', self)
23
23
 
24
+ def formatter_type
25
+ :binary
26
+ end
27
+
24
28
  def format(tag, time, record)
25
29
  record.to_msgpack
26
30
  end
@@ -21,6 +21,8 @@ module Fluent
21
21
  class StdoutFormatter < Formatter
22
22
  Plugin.register_formatter('stdout', self)
23
23
 
24
+ TIME_FORMAT = '%Y-%m-%d %H:%M:%S.%9N %z'
25
+
24
26
  config_param :output_type, :string, default: 'json'
25
27
 
26
28
  def configure(conf)
@@ -36,8 +38,7 @@ module Fluent
36
38
  end
37
39
 
38
40
  def format(tag, time, record)
39
- header = "#{Time.now.localtime} #{tag}: "
40
- "#{header}#{@sub_formatter.format(tag, time, record)}"
41
+ "#{Time.at(time).localtime.strftime(TIME_FORMAT)} #{tag}: #{@sub_formatter.format(tag, time, record).chomp}\n"
41
42
  end
42
43
 
43
44
  def stop
@@ -0,0 +1,34 @@
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 'fluent/plugin/formatter'
18
+
19
+ module Fluent
20
+ module Plugin
21
+ class TSVFormatter < Formatter
22
+ Plugin.register_formatter('tsv', self)
23
+
24
+ desc 'Field names included in each lines'
25
+ config_param :keys, :array, value_type: :string
26
+ desc 'The delimiter character (or string) of TSV values'
27
+ config_param :delimiter, :string, default: "\t"
28
+
29
+ def format(tag, time, record)
30
+ @keys.map{|k| record[k].to_s }.join(@delimiter)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -14,136 +14,91 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- require 'strptime'
18
- require 'yajl'
19
-
20
17
  require 'fluent/plugin/input'
21
- require 'fluent/time'
22
- require 'fluent/timezone'
23
- require 'fluent/config/error'
18
+ require 'yajl'
24
19
 
25
20
  module Fluent::Plugin
26
21
  class ExecInput < Fluent::Plugin::Input
27
22
  Fluent::Plugin.register_input('exec', self)
28
23
 
29
- helpers :child_process
30
-
31
- def initialize
32
- super
33
- require 'fluent/plugin/exec_util'
34
- end
24
+ helpers :compat_parameters, :extract, :parser, :child_process
35
25
 
36
26
  desc 'The command (program) to execute.'
37
27
  config_param :command, :string
38
- desc 'The format used to map the program output to the incoming event.(tsv,json,msgpack)'
39
- config_param :format, :string, default: 'tsv'
40
- desc 'Specify the comma-separated keys when using the tsv format.'
41
- config_param :keys, default: [] do |val|
42
- val.split(',')
28
+
29
+ config_section :parse do
30
+ config_set_default :@type, 'tsv'
31
+ config_set_default :time_type, :float
32
+ config_set_default :time_key, nil
33
+ config_set_default :estimate_current_event, false
34
+ end
35
+
36
+ config_section :extract do
37
+ config_set_default :time_type, :float
43
38
  end
39
+
44
40
  desc 'Tag of the output events.'
45
41
  config_param :tag, :string, default: nil
46
- desc 'The key to use as the event tag instead of the value in the event record. '
47
- config_param :tag_key, :string, default: nil
48
- desc 'The key to use as the event time instead of the value in the event record.'
49
- config_param :time_key, :string, default: nil
50
- desc 'The format of the event time used for the time_key parameter.'
51
- config_param :time_format, :string, default: nil
52
42
  desc 'The interval time between periodic program runs.'
53
43
  config_param :run_interval, :time, default: nil
44
+ desc 'The default block size to read if parser requires partial read.'
45
+ config_param :read_block_size, :size, default: 10240 # 10k
54
46
 
55
- def configure(conf)
56
- super
57
-
58
- if conf['localtime']
59
- @localtime = true
60
- elsif conf['utc']
61
- @localtime = false
62
- end
63
-
64
- if conf['timezone']
65
- @timezone = conf['timezone']
66
- Fluent::Timezone.validate!(@timezone)
67
- end
68
-
69
- if !@tag && !@tag_key
70
- raise Fleunt::ConfigError, "'tag' or 'tag_key' option is required on exec input"
71
- end
47
+ attr_reader :parser
72
48
 
73
- if @time_key
74
- if @time_format
75
- f = @time_format
76
- @time_parse_proc =
77
- begin
78
- strptime = Strptime.new(f)
79
- Proc.new { |str| Fluent::EventTime.from_time(strptime.exec(str)) }
80
- rescue
81
- Proc.new {|str| Fluent::EventTime.from_time(Time.strptime(str, f)) }
82
- end
83
- else
84
- @time_parse_proc = Proc.new {|str| Fluent::EventTime.from_time(Time.at(str.to_f)) }
49
+ def configure(conf)
50
+ compat_parameters_convert(conf, :extract, :parser)
51
+ ['parse', 'extract'].each do |subsection_name|
52
+ if subsection = conf.elements(subsection_name).first
53
+ if subsection.has_key?('time_format')
54
+ subsection['time_type'] ||= 'string'
55
+ end
85
56
  end
86
57
  end
87
58
 
88
- @parser = setup_parser(conf)
89
- end
59
+ super
90
60
 
91
- def setup_parser(conf)
92
- case @format
93
- when 'tsv'
94
- if @keys.empty?
95
- raise Fluent::ConfigError, "keys option is required on exec input for tsv format"
96
- end
97
- Fluent::ExecUtil::TSVParser.new(@keys, method(:on_message))
98
- when 'json'
99
- Fluent::ExecUtil::JSONParser.new(method(:on_message))
100
- when 'msgpack'
101
- Fluent::ExecUtil::MessagePackParser.new(method(:on_message))
102
- else
103
- Fluent::ExecUtil::TextParserWrapperParser.new(conf, method(:on_message))
61
+ if !@tag && (!@extract_config || !@extract_config.tag_key)
62
+ raise Fluent::ConfigError, "'tag' or 'tag_key' option is required on exec input"
104
63
  end
64
+ @parser = parser_create
105
65
  end
106
66
 
107
67
  def start
108
68
  super
109
69
 
110
70
  if @run_interval
111
- child_process_execute(:exec_input, @command, interval: @run_interval, mode: [:read]) do |io|
112
- run(io)
113
- end
71
+ child_process_execute(:exec_input, @command, interval: @run_interval, mode: [:read], &method(:run))
114
72
  else
115
- child_process_execute(:exec_input, @command, immediate: true, mode: [:read]) do |io|
116
- run(io)
117
- end
73
+ child_process_execute(:exec_input, @command, immediate: true, mode: [:read], &method(:run))
118
74
  end
119
75
  end
120
76
 
121
77
  def run(io)
122
- @parser.call(io)
123
- end
124
-
125
- private
126
-
127
- def on_message(record, parsed_time = nil)
128
- if val = record.delete(@tag_key)
129
- tag = val
130
- else
131
- tag = @tag
132
- end
133
-
134
- if parsed_time
135
- time = parsed_time
136
- else
137
- if val = record.delete(@time_key)
138
- time = @time_parse_proc.call(val)
139
- else
140
- time = Fluent::EventTime.now
78
+ case
79
+ when @parser.implement?(:parse_io)
80
+ @parser.parse_io(io, &method(:on_record))
81
+ when @parser.implement?(:parse_partial_data)
82
+ until io.eof?
83
+ @parser.parse_partial_data(io.readpartial(@read_block_size), &method(:on_record))
84
+ end
85
+ when @parser.parser_type == :text_per_line
86
+ io.each_line do |line|
87
+ @parser.parse(line.chomp, &method(:on_record))
141
88
  end
89
+ else
90
+ @parser.parse(io.read, &method(:on_record))
142
91
  end
92
+ end
143
93
 
94
+ def on_record(time, record)
95
+ tag = extract_tag_from_record(record)
96
+ tag ||= @tag
97
+ time ||= extract_time_from_record(record) || Fluent::EventTime.now
144
98
  router.emit(tag, time, record)
145
99
  rescue => e
146
- log.error "exec failed to emit", error: e, tag: tag, record: Yajl.dump(record)
100
+ log.error "exec failed to emit", tag: tag, record: Yajl.dump(record), error: e
101
+ router.emit_error_event(tag, time, record, e) if tag && time && record
147
102
  end
148
103
  end
149
104
  end