fluent-plugin-flatten 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +20 -13
- data/fluent-plugin-flatten.gemspec +3 -3
- data/lib/fluent/plugin/out_flatten.rb +37 -27
- data/test/plugin/test_out_flatten.rb +59 -14
- metadata +6 -4
data/README.md
CHANGED
@@ -4,17 +4,20 @@
|
|
4
4
|
|
5
5
|
### FlattenOutput
|
6
6
|
|
7
|
-
Fluentd
|
7
|
+
Fluentd plugin to extract values for nested key paths and re-emit them as flat tag/record pairs.
|
8
8
|
|
9
9
|
## Synopsis
|
10
10
|
|
11
|
-
|
11
|
+
Imagin you have a config as below:
|
12
12
|
|
13
13
|
```
|
14
14
|
<match test.**>
|
15
15
|
type flatten
|
16
|
+
|
16
17
|
key foo
|
17
|
-
add_tag_prefix
|
18
|
+
add_tag_prefix flattened.
|
19
|
+
remove_tag_prefix test.
|
20
|
+
inner_key value_for_flat_key
|
18
21
|
</match>
|
19
22
|
```
|
20
23
|
|
@@ -27,20 +30,20 @@ And you feed such a value into fluentd:
|
|
27
30
|
}
|
28
31
|
```
|
29
32
|
|
30
|
-
Then you'll get:
|
33
|
+
Then you'll get re-emmited tag/record-s below:
|
31
34
|
|
32
35
|
```
|
33
|
-
"flattened.
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
"foo.bar.qux" => "quux",
|
38
|
-
"foo.bar.hoe" => "poe",
|
39
|
-
"foo.baz" => "bazz"
|
40
|
-
}
|
36
|
+
"flattened.foo.bar.qux" => { "value_for_flat_key" => "quux" }
|
37
|
+
"flattened.foo.bar.hoe" => { "value_for_flat_key" => "poe" }
|
38
|
+
"flattened.foo.baz" => { "value_for_flat_key" => "bazz" }
|
41
39
|
```
|
42
40
|
|
43
|
-
That is
|
41
|
+
That is to say:
|
42
|
+
|
43
|
+
1. The JSON-formatted string in the value related to the key `foo` is inflated to a `Hash`.
|
44
|
+
2. The values are extracted as to be related to the nested key paths (`foo.bar.baz`).
|
45
|
+
3. This plugin re-emits them as new tag/record pairs.
|
46
|
+
4. Key/value pairs whose keys don't match `foo` are ignored (`"hoge" => "fuga"`).
|
44
47
|
|
45
48
|
## Configuration
|
46
49
|
|
@@ -55,6 +58,10 @@ These params are included from `Fluent::HandleTagNameMixin`. See that code for d
|
|
55
58
|
|
56
59
|
You must add at least one of these params.
|
57
60
|
|
61
|
+
### inner_key
|
62
|
+
|
63
|
+
This plugin sets `value` for this option as a default if it's not set.
|
64
|
+
|
58
65
|
## Installation
|
59
66
|
|
60
67
|
Add this line to your application's Gemfile:
|
@@ -1,11 +1,11 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
2
|
gem.name = 'fluent-plugin-flatten'
|
3
|
-
gem.version = '0.0.
|
3
|
+
gem.version = '0.0.3'
|
4
4
|
gem.authors = ['Kentaro Kuribayashi']
|
5
5
|
gem.email = ['kentarok@gmail.com']
|
6
6
|
gem.homepage = 'http://github.com/kentaro/fluent-plugin-flatten'
|
7
|
-
gem.description = %q{Fluentd plugin to
|
8
|
-
gem.summary = %q{Fluentd plugin to
|
7
|
+
gem.description = %q{Fluentd plugin to extract values for nested key paths and re-emit them as flat tag/record pairs.}
|
8
|
+
gem.summary = %q{Fluentd plugin to extract values for nested key paths and re-emit them as flat tag/record pairs.}
|
9
9
|
|
10
10
|
gem.files = `git ls-files`.split($\)
|
11
11
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
@@ -4,27 +4,34 @@ module Fluent
|
|
4
4
|
class FlattenOutput < Output
|
5
5
|
include Fluent::HandleTagNameMixin
|
6
6
|
class Error < StandardError; end
|
7
|
+
|
7
8
|
Fluent::Plugin.register_output('flatten', self)
|
8
9
|
|
9
|
-
config_param :key,
|
10
|
+
config_param :key, :string
|
11
|
+
config_param :inner_key, :string, :default => 'value'
|
10
12
|
|
11
13
|
def configure(conf)
|
12
14
|
super
|
13
15
|
|
14
|
-
if
|
15
|
-
|
16
|
+
if (
|
17
|
+
!remove_tag_prefix &&
|
18
|
+
!remove_tag_suffix &&
|
19
|
+
!add_tag_prefix &&
|
20
|
+
!add_tag_suffix
|
21
|
+
)
|
22
|
+
raise ConfigError, "out_flatten: At least one of remove_tag_prefix/remove_tag_suffix/add_tag_prefix/add_tag_suffix is required to be set"
|
16
23
|
end
|
17
24
|
end
|
18
25
|
|
19
26
|
def emit(tag, es, chain)
|
20
27
|
es.each do |time, record|
|
21
|
-
_tag = tag.clone
|
22
28
|
flattened = flatten(record)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
29
|
+
|
30
|
+
flattened.each do |keypath, value|
|
31
|
+
tag_with_keypath = [tag.clone, keypath].join('.')
|
32
|
+
filter_record(tag_with_keypath, time, value)
|
33
|
+
|
34
|
+
Engine.emit(tag_with_keypath, time, value)
|
28
35
|
end
|
29
36
|
end
|
30
37
|
|
@@ -32,31 +39,34 @@ module Fluent
|
|
32
39
|
end
|
33
40
|
|
34
41
|
def flatten(record)
|
35
|
-
|
36
|
-
hash = JSON.parse(record[@key])
|
37
|
-
record = record.merge(_flatten(@key, hash))
|
38
|
-
end
|
42
|
+
flattend = {}
|
39
43
|
|
40
|
-
record
|
41
|
-
|
44
|
+
if record.has_key?(key)
|
45
|
+
hash = JSON.parse(record[key])
|
46
|
+
processor = lambda do |root, hash|
|
47
|
+
unless hash.is_a?(Hash)
|
48
|
+
raise Error.new('The value to be flattened must be a Hash: #{hash}')
|
49
|
+
end
|
42
50
|
|
43
|
-
|
44
|
-
unless hash.is_a?(Hash)
|
45
|
-
raise Error.new('The value to be flattened must be a Hash: #{hash}')
|
46
|
-
end
|
51
|
+
flattened = {}
|
47
52
|
|
48
|
-
|
49
|
-
|
50
|
-
key = [root, path].join('.')
|
53
|
+
hash.each do |path, value|
|
54
|
+
keypath = [root, path].join('.')
|
51
55
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
+
if value.is_a?(Hash)
|
57
|
+
flattened = flattened.merge(processor.call(keypath, value))
|
58
|
+
else
|
59
|
+
flattened[keypath] = { inner_key => value }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
flattened
|
56
64
|
end
|
65
|
+
|
66
|
+
flattend = processor.call(key, hash)
|
57
67
|
end
|
58
68
|
|
59
|
-
|
69
|
+
flattend
|
60
70
|
end
|
61
71
|
end
|
62
72
|
end
|
@@ -5,19 +5,57 @@ class FlattenOutputTest < Test::Unit::TestCase
|
|
5
5
|
Fluent::Test.setup
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
key
|
10
|
-
add_tag_prefix
|
8
|
+
DEFAULT_CONFIG = %[
|
9
|
+
key foo
|
10
|
+
add_tag_prefix flattened.
|
11
|
+
remove_tag_prefix test.
|
11
12
|
]
|
12
13
|
|
13
|
-
def create_driver(conf =
|
14
|
+
def create_driver(conf = DEFAULT_CONFIG, tag = 'test')
|
14
15
|
Fluent::Test::OutputTestDriver.new(Fluent::FlattenOutput, tag).configure(conf)
|
15
16
|
end
|
16
17
|
|
17
18
|
def test_configure
|
19
|
+
# when `inner_key` option is not set
|
20
|
+
d1 = create_driver
|
21
|
+
|
22
|
+
assert_equal 'foo', d1.instance.key
|
23
|
+
assert_equal 'flattened.', d1.instance.add_tag_prefix
|
24
|
+
assert_equal /^test\./, d1.instance.remove_tag_prefix
|
25
|
+
assert_equal 'value', d1.instance.inner_key # default value
|
26
|
+
|
27
|
+
# when `inner_key` is set
|
28
|
+
d2 = create_driver(%[
|
29
|
+
key foo
|
30
|
+
add_tag_prefix flattened.
|
31
|
+
remove_tag_prefix test.
|
32
|
+
inner_key value_for_flat_key
|
33
|
+
])
|
34
|
+
|
35
|
+
assert_equal 'foo', d2.instance.key
|
36
|
+
assert_equal 'flattened.', d2.instance.add_tag_prefix
|
37
|
+
assert_equal /^test\./, d2.instance.remove_tag_prefix
|
38
|
+
assert_equal 'value_for_flat_key', d2.instance.inner_key
|
39
|
+
|
40
|
+
# when mandatory keys not set
|
41
|
+
assert_raise(Fluent::ConfigError) do
|
42
|
+
create_driver(%[
|
43
|
+
key foo
|
44
|
+
inner_key value_for_keypath
|
45
|
+
])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_flatten
|
18
50
|
d = create_driver
|
19
|
-
|
20
|
-
|
51
|
+
|
52
|
+
flattened = d.instance.flatten({ 'foo' => '{"bar" : "baz"}', 'hoge' => 'fuga' })
|
53
|
+
assert_equal({ 'foo.bar' => { 'value' => 'baz' } }, flattened)
|
54
|
+
|
55
|
+
# when not hash value is passed
|
56
|
+
assert_raise(Fluent::FlattenOutput::Error) do
|
57
|
+
d.instance.flatten({ 'foo' => '["bar", "baz"]' })
|
58
|
+
end
|
21
59
|
end
|
22
60
|
|
23
61
|
def test_emit
|
@@ -29,15 +67,22 @@ class FlattenOutputTest < Test::Unit::TestCase
|
|
29
67
|
end
|
30
68
|
emits = d.emits
|
31
69
|
|
32
|
-
assert_equal
|
33
|
-
|
70
|
+
assert_equal 4, emits.count
|
71
|
+
|
72
|
+
# ["flattened.foo.bar", 1354689632, {"value"=>"baz"}]
|
73
|
+
assert_equal 'flattened.foo.bar', emits[0][0]
|
74
|
+
assert_equal 'baz', emits[0][2]['value']
|
75
|
+
|
76
|
+
# ["flattened.foo.bar.qux", 1354689632, {"value"=>"quux"}]
|
77
|
+
assert_equal 'flattened.foo.bar.qux', emits[1][0]
|
78
|
+
assert_equal 'quux', emits[1][2]['value']
|
34
79
|
|
35
|
-
|
36
|
-
assert_equal '
|
37
|
-
assert_equal
|
38
|
-
assert_equal 'bazz', emits[1][2]['foo.baz']
|
80
|
+
# ["flattened.foo.bar.hoe", 1354689632, {"value"=>"poe"}]
|
81
|
+
assert_equal 'flattened.foo.bar.hoe', emits[2][0]
|
82
|
+
assert_equal 'poe', emits[2][2]['value']
|
39
83
|
|
40
|
-
|
41
|
-
assert_equal
|
84
|
+
# ["flattened.foo.bar.baz", 1354689632, {"value"=>"bazz"}]
|
85
|
+
assert_equal 'flattened.foo.baz', emits[3][0]
|
86
|
+
assert_equal 'bazz', emits[3][2]['value']
|
42
87
|
end
|
43
88
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-flatten
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -59,7 +59,8 @@ dependencies:
|
|
59
59
|
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
|
-
description: Fluentd plugin to
|
62
|
+
description: Fluentd plugin to extract values for nested key paths and re-emit them
|
63
|
+
as flat tag/record pairs.
|
63
64
|
email:
|
64
65
|
- kentarok@gmail.com
|
65
66
|
executables: []
|
@@ -98,7 +99,8 @@ rubyforge_project:
|
|
98
99
|
rubygems_version: 1.8.23
|
99
100
|
signing_key:
|
100
101
|
specification_version: 3
|
101
|
-
summary: Fluentd plugin to
|
102
|
+
summary: Fluentd plugin to extract values for nested key paths and re-emit them as
|
103
|
+
flat tag/record pairs.
|
102
104
|
test_files:
|
103
105
|
- test/plugin/test_out_flatten.rb
|
104
106
|
- test/test_helper.rb
|