fluentd 0.12.8 → 0.12.9

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 67639a7dc51e74c0269b78897487a90bd0acf29b
4
- data.tar.gz: 43fd091c294a06a0d88eea360a7efd5b215d5577
3
+ metadata.gz: 389d806680686ce59ee87528aeb56c6bb3eabe92
4
+ data.tar.gz: 7756ef8d28122b38f3ded3413a1735f664926117
5
5
  SHA512:
6
- metadata.gz: 1357f9b5a372172f9e6441dafdb106d8fa2e6756d3bb23c54b0d16c1e8888fc97e75b5ebbf94aac7ae589d48d42af6b08968653de0309cc8a9efe6b2a9ade81d
7
- data.tar.gz: 00d88127b76af84ba10b1830c0be4861047a571cb953dfd63c7887d145ca8752fb8a4a978b586159918356ee57f6b7b00190295d9a6509467bd41791e8b63dfb
6
+ metadata.gz: a1e17c1773eb0e805352862b6bc76a051aaa6ff257c5acef32fa244de245d9d67e261824c939187a76b22146c87a288494c9b31e92df176a4f910008f6ef198c
7
+ data.tar.gz: 07c21ddcdbf4d140e6151d60187b951a909e9269a48f037e18e7f5f43dc5f45cc2a42ea55ac538af1d36d42d0a273acdeed01f4835342163cd6893d7922d1d3b
data/ChangeLog CHANGED
@@ -1,5 +1,25 @@
1
1
  # v0.12
2
2
 
3
+ ## Release 0.12.9 - 2015/05/19
4
+
5
+ ### New features / Enhancement
6
+
7
+ * in_tail: Add read_lines_limit parameter to control chunk size
8
+ https://github.com/fluent/fluentd/pull/593
9
+ * filter: add filter_stdout plugin
10
+ https://github.com/fluent/fluentd/pull/586
11
+ * parser: add keep_time_key option
12
+ https://github.com/fluent/fluentd/pull/587
13
+ * parser: keys parameter accepts json array configuration
14
+ https://github.com/fluent/fluentd/pull/592
15
+ * Implement RPC server for better instance management
16
+ https://github.com/fluent/fluentd/pull/585
17
+
18
+ ### Bug fixes
19
+
20
+ * out_file: Fix out_file can create directory recursively
21
+ https://github.com/fluent/fluentd/pull/595
22
+
3
23
  ## Release 0.12.8 - 2015/04/22
4
24
 
5
25
  ### New features / Enhancement
@@ -0,0 +1,22 @@
1
+ <source>
2
+ type dummy
3
+ tag dummy
4
+ </source>
5
+
6
+ <filter **>
7
+ type stdout
8
+ </filter>
9
+
10
+ <filter **>
11
+ type stdout
12
+ output_type hash
13
+ </filter>
14
+
15
+ <filter **>
16
+ type stdout
17
+ format ltsv
18
+ </filter>
19
+
20
+ <match **>
21
+ type null
22
+ </match>
@@ -84,6 +84,22 @@ module Fluent
84
84
  end
85
85
  end
86
86
 
87
+ class StdoutFormatter < Formatter
88
+ config_param :output_type, :string, :default => 'json'
89
+
90
+ def configure(conf)
91
+ super
92
+
93
+ @formatter = Plugin.new_formatter(@output_type)
94
+ @formatter.configure(conf)
95
+ end
96
+
97
+ def format(tag, time, record)
98
+ header = "#{Time.now.localtime} #{tag}: "
99
+ "#{header}#{@formatter.format(tag, time, record)}"
100
+ end
101
+ end
102
+
87
103
  module StructuredFormatMixin
88
104
  def self.included(klass)
