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 +3 -0
- data/Gemfile.lock +52 -0
- data/LICENSE +21 -0
- data/README.md +75 -0
- data/fluent-plugin-eventlastvalue.gemspec +23 -0
- data/lib/fluent/plugin/out_eventlastvalue.rb +45 -0
- data/spec/out_eventlastvalue_spec.rb +96 -0
- data/spec/spec_helper.rb +11 -0
- metadata +154 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|