fluent-plugin-norikra 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/fluent-plugin-norikra.gemspec +1 -1
- data/lib/fluent/plugin/norikra/config_section.rb +5 -1
- data/lib/fluent/plugin/norikra/output.rb +1 -1
- data/lib/fluent/plugin/norikra/target.rb +10 -2
- data/test/test_config_section.rb +37 -0
- data/test/test_target.rb +13 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17d22de3fa94371d074467e259195bcf675198da
|
4
|
+
data.tar.gz: cfe8d59434ca08f513000b392e95f39af82d3b4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2138b0f8de9901ec4c5d99d49a41e8e5aa3d631dada661767306b829543810d5be9f7c8517f4c55cc3c57b4cc9b344ea3fb4a9fe9b374065eef5f21c071bec6a
|
7
|
+
data.tar.gz: c4437d0720878f816954b31b2e1e523240ce941de4cad94fd0fdc59f869bdd7dc79011604679bfa39d799b755160eb457f28eeaae0d1d6c0a8865b216a8c36e2
|
data/README.md
CHANGED
@@ -49,6 +49,7 @@ Sends events to remote Norikra server. Minimal configurations are:
|
|
49
49
|
```
|
50
50
|
|
51
51
|
NorikraOutput plugin opens Norikra's target for newly incoming tags. You can specify fields to include/exclude, and specify types of each fields, for each targets (and all targets by `default`). Definitions in `<target TARGET_NAME>` overwrites `<default>` specifications.
|
52
|
+
|
52
53
|
```apache
|
53
54
|
<match data.*>
|
54
55
|
type norikra
|
@@ -82,6 +83,7 @@ NorikraOutput plugin opens Norikra's target for newly incoming tags. You can spe
|
|
82
83
|
With default setting, all fields are defined as 'string', so you must use `field_xxxx` parameters for numerical processing in query (For more details, see Norikra and Esper's documents).
|
83
84
|
|
84
85
|
If fluentd's events has so many variations of sets of fields, you can specify not to include fields automatically, with `auto_field` option:
|
86
|
+
|
85
87
|
```apache
|
86
88
|
<match data.*>
|
87
89
|
type norikra
|
@@ -98,6 +100,8 @@ If fluentd's events has so many variations of sets of fields, you can specify no
|
|
98
100
|
|
99
101
|
Fields which are referred in queries are automatically registered on norikra server in spite of `auto_field false`.
|
100
102
|
|
103
|
+
Use `time_key FIELDNAME` to include time of Fluentd's event into data field of Norikra (by milliseconds with Norikra/Esper's rule). This is useful for queries with `.win:ext_timed_batch(FIELD, PERIOD)` views.
|
104
|
+
|
101
105
|
** NOTE: <default> and <target> sections in NorikraOutput ignores <query> sections. see NorikraFilterOutput **
|
102
106
|
|
103
107
|
## NorikraInput
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "fluent-plugin-norikra"
|
5
|
-
spec.version = "0.1.
|
5
|
+
spec.version = "0.1.2"
|
6
6
|
spec.authors = ["TAGOMORI Satoshi"]
|
7
7
|
spec.email = ["tagomoris@gmail.com"]
|
8
8
|
spec.description = %q{process events on fluentd with SQL like query, with built-in Norikra server if needed.}
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Fluent::NorikraPlugin
|
2
2
|
class ConfigSection
|
3
|
-
attr_accessor :target, :target_matcher
|
3
|
+
attr_accessor :target, :target_matcher
|
4
|
+
attr_accessor :auto_field, :time_key, :escape_fieldname
|
5
|
+
attr_accessor :filter_params, :field_definitions, :query_generators
|
4
6
|
|
5
7
|
def initialize(section, enable_auto_query=true)
|
6
8
|
@target = nil
|
@@ -16,6 +18,7 @@ module Fluent::NorikraPlugin
|
|
16
18
|
end
|
17
19
|
|
18
20
|
@auto_field = Fluent::Config.bool_value(section['auto_field'])
|
21
|
+
@time_key = section['time_key']
|
19
22
|
@escape_fieldname = Fluent::Config.bool_value(section['escape_fieldname'])
|
20
23
|
|
21
24
|
@filter_params = {
|
@@ -49,6 +52,7 @@ module Fluent::NorikraPlugin
|
|
49
52
|
end
|
50
53
|
r = self.class.new(Fluent::Config::Element.new('target', (other.target ? other.target : self.target), {}, []))
|
51
54
|
r.auto_field = (other.auto_field.nil? ? self.auto_field : other.auto_field)
|
55
|
+
r.time_key = other.time_key || self.time_key
|
52
56
|
|
53
57
|
others_filter = {}
|
54
58
|
other.filter_params.keys.each do |k|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Fluent::NorikraPlugin
|
2
2
|
class Target
|
3
|
-
attr_accessor :name, :auto_field, :fields, :queries
|
3
|
+
attr_accessor :name, :auto_field, :time_key, :fields, :queries
|
4
4
|
attr_reader :escaped_name
|
5
5
|
|
6
6
|
def self.escape(src)
|
@@ -24,15 +24,23 @@ module Fluent::NorikraPlugin
|
|
24
24
|
@name = target
|
25
25
|
@escaped_name = self.class.escape(@name)
|
26
26
|
@auto_field = config.auto_field.nil? ? true : config.auto_field
|
27
|
+
@time_key = config.time_key
|
27
28
|
@escape_fieldname = config.escape_fieldname
|
28
29
|
|
29
30
|
@filter = RecordFilter.new(*([:include, :include_regexp, :exclude, :exclude_regexp].map{|s| config.filter_params[s]}))
|
30
31
|
@fields = config.field_definitions
|
32
|
+
if @time_key
|
33
|
+
@fields[:integer].push @time_key
|
34
|
+
end
|
31
35
|
@queries = config.query_generators.map{|g| g.generate(@name, @escaped_name)}
|
32
36
|
end
|
33
37
|
|
34
|
-
def filter(record)
|
38
|
+
def filter(time, record)
|
35
39
|
r = @filter.filter(record)
|
40
|
+
if @time_key
|
41
|
+
# Fluentd time (sec) -> Norikra timestamp (milliseconds)
|
42
|
+
r = r.merge({ @time_key => time * 1000 })
|
43
|
+
end
|
36
44
|
if @escape_fieldname
|
37
45
|
escape_recursive(r)
|
38
46
|
else
|
data/test/test_config_section.rb
CHANGED
@@ -62,6 +62,38 @@ class ConfigSectionTest < Test::Unit::TestCase
|
|
62
62
|
assert_equal 0, s1.query_generators.size
|
63
63
|
end
|
64
64
|
|
65
|
+
def test_init_default_with_time_key
|
66
|
+
q1 = Fluent::Config::Element.new('query', nil, {
|
67
|
+
'name' => 'q1_${target}',
|
68
|
+
'expression' => 'SELECT * FROM ${target}.win:time_batch(10 min) WHERE q1',
|
69
|
+
'tag' => 'q1.${target}'
|
70
|
+
}, [])
|
71
|
+
q2 = Fluent::Config::Element.new('query', nil, {
|
72
|
+
'name' => 'q2_${target}',
|
73
|
+
'expression' => 'SELECT * FROM ${target}.win:time_batch(50 min) WHERE q2.length() > 0',
|
74
|
+
'tag' => 'q2.${target}'
|
75
|
+
}, [])
|
76
|
+
c1 = Fluent::Config::Element.new('default', nil, {
|
77
|
+
'time_key' => 'timestamp',
|
78
|
+
'include' => '*',
|
79
|
+
'exclude' => 'flag',
|
80
|
+
'exclude_regexp' => 'f_.*',
|
81
|
+
'field_string' => 's1,s2,s3',
|
82
|
+
'field_boolean' => 'bool1,bool2',
|
83
|
+
'field_integer' => 'i1,i2,i3,i4,num1,num2',
|
84
|
+
'field_float' => 'f1,f2,d',
|
85
|
+
}, [q1,q2])
|
86
|
+
s1 = @this.new(c1, false)
|
87
|
+
|
88
|
+
assert_nil s1.target
|
89
|
+
assert_equal({:include => '*', :include_regexp => nil, :exclude => 'flag', :exclude_regexp => 'f_.*'}, s1.filter_params)
|
90
|
+
assert_equal({
|
91
|
+
:string => %w(s1 s2 s3), :boolean => %w(bool1 bool2), :integer => %w(i1 i2 i3 i4 num1 num2),
|
92
|
+
:float => %w(f1 f2 d),
|
93
|
+
}, s1.field_definitions)
|
94
|
+
assert_equal 'timestamp', s1.time_key
|
95
|
+
end
|
96
|
+
|
65
97
|
def test_init_target
|
66
98
|
q3 = Fluent::Config::Element.new('query', nil, {
|
67
99
|
'name' => 'q3_test2',
|
@@ -131,6 +163,7 @@ class ConfigSectionTest < Test::Unit::TestCase
|
|
131
163
|
'tag' => 'q2.${target}'
|
132
164
|
}, [])
|
133
165
|
c1 = Fluent::Config::Element.new('default', nil, {
|
166
|
+
'time_key' => 'ts',
|
134
167
|
'include' => '*',
|
135
168
|
'exclude' => 'flag',
|
136
169
|
'exclude_regexp' => 'f_.*',
|
@@ -147,6 +180,7 @@ class ConfigSectionTest < Test::Unit::TestCase
|
|
147
180
|
'tag' => 'q3.test'
|
148
181
|
}, [])
|
149
182
|
c2 = Fluent::Config::Element.new('target', 'test', {
|
183
|
+
'time_key' => 'timestamp',
|
150
184
|
'exclude_regexp' => '(f|g)_.*',
|
151
185
|
'field_float' => 'd1,d2,d3,d4'
|
152
186
|
}, [q3])
|
@@ -162,6 +196,7 @@ class ConfigSectionTest < Test::Unit::TestCase
|
|
162
196
|
}, s.field_definitions)
|
163
197
|
assert_equal 3, s.query_generators.size
|
164
198
|
assert_equal (10 * 60 / 5), s.query_generators.map(&:fetch_interval).sort.first
|
199
|
+
assert_equal 'timestamp', s.time_key
|
165
200
|
end
|
166
201
|
|
167
202
|
def test_join_with_nil
|
@@ -207,6 +242,7 @@ class ConfigSectionTest < Test::Unit::TestCase
|
|
207
242
|
'tag' => 'q2.${target}'
|
208
243
|
}, [])
|
209
244
|
c1 = Fluent::Config::Element.new('default', nil, {
|
245
|
+
'time_key' => 'timestamp',
|
210
246
|
'include' => '*',
|
211
247
|
'exclude' => 'flag',
|
212
248
|
'exclude_regexp' => 'f_.*',
|
@@ -230,5 +266,6 @@ class ConfigSectionTest < Test::Unit::TestCase
|
|
230
266
|
|
231
267
|
s = s1 + s2
|
232
268
|
assert_equal 0, s.query_generators.size
|
269
|
+
assert_equal 'timestamp', s.time_key
|
233
270
|
end
|
234
271
|
end
|
data/test/test_target.rb
CHANGED
@@ -45,6 +45,7 @@ class TargetTest < Test::Unit::TestCase
|
|
45
45
|
'tag' => 'q3.test'
|
46
46
|
}, [])
|
47
47
|
C2 = Fluent::Config::Element.new('target', 'test', {
|
48
|
+
'time_key' => 'timestamp',
|
48
49
|
'exclude_regexp' => '(f|g)_.*',
|
49
50
|
'field_float' => 'd1,d2,d3,d4'
|
50
51
|
}, [Q3])
|
@@ -55,14 +56,16 @@ class TargetTest < Test::Unit::TestCase
|
|
55
56
|
|
56
57
|
assert_equal 'test', t.name
|
57
58
|
assert_equal({
|
58
|
-
:string => %w(s1 s2 s3), :boolean => %w(bool1 bool2), :integer => %w(i1 i2 i3 i4 num1 num2),
|
59
|
+
:string => %w(s1 s2 s3), :boolean => %w(bool1 bool2), :integer => %w(i1 i2 i3 i4 num1 num2 timestamp),
|
59
60
|
:float => %w(f1 f2 d d1 d2 d3 d4)
|
60
61
|
}, t.fields)
|
61
62
|
assert_equal 3, t.queries.size
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
now = Time.now.to_i
|
65
|
+
|
66
|
+
r = t.filter(now, {'x'=>1,'y'=>'y','z'=>'zett','flag'=>true,'f_x'=>'true','g_1'=>'g'})
|
67
|
+
assert_equal 4, r.size
|
68
|
+
assert_equal({'x'=>1,'y'=>'y','z'=>'zett','timestamp'=>(now*1000)}, r)
|
66
69
|
|
67
70
|
# reserve_fields
|
68
71
|
assert_equal({
|
@@ -70,7 +73,8 @@ class TargetTest < Test::Unit::TestCase
|
|
70
73
|
'bool1' => 'boolean', 'bool2' => 'boolean',
|
71
74
|
'i1' => 'integer', 'i2' => 'integer', 'i3' => 'integer', 'i4' => 'integer', 'num1' => 'integer', 'num2' => 'integer',
|
72
75
|
'f1' => 'float', 'f2' => 'float',
|
73
|
-
'd' => 'float', 'd1' => 'float', 'd2' => 'float', 'd3' => 'float', 'd4' => 'float'
|
76
|
+
'd' => 'float', 'd1' => 'float', 'd2' => 'float', 'd3' => 'float', 'd4' => 'float',
|
77
|
+
'timestamp' => 'integer', # time_key
|
74
78
|
}, t.reserve_fields)
|
75
79
|
end
|
76
80
|
|
@@ -102,8 +106,10 @@ class TargetTest < Test::Unit::TestCase
|
|
102
106
|
S4 = Fluent::NorikraPlugin::ConfigSection.new(C4)
|
103
107
|
|
104
108
|
def test_escape_fieldname
|
109
|
+
now = Time.now.to_i
|
110
|
+
|
105
111
|
t = @this.new('test.service', S3)
|
106
|
-
r = t.filter({'a 1' => '1', 'b 2' => 2, 'c-1' => { 'd/1' => '1', 'd 2' => '2' }, 'f' => [1, 2, {'g+1' => 3}] })
|
112
|
+
r = t.filter(now, {'a 1' => '1', 'b 2' => 2, 'c-1' => { 'd/1' => '1', 'd 2' => '2' }, 'f' => [1, 2, {'g+1' => 3}] })
|
107
113
|
assert_equal '1', r['a 1']
|
108
114
|
assert_equal 2, r['b 2']
|
109
115
|
assert_equal '1', r['c-1']['d/1']
|
@@ -118,7 +124,7 @@ class TargetTest < Test::Unit::TestCase
|
|
118
124
|
assert_nil r['f'][2]['g_1']
|
119
125
|
|
120
126
|
t = @this.new('test.service', S4)
|
121
|
-
r = t.filter({'a 1' => '1', 'b 2' => 2, 'c-1' => { 'd/1' => '1', 'd 2' => '2' }, 'f' => [1, 2, {'g+1' => 3}] })
|
127
|
+
r = t.filter(now, {'a 1' => '1', 'b 2' => 2, 'c-1' => { 'd/1' => '1', 'd 2' => '2' }, 'f' => [1, 2, {'g+1' => 3}] })
|
122
128
|
assert_nil r['a 1']
|
123
129
|
assert_nil r['b 2']
|
124
130
|
assert_nil r['c-1']
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-norikra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TAGOMORI Satoshi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: norikra-client
|