89
105
  klass.instance_eval {
@@ -120,6 +136,15 @@ module Fluent
120
136
  end
121
137
  end
122
138
 
139
+ class HashFormatter < Formatter
140
+ include HandleTagAndTimeMixin
141
+ include StructuredFormatMixin
142
+
143
+ def format_record(record)
144
+ "#{record.to_s}\n"
145
+ end
146
+ end
147
+
123
148
  class MessagePackFormatter < Formatter
124
149
  include HandleTagAndTimeMixin
125
150
  include StructuredFormatMixin
@@ -203,7 +228,9 @@ module Fluent
203
228
  TEMPLATE_REGISTRY = Registry.new(:formatter_type, 'fluent/plugin/formatter_')
204
229
  {
205
230
  'out_file' => Proc.new { OutFileFormatter.new },
231
+ 'stdout' => Proc.new { StdoutFormatter.new },
206
232
  'json' => Proc.new { JSONFormatter.new },
233
+ 'hash' => Proc.new { HashFormatter.new },
207
234
  'msgpack' => Proc.new { MessagePackFormatter.new },
208
235
  'ltsv' => Proc.new { LabeledTSVFormatter.new },
209
236
  'csv' => Proc.new { CsvFormatter.new },
@@ -21,6 +21,7 @@ require 'fluent/log'
21
21
  require 'fluent/status'
22
22
  require 'fluent/config'
23
23
  require 'fluent/engine'
24
+ require 'fluent/rpc'
24
25
  require 'fluent/mixin'
25
26
  require 'fluent/process'
26
27
  require 'fluent/plugin'
@@ -27,6 +27,8 @@ module Fluent
27
27
  # 'configure()' may raise errors for unexpected configurations
28
28
  attr_accessor :estimate_current_event
29
29
 
30
+ config_param :keep_time_key, :bool, :default => false
31
+
30
32
  def initialize
31
33
  super
32
34
  @estimate_current_event = true
@@ -201,6 +203,13 @@ module Fluent
201
203
  case name
202
204
  when "time"
203
205
  time = @mutex.synchronize { @time_parser.parse(value) }
206
+ if @keep_time_key
207
+ record[name] = if @type_converters.nil?
208
+ value
209
+ else
210
+ convert_type(name, value)
211
+ end
212
+ end
204
213
  else
205
214
  record[name] = if @type_converters.nil?
206
215
  value
@@ -239,7 +248,8 @@ module Fluent
239
248
  def parse(text)
240
249
  record = Yajl.load(text)
241
250
 
242
- if value = record.delete(@time_key)
251
+ value = @keep_time_key ? record[@time_key] : record.delete(@time_key)
252
+ if value
243
253
  if @time_format
244
254
  time = @mutex.synchronize { @time_parser.parse(value) }
245
255
  else
@@ -274,15 +284,19 @@ module Fluent
274
284
  class ValuesParser < Parser
275
285
  include TypeConverter
276
286
 
277
- config_param :keys, :string
287
+ config_param :keys, :default => [] do |val|
288
+ if val.start_with?('[') # This check is enough because keys parameter is simple. No '[' started column name.
289
+ JSON.load(val)
290
+ else
291
+ val.split(",")
292
+ end
293
+ end
278
294
  config_param :time_key, :string, :default => nil
279
295
  config_param :time_format, :string, :default => nil
280
296
 
281
297
  def configure(conf)
282
298
  super
283
299
 
284
- @keys = @keys.split(",")
285
-
286
300
  if @time_key && !@keys.include?(@time_key) && @estimate_current_event
287
301
  raise ConfigError, "time_key (#{@time_key.inspect}) is not included in keys (#{@keys.inspect})"
288
302
  end
@@ -299,7 +313,7 @@ module Fluent
299
313
  record = Hash[keys.zip(values)]
300
314
 
301
315
  if @time_key
302
- value = record.delete(@time_key)
316
+ value = @keep_time_key ? record[@time_key] : record.delete(@time_key)
303
317
  time = if value.nil?
304
318
  if @estimate_current_event
305
319
  Engine.now
@@ -465,6 +479,7 @@ module Fluent
465
479
  "referer" => referer,
466
480
  "agent" => agent,
467
481
  }
482
+ record["time"] = m['time'] if @keep_time_key
468
483
 
469
484
  if block_given?
470
485
  yield time, record
@@ -520,6 +535,7 @@ module Fluent
520
535
  record['pri'] = value.to_i
521
536
  when "time"
522
537
  time = @mutex.synchronize { @time_parser.parse(value.gsub(/ +/, ' ')) }
538
+ record[name] = value if @keep_time_key
523
539
  else
524
540
  record[name] = value
525
541
  end
@@ -22,9 +22,31 @@ module Fluent
22
22
  # @param [String] path File path
23
23
  # @return [Boolean] file is writable or not
24
24
  def writable?(path)
25
- path = File.exist?(path) ? path : File.dirname(path)
26
- File.writable?(path)
25
+ return false if File.directory?(path)
26
+ return File.writable?(path) if File.exist?(path)
27
+
28
+ dirname = File.dirname(path)
29
+ return false if !File.directory?(dirname)
30
+ File.writable?(dirname)
27
31
  end
28
32
  module_function :writable?
33
+
34
+ # Check file is writable in conjunction wtih mkdir_p(dirname(path))
35
+ #
36
+ # @param [String] path File path
37
+ # @return [Boolean] file writable or not
38
+ def writable_p?(path)
39
+ return false if File.directory?(path)
40
+ return File.writable?(path) if File.exist?(path)
41
+
42
+ dirname = File.dirname(path)
43
+ until File.exist?(dirname)
44
+ dirname = File.dirname(dirname)
45
+ end
46
+
47
+ return false if !File.directory?(dirname)
48
+ File.writable?(dirname)
49
+ end
50
+ module_function :writable_p?
29
51
  end
30
52
  end
@@ -0,0 +1,46 @@
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
+ module Fluent
18
+ class StdoutFilter < Filter
19
+ Plugin.register_filter('stdout', self)
20
+
21
+ # for tests
22
+ attr_reader :formatter
23
+
24
+ config_param :format, :string, :default => 'stdout'
25
+ # config_param :output_type, :string, :default => 'json' (StdoutFormatter defines this)
26
+
27
+ def configure(conf)
28
+ super
29
+
30
+ @formatter = Plugin.new_formatter(@format)
31
+ @formatter.configure(conf)
32
+ end
33
+
34
+ def filter_stream(tag, es)
35
+ es.each { |time, record|
36
+ begin
37
+ log.write @formatter.format(tag, time, record)
38
+ rescue => e
39
+ router.emit_error_event(tag, time, record, e)
40
+ end
41
+ }
42
+ log.flush
43
+ es
44
+ end
45
+ end
46
+ end
@@ -31,6 +31,7 @@ module Fluent
31
31
  config_param :pos_file, :string, :default => nil
32
32
  config_param :read_from_head, :bool, :default => false
33
33
  config_param :refresh_interval, :time, :default => 60
34
+ config_param :read_lines_limit, :integer, :default => 1000
34
35
 
35
36
  attr_reader :paths
36
37
 
@@ -131,7 +132,7 @@ module Fluent
131
132
  end
132
133
 
133
134
  def setup_watcher(path, pe)
134
- tw = TailWatcher.new(path, @rotate_wait, pe, log, @read_from_head, method(:update_watcher), &method(:receive_lines))
135
+ tw = TailWatcher.new(path, @rotate_wait, pe, log, @read_from_head, @read_lines_limit, method(:update_watcher), &method(:receive_lines))
135
136
  tw.attach(@loop)
136
137
  tw
137
138
  end
@@ -292,11 +293,12 @@ module Fluent
292
293
  end
293
294
 
294
295
  class TailWatcher
295
- def initialize(path, rotate_wait, pe, log, read_from_head, update_watcher, &receive_lines)
296
+ def initialize(path, rotate_wait, pe, log, read_from_head, read_lines_limit, update_watcher, &receive_lines)
296
297
  @path = path
297
298
  @rotate_wait = rotate_wait
298
299
  @pe = pe || MemoryPositionEntry.new
299
300
  @read_from_head = read_from_head
301
+ @read_lines_limit = read_lines_limit
300
302
  @receive_lines = receive_lines
301
303
  @update_watcher = update_watcher
302
304
 
@@ -377,7 +379,7 @@ module Fluent
377
379
  end
378
380
  io.seek(pos)
379
381
 
380
- @io_handler = IOHandler.new(io, @pe, @log, &method(:wrap_receive_lines))
382
+ @io_handler = IOHandler.new(io, @pe, @log, @read_lines_limit, &method(:wrap_receive_lines))
381
383
  else
382
384
  @io_handler = NullIOHandler.new
383
385
  end
@@ -391,12 +393,12 @@ module Fluent
391
393
  inode = stat.ino
392
394
  if inode == @pe.read_inode # truncated
393
395
  @pe.update_pos(stat.size)
394
- io_handler = IOHandler.new(io, @pe, @log, &method(:wrap_receive_lines))
396
+ io_handler = IOHandler.new(io, @pe, @log, @read_lines_limit, &method(:wrap_receive_lines))
395
397
  @io_handler.close
396
398
  @io_handler = io_handler
397
399
  elsif @io_handler.io.nil? # There is no previous file. Reuse TailWatcher
398
400
  @pe.update(inode, io.pos)
399
- io_handler = IOHandler.new(io, @pe, @log, &method(:wrap_receive_lines))
401
+ io_handler = IOHandler.new(io, @pe, @log, @read_lines_limit, &method(:wrap_receive_lines))
400
402
  @io_handler = io_handler
401
403
  else # file is rotated and new file found
402
404
  @update_watcher.call(@path, swap_state(@pe))
@@ -469,14 +471,13 @@ module Fluent
469
471
  end
470
472
  end
471
473
 
472
- MAX_LINES_AT_ONCE = 1000
473
-
474
474
  class IOHandler
475
- def initialize(io, pe, log, first = true, &receive_lines)
475
+ def initialize(io, pe, log, read_lines_limit, first = true, &receive_lines)
476
476
  @log = log
477
477
  @log.info "following tail of #{io.path}" if first
478
478
  @io = io
479
479
  @pe = pe
480
+ @read_lines_limit = read_lines_limit
480
481
  @receive_lines = receive_lines
481
482
  @buffer = ''.force_encoding('ASCII-8BIT')
482
483
  @iobuf = ''.force_encoding('ASCII-8BIT')
@@ -500,7 +501,7 @@ module Fluent
500
501
  while line = @buffer.slice!(/.*?\n/m)
501
502
  lines << line
502
503
  end
503
- if lines.size >= MAX_LINES_AT_ONCE
504
+ if lines.size >= @read_lines_limit
504
505
  # not to use too much memory in case the file is very large
505
506
  read_more = true
506
507
  break
@@ -61,7 +61,7 @@ module Fluent
61
61
  end
62
62
 
63
63
  test_path = generate_path(Time.now.strftime(@time_slice_format))
64
- unless ::Fluent::FileUtil.writable?(test_path)
64
+ unless ::Fluent::FileUtil.writable_p?(test_path)
65
65
  raise ConfigError, "out_file: `#{test_path}` is not writable"
66
66
  end
67
67
 
@@ -0,0 +1,94 @@
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
+ module Fluent
18
+ module RPC
19
+ require 'webrick'
20
+
21
+ class Server
22
+ def initialize(endpoint, log)
23
+ bind, port = endpoint.split(':')
24
+ @bind = bind
25
+ @port = port
26
+ @log = log
27
+
28
+ @server = WEBrick::HTTPServer.new(
29
+ :BindAddress => @bind,
30
+ :Port => @port,
31
+ :Logger => WEBrick::Log.new(STDERR, WEBrick::Log::FATAL),
32
+ :AccessLog => [],
33
+ )
34
+ end
35
+
36
+ def mount(path, servlet, *args)
37
+ @server.mount(path, servlet, *args)
38
+ @log.debug "register #{path} RPC servlet"
39
+ end
40
+
41
+ def mount_proc(path, &block)
42
+ @server.mount_proc(path) { |req, res|
43
+ begin
44
+ code, header, body = block.call(req, res)
45
+ rescue => e
46
+ @log.warn "failed to handle RPC request", :path => path, :error => e.to_s
47
+ @log.warn_backtrace e.backtrace
48
+
49
+ code = 500
50
+ body = {
51
+ 'message '=> 'Internal Server Error',
52
+ 'error' => "#{e}",
53
+ 'backtrace'=> e.backtrace,
54
+ }
55
+ end
56
+
57
+ code = 200 if code.nil?
58
+ header = {'Content-Type' => 'application/json'} if header.nil?
59
+ body = if body.nil?
60
+ '{"ok":true}'
61
+ else
62
+ body['ok'] = code == 200
63
+ body.to_json
64
+ end
65
+
66
+ res.status = code
67
+ header.each_pair { |k, v|
68
+ res[k] = v
69
+ }
70
+ res.body = body
71
+ }
72
+ @log.debug "register #{path} RPC handler"
73
+ end
74
+
75
+ def start
76
+ @log.debug "listening RPC http server on http://#{@bind}:#{@port}/"
77
+ @thread = Thread.new {
78
+ @server.start
79
+ }
80
+ end
81
+
82
+ def shutdown
83
+ if @server
84
+ @server.shutdown
85
+ @server = nil
86
+ end
87
+ if @thread
88
+ @thread.join
89
+ @thread = nil
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -109,6 +109,7 @@ module Fluent
109
109
  @plugin_dirs = opt[:plugin_dirs]
110
110
  @chgroup = opt[:chgroup]
111
111
  @chuser = opt[:chuser]
112
+ @rpc_server = nil
112
113
 
113
114
  @log_level = opt[:log_level]
114
115
  @suppress_interval = opt[:suppress_interval]
@@ -128,8 +129,10 @@ module Fluent
128
129
 
129
130
  dry_run if @dry_run
130
131
  start_daemonize if @daemonize
132
+ setup_rpc_server if @rpc_endpoint
131
133
  if @supervise
132
134
  install_supervisor_signal_handlers
135
+ run_rpc_server if @rpc_endpoint
133
136
  until @finished
134
137
  supervise do
135
138
  change_privilege
@@ -144,6 +147,7 @@ module Fluent
144
147
  end
145
148
  else
146
149
  $log.info "starting fluentd-#{Fluent::VERSION} without supervision"
150
+ run_rpc_server if @rpc_endpoint
147
151
  main_process do
148
152
  change_privilege
149
153
  init_engine
@@ -154,6 +158,7 @@ module Fluent
154
158
  exit 0
155
159
  end
156
160
  end
161
+ stop_rpc_server if @rpc_endpoint
157
162
  end
158
163
 
159
164
  def options
@@ -233,6 +238,41 @@ module Fluent
233
238
  end
234
239
  end
235
240
 
241
+ def setup_rpc_server
242
+ @rpc_server = RPC::Server.new(@rpc_endpoint, $log)
243
+
244
+ # built-in RPC for signals
245
+ @rpc_server.mount_proc('/api/processes.interruptWorkers') { |req, res|
246
+ $log.debug "fluentd RPC got /api/processes.interruptWorkers request"
247
+ supervisor_sigint_handler
248
+ nil
249
+ }
250
+ @rpc_server.mount_proc('/api/processes.killWorkers') { |req, res|
251
+ $log.debug "fluentd RPC got /api/processes.killWorkers request"
252
+ supervisor_sigterm_handler
253
+ nil
254
+ }
255
+ @rpc_server.mount_proc('/api/plugins.flushBuffers') { |req, res|
256
+ $log.debug "fluentd RPC got /api/plugins.flushBuffers request"
257
+ supervisor_sigusr1_handler
258
+ nil
259
+ }
260
+ @rpc_server.mount_proc('/api/config.reload') { |req, res|
261
+ $log.debug "fluentd RPC got /api/config.reload request"
262
+ $log.info "restarting"
263
+ supervisor_sighup_handler
264
+ nil
265
+ }
266
+ end
267
+
268
+ def run_rpc_server
269
+ @rpc_server.start
270
+ end
271
+
272
+ def stop_rpc_server
273
+ @rpc_server.shutdown
274
+ end
275
+
236
276
  def supervise(&block)
237
277
  start_time = Time.now
238
278
 
@@ -290,56 +330,72 @@ module Fluent
290
330
  def install_supervisor_signal_handlers
291
331
  trap :INT do
292
332
  $log.debug "fluentd supervisor process get SIGINT"
293
- @finished = true
294
- if pid = @main_pid
295
- # kill processes only still exists
296
- unless Process.waitpid(pid, Process::WNOHANG)
297
- begin
298
- Process.kill(:INT, pid)
299
- rescue Errno::ESRCH
300
- # ignore processes already died
301
- end
302
- end
303
- end
333
+ supervisor_sigint_handler
304
334
  end
305
335
 
306
336
  trap :TERM do
307
337
  $log.debug "fluentd supervisor process get SIGTERM"
308
- @finished = true
309
- if pid = @main_pid
310
- # kill processes only still exists
311
- unless Process.waitpid(pid, Process::WNOHANG)
312
- begin
313
- Process.kill(:TERM, pid)
314
- rescue Errno::ESRCH
315
- # ignore processes already died
316
- end
317
- end
318
- end
338
+ supervisor_sigterm_handler
319
339
  end
320
340
 
321
341
  trap :HUP do
322
342
  $log.debug "fluentd supervisor process get SIGHUP"
323
343
  $log.info "restarting"
324
- # Creating new thread due to mutex can't lock
325
- # in main thread during trap context
326
- Thread.new {
327
- read_config
328
- apply_system_config
329
- if pid = @main_pid
330
- Process.kill(:TERM, pid)
331
- # don't resuce Erro::ESRSH here (invalid status)
332
- end
333
- }.run
344
+ supervisor_sighup_handler
334
345
  end
335
346
 
336
347
  trap :USR1 do
337
348
  $log.debug "fluentd supervisor process get SIGUSR1"
338
- @log.reopen!
349
+ supervisor_sigusr1_handler
350
+ end
351
+ end
352
+
353
+ def supervisor_sigint_handler
354
+ @finished = true
355
+ if pid = @main_pid
356
+ # kill processes only still exists
357
+ unless Process.waitpid(pid, Process::WNOHANG)
358
+ begin
359
+ Process.kill(:INT, pid)
360
+ rescue Errno::ESRCH
361
+ # ignore processes already died
362
+ end
363
+ end
364
+ end
365
+ end
366
+
367
+ def supervisor_sigterm_handler
368
+ @finished = true
369
+ if pid = @main_pid
370
+ # kill processes only still exists
371
+ unless Process.waitpid(pid, Process::WNOHANG)
372
+ begin
373
+ Process.kill(:TERM, pid)
374
+ rescue Errno::ESRCH
375
+ # ignore processes already died
376
+ end
377
+ end
378
+ end
379
+ end
380
+
381
+ def supervisor_sighup_handler
382
+ # Creating new thread due to mutex can't lock
383
+ # in main thread during trap context
384
+ Thread.new {
385
+ read_config
386
+ apply_system_config
339
387
  if pid = @main_pid
340
- Process.kill(:USR1, pid)
388
+ Process.kill(:TERM, pid)
341
389
  # don't resuce Erro::ESRSH here (invalid status)
342
390
  end
391
+ }.run
392
+ end
393
+
394
+ def supervisor_sigusr1_handler
395
+ @log.reopen!
396
+ if pid = @main_pid
397
+ Process.kill(:USR1, pid)
398
+ # don't resuce Erro::ESRSH here (invalid status)
343
399
  end
344
400
  end
345
401
 
@@ -366,6 +422,7 @@ module Fluent
366
422
  config_param :emit_error_log_interval, :time, :default => nil
367
423
  config_param :suppress_config_dump, :bool, :default => nil
368
424
  config_param :without_source, :bool, :default => nil
425
+ config_param :rpc_endpoint, :string, :default => nil
369
426
 
370
427
  def initialize(conf)
371
428
  super()
@@ -380,6 +437,7 @@ module Fluent
380
437
  @suppress_config_dump = system.suppress_config_dump unless system.suppress_config_dump.nil?
381
438
  @suppress_repeated_stacktrace = system.suppress_repeated_stacktrace unless system.suppress_repeated_stacktrace.nil?
382
439
  @without_source = system.without_source unless system.without_source.nil?
440
+ @rpc_endpoint = system.rpc_endpoint unless system.rpc_endpoint.nil?
383
441
  }
