fluent-plugin-eventcounter 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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