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
@@ -14,28 +14,29 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
+ require 'fluent/plugin/input'
18
+ require 'fluent/plugin/parser'
19
+ require 'fluent/event'
20
+
21
+ require 'http/parser'
22
+ require 'webrick/httputils'
17
23
  require 'uri'
18
24
  require 'socket'
19
25
  require 'json'
20
26
 
21
- require 'cool.io'
22
-
23
- require 'fluent/input'
24
- require 'fluent/event'
25
- require 'fluent/process'
27
+ module Fluent::Plugin
28
+ class InHttpParser < Parser
29
+ Fluent::Plugin.register_parser('in_http', self)
30
+ def parse(text)
31
+ # this plugin is dummy implementation not to raise error
32
+ yield nil, nil
33
+ end
34
+ end
26
35
 
27
- module Fluent
28
36
  class HttpInput < Input
29
- Plugin.register_input('http', self)
30
-
31
- include DetachMultiProcessMixin
32
-
33
- require 'http/parser'
37
+ Fluent::Plugin.register_input('http', self)
34
38
 
35
- def initialize
36
- require 'webrick/httputils'
37
- super
38
- end
39
+ helpers :parser, :compat_parameters, :event_loop
39
40
 
40
41
  EMPTY_GIF_IMAGE = "GIF89a\u0001\u0000\u0001\u0000\x80\xFF\u0000\xFF\xFF\xFF\u0000\u0000\u0000,\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0000\u0002\u0002D\u0001\u0000;".force_encoding("UTF-8")
41
42
 
@@ -52,25 +53,36 @@ module Fluent
52
53
  config_param :add_http_headers, :bool, default: false
53
54
  desc 'Add REMOTE_ADDR header to the record.'
54
55
  config_param :add_remote_addr, :bool, default: false
55
- desc 'The format of the HTTP body.'
56
- config_param :format, :string, default: 'default'
57
56
  config_param :blocking_timeout, :time, default: 0.5
58
57
  desc 'Set a white list of domains that can do CORS (Cross-Origin Resource Sharing)'
59
58
  config_param :cors_allow_origins, :array, default: nil
60
59
  desc 'Respond with empty gif image of 1x1 pixel.'
61
60
  config_param :respond_with_empty_img, :bool, default: false
62
61
 
62
+ config_section :parse do
63
+ config_set_default :@type, 'in_http'
64
+ end
65
+
66
+ EVENT_RECORD_PARAMETER = '_event_record'
67
+
63
68
  def configure(conf)
69
+ compat_parameters_convert(conf, :parser)
70
+
64
71
  super
65
72
 
66
- m = if @format == 'default'
73
+ m = if @parser_configs.first['@type'] == 'in_http'
74
+ @parser_msgpack = parser_create(usage: 'parser_in_http_msgpack', type: 'msgpack')
75
+ @parser_msgpack.estimate_current_event = false
76
+ @parser_json = parser_create(usage: 'parser_in_http_json', type: 'json')
77
+ @parser_json.estimate_current_event = false
78
+ @format_name = 'default'
67
79
  method(:parse_params_default)
68
80
  else
69
- @parser = Plugin.new_parser(@format)
70
- @parser.configure(conf)
81
+ @parser = parser_create
82
+ @format_name = @parser_configs.first['@type']
71
83
  method(:parse_params_with_parser)
72
84
  end
73
- (class << self; self; end).module_eval do
85
+ self.singleton_class.module_eval do
74
86
  define_method(:parse_params, m)
75
87
  end
76
88
  end
@@ -100,7 +112,11 @@ module Fluent
100
112
  end
101
113
 
102
114
  def start
103
- log.debug "listening http on #{@bind}:#{@port}"
115
+ @_event_loop_run_timeout = @blocking_timeout
116
+
117
+ super
118
+
119
+ log.debug "listening http", bind: @bind, port: @port
104
120
 
105
121
  socket_manager_path = ENV['SERVERENGINE_SOCKETMANAGER_PATH']
106
122
  if Fluent.windows?
@@ -109,38 +125,24 @@ module Fluent
109
125
  client = ServerEngine::SocketManager::Client.new(socket_manager_path)
110
126
  lsock = client.listen_tcp(@bind, @port)
111
127
 