384
442
  end
385
443
  end
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '0.12.8'
19
+ VERSION = '0.12.9'
20
20
 
21
21
  end
@@ -22,18 +22,75 @@ class FileUtilTest < Test::Unit::TestCase
22
22
  assert_false Fluent::FileUtil.writable?("#{TEST_DIR}/test_file")
23
23
  end
24
24
 
25
- test 'file does not exist and directory is writable' do
26
- assert_true Fluent::FileUtil.writable?("#{TEST_DIR}/test_file")
25
+ test 'directory exists' do
26
+ FileUtils.mkdir_p("#{TEST_DIR}/test_dir")
27
+ assert_false Fluent::FileUtil.writable?("#{TEST_DIR}/test_dir")
27
28
  end
28
29
 
29
- test 'file does not exist and directory is not writable' do
30
- File.chmod(0444, TEST_DIR)
31
- assert_false Fluent::FileUtil.writable?("#{TEST_DIR}/test_file")
30
+ test 'file does not exist and parent directory is writable' do
31
+ FileUtils.mkdir_p("#{TEST_DIR}/test_dir")
32
+ assert_true Fluent::FileUtil.writable?("#{TEST_DIR}/test_dir/test_file")
32
33
  end
33
34
 
34
- test 'directory does not exist' do
35
- FileUtils.rm_rf(TEST_DIR)
36
- assert_false Fluent::FileUtil.writable?("#{TEST_DIR}/test_file")
35
+ test 'file does not exist and parent directory is not writable' do
36
+ FileUtils.mkdir_p("#{TEST_DIR}/test_dir")
37
+ File.chmod(0444, "#{TEST_DIR}/test_dir")
38
+ assert_false Fluent::FileUtil.writable?("#{TEST_DIR}/test_dir/test_file")
39
+ end
40
+
41
+ test 'parent directory does not exist' do
42
+ FileUtils.rm_rf("#{TEST_DIR}/test_dir")
43
+ assert_false Fluent::FileUtil.writable?("#{TEST_DIR}/test_dir/test_file")
44
+ end
45
+
46
+ test 'parent file (not directory) exists' do
47
+ FileUtils.touch("#{TEST_DIR}/test_file")
48
+ assert_false Fluent::FileUtil.writable?("#{TEST_DIR}/test_file/foo")
49
+ end
50
+ end
51
+
52
+ sub_test_case 'writable_p?' do
53
+ test 'file exists and writable' do
54
+ FileUtils.touch("#{TEST_DIR}/test_file")
55
+ assert_true Fluent::FileUtil.writable_p?("#{TEST_DIR}/test_file")
56
+ end
57
+
58
+ test 'file exists and not writable' do
59
+ FileUtils.touch("#{TEST_DIR}/test_file")
60
+ File.chmod(0444, "#{TEST_DIR}/test_file")
61
+ assert_false Fluent::FileUtil.writable_p?("#{TEST_DIR}/test_file")
62
+ end
63
+
64
+ test 'directory exists' do
65
+ FileUtils.mkdir_p("#{TEST_DIR}/test_dir")
66
+ assert_false Fluent::FileUtil.writable_p?("#{TEST_DIR}/test_dir")
67
+ end
68
+
69
+ test 'parent directory exists and writable' do
70
+ FileUtils.mkdir_p("#{TEST_DIR}/test_dir")
71
+ assert_true Fluent::FileUtil.writable_p?("#{TEST_DIR}/test_dir/test_file")
72
+ end
73
+
74
+ test 'parent directory exists and not writable' do
75
+ FileUtils.mkdir_p("#{TEST_DIR}/test_dir")
76
+ File.chmod(0555, "#{TEST_DIR}/test_dir")
77
+ assert_false Fluent::FileUtil.writable_p?("#{TEST_DIR}/test_dir/test_file")
78
+ end
79
+
80
+ test 'parent of parent (of parent ...) directory exists and writable' do
81
+ FileUtils.mkdir_p("#{TEST_DIR}/test_dir")
82
+ assert_true Fluent::FileUtil.writable_p?("#{TEST_DIR}/test_dir/foo/bar/baz")
83
+ end
84
+
85
+ test 'parent of parent (of parent ...) directory exists and not writable' do
86
+ FileUtils.mkdir_p("#{TEST_DIR}/test_dir")
87
+ File.chmod(0555, "#{TEST_DIR}/test_dir")
88
+ assert_false Fluent::FileUtil.writable_p?("#{TEST_DIR}/test_dir/foo/bar/baz")
89
+ end
90
+
91
+ test 'parent of parent (of parent ...) file (not directory) exists' do
92
+ FileUtils.touch("#{TEST_DIR}/test_file")
93
+ assert_false Fluent::FileUtil.writable_p?("#{TEST_DIR}/test_file/foo/bar/baz")
37
94
  end
