fluent-plugin-record-modifier 0.3.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +7 -2
- data/ChangeLog +7 -0
- data/README.md +45 -12
- data/VERSION +1 -1
- data/fluent-plugin-record-modifier.gemspec +1 -0
- data/lib/fluent/plugin/filter_record_modifier.rb +85 -20
- data/test/test_filter_record_modifier.rb +11 -8
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ff1d6de463980c890752f4eb32719f3f160c026
|
4
|
+
data.tar.gz: 4ed772c23ab2316e1bf064a9fd3c1ed498c1aae8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2477196fe7d51f5d26546107d4b9a01907e97e3dc38a0d5a2a1a4cc8182f298d24abb996b197e3609cae7e0a534781b93f0d5bd802d7afc31c0297f2f5e31924
|
7
|
+
data.tar.gz: e0826bc7e9203ea5a6bf24f715b5b63d2b13a95c407a4d298cfd8b9f2f7c781afed10c69248774e8930b7a0f86cc1f569c75a9c2e3c00e689e3dffc4fe2f6e5d
|
data/.travis.yml
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
language: ruby
|
2
2
|
|
3
3
|
rvm:
|
4
|
-
- 1.9.3
|
5
4
|
- 2.0.0
|
6
|
-
- 2.1
|
5
|
+
- 2.1
|
6
|
+
- 2.2.3
|
7
|
+
- 2.3.0
|
7
8
|
- ruby-head
|
8
9
|
- rbx
|
9
10
|
|
@@ -11,9 +12,13 @@ branches:
|
|
11
12
|
only:
|
12
13
|
- master
|
13
14
|
|
15
|
+
gemfile:
|
16
|
+
- Gemfile
|
17
|
+
|
14
18
|
matrix:
|
15
19
|
allow_failures:
|
16
20
|
- rvm: ruby-head
|
17
21
|
- rvm: rbx
|
18
22
|
|
23
|
+
before_install: gem update bundler
|
19
24
|
script: bundle exec rake test
|
data/ChangeLog
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# Filter plugin for modifying each event record for [Fluentd](http://fluentd.org)
|
2
2
|
|
3
3
|
Adding arbitary field to event record without custmizing existence plugin.
|
4
4
|
|
@@ -13,13 +13,16 @@ Use RubyGems:
|
|
13
13
|
|
14
14
|
## Configuration
|
15
15
|
|
16
|
-
|
17
|
-
type record_modifier
|
18
|
-
tag foo.filtered
|
16
|
+
Use `record_modifier` filter.
|
19
17
|
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
<filter pattern>
|
19
|
+
@type record_modifier
|
20
|
+
|
21
|
+
<record>
|
22
|
+
gen_host ${hostname}
|
23
|
+
foo bar
|
24
|
+
</record>
|
25
|
+
</filter>
|
23
26
|
|
24
27
|
If following record is passed:
|
25
28
|
|
@@ -33,6 +36,37 @@ then you got new record like below:
|
|
33
36
|
{"message":"hello world!", "gen_host":"oreore-mac.local", "foo":"bar"}
|
34
37
|
```
|
35
38
|
|
39
|
+
You can also use `record_transformer` like `${xxx}` placeholders and access `tag`, `time`, `record` and `tag_parts` values by Ruby code.
|
40
|
+
|
41
|
+
<filter pattern>
|
42
|
+
@type record_modifier
|
43
|
+
|
44
|
+
<record>
|
45
|
+
tag ${tag}
|
46
|
+
tag_extract ${tag_parts[0]}-${tag_pars[1]}-foo
|
47
|
+
formatted_time ${Time.at(time).to_s}
|
48
|
+
new_field foo:${record['key1'] + record['dict']['key']}
|
49
|
+
</record>
|
50
|
+
</filter>
|
51
|
+
|
52
|
+
`record_modifier` is faster than `record_transformer`. See [this comment](https://github.com/repeatedly/fluent-plugin-record-modifier/pull/7#issuecomment-169843012).
|
53
|
+
But unlike `record_transformer`, `record_modifier` doesn't support following features for now.
|
54
|
+
|
55
|
+
- tag_suffix and tag_prefix
|
56
|
+
- dynamic key placeholder
|
57
|
+
|
58
|
+
### record_modifier output
|
59
|
+
|
60
|
+
In v0.10, you can use `record_modifier` output to emulate filter. `record_modifier` output doesn't support `<record>` way.
|
61
|
+
|
62
|
+
<match pattern>
|
63
|
+
type record_modifier
|
64
|
+
tag foo.filtered
|
65
|
+
|
66
|
+
gen_host ${hostname}
|
67
|
+
foo bar
|
68
|
+
</match>
|
69
|
+
|
36
70
|
### char_encoding
|
37
71
|
|
38
72
|
Fluentd including some plugins treats the logs as a BINARY by default to forward.
|
@@ -41,7 +75,7 @@ But an user sometimes processes the logs depends on their requirements, e.g. han
|
|
41
75
|
`char_encoding` parameter is useful for this case.
|
42
76
|
|
43
77
|
```conf
|
44
|
-
<
|
78
|
+
<filter pattern>
|
45
79
|
type record_modifier
|
46
80
|
|
47
81
|
# set UTF-8 encoding information to string.
|
@@ -49,7 +83,7 @@ But an user sometimes processes the logs depends on their requirements, e.g. han
|
|
49
83
|
|
50
84
|
# change char encoding from 'UTF-8' to 'EUC-JP'
|
51
85
|
char_encoding utf-8:euc-jp
|
52
|
-
</
|
86
|
+
</filter>
|
53
87
|
```
|
54
88
|
|
55
89
|
### remove_keys
|
@@ -58,12 +92,12 @@ The logs include needless record keys in some cases.
|
|
58
92
|
You can remove it by using `remove_keys` parameter.
|
59
93
|
|
60
94
|
```conf
|
61
|
-
<
|
95
|
+
<filter pattern>
|
62
96
|
type record_modifier
|
63
97
|
|
64
98
|
# remove key1 and key2 keys from record
|
65
99
|
remove_keys key1,key2
|
66
|
-
</
|
100
|
+
</filter>
|
67
101
|
```
|
68
102
|
|
69
103
|
If following record is passed:
|
@@ -80,7 +114,6 @@ then you got new record like below:
|
|
80
114
|
|
81
115
|
### Mixins
|
82
116
|
|
83
|
-
* [SetTagKeyMixin](https://github.com/fluent/fluentd/blob/master/lib/fluent/mixin.rb#L181)
|
84
117
|
* [fluent-mixin-config-placeholders](https://github.com/tagomoris/fluent-mixin-config-placeholders)
|
85
118
|
|
86
119
|
## TODO
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
@@ -20,4 +20,5 @@ Gem::Specification.new do |gem|
|
|
20
20
|
gem.add_dependency "fluentd", [">= 0.10.58", "< 2"]
|
21
21
|
gem.add_dependency "fluent-mixin-config-placeholders", ">= 0.3.0"
|
22
22
|
gem.add_development_dependency "rake", ">= 0.9.2"
|
23
|
+
gem.add_development_dependency("test-unit", ["~> 3.1.4"])
|
23
24
|
end
|
@@ -7,19 +7,23 @@ module Fluent
|
|
7
7
|
config_param :char_encoding, :string, :default => nil
|
8
8
|
config_param :remove_keys, :string, :default => nil
|
9
9
|
|
10
|
-
include SetTagKeyMixin
|
11
10
|
include Fluent::Mixin::ConfigPlaceholders
|
12
11
|
|
13
|
-
BUILTIN_CONFIGURATIONS = %W(type @type log_level @log_level id @id
|
12
|
+
BUILTIN_CONFIGURATIONS = %W(type @type log_level @log_level id @id char_encoding remove_keys)
|
14
13
|
|
15
14
|
def configure(conf)
|
16
15
|
super
|
17
16
|
|
17
|
+
if conf.has_key?('include_tag_key')
|
18
|
+
raise ConfigError, "include_tag_key and tag_key parameters are removed. Use 'tag ${tag}' in <record> section"
|
19
|
+
end
|
20
|
+
|
18
21
|
@map = {}
|
19
22
|
conf.each_pair { |k, v|
|
20
23
|
unless BUILTIN_CONFIGURATIONS.include?(k)
|
21
24
|
conf.has_key?(k)
|
22
|
-
|
25
|
+
$log.warn "top level definition is deprecated. Please put parameters inside <record>: '#{k} #{v}'"
|
26
|
+
@map[k] = DynamicExpander.new(k, v)
|
23
27
|
end
|
24
28
|
}
|
25
29
|
|
@@ -39,33 +43,46 @@ module Fluent
|
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
46
|
+
@has_tag_parts = false
|
47
|
+
conf.elements.select { |element| element.name == 'record' }.each do |element|
|
48
|
+
element.each_pair do |k, v|
|
49
|
+
element.has_key?(k) # to suppress unread configuration warning
|
50
|
+
@has_tag_parts = true if v.include?('tag_parts')
|
51
|
+
@map[k] = DynamicExpander.new(k, v)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
42
55
|
if @remove_keys
|
43
|
-
@remove_keys = @remove_keys.split(',').map {|e| e.strip }
|
56
|
+
@remove_keys = @remove_keys.split(',').map { |e| e.strip }
|
44
57
|
end
|
45
|
-
end
|
46
58
|
|
47
|
-
|
48
|
-
|
49
|
-
modify_record(record)
|
59
|
+
# Collect DynamicExpander related garbage instructions
|
60
|
+
GC.start
|
50
61
|
end
|
51
62
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
@map.each_pair { |k, v|
|
56
|
-
record[k] = v
|
57
|
-
}
|
63
|
+
def filter_stream(tag, es)
|
64
|
+
new_es = MultiEventStream.new
|
65
|
+
tag_parts = @has_tag_parts ? tag.split('.') : nil
|
58
66
|
|
59
|
-
|
60
|
-
@
|
61
|
-
record.
|
67
|
+
es.each { |time, record|
|
68
|
+
@map.each_pair { |k, v|
|
69
|
+
record[k] = v.expand(tag, time, record, tag_parts)
|
62
70
|
}
|
63
|
-
end
|
64
71
|
|
65
|
-
|
66
|
-
|
72
|
+
if @remove_keys
|
73
|
+
@remove_keys.each { |v|
|
74
|
+
record.delete(v)
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
record = change_encoding(record) if @char_encoding
|
79
|
+
new_es.add(time, record)
|
80
|
+
}
|
81
|
+
new_es
|
67
82
|
end
|
68
83
|
|
84
|
+
private
|
85
|
+
|
69
86
|
def set_encoding(record)
|
70
87
|
record.each_pair { |k, v|
|
71
88
|
if v.is_a?(String)
|
@@ -82,5 +99,53 @@ module Fluent
|
|
82
99
|
end
|
83
100
|
}
|
84
101
|
end
|
102
|
+
|
103
|
+
class DynamicExpander
|
104
|
+
def initialize(param_key, param_value)
|
105
|
+
if param_value.include?('${')
|
106
|
+
__str_eval_code__ = parse_parameter(param_value)
|
107
|
+
|
108
|
+
# Use class_eval with string instead of define_method for performance.
|
109
|
+
# It can't share instructions but this is 2x+ faster than define_method in filter case.
|
110
|
+
# Refer: http://tenderlovemaking.com/2013/03/03/dynamic_method_definitions.html
|
111
|
+
(class << self; self; end).class_eval <<-EORUBY, __FILE__, __LINE__ + 1
|
112
|
+
def expand(tag, time, record, tag_parts)
|
113
|
+
#{__str_eval_code__}
|
114
|
+
end
|
115
|
+
EORUBY
|
116
|
+
else
|
117
|
+
@param_value = param_value
|
118
|
+
end
|
119
|
+
|
120
|
+
begin
|
121
|
+
# check eval genarates wrong code or not
|
122
|
+
expand(nil, nil, nil, nil)
|
123
|
+
rescue SyntaxError
|
124
|
+
raise ConfigError, "Pass invalid syntax parameter : key = #{param_key}, value = #{param_value}"
|
125
|
+
rescue
|
126
|
+
# Ignore other runtime errors
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Default implementation for fixed value. This is overwritten when parameter contains '${xxx}' placeholder
|
131
|
+
def expand(tag, time, record, tag_parts)
|
132
|
+
@param_value
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def parse_parameter(value)
|
138
|
+
num_placeholders = value.scan('${').size
|
139
|
+
if num_placeholders == 1
|
140
|
+
if value.start_with?('${') && value.end_with?('}')
|
141
|
+
return value[2..-2]
|
142
|
+
else
|
143
|
+
"\"#{value.gsub('${', '#{')}\""
|
144
|
+
end
|
145
|
+
else
|
146
|
+
"\"#{value.gsub('${', '#{')}\""
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
85
150
|
end if defined?(Filter)
|
86
151
|
end
|
@@ -12,12 +12,14 @@ class RecordModifierFilterTest < Test::Unit::TestCase
|
|
12
12
|
|
13
13
|
CONFIG = %[
|
14
14
|
type record_modifier
|
15
|
-
|
16
|
-
gen_host ${hostname}
|
17
|
-
foo bar
|
18
|
-
include_tag_key
|
19
|
-
tag_key included_tag
|
20
15
|
remove_keys hoge
|
16
|
+
|
17
|
+
<record>
|
18
|
+
gen_host ${hostname}
|
19
|
+
foo bar
|
20
|
+
included_tag ${tag}
|
21
|
+
tag_wrap -${tag_parts[0]}-${tag_parts[1]}-
|
22
|
+
</record>
|
21
23
|
]
|
22
24
|
|
23
25
|
def create_driver(conf = CONFIG)
|
@@ -33,8 +35,9 @@ class RecordModifierFilterTest < Test::Unit::TestCase
|
|
33
35
|
d = create_driver
|
34
36
|
map = d.instance.instance_variable_get(:@map)
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
+
map.each_pair { |k, v|
|
39
|
+
assert v.is_a?(Fluent::RecordModifierFilter::DynamicExpander)
|
40
|
+
}
|
38
41
|
end
|
39
42
|
|
40
43
|
def test_format
|
@@ -45,7 +48,7 @@ class RecordModifierFilterTest < Test::Unit::TestCase
|
|
45
48
|
d.emit("a" => 2)
|
46
49
|
end
|
47
50
|
|
48
|
-
mapped = {'gen_host' => get_hostname, 'foo' => 'bar', 'included_tag' => @tag}
|
51
|
+
mapped = {'gen_host' => get_hostname, 'foo' => 'bar', 'included_tag' => @tag, 'tag_wrap' => "-#{@tag.split('.')[0]}-#{@tag.split('.')[1]}-"}
|
49
52
|
assert_equal [
|
50
53
|
{"a" => 1}.merge(mapped),
|
51
54
|
{"a" => 2}.merge(mapped),
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-record-modifier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masahiro Nakagawa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -58,6 +58,20 @@ dependencies:
|
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: 0.9.2
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: test-unit
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 3.1.4
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 3.1.4
|
61
75
|
description: Output filter plugin for modifying each event record
|
62
76
|
email: repeatedly@gmail.com
|
63
77
|
executables: []
|