fluent-plugin-bufferize 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +84 -0
- data/Rakefile +13 -0
- data/fluent-plugin-bufferize.gemspec +23 -0
- data/lib/fluent/plugin/out_bufferize.rb +120 -0
- data/test/helper.rb +28 -0
- data/test/plugin/test_out_bufferize.rb +145 -0
- metadata +107 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Masahiro Sano
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# fluent-plugin-bufferize
|
2
|
+
|
3
|
+
An adapter plugin which enables existing non-buffered plugins to resend messages easily in case of unexpected exceptions without creating duplicate messages.
|
4
|
+
|
5
|
+
## Why
|
6
|
+
|
7
|
+
Buffered plugin accumulates many messages in buffer and sends all the messages at a same time. There are many APIs that does not support such reqeusts like bulk-insert. In that case, you have to use non-buffered output and implement resend meschanism yourself because non-buffered output lacks exception handling functionality.
|
8
|
+
|
9
|
+
To use this plugin, you just have to create non-buffered plugin without caring exception handling. If an exception happens in your plugin, the request is issued again automatically. With file buffer, none of messages are lost even on sudden fluentd process down.
|
10
|
+
|
11
|
+
## Configuration
|
12
|
+
|
13
|
+
Just embrace existing configuration by <config> directive.
|
14
|
+
|
15
|
+
If you use following configuration:
|
16
|
+
|
17
|
+
```
|
18
|
+
<match *>
|
19
|
+
type http
|
20
|
+
endpoint_url http://foo.bar.com/
|
21
|
+
http_method put
|
22
|
+
</match>
|
23
|
+
```
|
24
|
+
|
25
|
+
Modify it like this:
|
26
|
+
|
27
|
+
```
|
28
|
+
<match *>
|
29
|
+
type bufferize
|
30
|
+
buffer_type file
|
31
|
+
buffer_path /var/log/fluent/myapp.*.buffer
|
32
|
+
<config>
|
33
|
+
type http
|
34
|
+
endpoint_url http://foo.bar.com/
|
35
|
+
http_method put
|
36
|
+
</config>
|
37
|
+
</match>
|
38
|
+
```
|
39
|
+
|
40
|
+
This is a buffered output plugin. For more information about parameters, please refer [official document](http://docs.fluentd.org/articles/buffer-plugin-overview).
|
41
|
+
|
42
|
+
## Example of application
|
43
|
+
|
44
|
+
These plugins are good compatibility to fluent-plugin-bufferize.
|
45
|
+
|
46
|
+
- [fluent-plugin-out-http](https://github.com/ento/fluent-plugin-out-http)
|
47
|
+
- [fluent-plugin-jubatus](https://github.com/katsyoshi/fluent-plugin-jubatus)
|
48
|
+
- [fluent-plugin-irc](https://github.com/choplin/fluent-plugin-irc)
|
49
|
+
|
50
|
+
## Installation
|
51
|
+
|
52
|
+
Add this line to your application's Gemfile:
|
53
|
+
|
54
|
+
gem 'fluent-plugin-bufferize'
|
55
|
+
|
56
|
+
And then execute:
|
57
|
+
|
58
|
+
$ bundle
|
59
|
+
|
60
|
+
Or install it yourself as:
|
61
|
+
|
62
|
+
$ gem install fluent-plugin-bufferize
|
63
|
+
|
64
|
+
## Contributing
|
65
|
+
|
66
|
+
1. Fork it
|
67
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
68
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
69
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
70
|
+
5. Create new Pull Request
|
71
|
+
|
72
|
+
## Copyright
|
73
|
+
|
74
|
+
<table>
|
75
|
+
<tr>
|
76
|
+
<td>Author</td><td>Masahiro Sano <sabottenda@gmail.com></td>
|
77
|
+
</tr>
|
78
|
+
<tr>
|
79
|
+
<td>Copyright</td><td>Copyright (c) 2013- Masahiro Sano</td>
|
80
|
+
</tr>
|
81
|
+
<tr>
|
82
|
+
<td>License</td><td>MIT License</td>
|
83
|
+
</tr>
|
84
|
+
</table>
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "fluent-plugin-bufferize"
|
7
|
+
spec.version = "0.0.1"
|
8
|
+
spec.authors = ["Masahiro Sano"]
|
9
|
+
spec.email = ["sabottenda@gmail.com"]
|
10
|
+
spec.description = %q{A fluentd plugin that enhances existing non-buffered output plugin as buffered plugin.}
|
11
|
+
spec.summary = %q{A fluentd plugin that enhances existing non-buffered output plugin as buffered plugin.}
|
12
|
+
spec.homepage = "https://github.com/sabottenda/fluent-plugin-bufferize"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "fluentd", "~> 0.10.0"
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module Fluent
|
2
|
+
class BufferizeOutput < BufferedOutput
|
3
|
+
Plugin.register_output('bufferize', self)
|
4
|
+
|
5
|
+
class PosKeeper
|
6
|
+
@@instances = {}
|
7
|
+
|
8
|
+
def self.get(chunk)
|
9
|
+
@@instances[chunk.unique_id] ||= PosKeeper.new(chunk)
|
10
|
+
@@instances[chunk.unique_id]
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.remove(chunk)
|
14
|
+
@@instances.delete(chunk.unique_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(chunk)
|
18
|
+
@id = chunk.unique_id
|
19
|
+
@count = 0
|
20
|
+
@chunk = chunk
|
21
|
+
|
22
|
+
if chunk.respond_to? :path
|
23
|
+
@path = chunk.path + ".pos"
|
24
|
+
mode = File::CREAT | File::RDWR
|
25
|
+
perm = DEFAULT_FILE_PERMISSION
|
26
|
+
@io = File.open(@path, mode, perm)
|
27
|
+
@io.sync = true
|
28
|
+
line = @io.gets
|
29
|
+
@count = line ? line.to_i : 0
|
30
|
+
@type = :file
|
31
|
+
else
|
32
|
+
@type = :mem
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def each(&block)
|
37
|
+
@chunk.open do |io|
|
38
|
+
u = MessagePack::Unpacker.new(io)
|
39
|
+
begin
|
40
|
+
if @count > 0
|
41
|
+
$log.debug "Bufferize: skip first #{@count} messages"
|
42
|
+
@count.times do
|
43
|
+
u.skip
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
loop do
|
48
|
+
tag, time, record = u.read
|
49
|
+
yield(tag, time, record)
|
50
|
+
increment
|
51
|
+
end
|
52
|
+
|
53
|
+
rescue EOFError
|
54
|
+
end
|
55
|
+
end
|
56
|
+
remove
|
57
|
+
end
|
58
|
+
|
59
|
+
def increment
|
60
|
+
@count += 1
|
61
|
+
if @type == :file
|
62
|
+
@io.seek(0, IO::SEEK_SET)
|
63
|
+
@io.puts(@count)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def remove
|
68
|
+
if @type == :file
|
69
|
+
@io.close unless @io.closed?
|
70
|
+
File.unlink(@path)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
attr_reader :output
|
77
|
+
|
78
|
+
def initialize
|
79
|
+
super
|
80
|
+
end
|
81
|
+
|
82
|
+
def configure(conf)
|
83
|
+
super
|
84
|
+
|
85
|
+
configs = conf.elements.select{|e| e.name == 'config'}
|
86
|
+
if configs.size != 1
|
87
|
+
raise ConfigError, "Befferize: just one <config> directive is required"
|
88
|
+
end
|
89
|
+
|
90
|
+
type = configs.first['type']
|
91
|
+
unless type
|
92
|
+
raise ConfigError, "Befferize: 'type' parameter is required in <config> directive"
|
93
|
+
end
|
94
|
+
|
95
|
+
@output = Plugin.new_output(type)
|
96
|
+
@output.configure(configs.first)
|
97
|
+
end
|
98
|
+
|
99
|
+
def start
|
100
|
+
super
|
101
|
+
@output.start
|
102
|
+
end
|
103
|
+
|
104
|
+
def shutdown
|
105
|
+
super
|
106
|
+
@output.shutdown
|
107
|
+
end
|
108
|
+
|
109
|
+
def format(tag, time, record)
|
110
|
+
[tag, time, record].to_msgpack
|
111
|
+
end
|
112
|
+
|
113
|
+
def write(chunk)
|
114
|
+
PosKeeper.get(chunk).each { |tag, time, record |
|
115
|
+
@output.emit(tag, OneEventStream.new(time, record), NullOutputChain.instance)
|
116
|
+
}
|
117
|
+
PosKeeper.remove(chunk)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
13
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
14
|
+
require 'fluent/test'
|
15
|
+
unless ENV.has_key?('VERBOSE')
|
16
|
+
nulllogger = Object.new
|
17
|
+
nulllogger.instance_eval {|obj|
|
18
|
+
def method_missing(method, *args)
|
19
|
+
# pass
|
20
|
+
end
|
21
|
+
}
|
22
|
+
$log = nulllogger
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'fluent/plugin/out_bufferize'
|
26
|
+
|
27
|
+
class Test::Unit::TestCase
|
28
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class BufferizeOutputTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
Fluent::Test.setup
|
6
|
+
FileUtils.rm_rf('tmp')
|
7
|
+
FileUtils.mkdir_p('tmp')
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
FileUtils.mkdir_p('tmp')
|
12
|
+
end
|
13
|
+
|
14
|
+
BASE_CONFIG = %[
|
15
|
+
type bufferize
|
16
|
+
]
|
17
|
+
CONFIG_NO_CONFIG = BASE_CONFIG
|
18
|
+
CONFIG_NO_TYPE = BASE_CONFIG + %[
|
19
|
+
<config>
|
20
|
+
</config>
|
21
|
+
]
|
22
|
+
CONFIG_WITH_TYPE = BASE_CONFIG + %[
|
23
|
+
<config>
|
24
|
+
type test
|
25
|
+
</config>
|
26
|
+
]
|
27
|
+
|
28
|
+
def create_driver(conf = CONFIG_WITH_TYPE, tag='test')
|
29
|
+
Fluent::Test::BufferedOutputTestDriver.new(Fluent::BufferizeOutput, tag).configure(conf)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_configure
|
33
|
+
assert_raise(Fluent::ConfigError) {
|
34
|
+
create_driver(CONFIG_NO_CONFIG)
|
35
|
+
}
|
36
|
+
assert_raise(Fluent::ConfigError) {
|
37
|
+
create_driver(CONFIG_NO_TYPE)
|
38
|
+
}
|
39
|
+
assert_nothing_raised(Fluent::ConfigError) {
|
40
|
+
create_driver(CONFIG_WITH_TYPE)
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_resend_test_driver(conf = CONFIG_WITH_TYPE, tag='test')
|
45
|
+
output = Fluent::Plugin.new_output('test')
|
46
|
+
output.configure('name' => 'output')
|
47
|
+
output.define_singleton_method(:start) {}
|
48
|
+
output.define_singleton_method(:shutdown) {}
|
49
|
+
output.define_singleton_method(:emit) do |tag, es, chain|
|
50
|
+
@count ||= 0
|
51
|
+
es.each do |time, record|
|
52
|
+
@count += 1
|
53
|
+
raise if (@count % 3) == 0
|
54
|
+
super(tag, [[time, record]], chain)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
d = create_driver
|
59
|
+
d.instance.instance_eval { @output = output }
|
60
|
+
d
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_resend_with_memory_buffer
|
64
|
+
d = create_resend_test_driver
|
65
|
+
|
66
|
+
time = Time.parse("2013-11-02 12:12:12 UTC").to_i
|
67
|
+
entries = []
|
68
|
+
1.upto(5) { |i|
|
69
|
+
entries << [time, {"a"=>i}]
|
70
|
+
}
|
71
|
+
|
72
|
+
es = Fluent::ArrayEventStream.new(entries)
|
73
|
+
buffer = d.instance.format_stream('test', es)
|
74
|
+
chunk = Fluent::MemoryBufferChunk.new('', buffer)
|
75
|
+
|
76
|
+
assert_raise(RuntimeError) {
|
77
|
+
d.instance.write(chunk)
|
78
|
+
}
|
79
|
+
assert_equal [
|
80
|
+
{"a"=>1}, {"a"=>2},
|
81
|
+
], d.instance.output.records
|
82
|
+
|
83
|
+
assert_raise(RuntimeError) {
|
84
|
+
d.instance.write(chunk)
|
85
|
+
}
|
86
|
+
assert_equal [
|
87
|
+
{"a"=>1}, {"a"=>2}, {"a"=>3}, {"a"=>4},
|
88
|
+
], d.instance.output.records
|
89
|
+
|
90
|
+
assert_nothing_raised(RuntimeError) {
|
91
|
+
d.instance.write(chunk)
|
92
|
+
}
|
93
|
+
assert_equal [
|
94
|
+
{"a"=>1}, {"a"=>2}, {"a"=>3}, {"a"=>4}, {"a"=>5},
|
95
|
+
], d.instance.output.records
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_resend_with_file_buffer
|
99
|
+
d = create_resend_test_driver(CONFIG_WITH_TYPE + %[
|
100
|
+
buffer_type file
|
101
|
+
])
|
102
|
+
|
103
|
+
time = Time.parse("2013-11-02 12:12:12 UTC").to_i
|
104
|
+
entries = []
|
105
|
+
1.upto(5) { |i|
|
106
|
+
entries << [time, {"b"=>i}]
|
107
|
+
}
|
108
|
+
|
109
|
+
es = Fluent::ArrayEventStream.new(entries)
|
110
|
+
buffer = d.instance.format_stream('test', es)
|
111
|
+
chunk = Fluent::MemoryBufferChunk.new('', buffer)
|
112
|
+
|
113
|
+
es = Fluent::ArrayEventStream.new(entries)
|
114
|
+
chunk = Fluent::FileBufferChunk.new('', './tmp/test_buffer', 'xyz', "a+", nil)
|
115
|
+
chunk << d.instance.format_stream('test', es)
|
116
|
+
pos_file_path = "#{chunk.path}.pos"
|
117
|
+
|
118
|
+
assert_raise(RuntimeError) {
|
119
|
+
d.instance.write(chunk)
|
120
|
+
}
|
121
|
+
assert_equal [
|
122
|
+
{"b"=>1}, {"b"=>2},
|
123
|
+
], d.instance.output.records
|
124
|
+
assert File.exists?(pos_file_path)
|
125
|
+
assert_equal `head #{pos_file_path}`.chomp.to_i, 2
|
126
|
+
|
127
|
+
assert_raise(RuntimeError) {
|
128
|
+
d.instance.write(chunk)
|
129
|
+
}
|
130
|
+
assert_equal [
|
131
|
+
{"b"=>1}, {"b"=>2}, {"b"=>3}, {"b"=>4},
|
132
|
+
], d.instance.output.records
|
133
|
+
assert File.exists?(pos_file_path)
|
134
|
+
assert_equal `head #{pos_file_path}`.chomp.to_i, 4
|
135
|
+
|
136
|
+
assert_nothing_raised(RuntimeError) {
|
137
|
+
d.instance.write(chunk)
|
138
|
+
}
|
139
|
+
assert_equal [
|
140
|
+
{"b"=>1}, {"b"=>2}, {"b"=>3}, {"b"=>4}, {"b"=>5},
|
141
|
+
], d.instance.output.records
|
142
|
+
assert !File.exists?(pos_file_path)
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-bufferize
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Masahiro Sano
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-11-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fluentd
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.10.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.10.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.3'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.3'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: A fluentd plugin that enhances existing non-buffered output plugin as
|
63
|
+
buffered plugin.
|
64
|
+
email:
|
65
|
+
- sabottenda@gmail.com
|
66
|
+
executables: []
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- Gemfile
|
72
|
+
- LICENSE.txt
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- fluent-plugin-bufferize.gemspec
|
76
|
+
- lib/fluent/plugin/out_bufferize.rb
|
77
|
+
- test/helper.rb
|
78
|
+
- test/plugin/test_out_bufferize.rb
|
79
|
+
homepage: https://github.com/sabottenda/fluent-plugin-bufferize
|
80
|
+
licenses:
|
81
|
+
- MIT
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 1.8.23
|
101
|
+
signing_key:
|
102
|
+
specification_version: 3
|
103
|
+
summary: A fluentd plugin that enhances existing non-buffered output plugin as buffered
|
104
|
+
plugin.
|
105
|
+
test_files:
|
106
|
+
- test/helper.rb
|
107
|
+
- test/plugin/test_out_bufferize.rb
|