38
95
  end
39
96
  end
@@ -0,0 +1,112 @@
1
+ require_relative '../helper'
2
+ require 'fluent/plugin/filter_stdout'
3
+ require 'timecop'
4
+ require 'flexmock'
5
+
6
+ class StdoutFilterTest < Test::Unit::TestCase
7
+ include Fluent
8
+ include FlexMock::TestCase
9
+
10
+ def setup
11
+ Fluent::Test.setup
12
+ Timecop.freeze
13
+ end
14
+
15
+ def teardown
16
+ Timecop.return
17
+ end
18
+
19
+ CONFIG = %[
20
+ ]
21
+
22
+ def create_driver(conf = CONFIG)
23
+ Test::FilterTestDriver.new(StdoutFilter, 'filter.test').configure(conf)
24
+ end
25
+
26
+ def emit(d, msg, time)
27
+ d.run {
28
+ d.emit(msg, time)
29
+ }.filtered_as_array[0][2]
30
+ end
31
+
32
+ def test_through_record
33
+ d = create_driver
34
+ time = Time.now
35
+ filtered = emit(d, {'test' => 'test'}, time)
36
+ assert_equal({'test' => 'test'}, filtered)
37
+ end
38
+
39
+ def test_configure_default
40
+ d = create_driver
41
+ assert_equal 'json', d.instance.formatter.output_type
42
+ end
43
+
44
+ def test_configure_output_type
45
+ d = create_driver(CONFIG + "\noutput_type json")
46
+ assert_equal 'json', d.instance.formatter.output_type
47
+
48
+ d = create_driver(CONFIG + "\noutput_type hash")
49
+ assert_equal 'hash', d.instance.formatter.output_type
50
+
51
+ d = create_driver(CONFIG + "\noutput_type ltsv")
52
+ assert_equal 'ltsv', d.instance.formatter.output_type
53
+
54
+ assert_raise(Fluent::ConfigError) do
55
+ d = create_driver(CONFIG + "\noutput_type foo")
56
+ end
57
+ end
58
+
59
+ def test_output_type_json
60
+ d = create_driver(CONFIG + "\noutput_type json")
61
+ time = Time.now
62
+ out = capture_log(d) { emit(d, {'test' => 'test'}, time) }
63
+ assert_equal "#{time.localtime} filter.test: {\"test\":\"test\"}\n", out
64
+
65
+ # NOTE: Float::NAN is not jsonable
66
+ d = create_driver(CONFIG + "\noutput_type json")
67
+ flexmock(d.instance.router).should_receive(:emit_error_event)
68
+ emit(d, {'test' => Float::NAN}, time)
69
+ end
70
+
71
+ def test_output_type_hash
72
+ d = create_driver(CONFIG + "\noutput_type hash")
73
+ time = Time.now
74
+ out = capture_log(d) { emit(d, {'test' => 'test'}, time) }
75
+ assert_equal "#{time.localtime} filter.test: {\"test\"=>\"test\"}\n", out
76
+
77
+ # NOTE: Float::NAN is not jsonable, but hash string can output it.
78
+ d = create_driver(CONFIG + "\noutput_type hash")
79
+ out = capture_log(d) { emit(d, {'test' => Float::NAN}, time) }
80
+ assert_equal "#{time.localtime} filter.test: {\"test\"=>NaN}\n", out
81
+ end
82
+
83
+ # Use include_time_key to output the message's time
84
+ def test_include_time_key
85
+ d = create_driver(CONFIG + "\noutput_type json\ninclude_time_key true\nutc")
86
+ time = Time.now
87
+ message_time = Time.parse("2011-01-02 13:14:15 UTC").to_i
88
+ out = capture_log(d) { emit(d, {'test' => 'test'}, message_time) }
89
+ assert_equal "#{time.localtime} filter.test: {\"test\":\"test\",\"time\":\"2011-01-02T13:14:15Z\"}\n", out
90
+ end
91
+
92
+ # out_stdout formatter itself can also be replaced
93
+ def test_format_json
94
+ d = create_driver(CONFIG + "\nformat json")
95
+ time = Time.now
96
+ out = capture_log(d) { emit(d, {'test' => 'test'}, time) }
97
+ assert_equal "{\"test\":\"test\"}\n", out
98
+ end
99
+
100
+ private
101
+
102
+ # Capture the log output of the block given
103
+ def capture_log(d, &block)
104
+ tmp = d.instance.log
105
+ d.instance.log = StringIO.new
106
+ yield
107
+ return d.instance.log.string
108
+ ensure
109
+ d.instance.log = tmp
110
+ end
111
+ end
112
+
@@ -40,6 +40,7 @@ class TailInputTest < Test::Unit::TestCase
40
40
  assert_equal "t1", d.instance.tag