112
- detach_multi_process do
113
- super
114
- @km = KeepaliveManager.new(@keepalive_timeout)
115
- @lsock = Coolio::TCPServer.new(lsock, nil, Handler, @km, method(:on_request),
116
- @body_size_limit, @format, log,
117
- @cors_allow_origins)
118
- @lsock.listen(@backlog) unless @backlog.nil?
119
-
120
- @loop = Coolio::Loop.new
121
- @loop.attach(@km)
122
- @loop.attach(@lsock)
123
-
124
- @thread = Thread.new(&method(:run))
125
- end
128
+ @km = KeepaliveManager.new(@keepalive_timeout)
129
+ @lsock = Coolio::TCPServer.new(
130
+ lsock, nil, Handler, @km, method(:on_request),
131
+ @body_size_limit, @format_name, log,
132
+ @cors_allow_origins
133
+ )
134
+ @lsock.listen(@backlog) unless @backlog.nil?
135
+ event_loop_attach(@km)
136
+ event_loop_attach(@lsock)
137
+
138
+ @float_time_parser = Fluent::NumericTimeParser.new(:float)
126
139
  end
127
140
 
128
- def shutdown
129
- @loop.watchers.each {|w| w.detach }
130
- @loop.stop
141
+ def close
131
142
  @lsock.close
132
- @thread.join
133
-
134
143
  super
135
144
  end
136
145
 
137
- def run
138
- @loop.run(@blocking_timeout)
139
- rescue
140
- log.error "unexpected error", error: $!.to_s
141
- log.error_backtrace
142
- end
143
-
144
146
  def on_request(path_info, params)
145
147
  begin
146
148
  path = path_info[1..-1] # remove /
@@ -170,9 +172,9 @@ module Fluent
170
172
  end
171
173
  time = if param_time = params['time']
172
174
  param_time = param_time.to_f
173
- param_time.zero? ? Engine.now : Fluent::EventTime.from_time(Time.at(param_time))
175
+ param_time.zero? ? Fluent::Engine.now : @float_time_parser.parse(param_time)
174
176
  else
175
- record_time.nil? ? Engine.now : record_time
177
+ record_time.nil? ? Fluent::Engine.now : record_time
176
178
  end
177
179
  rescue
178
180
  return ["400 Bad Request", {'Content-Type'=>'text/plain'}, "400 Bad Request\n#{$!}\n"]
@@ -182,7 +184,7 @@ module Fluent
182
184
  begin
183
185
  # Support batched requests
184
186
  if record.is_a?(Array)
185
- mes = MultiEventStream.new
187
+ mes = Fluent::MultiEventStream.new
186
188
  record.each do |single_record|
187
189
  if @add_http_headers
