fluent-plugin-flatten 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|