41
41
  assert_equal 2, d.instance.rotate_wait
42
42
  assert_equal "#{TMP_DIR}/tail.pos", d.instance.pos_file
43
+ assert_equal 1000, d.instance.read_lines_limit
43
44
  end
44
45
 
45
46
  # TODO: Should using more better approach instead of sleep wait
@@ -66,6 +67,30 @@ class TailInputTest < Test::Unit::TestCase
66
67
  assert_equal(true, emits.length > 0)
67
68
  assert_equal({"message" => "test3"}, emits[0][2])
68
69
  assert_equal({"message" => "test4"}, emits[1][2])
70
+ assert_equal(1, d.emit_streams.size)
71
+ end
72
+
73
+ data('1' => [1, 2], '10' => [10, 1])
74
+ def test_emit_with_read_lines_limit(data)
75
+ limit, num_emits = data
76
+ d = create_driver(CONFIG_READ_FROM_HEAD + SINGLE_LINE_CONFIG + "read_lines_limit #{limit}")
77
+ msg = 'test' * 500 # in_tail reads 2048 bytes at once.
78
+
79
+ d.run do
80
+ sleep 1
81
+
82
+ File.open("#{TMP_DIR}/tail.txt", "a") {|f|
83
+ f.puts msg
84
+ f.puts msg
85
+ }
86
+ sleep 1
87
+ end
88
+
89
+ emits = d.emits
90
+ assert_equal(true, emits.length > 0)
91
+ assert_equal({"message" => msg}, emits[0][2])
92
+ assert_equal({"message" => msg}, emits[1][2])
93
+ assert_equal(num_emits, d.emit_streams.size)
69
94
  end