188
190
  params.each_pair { |k,v|
@@ -215,22 +217,23 @@ module Fluent
215
217
  private
216
218
 
217
219
  def parse_params_default(params)
218
- record = if msgpack = params['msgpack']
219
- Engine.msgpack_factory.unpacker.feed(msgpack).read
220
- elsif js = params['json']
221
- JSON.parse(js)
222
- else
223
- raise "'json' or 'msgpack' parameter is required"
224
- end
225
- return nil, record
220
+ if msgpack = params['msgpack']
221
+ @parser_msgpack.parse(msgpack) do |_time, record|
222
+ return nil, record
223
+ end
224
+ elsif js = params['json']
225
+ @parser_json.parse(js) do |_time, record|
226
+ return nil, record
227
+ end
228
+ else
229
+ raise "'json' or 'msgpack' parameter is required"
230
+ end
226
231
  end
227
232
 
228
- EVENT_RECORD_PARAMETER = '_event_record'
229
-
230
233
  def parse_params_with_parser(params)
231
234
  if content = params[EVENT_RECORD_PARAMETER]
232
235
  @parser.parse(content) { |time, record|
233
- raise "Received event is not #{@format}: #{content}" if record.nil?
236
+ raise "Received event is not #{@format_name}: #{content}" if record.nil?
234
237
  return time, record
235
238
  }
236
239
  else
@@ -241,13 +244,13 @@ module Fluent
241
244
  class Handler < Coolio::Socket
242
245
  attr_reader :content_type
243
246
 
244
- def initialize(io, km, callback, body_size_limit, format, log, cors_allow_origins)
247
+ def initialize(io, km, callback, body_size_limit, format_name, log, cors_allow_origins)
245
248
  super(io)
246
249
  @km = km
247
250
  @callback = callback
248
251
  @body_size_limit = body_size_limit
249
252
  @next_close = false
250
- @format = format
253
+ @format_name = format_name
251
254
  @log = log
252
255
  @cors_allow_origins = cors_allow_origins
253
256
  @idle = 0
@@ -355,7 +358,7 @@ module Fluent
355
358
  uri = URI.parse(@parser.request_url)
356
359
  params = WEBrick::HTTPUtils.parse_query(uri.query)
357
360
 
358
- if @format != 'default'
361
+ if @format_name != 'default'
359
362
  params[EVENT_RECORD_PARAMETER] = @body
360
363
  elsif @content_type =~ /^application\/x-www-form-urlencoded/
361
364
  params.update WEBrick::HTTPUtils.parse_query(@body)
@@ -18,8 +18,7 @@ require 'json'
18
18
  require 'webrick'
19
19
  require 'cgi'
20
20
 
21
- require 'cool.io'
22
-
21
+ require 'fluent/config/types'
23
22
  require 'fluent/plugin/input'
24
23
  require 'fluent/plugin/output'
25
24
  require 'fluent/plugin/multi_output'
@@ -35,6 +34,7 @@ module Fluent::Plugin
35
34
  config_param :port, :integer, default: 24220
36
35
  config_param :tag, :string, default: nil
37
36
  config_param :emit_interval, :time, default: 60
37
+ config_param :include_config, :bool, default: true
38
38
 
39
39
  class MonitorServlet < WEBrick::HTTPServlet::AbstractServlet
40
40
  def initialize(server, agent)
@@ -78,12 +78,16 @@ module Fluent::Plugin
78
78
 
79
79
  # if ?debug=1 is set, set :with_debug_info for get_monitor_info
80
80
  # and :pretty_json for render_json_error
81
- opts = {}
81
+ opts = {with_config: @agent.include_config}
82
82
  if s = qs['debug'] and s[0]
83
83
  opts[:with_debug_info] = true
84
84
  opts[:pretty_json] = true
85
85
  end
86
86
 
87
+ if with_config = get_search_parameter(qs, 'with_config'.freeze)
88
+ opts[:with_config] = Fluent::Config.bool_value(with_config)
89
+ end
90
+
87
91
  if tag = get_search_parameter(qs, 'tag'.freeze)
88
92
  # ?tag= to search an output plugin by match pattern
89
93
  if obj = @agent.plugin_info_by_tag(tag, opts)
@@ -329,7 +333,7 @@ module Fluent::Plugin
329
333
  obj['plugin_id'] = pe.plugin_id
330
334
  obj['plugin_category'] = plugin_category(pe)
331
335
  obj['type'] = pe.config['@type']
332
- obj['config'] = pe.config if !opts.has_key?(:with_config) || opts[:with_config]
336
+ obj['config'] = pe.config if opts[:with_config]
333
337
 
334
338
  # run MONITOR_INFO in plugins' instance context and store the info to obj
335
339
  MONITOR_INFO.each_pair {|key,code|
@@ -25,8 +25,9 @@ module Fluent::Plugin
25
25
  class SyslogInput < Input
26
26
  Fluent::Plugin.register_input('syslog', self)
27
27
 
28
- helpers :parser, :event_loop
28
+ helpers :parser, :compat_parameters, :event_loop
29
29
 
30
+ DEFAULT_PARSER = 'syslog'
30
31
  SYSLOG_REGEXP = /^\<([0-9]+)\>(.*)/
31
32
 
32
33
  FACILITY_MAP = {
@@ -79,48 +80,40 @@ module Fluent::Plugin
79
80
  desc 'The prefix of the tag. The tag itself is generated by the tag prefix, facility level, and priority.'
80
81
  config_param :tag, :string
81
82
  desc 'The transport protocol used to receive logs.(udp, tcp)'
82
- config_param :protocol_type, default: :udp do |val|
83
- case val.downcase
84
- when 'tcp'
85
- :tcp
86
- when 'udp'
87
- :udp
88
- else
89
- raise Fluent::ConfigError, "syslog input protocol type should be 'tcp' or 'udp'"
90
- end
91
- end
83
+ config_param :protocol_type, :enum, list: [:tcp, :udp], default: :udp
92
84
  desc 'If true, add source host to event record.'
93
85
  config_param :include_source_host, :bool, default: false
94
86
  desc 'Specify key of source host when include_source_host is true.'
95
87
  config_param :source_host_key, :string, default: 'source_host'.freeze
88
+ desc 'The field name of the priority.'
89
+ config_param :priority_key, :string, default: nil
90
+ desc 'The field name of the facility.'
91
+ config_param :facility_key, :string, default: nil
96
92
  config_param :blocking_timeout, :time, default: 0.5
97
93
  config_param :message_length_limit, :size, default: 2048
98
94
 
95
+ config_section :parse do
96
+ config_set_default :@type, DEFAULT_PARSER
97
+ config_param :with_priority, :bool, default: true
98
+ end
99
+
99
100
  def configure(conf)
101
+ compat_parameters_convert(conf, :parser)
102
+
100
103
  super
101
104
 
102
105
  @use_default = false
103
106
 
104
- if conf.has_key?('format')
105
- @parser = parser_create(usage: 'syslog_input', type: conf['format'], conf: conf)
106
- else
107
- conf['with_priority'] = true
108
- @parser = parser_create(usage: 'syslog_input', type: 'syslog', conf: conf)
109
- @use_default = true
110
- end
107
+ @parser = parser_create
108
+ @parser_parse_priority = @parser.respond_to?(:with_priority) && @parser.with_priority
109
+
111
110
  @_event_loop_run_timeout = @blocking_timeout
112
111
  end
113
112
 
114
113
  def start
115
114
  super
116
115
 
117
- callback = if @use_default
118
- method(:receive_data)
119
- else
120
- method(:receive_data_parser)
121
- end
122
-
123
- @handler = listen(callback)
116
+ @handler = listen(method(:message_handler))
124
117
  event_loop_attach(@handler)
125
118
  end
126
119
 
@@ -132,42 +125,38 @@ module Fluent::Plugin
132
125
 
133
126
  private
134
127
 
135
- def receive_data_parser(data, addr)
136
- m = SYSLOG_REGEXP.match(data)
137
- unless m
138
- log.warn "invalid syslog message: #{data.dump}"
139
- return
140
- end
141
- pri = m[1].to_i
142
- text = m[2]
143
-
144
- @parser.parse(text) { |time, record|
145
- unless time && record
146
- log.warn "pattern not match: #{text.inspect}"
128
+ def message_handler(data, addr)
129
+ pri = nil
130
+ text = data
131
+ unless @parser_parse_priority
132
+ m = SYSLOG_REGEXP.match(data)
133
+ unless m
134
+ log.warn "invalid syslog message: #{data.dump}"
147
135
  return
148
136
  end
137
+ pri = m[1].to_i
138
+ text = m[2]
139
+ end
149
140
 
150
- record[@source_host_key] = addr[2] if @include_source_host
151
- emit(pri, time, record)
152
- }
153
- rescue => e
154
- log.error data.dump, error: e.to_s
155
- log.error_backtrace
156
- end
157
-
158
- def receive_data(data, addr)
159
- @parser.parse(data) { |time, record|
141
+ @parser.parse(text) do |time, record|
160
142
  unless time && record
161
- log.warn "invalid syslog message", data: data
143
+ log.warn "failed to parse message", data: data
162
144
  return
163
145
  end
164
146
 
165
- pri = record.delete('pri')
147
+ pri ||= record.delete('pri')
148
+ facility = FACILITY_MAP[pri >> 3]
149
+ priority = PRIORITY_MAP[pri & 0b111]
150
+
151
+ record[@priority_key] = priority if @priority_key
152
+ record[@facility_key] = facility if @facility_key
166
153
  record[@source_host_key] = addr[2] if @include_source_host
167
- emit(pri, time, record)
168
- }
154
+
155
+ tag = "#{@tag}.#{facility}.#{priority}"
156
+ emit(tag, time, record)
157
+ end
169
158
  rescue => e
170
- log.error data.dump, error: e.to_s
159
+ log.error "invalid input", data: data, error: e
171
160
  log.error_backtrace
172
161
  end
173
162
 
@@ -190,12 +179,7 @@ module Fluent::Plugin
190
179
  end
191
180
  end
192
181
 
193
- def emit(pri, time, record)
194
- facility = FACILITY_MAP[pri >> 3]
195
- priority = PRIORITY_MAP[pri & 0b111]
196
-
197
- tag = "#{@tag}.#{facility}.#{priority}"
198
-
182
+ def emit(tag, time, record)
199
183
  router.emit(tag, time, record)
200
184
  rescue => e
201
185
  log.error "syslog failed to emit", error: e, tag: tag, record: Yajl.dump(record)
@@ -164,6 +164,12 @@ module Fluent::Plugin
164
164
  super
165
165
  end
166
166
 
167
+ def close
168
+ super
169
+ # close file handles after all threads stopped (in #close of thread plugin helper)
170
+ close_watcher_handles
171
+ end
172
+
167
173
  def expand_paths
168
174
  date = Time.now
169
175
  paths = []
@@ -234,18 +240,27 @@ module Fluent::Plugin
234
240
 
235
241
  def stop_watchers(paths, immediate = false, unwatched = false)
236
242
  paths.each { |path|
237
- tw = @tails.delete(path)
243
+ tw = @tails[path]
238
244
  if tw
239
245
  tw.unwatched = unwatched
240
246
  if immediate
241
- close_watcher(tw, false)
247
+ detach_watcher(tw, false)
242
248
  else
243
- close_watcher_after_rotate_wait(tw)
249
+ detach_watcher_after_rotate_wait(tw)
244
250
  end
245
251
  end
246
252
  }
247
253
  end
248
254
 
255
+ def close_watcher_handles
256
+ @tails.keys.each do |path|
257
+ tw = @tails.delete(path)
258
+ if tw
259
+ tw.close
260
+ end
261
+ end
262
+ end
263
+
249
264
  # refresh_watchers calls @tails.keys so we don't use stop_watcher -> start_watcher sequence for safety.
250
265
  def update_watcher(path, pe)
251
266
  if @pf
@@ -256,24 +271,25 @@ module Fluent::Plugin
256
271
  end
257
272
  rotated_tw = @tails[path]
258
273
  @tails[path] = setup_watcher(path, pe)
259
- close_watcher_after_rotate_wait(rotated_tw) if rotated_tw
274
+ detach_watcher_after_rotate_wait(rotated_tw) if rotated_tw
260
275
  end
261
276
 
262
277
  # TailWatcher#close is called by another thread at shutdown phase.
263
278
  # It causes 'can't modify string; temporarily locked' error in IOHandler
264
279
  # so adding close_io argument to avoid this problem.
265
280
  # At shutdown, IOHandler's io will be released automatically after detached the event loop
266
- def close_watcher(tw, close_io = true)
267
- tw.close(close_io)
281
+ def detach_watcher(tw, close_io = true)
282
+ tw.detach
283
+ tw.close if close_io
268
284
  flush_buffer(tw)
269
285
  if tw.unwatched && @pf
270
286
  @pf[tw.path].update_pos(PositionFile::UNWATCHED_POSITION)
271
287
  end
272
288
  end
273
289
 
274
- def close_watcher_after_rotate_wait(tw)
290
+ def detach_watcher_after_rotate_wait(tw)
275
291
  timer_execute(:in_tail_close_watcher, @rotate_wait, repeat: false) do
276
- close_watcher(tw)
292
+ detach_watcher(tw)
277
293
  end
278
294
  end
279
295
 
@@ -435,14 +451,13 @@ module Fluent::Plugin
435
451
  def detach
436
452
  @timer_trigger.detach if @enable_watch_timer && @timer_trigger.attached?
437
453
  @stat_trigger.detach if @stat_trigger.attached?
454
+ @io_handler.on_notify if @io_handler
438
455
  end
439
456
 
440
- def close(close_io = true)
441
- if close_io && @io_handler
442
- @io_handler.on_notify
457
+ def close
458
+ if @io_handler
443
459
  @io_handler.close
444
460
  end
445
- detach
446
461
  end
447
462
 
448
463
  def on_notify
@@ -570,8 +585,8 @@ module Fluent::Plugin
570
585
  else
571
586
  @buffer << @io.readpartial(2048, @iobuf)
572
587
  end
573
- while line = @buffer.slice!(/.*?\n/m)
574
- @lines << line
588
+ while idx = @buffer.index("\n".freeze)
589
+ @lines << @buffer.slice!(0, idx + 1)
575
590
  end
576
591
  if @lines.size >= @read_lines_limit
577
592
  # not to use too much memory in case the file is very large