fluent-plugin-eventlastvalue 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,52 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fluent-plugin-eventlastvalue (0.0.1)
5
+ fluentd
6
+ redis
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ cool.io (1.3.0)
12
+ diff-lcs (1.2.4)
13
+ fluentd (0.12.7)
14
+ cool.io (>= 1.2.2, < 2.0.0)
15
+ http_parser.rb (>= 0.5.1, < 0.7.0)
16
+ json (>= 1.4.3)
17
+ msgpack (>= 0.5.11, < 0.6.0)
18
+ sigdump (~> 0.2.2)
19
+ string-scrub (>= 0.0.3)
20
+ tzinfo (>= 1.0.0)
21
+ tzinfo-data (>= 1.0.0)
22
+ yajl-ruby (~> 1.0)
23
+ http_parser.rb (0.6.0)
24
+ json (1.8.1)
25
+ msgpack (0.5.11)
26
+ rake (10.3.2)
27
+ redis (3.0.7)
28
+ rspec (2.14.1)
29
+ rspec-core (~> 2.14.0)
30
+ rspec-expectations (~> 2.14.0)
31
+ rspec-mocks (~> 2.14.0)
32
+ rspec-core (2.14.4)
33
+ rspec-expectations (2.14.0)
34
+ diff-lcs (>= 1.1.3, < 2.0)
35
+ rspec-mocks (2.14.1)
36
+ sigdump (0.2.2)
37
+ string-scrub (0.0.5)
38
+ thread_safe (0.3.4)
39
+ tzinfo (1.2.2)
40
+ thread_safe (~> 0.1)
41
+ tzinfo-data (1.2015.2)
42
+ tzinfo (>= 1.0.0)
43
+ yajl-ruby (1.1.0)
44
+
45
+ PLATFORMS
46
+ ruby
47
+
48
+ DEPENDENCIES
49
+ bundler
50
+ fluent-plugin-eventlastvalue!
51
+ rake
52
+ rspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Michael Arick 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.
@@ -0,0 +1,75 @@
1
+ fluent-plugin-eventlastvalue
2
+ ==========================
3
+
4
+ This plugin is designed to find the last value in a specified key and pass it through as lastvalue as a re-emit. As it's a buffered plugin it will write or re-emit at a (tunable) sane pace.
5
+
6
+ ##Example
7
+
8
+ Given a set of input like
9
+
10
+ ```
11
+ count_stream { 'time': 1413544890, 'count': 28, 'id': 1337 }
12
+ count_stream { 'time': 1413544830, 'count': 24, 'id': 33864 }
13
+ count_stream { 'time': 1413544860, 'count': 25, 'id': 12345, ... }
14
+ count_stream { 'time': 1413544890, 'count': 18, 'id': 40555 }
15
+ count_stream { 'time': 1413544830, 'count': 5, 'id': 12345 }
16
+ count_stream { 'time': 1413544860, 'count': 6, 'id': 12345 }
17
+ ```
18
+
19
+ With a conf like
20
+
21
+ ```
22
+ <match count_stream>
23
+ type eventlastvalue
24
+ emit_to output.lastvalue
25
+ id_key id
26
+ comparator_key timestamp
27
+ last_value_key count
28
+ flush_interval 1m
29
+ </match>
30
+ ```
31
+
32
+ You would get
33
+
34
+ ```
35
+ output.lastvalue { 'id': 12345, 'count': 6 }
36
+ output.lastvalue { 'id': 1337, 'count': 28 }
37
+ output.lastvalue { 'id': 33864, 'count': 24 }
38
+ output.lastvalue { 'id': 40555, 'count': 18 }
39
+ ```
40
+
41
+ ##Installation
42
+
43
+ OSX
44
+
45
+ /opt/td-agent/embedded/bin/gem install fluent-plugin-eventlastvalue
46
+
47
+ or
48
+
49
+ fluent-gem install fluent-plugin-eventlastvalue
50
+
51
+
52
+ ##Configuration
53
+
54
+ ###Parameters
55
+
56
+ #### Basic
57
+
58
+ - **id_key** (**required**)
59
+ - The key within the record that identifies a group of events to select from.
60
+
61
+ - **last_value_key** (**required**)
62
+ - the key from whose values we want to record the last
63
+
64
+ - **emit_to** (optional) - *string*
65
+ - Tag to re-emit with
66
+ - *default: debug.events*
67
+ - **comparator_key** (optional)
68
+ - Key to use for numeric comparison, used to ensure that the last received message is the one that is counted. If none is set it will record the last received event.
69
+ - *default: nil
70
+
71
+ #### Other
72
+
73
+ - **flush_interval** (optional)
74
+ - Provided from **Fluent::BufferedOutput** time in seconds between flushes
75
+ - *default: 60*
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |gem|
3
+ gem.name = "fluent-plugin-eventlastvalue"
4
+ gem.version = "0.0.2"
5
+ gem.authors = ["Michael Arick", "Change.org"]
6
+ gem.email = ["marick@change.org"]
7
+ gem.homepage = "https://github.com/change/fluent-plugin-eventlastvalue"
8
+ gem.summary = %q{Fluentd plugin to find the last value in a time-period }
9
+ gem.description = %q{Fluentd plugin to find the last value in a time-period of a field and emit it or write it 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
+ gem.add_runtime_dependency "bundler"
19
+
20
+ gem.add_development_dependency "bundler"
21
+ gem.add_development_dependency "rake"
22
+ gem.add_development_dependency "rspec"
23
+ end
@@ -0,0 +1,45 @@
1
+ class Fluent::EventLastValueOutput < Fluent::BufferedOutput
2
+ Fluent::Plugin.register_output('eventlastvalue', self)
3
+ def initialize
4
+ super
5
+ end
6
+
7
+ config_param :emit_to, :string, :default => 'debug.events'
8
+ config_param :id_key, :string, :default => 'id'
9
+ config_param :last_value_key, :string # REQUIRED
10
+ config_param :comparator_key, :string, :default => nil
11
+
12
+ attr_accessor :last_values
13
+
14
+ def configure(conf)
15
+ super
16
+ end
17
+
18
+ def start
19
+ super
20
+ end
21
+
22
+ def format(tag, time, record)
23
+ return '' unless record[@last_value_key]
24
+ [record[@id_key], record[@last_value_key], (record[@comparator_key] || 0).to_f].to_json + "\n"
25
+ end
26
+
27
+ def write(chunk)
28
+ last_values = Hash.new {|hash, key| hash[key] = Hash.new {|h,k| h[k] = nil } }
29
+ last_times = Hash.new {|hash, key| hash[key] = 0}
30
+ chunk.open do |io|
31
+ items = io.read.split("\n")
32
+ items.each do |item|
33
+ key, event, t = JSON.parse(item)
34
+ if @comparator_key.nil? || last_times[key] < t
35
+ last_times[key] = t
36
+ last_values[key] = event
37
+ end
38
+ end
39
+ end
40
+
41
+ last_values.each do |key, value|
42
+ Fluent::Engine.emit(@emit_to, Time.now.to_i, @id_key => key, @last_value_key => value, 'ts' => Time.now.to_s)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fluent::EventLastValueOutput do
4
+ before { Fluent::Test.setup }
5
+
6
+
7
+ describe '#format' do
8
+ let (:conf) {
9
+ %[
10
+ emit_to output.lastvalue
11
+ id_key id
12
+ comparator_key timestamp
13
+ last_value_key count
14
+ ]
15
+ }
16
+ let (:eventlastvalue) { Fluent::Test::BufferedOutputTestDriver.new(Fluent::EventLastValueOutput.new).configure(conf) }
17
+ context 'the input contains the last_value key' do
18
+ it 'produces the expected output' do
19
+ eventlastvalue.tag = 'something'
20
+ eventlastvalue.emit( { 'id' => '4444', 'timestamp' => 123456789, 'count' => 12345 }, Time.now )
21
+ eventlastvalue.expect_format ["4444", 12345, 123456789].to_json + "\n"
22
+ eventlastvalue.run
23
+ end
24
+ end
25
+
26
+ context 'the input does not contain the last_value_key' do
27
+ it 'does not add it to the buffer' do
28
+ eventlastvalue.tag = 'something'
29
+ eventlastvalue.emit( { 'not_last_value_key' => 12345}, Time.now )
30
+ eventlastvalue.expect_format ''
31
+ eventlastvalue.run
32
+ end
33
+ end
34
+ end
35
+
36
+ describe 'output' do
37
+ let (:conf) {
38
+ %[
39
+ emit_to output.lastvalue
40
+ id_key input_id
41
+ last_value_key count
42
+ comparator_key timestamp
43
+ ]
44
+ }
45
+ let (:input) {
46
+ %[{"email": "john.doe@example.com", "count": 12345, "timestamp": "1", "input_id": "1234"}
47
+ {"email": "john.doe@example.com", "count": 12340, "timestamp": "6", "input_id": "1234"}
48
+ {"email": "john.doe@example.com", "count": 12346, "timestamp": "2", "input_id": "1234"}
49
+ {"email": "john.doe@example.com", "count": 12344, "timestamp": "3", "input_id": "1234"}
50
+ {"email": "john.doe@example.com", "count": 12342, "timestamp": "4", "input_id": "1234"}
51
+ {"email": "john.doe@example.com", "count": 12349, "timestamp": "5", "input_id": "1234"}]
52
+ }
53
+ let (:eventlastvalue) { Fluent::Test::BufferedOutputTestDriver.new(Fluent::EventLastValueOutput.new).configure(conf) }
54
+
55
+ context "a comparator key is specified" do
56
+ it "formats the lastvalue against the provided tag" do
57
+ line = input.split("\n").first
58
+ data = JSON.parse line
59
+ eventlastvalue.emit data, Time.now
60
+ output = eventlastvalue.run
61
+ expect(output['1234']).to eq 12345
62
+ end
63
+
64
+ it "returns the latest count given the comparator key" do
65
+ input.split("\n").each do |line|
66
+ data = JSON.parse line
67
+ eventlastvalue.emit data, Time.now
68
+ end
69
+
70
+ output = eventlastvalue.run
71
+ expect(output['1234']).to eq 12340
72
+ end
73
+ end
74
+
75
+ context "a comparator key is NOT specified" do
76
+ let (:conf) {
77
+ %[
78
+ emit_to output.lastvalue
79
+ id_key input_id
80
+ last_value_key count
81
+ ]
82
+ }
83
+
84
+ let (:eventlastvalue) { Fluent::Test::BufferedOutputTestDriver.new(Fluent::EventLastValueOutput.new).configure(conf) }
85
+ it "returns the last received count" do
86
+ input.split("\n").each do |line|
87
+ data = JSON.parse line
88
+ eventlastvalue.emit data, Time.now
89
+ end
90
+
91
+ output = eventlastvalue.run
92
+ expect(output['1234']).to eq 12349
93
+ end
94
+ end
95
+ end
96
+ 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_eventlastvalue'
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-eventlastvalue
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Michael Arick
9
+ - Change.org
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2015-04-28 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: :runtime
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: bundler
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: rake
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
+ - !ruby/object:Gem::Dependency
96
+ name: rspec
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Fluentd plugin to find the last value in a time-period of a field and
112
+ emit it or write it to redis
113
+ email:
114
+ - marick@change.org
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - Gemfile
120
+ - Gemfile.lock
121
+ - LICENSE
122
+ - README.md
123
+ - fluent-plugin-eventlastvalue.gemspec
124
+ - lib/fluent/plugin/out_eventlastvalue.rb
125
+ - spec/out_eventlastvalue_spec.rb
126
+ - spec/spec_helper.rb
127
+ homepage: https://github.com/change/fluent-plugin-eventlastvalue
128
+ licenses:
129
+ - MIT
130
+ post_install_message:
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ! '>='
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ none: false
142
+ requirements:
143
+ - - ! '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ requirements: []
147
+ rubyforge_project:
148
+ rubygems_version: 1.8.23
149
+ signing_key:
150
+ specification_version: 3
151
+ summary: Fluentd plugin to find the last value in a time-period
152
+ test_files:
153
+ - spec/out_eventlastvalue_spec.rb
154
+ - spec/spec_helper.rb