fluent-plugin-eventcounter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /*.gem
2
+ ~*
3
+ #*
4
+ *~
5
+ .bundle
6
+ Gemfile.lock
7
+ .rbenv-version
8
+ vendor
9
+ doc/*
10
+ tmp/*
11
+ coverage
12
+ .yardoc
13
+ .ruby-version
14
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Sean Dick and Change.org
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,22 @@
1
+ fluent-plugin-eventcounter
2
+ ==========================
3
+
4
+ This plugin is designed to count occurrences of unique values in a specified key and pass them through as counts either as a re-emit or by directly incrementing a specified redis hash.
5
+
6
+ Installation
7
+ ------------
8
+
9
+ OSX/fluentd
10
+
11
+ /opt/td-agent/embedded/bin/gem install fluent-plugin-eventcounter
12
+
13
+ or
14
+
15
+ fluent-gem install fluent-plugin-eventcounter
16
+
17
+
18
+ Configuration
19
+ -------------
20
+
21
+
22
+
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |gem|
3
+ gem.name = "fluent-plugin-eventcounter"
4
+ gem.version = "0.0.1"
5
+ gem.authors = ["Sean Dick", "Change.org"]
6
+ gem.email = ["sean@change.org"]
7
+ gem.homepage = "https://github.com/seanmdick/fluent-plugin-eventcounter"
8
+ gem.summary = %q{Fluentd plugin to count occurences of values in a field and emit them or write them to redis}
9
+ gem.description = %q{Fluentd plugin to count occurences of values in a field and emit them or write them to redis}
10
+ gem.license = "MIT"
11
+
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.require_paths = ["lib"]
15
+
16
+ gem.add_runtime_dependency "fluentd"
17
+ gem.add_runtime_dependency "redis"
18
+
19
+ gem.add_development_dependency "bundler"
20
+ gem.add_development_dependency "rake"
21
+ gem.add_development_dependency "rspec"
22
+ end
@@ -0,0 +1,79 @@
1
+ class Fluent::EventCounterOutput < Fluent::BufferedOutput
2
+ Fluent::Plugin.register_output('eventcounter', self)
3
+ def initialize
4
+ super
5
+ require 'redis'
6
+ end
7
+
8
+ config_param :emit_only, :bool, :default => false
9
+ config_param :emit_to, :string, :default => 'debug.events'
10
+
11
+ config_param :redis_host, :string, :default => 'localhost'
12
+ config_param :redis_port, :integer, :default => 6379
13
+ config_param :redis_password, :string, :default => nil
14
+ config_param :redis_db_number, :integer, :default => 0
15
+ config_param :redis_output_key, :string, :default => ''
16
+
17
+ config_param :input_tag_exclude, :string, :default => ''
18
+ config_param :capture_extra_if, :string, :default => nil
19
+ config_param :capture_extra_replace, :string, :default => ''
20
+
21
+ config_param :count_key, :string
22
+ config_param :flush_interval, :time, :default => 10
23
+
24
+ attr_accessor :counts
25
+
26
+ def configure(conf)
27
+ super
28
+ @capture_extra_replace = Regexp.new(@capture_extra_replace) if @capture_extra_replace.length > 0
29
+ end
30
+
31
+ def start
32
+ super
33
+ @redis = Redis.new(
34
+ host: @redis_host,
35
+ port: @redis_port,
36
+ password: @redis_password,
37
+ thread_safe: true,
38
+ db: @redis_db_number
39
+ ) unless @emit_only
40
+ end
41
+
42
+ def format(tag, time, record)
43
+ return '' unless record[@count_key]
44
+
45
+ if @capture_extra_if && record[@capture_extra_if]
46
+ extra = record[@capture_extra_if].gsub(@capture_extra_replace, '')
47
+ [tag.gsub(@input_tag_exclude,""), [record[@count_key], extra].compact.join(':')].to_json + "\n"
48
+ else
49
+ [tag.gsub(@input_tag_exclude,""), record[@count_key]].to_json + "\n"
50
+ end
51
+ end
52
+
53
+ def write(chunk)
54
+ counts = Hash.new {|hash, key| hash[key] = Hash.new {|h,k| h[k] = 0 } }
55
+ chunk.open do |io|
56
+ items = io.read.split("\n")
57
+ items.each do |item|
58
+ key, event = JSON.parse(item)
59
+ counts[key][event] += 1
60
+ end
61
+ end
62
+ if @emit_only
63
+ counts.each do |tag, events|
64
+ Fluent::Engine.emit(@emit_to, Time.now, tag => events)
65
+ end
66
+ else
67
+ @redis.pipelined do
68
+ counts.each do |tag,events|
69
+ events.each do |event, c|
70
+ redis_key = [@redis_output_key,tag].join(':')
71
+ Fluent::Engine.emit(@emit_to, Time.now, redis_key => { event => c})
72
+ @redis.hincrby(redis_key, event, c.to_i)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fluent::EventCounterOutput do
4
+ before { Fluent::Test.setup }
5
+
6
+
7
+ describe '#format' do
8
+ context 'no capture extra is set' do
9
+ let (:conf) {
10
+ %[
11
+ count_key event
12
+ ]
13
+ }
14
+ let (:eventcounter) { Fluent::Test::BufferedOutputTestDriver.new(Fluent::EventCounterOutput.new).configure(conf) }
15
+ context 'the input contains the count key' do
16
+ it 'produces the expected output' do
17
+ eventcounter.tag = 'something'
18
+ eventcounter.emit( { 'event' => 'the_event'}, Time.now )
19
+ eventcounter.expect_format ['something', 'the_event'].to_json + "\n"
20
+ eventcounter.run
21
+ end
22
+ end
23
+
24
+ context 'the input does not contain the count key' do
25
+ it 'does not add it to the buffer' do
26
+ eventcounter.tag = 'something'
27
+ eventcounter.emit( { 'not_an_event' => 'the_event'}, Time.now )
28
+ eventcounter.expect_format ''
29
+ eventcounter.run
30
+ end
31
+ end
32
+ end
33
+ context 'capture_extra_if is set' do
34
+ let (:conf) {
35
+ %[
36
+ count_key event
37
+ capture_extra_if url
38
+ ]
39
+ }
40
+
41
+ let (:eventcounter) { Fluent::Test::BufferedOutputTestDriver.new(Fluent::EventCounterOutput.new).configure(conf) }
42
+
43
+ context 'the provided data contains the capture extra' do
44
+ it 'captures the count_key:capture_extra' do
45
+ eventcounter.tag = 'something'
46
+ eventcounter.emit( { 'event' => 'the_event', 'url' => 'http://www.example.com?someparam=somethingElse'}, Time.now )
47
+ eventcounter.expect_format ['something', 'the_event:http://www.example.com?someparam=somethingElse'].to_json + "\n"
48
+ eventcounter.run
49
+ end
50
+ context 'with capture_extra_replace' do
51
+ let (:conf) {
52
+ %[
53
+ count_key event
54
+ capture_extra_if url
55
+ capture_extra_replace \\?.*$
56
+ ]
57
+ }
58
+ let (:eventcounter) { Fluent::Test::BufferedOutputTestDriver.new(Fluent::EventCounterOutput.new).configure(conf) }
59
+
60
+ it 'transforms the capture_extra with the provided regex' do
61
+ eventcounter.tag = 'something'
62
+ eventcounter.emit( { 'event' => 'the_event', 'url' => 'http://www.example.com?someparam=somethingElse'}, Time.now )
63
+ eventcounter.expect_format ['something', 'the_event:http://www.example.com'].to_json + "\n"
64
+ eventcounter.run
65
+ end
66
+ end
67
+ end
68
+ context 'the provided data DOES NOT contain the capture extra' do
69
+ it 'captures only the count_key' do
70
+ eventcounter.tag = 'something'
71
+ eventcounter.emit( { 'event' => 'the_event', 'not_a_url' => 'http://www.example.com'}, Time.now )
72
+ eventcounter.expect_format ['something', 'the_event'].to_json + "\n"
73
+ eventcounter.run
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ Bundler.setup(:default, :test)
5
+ Bundler.require(:default, :test)
6
+
7
+ require 'fluent/test'
8
+ require 'rspec'
9
+
10
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
11
+ require 'fluent/plugin/out_eventcounter'
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-eventcounter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sean Dick
9
+ - Change.org
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2014-10-16 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: fluentd
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: redis
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: rake
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ - !ruby/object:Gem::Dependency
80
+ name: rspec
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ description: Fluentd plugin to count occurences of values in a field and emit them
96
+ or write them to redis
97
+ email:
98
+ - sean@change.org
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - .gitignore
104
+ - Gemfile
105
+ - LICENSE
106
+ - README.md
107
+ - fluent-plugin-eventcounter.gemspec
108
+ - lib/fluent/plugin/out_eventcounter.rb
109
+ - spec/out_eventcounter_spec.rb
110
+ - spec/spec_helper.rb
111
+ homepage: https://github.com/seanmdick/fluent-plugin-eventcounter
112
+ licenses:
113
+ - MIT
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 1.8.23
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: Fluentd plugin to count occurences of values in a field and emit them or
136
+ write them to redis
137
+ test_files:
138
+ - spec/out_eventcounter_spec.rb
139
+ - spec/spec_helper.rb