fluent-plugin-datacounter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ # For TextMate, emacs, vim
6
+ *.tmproj
7
+ tmtags
8
+ *~
9
+ \#*
10
+ .\#*
11
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-datacounter.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012- TAGOMORI Satoshi
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.rdoc ADDED
@@ -0,0 +1,72 @@
1
+ = fluent-plugin-datacounter
2
+
3
+ == Component
4
+
5
+ === DataCounterOutput
6
+
7
+ Count messages with data matches any of specified regexp patterns in specified attribute.
8
+
9
+ - Counts per min/hour/day
10
+ - Counts per second (average every min/hour/day)
11
+ - Percentage of each pattern in total counts of messages
12
+
13
+ DataCounterOutput emits messages contains results data, so you can output these message (with 'datacount' tag by default) to any outputs you want.
14
+
15
+ output ex1 (aggragates all inputs): {"pattern1_count":20, "pattern1_rate":0.333, "pattern1_percentage":25.0, "pattern2_count":40, "pattern2_rate":0.666, "pattern2_percentage":50.0, "unmatched_count":20, "unmatched_rate":0.333, "unmatched_percentage":25.0}
16
+ output ex2 (aggragates per tag): {"test_pattern1_count":10, "test_pattern1_rate":0.333, "test_pattern1_percentage":25.0, "test_pattern2_count":40, "test_pattern2_rate":0.666, "test_pattern2_percentage":50.0, "test_unmatched_count":20, "test_unmatched_rate":0.333, "test_unmatched_percentage":25.0}
17
+
18
+ 'input_tag_remove_prefix' option available if you want to remove tag prefix from output field names.
19
+
20
+ == Configuration
21
+
22
+ === DataCounterOutput
23
+
24
+ Count messages that have attribute 'referer' as 'google.com', 'yahoo.com' and 'facebook.com' from all messages matched, per minutes.
25
+
26
+ <match accesslog.**>
27
+ type datacounter
28
+ unit minute
29
+ aggregate all
30
+ count_key referer
31
+ # patternX: X(1-9)
32
+ pattern1 google google.com
33
+ pattern2 yahoo yahoo.com
34
+ pattern3 facebook facebook.com
35
+ # but patterns above matches 'this-is-facebookXcom.xxxsite.com' ...
36
+ </match>
37
+
38
+ Or, more exact match pattern, output per tags (default 'aggregate tag'), per hours.
39
+
40
+ <match accesslog.**>
41
+ type datacounter
42
+ unit hour
43
+ count_key referer
44
+ # patternX: X(1-9)
45
+ pattern1 google ^http://www\.google\.com/.*
46
+ pattern2 yahoo ^http://www\.yahoo\.com/.*
47
+ pattern3 twitter ^https://twitter.com/.*
48
+ </match>
49
+
50
+ HTTP status code patterns.
51
+
52
+ <match accesslog.**>
53
+ type datacounter
54
+ unit min
55
+ count_key status
56
+ # patternX: X(1-9)
57
+ pattern1 2xx ^2\d\d$
58
+ pattern2 3xx ^3\d\d$
59
+ pattern3 404 ^404$ # we want only 404 counts...
60
+ pattern4 4xx ^4\d\d$ # pattern4 doesn't matches messages matches pattern[123]
61
+ pattern5 5xx ^5\d\d$
62
+ </match>
63
+
64
+ == TODO
65
+
66
+ - consider what to do next
67
+ - patches welcome!
68
+
69
+ == Copyright
70
+
71
+ Copyright:: Copyright (c) 2012- TAGOMORI Satoshi (tagomoris)
72
+ License:: Apache License, Version 2.0
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/**/test_*.rb'
7
+ test.verbose = true
8
+ end
9
+
10
+ task :default => :test
11
+
data/example.conf ADDED
@@ -0,0 +1,24 @@
1
+ <source>
2
+ type forward
3
+ </source>
4
+
5
+ # out_sampling_filter strongly recommended
6
+ <match test.**>
7
+ type sampling_filter
8
+ interval 2
9
+ remove_prefix test
10
+ add_prefix sampled
11
+ </match>
12
+
13
+ <match sampled.**>
14
+ type datacounter
15
+ tag result
16
+ aggregate all
17
+ count_key field
18
+ pattern1 ok ^OK
19
+ pattern2 ng ^NG
20
+ </match>
21
+
22
+ <match result>
23
+ type stdout
24
+ </match>
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "fluent-plugin-datacounter"
6
+ s.version = "0.1.0"
7
+ s.authors = ["TAGOMORI Satoshi"]
8
+ s.email = ["tagomoris@gmail.com"]
9
+ s.homepage = "https://github.com/tagomoris/fluent-plugin-datacounter"
10
+ s.summary = %q{Output filter plugin to count messages that matches specified conditions}
11
+ s.description = %q{Output filter plugin to count messages that matches specified conditions}
12
+
13
+ s.rubyforge_project = "fluent-plugin-datacounter"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ # specify any dependencies here; for example:
21
+ # s.add_development_dependency "rspec"
22
+ # s.add_runtime_dependency "rest-client"
23
+ s.add_development_dependency "fluentd"
24
+ s.add_runtime_dependency "fluentd"
25
+ end
@@ -0,0 +1,185 @@
1
+ class Fluent::DataCounterOutput < Fluent::Output
2
+ Fluent::Plugin.register_output('datacounter', self)
3
+
4
+ config_param :unit, :string, :default => 'minute'
5
+ config_param :aggregate, :string, :default => 'tag'
6
+ config_param :tag, :string, :default => 'datacount'
7
+ config_param :input_tag_remove_prefix, :string, :default => nil
8
+ config_param :count_key, :string
9
+
10
+ # pattern0 reserved as unmatched counts
11
+ config_param :pattern1, :string # string: NAME REGEXP
12
+ (2..9).each do |i|
13
+ config_param ('pattern' + i.to_s).to_sym, :string, :default => nil # NAME REGEXP
14
+ end
15
+
16
+ attr_accessor :counts
17
+ attr_accessor :last_checked
18
+
19
+ def configure(conf)
20
+ super
21
+
22
+ @unit = case @unit
23
+ when 'minute' then :minute
24
+ when 'hour' then :hour
25
+ when 'day' then :day
26
+ else
27
+ raise Fluent::ConfigError, "flowcounter unit allows minute/hour/day"
28
+ end
29
+ @aggregate = case @aggregate
30
+ when 'tag' then :tag
31
+ when 'all' then :all
32
+ else
33
+ raise Fluent::ConfigError, "flowcounter aggregate allows tag/all"
34
+ end
35
+
36
+ @patterns = [[0, 'unmatched', nil]]
37
+ pattern_names = ['unmatched']
38
+ (1..9).each do |i|
39
+ next unless conf["pattern#{i}"]
40
+ name,regexp = conf["pattern#{i}"].split(' ', 2)
41
+ @patterns.push([i, name, Regexp.new(regexp)])
42
+ pattern_names.push(name)
43
+ end
44
+ pattern_index_list = conf.keys.select{|s| s =~ /^pattern\d$/}.map{|v| (/^pattern(\d)$/.match(v))[1].to_i}
45
+ unless pattern_index_list.reduce(true){|v,i| v and @patterns[i]}
46
+ raise Fluent::ConfigError, "jump of pattern index found"
47
+ end
48
+ unless @patterns.length == pattern_names.uniq.length
49
+ raise Fluent::ConfigError, "duplicated pattern names"
50
+ end
51
+
52
+ if @input_tag_remove_prefix
53
+ @removed_prefix_string = @input_tag_remove_prefix + '.'
54
+ @removed_length = @removed_prefix_string.length
55
+ end
56
+
57
+ @counts = count_initialized
58
+ end
59
+
60
+ def start
61
+ super
62
+ @counts = count_initialized
63
+ start_watch
64
+ end
65
+
66
+ def shutdown
67
+ super
68
+ @watcher.terminate
69
+ @watcher.join
70
+ end
71
+
72
+ def count_initialized(keys=nil)
73
+ # counts['tag'][num] = count
74
+ if @aggregate == :all
75
+ {'all' => ([0] * @patterns.length)}
76
+ elsif keys
77
+ values = Array.new(keys.length) {|i|
78
+ Array.new(@patterns.length){|j| 0 }
79
+ }
80
+ Hash[[keys, values].transpose]
81
+ else
82
+ {}
83
+ end
84
+ end
85
+
86
+ def countups(tag, counts)
87
+ if @aggregate == :all
88
+ tag = 'all'
89
+ end
90
+ @counts[tag] ||= [0] * @patterns.length
91
+
92
+ counts.each_with_index do |count, i|
93
+ @counts[tag][i] += count
94
+ end
95
+ end
96
+
97
+ def stripped_tag(tag)
98
+ return tag unless @input_tag_remove_prefix
99
+ return tag[@removed_length..-1] if tag.start_with?(@removed_prefix_string) and tag.length > @removed_length
100
+ return tag[@removed_length..-1] if tag == @input_tag_remove_prefix
101
+ tag
102
+ end
103
+
104
+ def generate_output(counts, step)
105
+ output = {}
106
+ if @aggregate == :all
107
+ sum = counts['all'].inject(:+)
108
+ counts['all'].each_with_index do |count,i|
109
+ name = @patterns[i][1]
110
+ output[name + '_count'] = count
111
+ output[name + '_rate'] = ((count * 100.0) / (1.00 * step)).floor / 100.0
112
+ output[name + '_percentage'] = count * 100.0 / (1.00 * sum) if sum > 0
113
+ end
114
+ return output
115
+ end
116
+
117
+ counts.keys.each do |tag|
118
+ t = stripped_tag(tag)
119
+ sum = counts[tag].inject(:+)
120
+ counts[tag].each_with_index do |count,i|
121
+ name = @patterns[i][1]
122
+ output[t + '_' + name + '_count'] = count
123
+ output[t + '_' + name + '_rate'] = ((count * 100.0) / (1.00 * step)).floor / 100.0
124
+ output[t + '_' + name + '_percentage'] = count * 100.0 / (1.00 * sum) if sum > 0
125
+ end
126
+ end
127
+ output
128
+ end
129
+
130
+ def flush(step)
131
+ flushed,@counts = @counts,count_initialized(@counts.keys.dup)
132
+ generate_output(flushed, step)
133
+ end
134
+
135
+ def flush_emit(step)
136
+ Fluent::Engine.emit(@tag, Fluent::Engine.now, flush(step))
137
+ end
138
+
139
+ def start_watch
140
+ # for internal, or tests only
141
+ @watcher = Thread.new(&method(:watch))
142
+ end
143
+
144
+ def watch
145
+ # instance variable, and public accessable, for test
146
+ @last_checked = Fluent::Engine.now
147
+ tick = case @unit
148
+ when :minute then 60
149
+ when :hour then 3600
150
+ when :day then 86400
151
+ else
152
+ raise RuntimeError, "@unit must be one of minute/hour/day"
153
+ end
154
+ while true
155
+ sleep 0.5
156
+ if Fluent::Engine.now - @last_checked >= tick
157
+ now = Fluent::Engine.now
158
+ flush_emit(now - @last_checked)
159
+ @last_checked = now
160
+ end
161
+ end
162
+ end
163
+
164
+ def emit(tag, es, chain)
165
+ c = [0] * @patterns.length
166
+
167
+ es.each do |time,record|
168
+ value = record[@count_key]
169
+ next if value.nil?
170
+
171
+ value = value.to_s
172
+ matched = false
173
+ @patterns.each do |index, name, regexp|
174
+ next unless regexp and regexp.match(value)
175
+ c[index] += 1
176
+ matched = true
177
+ break
178
+ end
179
+ c[0] += 1 unless matched
180
+ end
181
+ countups(tag, c)
182
+
183
+ chain.next
184
+ end
185
+ 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_datacounter'
26
+
27
+ class Test::Unit::TestCase
28
+ end
@@ -0,0 +1,205 @@
1
+ require 'helper'
2
+
3
+ class DataCounterOutputTest < Test::Unit::TestCase
4
+ def setup
5
+ Fluent::Test.setup
6
+ end
7
+
8
+ CONFIG = %[
9
+ unit minute
10
+ aggregate tag
11
+ input_tag_remove_prefix test
12
+ count_key target
13
+ pattern1 status2xx ^2\\d\\d$
14
+ pattern2 status3xx ^3\\d\\d$
15
+ pattern3 status4xx ^4\\d\\d$
16
+ pattern4 status5xx ^5\\d\\d$
17
+ ]
18
+
19
+ def create_driver(conf = CONFIG, tag='test.input')
20
+ Fluent::Test::OutputTestDriver.new(Fluent::DataCounterOutput, tag).configure(conf)
21
+ end
22
+
23
+ def test_configure
24
+ assert_raise(Fluent::ConfigError) {
25
+ d = create_driver('')
26
+ }
27
+ assert_raise(Fluent::ConfigError) {
28
+ d = create_driver %[
29
+ count_key field
30
+ ]
31
+ }
32
+ assert_raise(Fluent::ConfigError) {
33
+ d = create_driver %[
34
+ pattern1 hoge ^1\\d\\d$
35
+ ]
36
+ }
37
+ assert_raise(Fluent::ConfigError) {
38
+ d = create_driver %[
39
+ count_key field
40
+ pattern2 hoge ^1\\d\\d$
41
+ ]
42
+ }
43
+ assert_raise(Fluent::ConfigError) {
44
+ d = create_driver %[
45
+ count_key field
46
+ pattern1 hoge ^1\\d\\d$
47
+ pattern4 pos ^4\\d\\d$
48
+ ]
49
+ }
50
+ assert_raise(Fluent::ConfigError) {
51
+ d = create_driver %[
52
+ count_key field
53
+ pattern1 hoge ^1\\d\\d$
54
+ pattern2 hoge ^4\\d\\d$
55
+ ]
56
+ }
57
+ d = create_driver %[
58
+ count_key field
59
+ pattern1 ok ^2\\d\\d$
60
+ ]
61
+ assert_equal :minute, d.instance.unit
62
+ assert_equal :tag, d.instance.aggregate
63
+ assert_equal 'datacount', d.instance.tag
64
+ assert_nil d.instance.input_tag_remove_prefix
65
+ assert_equal 'field', d.instance.count_key
66
+ assert_equal 'ok ^2\d\d$', d.instance.pattern1
67
+ end
68
+
69
+ def test_count_initialized
70
+ d = create_driver %[
71
+ aggregate all
72
+ count_key field
73
+ pattern1 hoge 1\d\d
74
+ pattern2 moge 2\d\d
75
+ ]
76
+ assert_equal [0,0,0], d.instance.counts['all']
77
+ end
78
+
79
+ def test_countups
80
+ d = create_driver
81
+ assert_nil d.instance.counts['test.input']
82
+
83
+ d.instance.countups('test.input', [0, 0, 0, 0, 0])
84
+ assert_equal [0,0,0,0,0], d.instance.counts['test.input']
85
+ d.instance.countups('test.input', [1, 1, 1, 0, 0])
86
+ assert_equal [1,1,1,0,0], d.instance.counts['test.input']
87
+ d.instance.countups('test.input', [0, 5, 1, 0, 0])
88
+ assert_equal [1,6,2,0,0], d.instance.counts['test.input']
89
+ end
90
+
91
+ def test_stripped_tag
92
+ d = create_driver
93
+ assert_equal 'input', d.instance.stripped_tag('test.input')
94
+ assert_equal 'test.input', d.instance.stripped_tag('test.test.input')
95
+ assert_equal 'input', d.instance.stripped_tag('input')
96
+ end
97
+
98
+ def test_generate_output
99
+ d = create_driver
100
+ r1 = d.instance.generate_output({'test.input' => [60,240,120,180,0], 'test.input2' => [0,600,0,0,0]}, 60)
101
+ assert_equal 60, r1['input_unmatched_count']
102
+ assert_equal 1.0, r1['input_unmatched_rate']
103
+ assert_equal 10.0, r1['input_unmatched_percentage']
104
+ assert_equal 240, r1['input_status2xx_count']
105
+ assert_equal 4.0, r1['input_status2xx_rate']
106
+ assert_equal 40.0, r1['input_status2xx_percentage']
107
+ assert_equal 120, r1['input_status3xx_count']
108
+ assert_equal 2.0, r1['input_status3xx_rate']
109
+ assert_equal 20.0, r1['input_status3xx_percentage']
110
+ assert_equal 180, r1['input_status4xx_count']
111
+ assert_equal 3.0, r1['input_status4xx_rate']
112
+ assert_equal 30.0, r1['input_status4xx_percentage']
113
+ assert_equal 0, r1['input_status5xx_count']
114
+ assert_equal 0.0, r1['input_status5xx_rate']
115
+ assert_equal 0.0, r1['input_status5xx_percentage']
116
+
117
+ assert_equal 0, r1['input2_unmatched_count']
118
+ assert_equal 0.0, r1['input2_unmatched_rate']
119
+ assert_equal 0.0, r1['input2_unmatched_percentage']
120
+ assert_equal 600, r1['input2_status2xx_count']
121
+ assert_equal 10.0, r1['input2_status2xx_rate']
122
+ assert_equal 100.0, r1['input2_status2xx_percentage']
123
+ assert_equal 0, r1['input2_status3xx_count']
124
+ assert_equal 0.0, r1['input2_status3xx_rate']
125
+ assert_equal 0.0, r1['input2_status3xx_percentage']
126
+ assert_equal 0, r1['input2_status4xx_count']
127
+ assert_equal 0.0, r1['input2_status4xx_rate']
128
+ assert_equal 0.0, r1['input2_status4xx_percentage']
129
+ assert_equal 0, r1['input2_status5xx_count']
130
+ assert_equal 0.0, r1['input2_status5xx_rate']
131
+ assert_equal 0.0, r1['input2_status5xx_percentage']
132
+
133
+ d = create_driver %[
134
+ aggregate all
135
+ count_key field
136
+ pattern1 hoge xxx\d\d
137
+ ]
138
+ r2 = d.instance.generate_output({'all' => [60,240]}, 60)
139
+ assert_equal 60, r2['unmatched_count']
140
+ assert_equal 1.0, r2['unmatched_rate']
141
+ assert_equal 20.0, r2['unmatched_percentage']
142
+ assert_equal 240, r2['hoge_count']
143
+ assert_equal 4.0, r2['hoge_rate']
144
+ assert_equal 80.0, r2['hoge_percentage']
145
+ end
146
+
147
+ def test_emit
148
+ d1 = create_driver(CONFIG, 'test.tag1')
149
+ d1.run do
150
+ 60.times do
151
+ d1.emit({'target' => '200'})
152
+ d1.emit({'target' => '100'})
153
+ d1.emit({'target' => '200'})
154
+ d1.emit({'target' => '400'})
155
+ end
156
+ end
157
+ r1 = d1.instance.flush(60)
158
+ assert_equal 120, r1['tag1_status2xx_count']
159
+ assert_equal 2.0, r1['tag1_status2xx_rate']
160
+ assert_equal 50.0, r1['tag1_status2xx_percentage']
161
+
162
+ assert_equal 60, r1['tag1_status4xx_count']
163
+ assert_equal 1.0, r1['tag1_status4xx_rate']
164
+ assert_equal 25.0, r1['tag1_status4xx_percentage']
165
+
166
+ assert_equal 60, r1['tag1_unmatched_count']
167
+ assert_equal 1.0, r1['tag1_unmatched_rate']
168
+ assert_equal 25.0, r1['tag1_unmatched_percentage']
169
+
170
+ assert_equal 0, r1['tag1_status3xx_count']
171
+ assert_equal 0.0, r1['tag1_status3xx_rate']
172
+ assert_equal 0.0, r1['tag1_status3xx_percentage']
173
+ assert_equal 0, r1['tag1_status5xx_count']
174
+ assert_equal 0.0, r1['tag1_status5xx_rate']
175
+ assert_equal 0.0, r1['tag1_status5xx_percentage']
176
+
177
+ d2 = create_driver(%[
178
+ aggregate all
179
+ count_key target
180
+ pattern1 ok 2\\d\\d
181
+ pattern2 redirect 3\\d\\d
182
+ ], 'test.tag2')
183
+ d2.run do
184
+ 60.times do
185
+ d2.emit({'target' => '200'})
186
+ d2.emit({'target' => '300 200'})
187
+ end
188
+ end
189
+ d2.instance.flush_emit(120)
190
+ emits = d2.emits
191
+ assert_equal 1, emits.length
192
+ data = emits[0]
193
+ assert_equal 'datacount', data[0] # tag
194
+ assert_equal 120, data[2]['ok_count']
195
+ assert_equal 1.0, data[2]['ok_rate']
196
+ assert_equal 100.0, data[2]['ok_percentage']
197
+ assert_equal 0, data[2]['redirect_count']
198
+ assert_equal 0.0, data[2]['redirect_rate']
199
+ assert_equal 0.0, data[2]['redirect_percentage']
200
+ assert_equal 0, data[2]['unmatched_count']
201
+ assert_equal 0.0, data[2]['unmatched_rate']
202
+ assert_equal 0.0, data[2]['unmatched_percentage']
203
+ end
204
+
205
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-datacounter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - TAGOMORI Satoshi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-23 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: fluentd
16
+ requirement: &2153804860 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2153804860
25
+ - !ruby/object:Gem::Dependency
26
+ name: fluentd
27
+ requirement: &2153804420 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2153804420
36
+ description: Output filter plugin to count messages that matches specified conditions
37
+ email:
38
+ - tagomoris@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - LICENSE.txt
46
+ - README.rdoc
47
+ - Rakefile
48
+ - example.conf
49
+ - fluent-plugin-datacounter.gemspec
50
+ - lib/fluent/plugin/out_datacounter.rb
51
+ - test/helper.rb
52
+ - test/plugin/test_out_datacounter.rb
53
+ homepage: https://github.com/tagomoris/fluent-plugin-datacounter
54
+ licenses: []
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubyforge_project: fluent-plugin-datacounter
73
+ rubygems_version: 1.8.6
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Output filter plugin to count messages that matches specified conditions
77
+ test_files:
78
+ - test/helper.rb
79
+ - test/plugin/test_out_datacounter.rb