fluent-plugin-time-sliced-filter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8e858fb0b83830d452c10b35371e4f20294ecc1f
4
+ data.tar.gz: 51f24bb1e31d582df578cfcec2841efc194fe169
5
+ SHA512:
6
+ metadata.gz: 33dc331b7d67f672bedff16c95d81c3e3a61cd5697589035e2f8153e12db00ab2ba371326c8e98991750f136039ad77cd5e4fe5505a3b1ea1d7377c9413a087e
7
+ data.tar.gz: 04130af50cbe38845fbfe5dd02e9cf08792e9f513ee5b6854cc2b0c2b619ccd8b067fcb4428a4146684f2b8477e08dbefe2018a4744ea16c08e7be7dc8ff5d60
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require spec_helper
2
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-time-sliced-filter.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Genki Sugawara
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,58 @@
1
+ # fluent-plugin-time-sliced-filter
2
+
3
+ TimeSlicedOutput Plugin to aggregate by unit time
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/fluent-plugin-time-sliced-filter)](http://badge.fury.io/rb/fluent-plugin-time-sliced-filter)
6
+ [![Build Status](https://drone.io/bitbucket.org/winebarrel/fluent-plugin-time-sliced-filter/status.png)](https://drone.io/bitbucket.org/winebarrel/fluent-plugin-time-sliced-filter/latest)
7
+
8
+ ## Installation
9
+
10
+ $ gem install fluent-plugin-time-sliced-filter
11
+
12
+ ## Configuration
13
+
14
+ ```
15
+ <match my.**>
16
+ type time_sliced_filter
17
+ filter_path /foo/bar/my_filrer.rb
18
+ time_slice_format %Y%m%d%H%M%S
19
+ #prefix filtered
20
+ #emit_each_tag false
21
+ #pass_hash_row false
22
+ #include_tag_key false
23
+ #include_time_key false
24
+ </match>
25
+
26
+ <match filtered.my.**>
27
+ type stdout
28
+ </match>
29
+ ```
30
+
31
+ ## Usage
32
+
33
+ ```ruby
34
+ # Count the number of records of every unit time
35
+
36
+ proc {|records|
37
+
38
+ # `records` is an Array such as:
39
+ # [[tag, time, record], [tag, time, record], ...]
40
+ #
41
+ # e.g.)
42
+ # [["my.data", 1391820170, {"hoge"=>"fuga"}],
43
+ # ["my.data", 1391820170, {"hoge"=>"fuga"}],
44
+ # ["my.data", 1391820170, {"hoge"=>"fuga"}],
45
+ # ...
46
+
47
+ {'count' => records.count}
48
+ # or [{...},{...},{...}, ...]
49
+ }
50
+ ```
51
+
52
+ ## Contributing
53
+
54
+ 1. Fork it
55
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
56
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
57
+ 4. Push to the branch (`git push origin my-new-feature`)
58
+ 5. Create new Pull Request
@@ -0,0 +1,5 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new('spec')
5
+ task :default => :spec
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+ Gem::Specification.new do |spec|
3
+ spec.name = 'fluent-plugin-time-sliced-filter'
4
+ spec.version = '0.1.0'
5
+ spec.authors = ['Genki Sugawara']
6
+ spec.email = ['sgwr_dts@yahoo.co.jp']
7
+ spec.description = %q{TimeSlicedOutput Plugin to aggregate by unit time}
8
+ spec.summary = %q{TimeSlicedOutput Plugin to aggregate by unit time}
9
+ spec.homepage = 'https://bitbucket.org/winebarrel/fluent-plugin-time-sliced-filter'
10
+ spec.license = 'MIT'
11
+
12
+ spec.files = `git ls-files`.split($/)
13
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
+ spec.require_paths = ['lib']
16
+
17
+ spec.add_dependency 'fluentd'
18
+ spec.add_development_dependency 'bundler', '~> 1.3'
19
+ spec.add_development_dependency 'rake'
20
+ spec.add_development_dependency 'rspec', '>= 2.11.0'
21
+ end
@@ -0,0 +1,68 @@
1
+ class Fluent::TimeSlicedFilterOutput < Fluent::TimeSlicedOutput
2
+ include Fluent::SetTagKeyMixin
3
+ include Fluent::SetTimeKeyMixin
4
+
5
+ Fluent::Plugin.register_output('time_sliced_filter', self)
6
+
7
+ unless method_defined?(:log)
8
+ define_method('log') { $log }
9
+ end
10
+
11
+ config_param :filter_path, :type => :string
12
+ config_param :prefix, :type => :string, :default => 'filtered'
13
+ config_param :emit_each_tag, :type => :bool, :default => false
14
+ config_param :pass_hash_row, :type => :bool, :default => false
15
+
16
+ def configure(conf)
17
+ super
18
+
19
+ unless File.exist?(@filter_path)
20
+ raise Fluent::ConfigError, "No such file: #{@filter_path}"
21
+ end
22
+
23
+ begin
24
+ @filter = Object.new.instance_eval(File.read(@filter_path), @filter_path)
25
+ rescue => e
26
+ raise Fluent::ConfigError, "Invalid filter: #{@filter_path}: #{e}"
27
+ end
28
+
29
+ unless @filter.respond_to?(:call)
30
+ raise Fluent::ConfigError, "`call` method not implemented in filter: #{@filter_path}"
31
+ end
32
+ end
33
+
34
+ def format(tag, time, record)
35
+ # XXX: format_stream is not called
36
+ # https://github.com/fluent/fluentd/blob/v0.10.43/lib/fluent/output.rb#L516
37
+ filter_record(tag, time, record)
38
+ [tag, time, record].to_msgpack
39
+ end
40
+
41
+ def write(chunk)
42
+ enum = chunk.to_enum(:msgpack_each)
43
+ rows = @pass_hash_row ? enum.map {|_, _, record| record } : enum.to_a
44
+ records = @filter.call(rows)
45
+ records = [records] unless records.kind_of?(Array)
46
+ time = enum.map {|_, time, _| time }.min
47
+
48
+ if @emit_each_tag
49
+ tags = enum.map {|tag, _, _| tag }
50
+ tags.each {|tag| emit_records(tag, time, records) }
51
+ else
52
+ tag = enum.first[0]
53
+ emit_records(tag, time, records)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def emit_records(tag, time, records)
60
+ records.each do |record|
61
+ if record.kind_of?(Hash)
62
+ Fluent::Engine.emit("#{@prefix}.#{tag}", time, record)
63
+ else
64
+ log.warn("Record must be Hash: #{record.inspect} (#{record.class})")
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,402 @@
1
+ describe Fluent::TimeSlicedFilterOutput do
2
+ let(:time) {
3
+ Time.parse('2014-02-08 13:14:15 +0900').to_i
4
+ }
5
+
6
+ describe 'when 2 records transmitted per second' do
7
+ it 'should be aggregated to two records' do
8
+ emits = run_driver do |d|
9
+ (0...8).each do |i|
10
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
11
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
12
+ end
13
+ end
14
+
15
+ expect(emits).to eq(
16
+ [["filtered.test.default", 1391832855, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832855, {\"key0\"=>\"val0\"}], [\"test.default\", 1391832855, {\"key0_\"=>\"val0_\"}]]"}],
17
+ ["filtered.test.default", 1391832856, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832856, {\"key1\"=>\"val1\"}], [\"test.default\", 1391832856, {\"key1_\"=>\"val1_\"}]]"}],
18
+ ["filtered.test.default", 1391832857, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832857, {\"key2\"=>\"val2\"}], [\"test.default\", 1391832857, {\"key2_\"=>\"val2_\"}]]"}],
19
+ ["filtered.test.default", 1391832858, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832858, {\"key3\"=>\"val3\"}], [\"test.default\", 1391832858, {\"key3_\"=>\"val3_\"}]]"}],
20
+ ["filtered.test.default", 1391832859, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832859, {\"key4\"=>\"val4\"}], [\"test.default\", 1391832859, {\"key4_\"=>\"val4_\"}]]"}],
21
+ ["filtered.test.default", 1391832860, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832860, {\"key5\"=>\"val5\"}], [\"test.default\", 1391832860, {\"key5_\"=>\"val5_\"}]]"}],
22
+ ["filtered.test.default", 1391832861, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832861, {\"key6\"=>\"val6\"}], [\"test.default\", 1391832861, {\"key6_\"=>\"val6_\"}]]"}],
23
+ ["filtered.test.default", 1391832862, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832862, {\"key7\"=>\"val7\"}], [\"test.default\", 1391832862, {\"key7_\"=>\"val7_\"}]]"}]]
24
+ )
25
+ end
26
+
27
+ it 'should be rewritten to the specified tag' do
28
+ emits = run_driver(:prefix => 'any_prefix') do |d|
29
+ (0...8).each do |i|
30
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
31
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
32
+ end
33
+ end
34
+
35
+ expect(emits).to eq(
36
+ [["any_prefix.test.default", 1391832855, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832855, {\"key0\"=>\"val0\"}], [\"test.default\", 1391832855, {\"key0_\"=>\"val0_\"}]]"}],
37
+ ["any_prefix.test.default", 1391832856, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832856, {\"key1\"=>\"val1\"}], [\"test.default\", 1391832856, {\"key1_\"=>\"val1_\"}]]"}],
38
+ ["any_prefix.test.default", 1391832857, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832857, {\"key2\"=>\"val2\"}], [\"test.default\", 1391832857, {\"key2_\"=>\"val2_\"}]]"}],
39
+ ["any_prefix.test.default", 1391832858, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832858, {\"key3\"=>\"val3\"}], [\"test.default\", 1391832858, {\"key3_\"=>\"val3_\"}]]"}],
40
+ ["any_prefix.test.default", 1391832859, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832859, {\"key4\"=>\"val4\"}], [\"test.default\", 1391832859, {\"key4_\"=>\"val4_\"}]]"}],
41
+ ["any_prefix.test.default", 1391832860, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832860, {\"key5\"=>\"val5\"}], [\"test.default\", 1391832860, {\"key5_\"=>\"val5_\"}]]"}],
42
+ ["any_prefix.test.default", 1391832861, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832861, {\"key6\"=>\"val6\"}], [\"test.default\", 1391832861, {\"key6_\"=>\"val6_\"}]]"}],
43
+ ["any_prefix.test.default", 1391832862, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832862, {\"key7\"=>\"val7\"}], [\"test.default\", 1391832862, {\"key7_\"=>\"val7_\"}]]"}]]
44
+ )
45
+ end
46
+
47
+ it 'should receive multiple converted records' do
48
+ filter = <<-EOS
49
+ proc {|rs|
50
+ [
51
+ {'foo' => 'bar', 100 => 200},
52
+ {'bar' => 'baz', 200 => 300},
53
+ ]
54
+ }
55
+ EOS
56
+
57
+ emits = run_driver(:filter => filter) do |d|
58
+ (0...8).each do |i|
59
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
60
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
61
+ end
62
+ end
63
+
64
+ expect(emits).to eq(
65
+ [["filtered.test.default", 1391832855, {"foo"=>"bar", 100=>200}],
66
+ ["filtered.test.default", 1391832855, {"bar"=>"baz", 200=>300}],
67
+ ["filtered.test.default", 1391832856, {"foo"=>"bar", 100=>200}],
68
+ ["filtered.test.default", 1391832856, {"bar"=>"baz", 200=>300}],
69
+ ["filtered.test.default", 1391832857, {"foo"=>"bar", 100=>200}],
70
+ ["filtered.test.default", 1391832857, {"bar"=>"baz", 200=>300}],
71
+ ["filtered.test.default", 1391832858, {"foo"=>"bar", 100=>200}],
72
+ ["filtered.test.default", 1391832858, {"bar"=>"baz", 200=>300}],
73
+ ["filtered.test.default", 1391832859, {"foo"=>"bar", 100=>200}],
74
+ ["filtered.test.default", 1391832859, {"bar"=>"baz", 200=>300}],
75
+ ["filtered.test.default", 1391832860, {"foo"=>"bar", 100=>200}],
76
+ ["filtered.test.default", 1391832860, {"bar"=>"baz", 200=>300}],
77
+ ["filtered.test.default", 1391832861, {"foo"=>"bar", 100=>200}],
78
+ ["filtered.test.default", 1391832861, {"bar"=>"baz", 200=>300}],
79
+ ["filtered.test.default", 1391832862, {"foo"=>"bar", 100=>200}],
80
+ ["filtered.test.default", 1391832862, {"bar"=>"baz", 200=>300}]]
81
+ )
82
+ end
83
+ end
84
+
85
+ describe 'when 3 records transmitted per second' do
86
+ it 'should be aggregated to two records' do
87
+ emits = run_driver do |d|
88
+ (0...8).each do |i|
89
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
90
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
91
+ d.emit({"key#{i}__" => "val#{i}__"}, time + i)
92
+ end
93
+ end
94
+
95
+ expect(emits).to eq(
96
+ [["filtered.test.default", 1391832855, {"count"=>3, "inspect"=>"[[\"test.default\", 1391832855, {\"key0\"=>\"val0\"}], [\"test.default\", 1391832855, {\"key0_\"=>\"val0_\"}], [\"test.default\", 1391832855, {\"key0__\"=>\"val0__\"}]]"}],
97
+ ["filtered.test.default", 1391832856, {"count"=>3, "inspect"=>"[[\"test.default\", 1391832856, {\"key1\"=>\"val1\"}], [\"test.default\", 1391832856, {\"key1_\"=>\"val1_\"}], [\"test.default\", 1391832856, {\"key1__\"=>\"val1__\"}]]"}],
98
+ ["filtered.test.default", 1391832857, {"count"=>3, "inspect"=>"[[\"test.default\", 1391832857, {\"key2\"=>\"val2\"}], [\"test.default\", 1391832857, {\"key2_\"=>\"val2_\"}], [\"test.default\", 1391832857, {\"key2__\"=>\"val2__\"}]]"}],
99
+ ["filtered.test.default", 1391832858, {"count"=>3, "inspect"=>"[[\"test.default\", 1391832858, {\"key3\"=>\"val3\"}], [\"test.default\", 1391832858, {\"key3_\"=>\"val3_\"}], [\"test.default\", 1391832858, {\"key3__\"=>\"val3__\"}]]"}],
100
+ ["filtered.test.default", 1391832859, {"count"=>3, "inspect"=>"[[\"test.default\", 1391832859, {\"key4\"=>\"val4\"}], [\"test.default\", 1391832859, {\"key4_\"=>\"val4_\"}], [\"test.default\", 1391832859, {\"key4__\"=>\"val4__\"}]]"}],
101
+ ["filtered.test.default", 1391832860, {"count"=>3, "inspect"=>"[[\"test.default\", 1391832860, {\"key5\"=>\"val5\"}], [\"test.default\", 1391832860, {\"key5_\"=>\"val5_\"}], [\"test.default\", 1391832860, {\"key5__\"=>\"val5__\"}]]"}],
102
+ ["filtered.test.default", 1391832861, {"count"=>3, "inspect"=>"[[\"test.default\", 1391832861, {\"key6\"=>\"val6\"}], [\"test.default\", 1391832861, {\"key6_\"=>\"val6_\"}], [\"test.default\", 1391832861, {\"key6__\"=>\"val6__\"}]]"}],
103
+ ["filtered.test.default", 1391832862, {"count"=>3, "inspect"=>"[[\"test.default\", 1391832862, {\"key7\"=>\"val7\"}], [\"test.default\", 1391832862, {\"key7_\"=>\"val7_\"}], [\"test.default\", 1391832862, {\"key7__\"=>\"val7__\"}]]"}]]
104
+ )
105
+ end
106
+ end
107
+
108
+ describe 'when unit time 1m' do
109
+ it 'should be aggregated by every 1 min (aggregated to 2 records)' do
110
+ emits = run_driver(:time_slice_format => '%Y%m%d%H%M') do |d|
111
+ (0...8).each do |i|
112
+ i *= 20
113
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
114
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
115
+ end
116
+ end
117
+
118
+ expect(emits).to eq(
119
+ [["filtered.test.default", 1391832855, {"count"=>6, "inspect"=>"[[\"test.default\", 1391832855, {\"key0\"=>\"val0\"}], [\"test.default\", 1391832855, {\"key0_\"=>\"val0_\"}], [\"test.default\", 1391832875, {\"key20\"=>\"val20\"}], [\"test.default\", 1391832875, {\"key20_\"=>\"val20_\"}], [\"test.default\", 1391832895, {\"key40\"=>\"val40\"}], [\"test.default\", 1391832895, {\"key40_\"=>\"val40_\"}]]"}],
120
+ ["filtered.test.default", 1391832915, {"count"=>6, "inspect"=>"[[\"test.default\", 1391832915, {\"key60\"=>\"val60\"}], [\"test.default\", 1391832915, {\"key60_\"=>\"val60_\"}], [\"test.default\", 1391832935, {\"key80\"=>\"val80\"}], [\"test.default\", 1391832935, {\"key80_\"=>\"val80_\"}], [\"test.default\", 1391832955, {\"key100\"=>\"val100\"}], [\"test.default\", 1391832955, {\"key100_\"=>\"val100_\"}]]"}],
121
+ ["filtered.test.default", 1391832975, {"count"=>4, "inspect"=>"[[\"test.default\", 1391832975, {\"key120\"=>\"val120\"}], [\"test.default\", 1391832975, {\"key120_\"=>\"val120_\"}], [\"test.default\", 1391832995, {\"key140\"=>\"val140\"}], [\"test.default\", 1391832995, {\"key140_\"=>\"val140_\"}]]"}]]
122
+ )
123
+ end
124
+
125
+ it 'should be aggregated by every 1 min (aggregated to 3 records)' do
126
+ emits = run_driver(:time_slice_format => '%Y%m%d%H%M') do |d|
127
+ (0...8).each do |i|
128
+ i *= 20
129
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
130
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
131
+ d.emit({"key#{i}__" => "val#{i}__"}, time + i)
132
+ end
133
+ end
134
+
135
+ expect(emits).to eq(
136
+ [["filtered.test.default", 1391832855, {"count"=>9, "inspect"=>"[[\"test.default\", 1391832855, {\"key0\"=>\"val0\"}], [\"test.default\", 1391832855, {\"key0_\"=>\"val0_\"}], [\"test.default\", 1391832855, {\"key0__\"=>\"val0__\"}], [\"test.default\", 1391832875, {\"key20\"=>\"val20\"}], [\"test.default\", 1391832875, {\"key20_\"=>\"val20_\"}], [\"test.default\", 1391832875, {\"key20__\"=>\"val20__\"}], [\"test.default\", 1391832895, {\"key40\"=>\"val40\"}], [\"test.default\", 1391832895, {\"key40_\"=>\"val40_\"}], [\"test.default\", 1391832895, {\"key40__\"=>\"val40__\"}]]"}],
137
+ ["filtered.test.default", 1391832915, {"count"=>9, "inspect"=>"[[\"test.default\", 1391832915, {\"key60\"=>\"val60\"}], [\"test.default\", 1391832915, {\"key60_\"=>\"val60_\"}], [\"test.default\", 1391832915, {\"key60__\"=>\"val60__\"}], [\"test.default\", 1391832935, {\"key80\"=>\"val80\"}], [\"test.default\", 1391832935, {\"key80_\"=>\"val80_\"}], [\"test.default\", 1391832935, {\"key80__\"=>\"val80__\"}], [\"test.default\", 1391832955, {\"key100\"=>\"val100\"}], [\"test.default\", 1391832955, {\"key100_\"=>\"val100_\"}], [\"test.default\", 1391832955, {\"key100__\"=>\"val100__\"}]]"}],
138
+ ["filtered.test.default", 1391832975, {"count"=>6, "inspect"=>"[[\"test.default\", 1391832975, {\"key120\"=>\"val120\"}], [\"test.default\", 1391832975, {\"key120_\"=>\"val120_\"}], [\"test.default\", 1391832975, {\"key120__\"=>\"val120__\"}], [\"test.default\", 1391832995, {\"key140\"=>\"val140\"}], [\"test.default\", 1391832995, {\"key140_\"=>\"val140_\"}], [\"test.default\", 1391832995, {\"key140__\"=>\"val140__\"}]]"}]]
139
+ )
140
+ end
141
+ end
142
+
143
+ describe 'when multiple tags' do
144
+ it 'should be output only the first tag' do
145
+ emits = run_driver do |d|
146
+ (0...8).each do |i|
147
+ d.tag = 'test.1'
148
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
149
+ d.tag = 'test.2'
150
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
151
+ end
152
+ end
153
+
154
+ expect(emits).to eq(
155
+ [["filtered.test.1", 1391832855, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832855, {\"key0\"=>\"val0\"}], [\"test.2\", 1391832855, {\"key0_\"=>\"val0_\"}]]"}],
156
+ ["filtered.test.1", 1391832856, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832856, {\"key1\"=>\"val1\"}], [\"test.2\", 1391832856, {\"key1_\"=>\"val1_\"}]]"}],
157
+ ["filtered.test.1", 1391832857, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832857, {\"key2\"=>\"val2\"}], [\"test.2\", 1391832857, {\"key2_\"=>\"val2_\"}]]"}],
158
+ ["filtered.test.1", 1391832858, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832858, {\"key3\"=>\"val3\"}], [\"test.2\", 1391832858, {\"key3_\"=>\"val3_\"}]]"}],
159
+ ["filtered.test.1", 1391832859, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832859, {\"key4\"=>\"val4\"}], [\"test.2\", 1391832859, {\"key4_\"=>\"val4_\"}]]"}],
160
+ ["filtered.test.1", 1391832860, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832860, {\"key5\"=>\"val5\"}], [\"test.2\", 1391832860, {\"key5_\"=>\"val5_\"}]]"}],
161
+ ["filtered.test.1", 1391832861, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832861, {\"key6\"=>\"val6\"}], [\"test.2\", 1391832861, {\"key6_\"=>\"val6_\"}]]"}],
162
+ ["filtered.test.1", 1391832862, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832862, {\"key7\"=>\"val7\"}], [\"test.2\", 1391832862, {\"key7_\"=>\"val7_\"}]]"}]]
163
+ )
164
+ end
165
+
166
+ it 'should be output to each tag' do
167
+ emits = run_driver(:emit_each_tag => true) do |d|
168
+ (0...8).each do |i|
169
+ d.tag = 'test.1'
170
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
171
+ d.tag = 'test.2'
172
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
173
+ end
174
+ end
175
+
176
+ expect(emits).to eq(
177
+ [["filtered.test.1", 1391832855, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832855, {\"key0\"=>\"val0\"}], [\"test.2\", 1391832855, {\"key0_\"=>\"val0_\"}]]"}],
178
+ ["filtered.test.2", 1391832855, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832855, {\"key0\"=>\"val0\"}], [\"test.2\", 1391832855, {\"key0_\"=>\"val0_\"}]]"}],
179
+ ["filtered.test.1", 1391832856, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832856, {\"key1\"=>\"val1\"}], [\"test.2\", 1391832856, {\"key1_\"=>\"val1_\"}]]"}],
180
+ ["filtered.test.2", 1391832856, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832856, {\"key1\"=>\"val1\"}], [\"test.2\", 1391832856, {\"key1_\"=>\"val1_\"}]]"}],
181
+ ["filtered.test.1", 1391832857, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832857, {\"key2\"=>\"val2\"}], [\"test.2\", 1391832857, {\"key2_\"=>\"val2_\"}]]"}],
182
+ ["filtered.test.2", 1391832857, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832857, {\"key2\"=>\"val2\"}], [\"test.2\", 1391832857, {\"key2_\"=>\"val2_\"}]]"}],
183
+ ["filtered.test.1", 1391832858, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832858, {\"key3\"=>\"val3\"}], [\"test.2\", 1391832858, {\"key3_\"=>\"val3_\"}]]"}],
184
+ ["filtered.test.2", 1391832858, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832858, {\"key3\"=>\"val3\"}], [\"test.2\", 1391832858, {\"key3_\"=>\"val3_\"}]]"}],
185
+ ["filtered.test.1", 1391832859, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832859, {\"key4\"=>\"val4\"}], [\"test.2\", 1391832859, {\"key4_\"=>\"val4_\"}]]"}],
186
+ ["filtered.test.2", 1391832859, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832859, {\"key4\"=>\"val4\"}], [\"test.2\", 1391832859, {\"key4_\"=>\"val4_\"}]]"}],
187
+ ["filtered.test.1", 1391832860, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832860, {\"key5\"=>\"val5\"}], [\"test.2\", 1391832860, {\"key5_\"=>\"val5_\"}]]"}],
188
+ ["filtered.test.2", 1391832860, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832860, {\"key5\"=>\"val5\"}], [\"test.2\", 1391832860, {\"key5_\"=>\"val5_\"}]]"}],
189
+ ["filtered.test.1", 1391832861, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832861, {\"key6\"=>\"val6\"}], [\"test.2\", 1391832861, {\"key6_\"=>\"val6_\"}]]"}],
190
+ ["filtered.test.2", 1391832861, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832861, {\"key6\"=>\"val6\"}], [\"test.2\", 1391832861, {\"key6_\"=>\"val6_\"}]]"}],
191
+ ["filtered.test.1", 1391832862, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832862, {\"key7\"=>\"val7\"}], [\"test.2\", 1391832862, {\"key7_\"=>\"val7_\"}]]"}],
192
+ ["filtered.test.2", 1391832862, {"count"=>2, "inspect"=>"[[\"test.1\", 1391832862, {\"key7\"=>\"val7\"}], [\"test.2\", 1391832862, {\"key7_\"=>\"val7_\"}]]"}]]
193
+ )
194
+ end
195
+ end
196
+
197
+ describe 'when the array of Hash is passed' do
198
+ it 'should receive an array of Hash' do
199
+ emits = run_driver(:pass_hash_row => true) do |d|
200
+ (0...8).each do |i|
201
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
202
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
203
+ end
204
+ end
205
+
206
+ expect(emits).to eq(
207
+ [["filtered.test.default", 1391832855, {"count"=>2, "inspect"=>"[{\"key0\"=>\"val0\"}, {\"key0_\"=>\"val0_\"}]"}],
208
+ ["filtered.test.default", 1391832856, {"count"=>2, "inspect"=>"[{\"key1\"=>\"val1\"}, {\"key1_\"=>\"val1_\"}]"}],
209
+ ["filtered.test.default", 1391832857, {"count"=>2, "inspect"=>"[{\"key2\"=>\"val2\"}, {\"key2_\"=>\"val2_\"}]"}],
210
+ ["filtered.test.default", 1391832858, {"count"=>2, "inspect"=>"[{\"key3\"=>\"val3\"}, {\"key3_\"=>\"val3_\"}]"}],
211
+ ["filtered.test.default", 1391832859, {"count"=>2, "inspect"=>"[{\"key4\"=>\"val4\"}, {\"key4_\"=>\"val4_\"}]"}],
212
+ ["filtered.test.default", 1391832860, {"count"=>2, "inspect"=>"[{\"key5\"=>\"val5\"}, {\"key5_\"=>\"val5_\"}]"}],
213
+ ["filtered.test.default", 1391832861, {"count"=>2, "inspect"=>"[{\"key6\"=>\"val6\"}, {\"key6_\"=>\"val6_\"}]"}],
214
+ ["filtered.test.default", 1391832862, {"count"=>2, "inspect"=>"[{\"key7\"=>\"val7\"}, {\"key7_\"=>\"val7_\"}]"}]]
215
+ )
216
+ end
217
+
218
+ it 'should receive an array of Hash (include time/tag)' do
219
+ emits = run_driver(:pass_hash_row => true, :include_time_key => true, :include_tag_key => true, :utc => true) do |d|
220
+ (0...8).each do |i|
221
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
222
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
223
+ end
224
+ end
225
+
226
+ expect(emits).to eq(
227
+ [["filtered.test.default", 1391832855, {"count"=>2, "inspect"=>"[{\"key0\"=>\"val0\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:15Z\"}, {\"key0_\"=>\"val0_\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:15Z\"}]"}],
228
+ ["filtered.test.default", 1391832856, {"count"=>2, "inspect"=>"[{\"key1\"=>\"val1\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:16Z\"}, {\"key1_\"=>\"val1_\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:16Z\"}]"}],
229
+ ["filtered.test.default", 1391832857, {"count"=>2, "inspect"=>"[{\"key2\"=>\"val2\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:17Z\"}, {\"key2_\"=>\"val2_\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:17Z\"}]"}],
230
+ ["filtered.test.default", 1391832858, {"count"=>2, "inspect"=>"[{\"key3\"=>\"val3\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:18Z\"}, {\"key3_\"=>\"val3_\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:18Z\"}]"}],
231
+ ["filtered.test.default", 1391832859, {"count"=>2, "inspect"=>"[{\"key4\"=>\"val4\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:19Z\"}, {\"key4_\"=>\"val4_\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:19Z\"}]"}],
232
+ ["filtered.test.default", 1391832860, {"count"=>2, "inspect"=>"[{\"key5\"=>\"val5\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:20Z\"}, {\"key5_\"=>\"val5_\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:20Z\"}]"}],
233
+ ["filtered.test.default", 1391832861, {"count"=>2, "inspect"=>"[{\"key6\"=>\"val6\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:21Z\"}, {\"key6_\"=>\"val6_\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:21Z\"}]"}],
234
+ ["filtered.test.default", 1391832862, {"count"=>2, "inspect"=>"[{\"key7\"=>\"val7\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:22Z\"}, {\"key7_\"=>\"val7_\", \"tag\"=>\"test.default\", \"time\"=>\"2014-02-08T04:14:22Z\"}]"}]]
235
+ )
236
+ end
237
+
238
+ it 'should receive an array of Hash (include time/tag, not default key)' do
239
+ emits = run_driver(:pass_hash_row => true, :include_time_key => true, :time_key => '__TIME__', :include_tag_key => true, :tag_key => '__TAG__', :utc => true) do |d|
240
+ (0...10).each do |i|
241
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
242
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
243
+ end
244
+ end
245
+
246
+ expect(emits).to eq(
247
+ [["filtered.test.default", 1391832855, {"count"=>2, "inspect"=>"[{\"key0\"=>\"val0\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:15Z\"}, {\"key0_\"=>\"val0_\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:15Z\"}]"}],
248
+ ["filtered.test.default", 1391832856, {"count"=>2, "inspect"=>"[{\"key1\"=>\"val1\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:16Z\"}, {\"key1_\"=>\"val1_\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:16Z\"}]"}],
249
+ ["filtered.test.default", 1391832857, {"count"=>2, "inspect"=>"[{\"key2\"=>\"val2\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:17Z\"}, {\"key2_\"=>\"val2_\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:17Z\"}]"}],
250
+ ["filtered.test.default", 1391832858, {"count"=>2, "inspect"=>"[{\"key3\"=>\"val3\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:18Z\"}, {\"key3_\"=>\"val3_\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:18Z\"}]"}],
251
+ ["filtered.test.default", 1391832859, {"count"=>2, "inspect"=>"[{\"key4\"=>\"val4\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:19Z\"}, {\"key4_\"=>\"val4_\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:19Z\"}]"}],
252
+ ["filtered.test.default", 1391832860, {"count"=>2, "inspect"=>"[{\"key5\"=>\"val5\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:20Z\"}, {\"key5_\"=>\"val5_\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:20Z\"}]"}],
253
+ ["filtered.test.default", 1391832861, {"count"=>2, "inspect"=>"[{\"key6\"=>\"val6\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:21Z\"}, {\"key6_\"=>\"val6_\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:21Z\"}]"}],
254
+ ["filtered.test.default", 1391832862, {"count"=>2, "inspect"=>"[{\"key7\"=>\"val7\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:22Z\"}, {\"key7_\"=>\"val7_\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:22Z\"}]"}],
255
+ ["filtered.test.default", 1391832863, {"count"=>2, "inspect"=>"[{\"key8\"=>\"val8\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:23Z\"}, {\"key8_\"=>\"val8_\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:23Z\"}]"}],
256
+ ["filtered.test.default", 1391832864, {"count"=>2, "inspect"=>"[{\"key9\"=>\"val9\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:24Z\"}, {\"key9_\"=>\"val9_\", \"__TAG__\"=>\"test.default\", \"__TIME__\"=>\"2014-02-08T04:14:24Z\"}]"}]]
257
+ )
258
+ end
259
+ end
260
+
261
+ describe 'when an invalid record was included' do
262
+ it 'should skip the bad records (Filter returns a Hash)' do
263
+ filter = <<-EOS
264
+ proc {|rs|
265
+ if rs.any? {|i| i[2].has_key?('return_nil')}
266
+ nil
267
+ else
268
+ {
269
+ 'count' => rs.count,
270
+ 'inspect' => rs.inspect
271
+ }
272
+ end
273
+ }
274
+ EOS
275
+
276
+ emits = run_driver(:filter => filter) do |d|
277
+ d.instance.log.should_receive(:warn) {|msg| expect(msg).to eq('Record must be Hash: nil (NilClass)') }
278
+
279
+ (0...10).each do |i|
280
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
281
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
282
+ end
283
+
284
+ d.emit({"return_nil" => 1}, time + 10)
285
+
286
+ (10...20).each do |i|
287
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
288
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
289
+ end
290
+ end
291
+
292
+ expect(emits).to eq(
293
+ [["filtered.test.default", 1391832855, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832855, {\"key0\"=>\"val0\"}], [\"test.default\", 1391832855, {\"key0_\"=>\"val0_\"}]]"}],
294
+ ["filtered.test.default", 1391832856, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832856, {\"key1\"=>\"val1\"}], [\"test.default\", 1391832856, {\"key1_\"=>\"val1_\"}]]"}],
295
+ ["filtered.test.default", 1391832857, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832857, {\"key2\"=>\"val2\"}], [\"test.default\", 1391832857, {\"key2_\"=>\"val2_\"}]]"}],
296
+ ["filtered.test.default", 1391832858, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832858, {\"key3\"=>\"val3\"}], [\"test.default\", 1391832858, {\"key3_\"=>\"val3_\"}]]"}],
297
+ ["filtered.test.default", 1391832859, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832859, {\"key4\"=>\"val4\"}], [\"test.default\", 1391832859, {\"key4_\"=>\"val4_\"}]]"}],
298
+ ["filtered.test.default", 1391832860, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832860, {\"key5\"=>\"val5\"}], [\"test.default\", 1391832860, {\"key5_\"=>\"val5_\"}]]"}],
299
+ ["filtered.test.default", 1391832861, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832861, {\"key6\"=>\"val6\"}], [\"test.default\", 1391832861, {\"key6_\"=>\"val6_\"}]]"}],
300
+ ["filtered.test.default", 1391832862, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832862, {\"key7\"=>\"val7\"}], [\"test.default\", 1391832862, {\"key7_\"=>\"val7_\"}]]"}],
301
+ ["filtered.test.default", 1391832863, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832863, {\"key8\"=>\"val8\"}], [\"test.default\", 1391832863, {\"key8_\"=>\"val8_\"}]]"}],
302
+ ["filtered.test.default", 1391832864, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832864, {\"key9\"=>\"val9\"}], [\"test.default\", 1391832864, {\"key9_\"=>\"val9_\"}]]"}],
303
+ ["filtered.test.default", 1391832866, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832866, {\"key11\"=>\"val11\"}], [\"test.default\", 1391832866, {\"key11_\"=>\"val11_\"}]]"}],
304
+ ["filtered.test.default", 1391832867, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832867, {\"key12\"=>\"val12\"}], [\"test.default\", 1391832867, {\"key12_\"=>\"val12_\"}]]"}],
305
+ ["filtered.test.default", 1391832868, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832868, {\"key13\"=>\"val13\"}], [\"test.default\", 1391832868, {\"key13_\"=>\"val13_\"}]]"}],
306
+ ["filtered.test.default", 1391832869, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832869, {\"key14\"=>\"val14\"}], [\"test.default\", 1391832869, {\"key14_\"=>\"val14_\"}]]"}],
307
+ ["filtered.test.default", 1391832870, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832870, {\"key15\"=>\"val15\"}], [\"test.default\", 1391832870, {\"key15_\"=>\"val15_\"}]]"}],
308
+ ["filtered.test.default", 1391832871, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832871, {\"key16\"=>\"val16\"}], [\"test.default\", 1391832871, {\"key16_\"=>\"val16_\"}]]"}],
309
+ ["filtered.test.default", 1391832872, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832872, {\"key17\"=>\"val17\"}], [\"test.default\", 1391832872, {\"key17_\"=>\"val17_\"}]]"}],
310
+ ["filtered.test.default", 1391832873, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832873, {\"key18\"=>\"val18\"}], [\"test.default\", 1391832873, {\"key18_\"=>\"val18_\"}]]"}],
311
+ ["filtered.test.default", 1391832874, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832874, {\"key19\"=>\"val19\"}], [\"test.default\", 1391832874, {\"key19_\"=>\"val19_\"}]]"}]]
312
+ )
313
+ end
314
+
315
+ it 'should skip the bad records (Filter returns an Array)' do
316
+ filter = <<-EOS
317
+ proc {|rs|
318
+ if rs.any? {|i| i[2].has_key?('return_nil')}
319
+ [nil, 1]
320
+ else
321
+ {
322
+ 'count' => rs.count,
323
+ 'inspect' => rs.inspect
324
+ }
325
+ end
326
+ }
327
+ EOS
328
+
329
+ emits = run_driver(:filter => filter) do |d|
330
+ d.instance.log.should_receive(:warn) {|msg| expect(msg).to eq('Record must be Hash: nil (NilClass)') }
331
+ d.instance.log.should_receive(:warn) {|msg| expect(msg).to eq('Record must be Hash: 1 (Fixnum)') }
332
+
333
+ (0...10).each do |i|
334
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
335
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
336
+ end
337
+
338
+ d.emit({"return_nil" => 1}, time + 10)
339
+
340
+ (10...20).each do |i|
341
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
342
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
343
+ end
344
+ end
345
+
346
+ expect(emits).to eq(
347
+ [["filtered.test.default", 1391832855, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832855, {\"key0\"=>\"val0\"}], [\"test.default\", 1391832855, {\"key0_\"=>\"val0_\"}]]"}],
348
+ ["filtered.test.default", 1391832856, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832856, {\"key1\"=>\"val1\"}], [\"test.default\", 1391832856, {\"key1_\"=>\"val1_\"}]]"}],
349
+ ["filtered.test.default", 1391832857, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832857, {\"key2\"=>\"val2\"}], [\"test.default\", 1391832857, {\"key2_\"=>\"val2_\"}]]"}],
350
+ ["filtered.test.default", 1391832858, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832858, {\"key3\"=>\"val3\"}], [\"test.default\", 1391832858, {\"key3_\"=>\"val3_\"}]]"}],
351
+ ["filtered.test.default", 1391832859, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832859, {\"key4\"=>\"val4\"}], [\"test.default\", 1391832859, {\"key4_\"=>\"val4_\"}]]"}],
352
+ ["filtered.test.default", 1391832860, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832860, {\"key5\"=>\"val5\"}], [\"test.default\", 1391832860, {\"key5_\"=>\"val5_\"}]]"}],
353
+ ["filtered.test.default", 1391832861, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832861, {\"key6\"=>\"val6\"}], [\"test.default\", 1391832861, {\"key6_\"=>\"val6_\"}]]"}],
354
+ ["filtered.test.default", 1391832862, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832862, {\"key7\"=>\"val7\"}], [\"test.default\", 1391832862, {\"key7_\"=>\"val7_\"}]]"}],
355
+ ["filtered.test.default", 1391832863, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832863, {\"key8\"=>\"val8\"}], [\"test.default\", 1391832863, {\"key8_\"=>\"val8_\"}]]"}],
356
+ ["filtered.test.default", 1391832864, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832864, {\"key9\"=>\"val9\"}], [\"test.default\", 1391832864, {\"key9_\"=>\"val9_\"}]]"}],
357
+ ["filtered.test.default", 1391832866, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832866, {\"key11\"=>\"val11\"}], [\"test.default\", 1391832866, {\"key11_\"=>\"val11_\"}]]"}],
358
+ ["filtered.test.default", 1391832867, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832867, {\"key12\"=>\"val12\"}], [\"test.default\", 1391832867, {\"key12_\"=>\"val12_\"}]]"}],
359
+ ["filtered.test.default", 1391832868, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832868, {\"key13\"=>\"val13\"}], [\"test.default\", 1391832868, {\"key13_\"=>\"val13_\"}]]"}],
360
+ ["filtered.test.default", 1391832869, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832869, {\"key14\"=>\"val14\"}], [\"test.default\", 1391832869, {\"key14_\"=>\"val14_\"}]]"}],
361
+ ["filtered.test.default", 1391832870, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832870, {\"key15\"=>\"val15\"}], [\"test.default\", 1391832870, {\"key15_\"=>\"val15_\"}]]"}],
362
+ ["filtered.test.default", 1391832871, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832871, {\"key16\"=>\"val16\"}], [\"test.default\", 1391832871, {\"key16_\"=>\"val16_\"}]]"}],
363
+ ["filtered.test.default", 1391832872, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832872, {\"key17\"=>\"val17\"}], [\"test.default\", 1391832872, {\"key17_\"=>\"val17_\"}]]"}],
364
+ ["filtered.test.default", 1391832873, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832873, {\"key18\"=>\"val18\"}], [\"test.default\", 1391832873, {\"key18_\"=>\"val18_\"}]]"}],
365
+ ["filtered.test.default", 1391832874, {"count"=>2, "inspect"=>"[[\"test.default\", 1391832874, {\"key19\"=>\"val19\"}], [\"test.default\", 1391832874, {\"key19_\"=>\"val19_\"}]]"}]]
366
+ )
367
+ end
368
+ end
369
+
370
+ describe 'when the non-Proc filter passed' do
371
+ it 'should be filtered' do
372
+ filter = <<-EOS
373
+ class Filter
374
+ def call(records)
375
+ @total_count ||= 0
376
+ @total_count += records.count
377
+ {'total_count' => @total_count}
378
+ end
379
+ end
380
+ Filter.new
381
+ EOS
382
+
383
+ emits =run_driver(:filter => filter) do |d|
384
+ (0...8).each do |i|
385
+ d.emit({"key#{i}" => "val#{i}"}, time + i)
386
+ d.emit({"key#{i}_" => "val#{i}_"}, time + i)
387
+ end
388
+ end
389
+
390
+ expect(emits).to eq(
391
+ [["filtered.test.default", 1391832855, {"total_count"=>2}],
392
+ ["filtered.test.default", 1391832856, {"total_count"=>4}],
393
+ ["filtered.test.default", 1391832857, {"total_count"=>6}],
394
+ ["filtered.test.default", 1391832858, {"total_count"=>8}],
395
+ ["filtered.test.default", 1391832859, {"total_count"=>10}],
396
+ ["filtered.test.default", 1391832860, {"total_count"=>12}],
397
+ ["filtered.test.default", 1391832861, {"total_count"=>14}],
398
+ ["filtered.test.default", 1391832862, {"total_count"=>16}]]
399
+ )
400
+ end
401
+ end
402
+ end
@@ -0,0 +1,85 @@
1
+ require 'fluent/test'
2
+ require 'fluent/plugin/out_time_sliced_filter'
3
+ require 'tempfile'
4
+ require 'tmpdir'
5
+ require 'time'
6
+
7
+ # Disable Test::Unit
8
+ module Test::Unit::RunCount; def run(*); end; end
9
+
10
+ RSpec.configure do |config|
11
+ config.before(:all) do
12
+ Fluent::Test.setup
13
+ end
14
+ end
15
+
16
+ def tempfile(content, basename = nil)
17
+ basename ||= "#{File.basename __FILE__}.#{$$}"
18
+
19
+ Tempfile.open(basename) do |f|
20
+ f << content
21
+ f.flush
22
+ f.rewind
23
+ yield(f)
24
+ end
25
+ end
26
+
27
+ def run_driver(options = {})
28
+ options = options.dup
29
+
30
+ filter = options[:filter] || (<<-EOS)
31
+ proc {|rs|
32
+ {
33
+ 'count' => rs.count,
34
+ 'inspect' => rs.inspect
35
+ }
36
+ }
37
+ EOS
38
+
39
+ tag = options[:tag] || 'test.default'
40
+ time_slice_format = options[:time_slice_format] || '%Y%m%d%H%M%S'
41
+
42
+ option_keys = [
43
+ :prefix,
44
+ :emit_each_tag,
45
+ :pass_hash_row,
46
+ :include_time_key,
47
+ :include_tag_key,
48
+ :time_key,
49
+ :tag_key,
50
+ :utc,
51
+ ]
52
+
53
+ additional_options = option_keys.map {|key|
54
+ if options[key]
55
+ "#{key} #{options[key]}"
56
+ end
57
+ }.join("\n")
58
+
59
+ Dir.mktmpdir do |tmpdir|
60
+ tempfile(filter, options[:tempfile]) do |f|
61
+ fluentd_conf = <<-EOS
62
+ filter_path #{f.path}
63
+ buffer_path #{tmpdir}/*
64
+ time_slice_format #{time_slice_format}
65
+ #{additional_options}
66
+ EOS
67
+
68
+ driver = Fluent::Test::OutputTestDriver.new(Fluent::TimeSlicedFilterOutput, tag).configure(fluentd_conf)
69
+
70
+ driver.run do
71
+ yield(driver)
72
+
73
+ driver.instance.enqueue_buffer
74
+ buffer = driver.instance.instance_variable_get(:@buffer)
75
+
76
+ # XXX: The last one is not added to the queue...
77
+ until buffer.queue_size.zero?
78
+ driver.instance.try_flush
79
+ end
80
+ end
81
+
82
+ driver.emits
83
+ end
84
+ end
85
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-time-sliced-filter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Genki Sugawara
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.11.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: 2.11.0
69
+ description: TimeSlicedOutput Plugin to aggregate by unit time
70
+ email:
71
+ - sgwr_dts@yahoo.co.jp
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - .rspec
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - fluent-plugin-time-sliced-filter.gemspec
83
+ - lib/fluent/plugin/out_time_sliced_filter.rb
84
+ - spec/out_time_sliced_filter_spec.rb
85
+ - spec/spec_helper.rb
86
+ homepage: https://bitbucket.org/winebarrel/fluent-plugin-time-sliced-filter
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.0.14
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: TimeSlicedOutput Plugin to aggregate by unit time
110
+ test_files:
111
+ - spec/out_time_sliced_filter_spec.rb
112
+ - spec/spec_helper.rb