70
95
 
71
96
  def test_emit_with_read_from_head
@@ -409,7 +434,7 @@ class TailInputTest < Test::Unit::TestCase
409
434
 
410
435
  flexstub(Fluent::NewTailInput::TailWatcher) do |watcherclass|
411
436
  EX_PATHS.each do |path|
412
- watcherclass.should_receive(:new).with(path, EX_RORATE_WAIT, Fluent::NewTailInput::FilePositionEntry, any, true, any, any).once.and_return do
437
+ watcherclass.should_receive(:new).with(path, EX_RORATE_WAIT, Fluent::NewTailInput::FilePositionEntry, any, true, 1000, any, any).once.and_return do
413
438
  flexmock('TailWatcher') { |watcher|
414
439
  watcher.should_receive(:attach).once
415
440
  watcher.should_receive(:unwatched=).zero_or_more_times
@@ -425,7 +450,7 @@ class TailInputTest < Test::Unit::TestCase
425
450
  end
426
451
 
427
452
  flexstub(Fluent::NewTailInput::TailWatcher) do |watcherclass|
428
- watcherclass.should_receive(:new).with('test/plugin/data/2010/01/20100102-030406.log', EX_RORATE_WAIT, Fluent::NewTailInput::FilePositionEntry, any, true, any, any).once.and_return do
453
+ watcherclass.should_receive(:new).with('test/plugin/data/2010/01/20100102-030406.log', EX_RORATE_WAIT, Fluent::NewTailInput::FilePositionEntry, any, true, 1000, any, any).once.and_return do
429
454
  flexmock('TailWatcher') do |watcher|
430
455
  watcher.should_receive(:attach).once
431
456
  watcher.should_receive(:unwatched=).zero_or_more_times
@@ -45,8 +45,16 @@ class FileOutputTest < Test::Unit::TestCase
45
45
  create_driver %[path #{TMP_DIR}/test_path]
46
46
  end
47
47
 
48
+ assert_nothing_raised do
49
+ FileUtils.mkdir_p("#{TMP_DIR}/test_dir")
50
+ File.chmod(0777, "#{TMP_DIR}/test_dir")
51
+ create_driver %[path #{TMP_DIR}/test_dir/foo/bar/baz]
52
+ end
53
+
48
54
  assert_raise(Fluent::ConfigError) do
49
- create_driver %[path #{TMP_DIR}/does_not_exist/test_path]
55
+ FileUtils.mkdir_p("#{TMP_DIR}/test_dir")
56
+ File.chmod(0555, "#{TMP_DIR}/test_dir")
57
+ create_driver %[path #{TMP_DIR}/test_dir/foo/bar/baz]
50
58
  end
51
59
  end
52
60
 
@@ -131,6 +131,31 @@ module ParserTest
131
131
  assert_nil time, "parser returns nil if configured so"
132
132
  }
133
133
  end
134
+
135
+ def test_parse_with_keep_time_key
136
+ parser = TextParser::RegexpParser.new(
137
+ Regexp.new(%q!(?<time>.*)!),
138
+ 'time_format'=>"%d/%b/%Y:%H:%M:%S %z",
139
+ 'keep_time_key'=>'true',
140
+ )
141
+ text = '28/Feb/2013:12:00:00 +0900'
142
+ parser.parse(text) do |time, record|
143
+ assert_equal text, record['time']
144
+ end
145
+ end
146
+
147
+ def test_parse_with_keep_time_key_with_typecast
148
+ parser = TextParser::RegexpParser.new(
149
+ Regexp.new(%q!(?<time>.*)!),
150
+ 'time_format'=>"%d/%b/%Y:%H:%M:%S %z",
151
+ 'keep_time_key'=>'true',
152
+ 'types'=>'time:time:%d/%b/%Y:%H:%M:%S %z',
153
+ )
154
+ text = '28/Feb/2013:12:00:00 +0900'
155
+ parser.parse(text) do |time, record|
156
+ assert_equal 1362020400, record['time']
157
+ end
158
+ end
134
159
  end
135
160
 
136
161
  class ApacheParserTest < ::Test::Unit::TestCase
@@ -155,6 +180,18 @@ module ParserTest
155
180
  }, record)
156
181
  }
157
182
  end
183
+
184
+ def test_parse_with_keep_time_key
185
+ parser = TextParser::ApacheParser.new
186
+ parser.configure(
187
+ 'time_format'=>"%d/%b/%Y:%H:%M:%S %z",
188
+ 'keep_time_key'=>'true',
189
+ )
190
+ text = '192.168.0.1 - - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777'
191
+ parser.parse(text) do |time, record|
192
+ assert_equal "28/Feb/2013:12:00:00 +0900", record['time']
193
+ end
194
+ end
158
195
  end
159
196
 
160
197
  class ApacheErrorParserTest < ::Test::Unit::TestCase
@@ -279,6 +316,17 @@ module ParserTest
279
316
  assert_equal(TextParser::SyslogParser::REGEXP, @parser.patterns['format'])
280
317
  assert_equal("%b %d %H:%M:%S", @parser.patterns['time_format'])
281
318
  end
319
+
320
+ def test_parse_with_keep_time_key
321
+ @parser.configure(
322
+ 'time_format' => '%b %d %M:%S:%H',
323
+ 'keep_time_key'=>'true',
324
+ )
325
+ text = 'Feb 28 00:00:12 192.168.0.1 fluentd[11111]: [error] Syslog test'
326
+ @parser.parse(text) do |time, record|
327
+ assert_equal "Feb 28 00:00:12", record['time']
328
+ end
329
+ end
282
330
  end
283
331
 
284
332
  class JsonParserTest < ::Test::Unit::TestCase
@@ -329,6 +377,18 @@ module ParserTest
329
377
  @parser.parse('{"time":[],"k":"v"}') { |time, record| }
330
378
  end
331
379
  end
380
+
381
+ def test_parse_with_keep_time_key
382
+ parser = TextParser::JSONParser.new
383
+ parser.configure(
384
+ 'time_format'=>"%d/%b/%Y:%H:%M:%S %z",
385
+ 'keep_time_key'=>'true',
386
+ )
387
+ text = "28/Feb/2013:12:00:00 +0900"
388
+ parser.parse("{\"time\":\"#{text}\"}") do |time, record|
389
+ assert_equal text, record['time']
390
+ end
391
+ end
332
392
  end
333
393
 
334
394
  class NginxParserTest < ::Test::Unit::TestCase
@@ -374,22 +434,25 @@ module ParserTest
374
434
  class TSVParserTest < ::Test::Unit::TestCase
375
435
  include ParserTest
376
436
 
377
- def test_config_params
437
+ data('array param' => '["a","b"]', 'string param' => 'a,b')
438
+ def test_config_params(param)
378
439
  parser = TextParser::TSVParser.new
379
440
 
380
441
  assert_equal "\t", parser.delimiter
381
442
 
382
443
  parser.configure(
383
- 'keys' => 'a,b',
444
+ 'keys' => param,
384
445
  'delimiter' => ',',
385
446
  )
386
447
 
448
+ assert_equal ['a', 'b'], parser.keys
387
449
  assert_equal ",", parser.delimiter
388
450
  end
389
451
 
390
- def test_parse
452
+ data('array param' => '["time","a","b"]', 'string param' => 'time,a,b')
453
+ def test_parse(param)
391
454
  parser = TextParser::TSVParser.new
392
- parser.configure('keys' => 'time,a,b', 'time_key' => 'time')
455
+ parser.configure('keys' => param, 'time_key' => 'time')
393
456
  parser.parse("2013/02/28 12:00:00\t192.168.0.1\t111") { |time, record|
394
457
  assert_equal(str2time('2013/02/28 12:00:00', '%Y/%m/%d %H:%M:%S'), time)
395
458
  assert_equal({
@@ -440,14 +503,29 @@ module ParserTest
440
503
  assert_equal(expected, record)
441
504
  }
442
505
  end
506
+
507
+ def test_parse_with_keep_time_key
508
+ parser = TextParser::TSVParser.new
509
+ parser.configure(
510
+ 'keys'=>'time',
511
+ 'time_key'=>'time',
512
+ 'time_format'=>"%d/%b/%Y:%H:%M:%S %z",
513
+ 'keep_time_key'=>'true',
514
+ )
515
+ text = '28/Feb/2013:12:00:00 +0900'
516
+ parser.parse(text) do |time, record|
517
+ assert_equal text, record['time']
518
+ end
519
+ end
443
520
  end
444
521
 
445
522
  class CSVParserTest < ::Test::Unit::TestCase
446
523
  include ParserTest
447
524
 
448
- def test_parse
525
+ data('array param' => '["time","c","d"]', 'string param' => 'time,c,d')
526
+ def test_parse(param)
449
527
  parser = TextParser::CSVParser.new
450
- parser.configure('keys' => 'time,c,d', 'time_key' => 'time')
528
+ parser.configure('keys' => param, 'time_key' => 'time')
451
529
  parser.parse("2013/02/28 12:00:00,192.168.0.1,111") { |time, record|
452
530
  assert_equal(str2time('2013/02/28 12:00:00', '%Y/%m/%d %H:%M:%S'), time)
453
531
  assert_equal({
@@ -457,11 +535,12 @@ module ParserTest
457
535
  }
458
536
  end
459
537
 
460
- def test_parse_without_time
538
+ data('array param' => '["c","d"]', 'string param' => 'c,d')
539
+ def test_parse_without_time(param)
461
540
  time_at_start = Time.now.to_i
462
541
 
463
542
  parser = TextParser::CSVParser.new
464
- parser.configure('keys' => 'c,d')
543
+ parser.configure('keys' => param)
465
544
  parser.parse("192.168.0.1,111") { |time, record|
466
545
  assert time && time >= time_at_start, "parser puts current time without time input"
467
546
  assert_equal({
@@ -472,7 +551,7 @@ module ParserTest
472
551
 
473
552
  parser = TextParser::CSVParser.new
474
553
  parser.estimate_current_event = false
475
- parser.configure('keys' => 'c,d', 'time_key' => 'time')
554
+ parser.configure('keys' => param, 'time_key' => 'time')
476
555
  parser.parse("192.168.0.1,111") { |time, record|
477
556
  assert_equal({
478
557
  'c' => '192.168.0.1',
@@ -481,6 +560,20 @@ module ParserTest
481
560
  assert_nil time, "parser returns nil w/o time and if configured so"
482
561
  }
483
562
  end
563
+
564
+ def test_parse_with_keep_time_key
565
+ parser = TextParser::CSVParser.new
566
+ parser.configure(
567
+ 'keys'=>'time',
568
+ 'time_key'=>'time',
569
+ 'time_format'=>"%d/%b/%Y:%H:%M:%S %z",
570
+ 'keep_time_key'=>'true',
571
+ )
572
+ text = '28/Feb/2013:12:00:00 +0900'
573
+ parser.parse(text) do |time, record|
574
+ assert_equal text, record['time']
575
+ end
576
+ end
484
577
  end
485
578
 
486
579
  class LabeledTSVParserTest < ::Test::Unit::TestCase
@@ -567,7 +660,19 @@ module ParserTest
567
660
  assert_nil time, "parser returns nil w/o time and if configured so"
568
661
  }
569
662
  end
570
- end
663
+
664
+ def test_parse_with_keep_time_key
665
+ parser = TextParser::LabeledTSVParser.new
666
+ parser.configure(
667
+ 'time_format'=>"%d/%b/%Y:%H:%M:%S %z",
668
+ 'keep_time_key'=>'true',
669
+ )
670
+ text = '28/Feb/2013:12:00:00 +0900'
671
+ parser.parse("time:#{text}") do |time, record|
672
+ assert_equal text, record['time']
673
+ end
674
+ end
675
+ end
571
676
 
572
677
  class NoneParserTest < ::Test::Unit::TestCase
573
678
  include ParserTest
@@ -700,6 +805,18 @@ EOS
700
805
  }, record)
701
806
  }
702
807
  end
808
+
809
+ def test_parse_with_keep_time_key
810
+ parser = TextParser::MultilineParser.new
811
+ parser.configure(
812
+ 'format1' => '/^(?<time>\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2})/',
813
+ 'keep_time_key' => 'true'
814
+ )
815
+ text = '2013-3-03 14:27:33'
816
+ parser.parse(text) { |time, record|
817
+ assert_equal text, record['time']
818
+ }
819
+ end
703
820
  end
704
821
 
705
822
  class TextParserTest < ::Test::Unit::TestCase
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluentd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.8
4
+ version: 0.12.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-21 00:00:00.000000000 Z
11
+ date: 2015-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -291,6 +291,7 @@ files:
291
291
  - bin/fluent-debug
292
292
  - bin/fluent-gem
293
293
  - bin/fluentd
294
+ - example/filter_stdout.conf
294
295
  - example/in_http.conf
295
296
  - example/in_syslog.conf
296
297
  - example/in_tail.conf
@@ -342,6 +343,7 @@ files:
342
343
  - lib/fluent/plugin/file_util.rb
343
344
  - lib/fluent/plugin/filter_grep.rb
344
345
  - lib/fluent/plugin/filter_record_transformer.rb
346
+ - lib/fluent/plugin/filter_stdout.rb
345
347
  - lib/fluent/plugin/in_debug_agent.rb
346
348
  - lib/fluent/plugin/in_dummy.rb
347
349
  - lib/fluent/plugin/in_exec.rb
@@ -370,6 +372,7 @@ files:
370
372
  - lib/fluent/process.rb
371
373
  - lib/fluent/registry.rb
372
374
  - lib/fluent/root_agent.rb
375
+ - lib/fluent/rpc.rb
373
376
  - lib/fluent/status.rb
374
377
  - lib/fluent/supervisor.rb
375
378
  - lib/fluent/test.rb
@@ -400,6 +403,7 @@ files:
400
403
  - test/plugin/test_file_util.rb
401
404
  - test/plugin/test_filter_grep.rb
402
405
  - test/plugin/test_filter_record_transformer.rb
406
+ - test/plugin/test_filter_stdout.rb
403
407
  - test/plugin/test_in_debug_agent.rb
404
408
  - test/plugin/test_in_dummy.rb
405
409
  - test/plugin/test_in_exec.rb
@@ -484,6 +488,7 @@ test_files:
484
488
  - test/plugin/test_file_util.rb
485
489
  - test/plugin/test_filter_grep.rb
486
490
  - test/plugin/test_filter_record_transformer.rb
491
+ - test/plugin/test_filter_stdout.rb
487
492
  - test/plugin/test_in_debug_agent.rb
488
493
  - test/plugin/test_in_dummy.rb
489
494
  - test/plugin/test_in_exec.rb