fluent-plugin-record-reformer 0.1.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6cb811fb3f7274893d0f871c070fa298b0f9c138
4
- data.tar.gz: 504bb732f1e60a2bc98f80b44a78294de6770627
3
+ metadata.gz: 2166c7d160e63370e3400203a591cbb9c2de22e7
4
+ data.tar.gz: e01e518088e90bdb32e4040ed5a2fbbca5ee6bf8
5
5
  SHA512:
6
- metadata.gz: 29c43c2e9b76b18de8c5744219814a1a9ca4babfa1f332c88d84c7b1db2e89fe38a57e4f78fc6c8a320cacb4ab88542174a05728f997a913857bc0603511d0b5
7
- data.tar.gz: b6a984d357f3a1f74221284a3982265001a01338c6c3667b60d1ad1d7455270553e46345351172510c7d4d6775409daf59dda35fbd686b4bbcee80b22c903455
6
+ metadata.gz: b2e3901a0af27f800d9a81e34477409f8696b13bed9c2e47425911cd45ae0295455a5686e42969daa31a4a327c8cf779b821f0fe4a8b4625eedfe72fce58b0f9
7
+ data.tar.gz: 8812a93c884c231525b95bf29b14e5f9d4381ea0f9cece5a3109b3d7439b3cfff677c99831741d7aa7f509798bc4cea68348cbe4747a15676c45c471ff26cb62
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 0.2.0 (2014/01/15)
2
+
3
+ Enhancement:
4
+
5
+ * Support a record directive
6
+ * Add `remove_keys` option
7
+ * Add `extends` option
8
+ * Add `enable_ruby` option
9
+
1
10
  ## 0.1.1 (2013/11/21)
2
11
 
3
12
  Changes:
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # fluent-plugin-record-reformer
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/sonots/fluent-plugin-record-reformer.png?branch=master)](http://travis-ci.org/sonots/fluent-plugin-record-reformer) [![Dependency Status](https://gemnasium.com/sonots/fluent-plugin-record-reformer.png)](https://gemnasium.com/sonots/fluent-plugin-record-reformer)
3
+ [![Build Status](https://secure.travis-ci.org/sonots/fluent-plugin-record-reformer.png?branch=master)](http://travis-ci.org/sonots/fluent-plugin-record-reformer)
4
4
 
5
5
  Fluentd pluging to add or replace fields of a event record
6
6
 
@@ -16,63 +16,108 @@ Example:
16
16
 
17
17
  <match foo.**>
18
18
  type record_reformer
19
- output_tag reformed.${tag}
19
+ remove_keys remove_me
20
+ renew_record false
21
+ enable_ruby false
20
22
 
21
- hostname ${hostname}
22
- tag ${tag}
23
- time ${time.strftime('%Y-%m-%dT%H:%M:%S%z')}
24
- message ${hostname} ${tag_parts.last} ${message}
23
+ output_tag reformed.${tag}
24
+ <record>
25
+ hostname ${hostname}
26
+ input_tag ${tag}
27
+ message ${message}, ${tag_parts[-1]}
28
+ </record>
25
29
  </match>
26
30
 
27
- Assume following input is coming:
31
+ Assume following input is coming (indented):
28
32
 
29
33
  ```js
30
- foo.bar {"message":"hello world!", "foo":"bar"}
34
+ foo.bar {
35
+ "remove_me":"bar",
36
+ "foo":"bar",
37
+ "message":"Hello world!"
38
+ }
31
39
  ```
32
40
 
33
41
  then output becomes as below (indented):
34
42
 
35
43
  ```js
36
44
  reformed.foo.bar {
37
- "hostname":"your_hostname",
38
- "tag":"foo.bar",
39
- "time":"2013-05-01T01:13:14Z",
40
- "message":"your_hostname bar hello world!",
41
- "foo":"bar"
45
+ "foo":"bar",
46
+ "hostname":"YOUR_HOSTNAME",
47
+ "input_tag":"foo.bar",
48
+ "message":"Hello world!, bar",
42
49
  }
43
50
  ```
44
51
 
45
- Note that the keyword `output_tag` is reserved for the output tag. It can not be used as a record key.
52
+ ## Configuration (Classic Style)
53
+
54
+ Example:
55
+
56
+ <match foo.**>
57
+ type record_reformer
58
+ remove_keys remove_me
59
+ renew_record false
60
+ enable_ruby false
61
+ output_tag reformed.${tag}
62
+
63
+ hostname ${hostname}
64
+ input_tag ${tag}
65
+ message ${message}, ${tag_parts[-1]}
66
+ </match>
67
+
68
+ This results in same, but please note that following option parameters are reserved, so can not be used as a record key.
69
+
70
+ ## Parameters
71
+
72
+ - output_tag
73
+
74
+ The output tag name
75
+
76
+ - remove_keys
77
+
78
+ Specify record keys to be removed by a string separated by , (comma) like
79
+
80
+ remove_keys message,foo
46
81
 
47
- ### Placeholders
82
+ - renew_record *bool*
83
+
84
+ Set to `true` if you do not want to extend (or merge) the input record fields. Default is `false`.
85
+
86
+ - enable_ruby *bool*
87
+
88
+ Enable to use ruby codes in placeholders. See `Placeholders` section.
89
+ Default is `true` (just for lower version compatibility).
90
+
91
+ ## Placeholders
48
92
 
49
93
  The keys of input json are available as placeholders. In the above example,
50
94
 
51
95
  * ${foo}
52
96
  * ${message}
97
+ * ${remove_me}
53
98
 
54
99
  shall be available. In addition, following placeholders are reserved:
55
100
 
56
101
  * ${hostname} hostname
57
102
  * ${tag} input tag
58
- * ${tags} input tag splitted by '.' (obsolete. use tag_parts)
59
- * ${tag_parts} input tag splitted by '.'
60
103
  * ${time} time of the event
104
+ * ${tags[N]} input tag splitted by '.' (obsolete. use tag\_parts)
105
+ * ${tag\_parts[N]} input tag splitted by '.' indexed with N such as `${tag_parts[0]}`, `${tag_parts[-1]}`.
61
106
 
62
- It is also possible to write a ruby code in placeholders, so you may write some codes as
107
+ It is also possible to write a ruby code in placeholders if you set `enable_ruby true` option, so you may write some codes as
63
108
 
64
109
  * ${time.strftime('%Y-%m-%dT%H:%M:%S%z')}
65
- * ${tag_parts[0]}
66
- * ${tag_parts.last}
67
-
68
- ## Notice
110
+ * ${tag\_parts.last}
69
111
 
70
- Please note that this plugin enables to execute any ruby codes. Do not allow anyone to write fluentd configuration from outside of your system by security reasons.
112
+ but, please note that enabling ruby codes is not encouraged by security reasons and also in terms of the performance.
71
113
 
72
114
  ## Relatives
73
115
 
74
- I created this plugin inspired by [fluent-plugin-record-modifier](https://github.com/repeatedly/fluent-plugin-record-modifier).
75
- I chose not to send pull requests because the implementation of this plugin became completely different with it.
116
+ Following plugins look similar:
117
+
118
+ * [fluent-plugin-record-modifier](https://github.com/repeatedly/fluent-plugin-record-modifier)
119
+ * [fluent-plugin-format](https://github.com/mach/fluent-plugin-format)
120
+ * [fluent-plugin-add](https://github.com/yu-yamada/fluent-plugin-add)
76
121
 
77
122
  ## ChangeLog
78
123
 
@@ -3,7 +3,7 @@ $:.push File.expand_path('../lib', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.name = "fluent-plugin-record-reformer"
6
- gem.version = "0.1.1"
6
+ gem.version = "0.2.0"
7
7
  gem.authors = ["Naotoshi Seo"]
8
8
  gem.email = "sonots@gmail.com"
9
9
  gem.homepage = "https://github.com/sonots/fluent-plugin-record-reformer"
@@ -21,4 +21,5 @@ Gem::Specification.new do |gem|
21
21
  gem.add_development_dependency "rake"
22
22
  gem.add_development_dependency "rspec"
23
23
  gem.add_development_dependency "pry"
24
+ gem.add_development_dependency "pry-nav"
24
25
  end
@@ -13,8 +13,11 @@ module Fluent
13
13
  end
14
14
 
15
15
  config_param :output_tag, :string
16
+ config_param :remove_keys, :string, :default => nil
17
+ config_param :renew_record, :bool, :default => false
18
+ config_param :enable_ruby, :bool, :default => true # true for lower version compatibility
16
19
 
17
- BUILTIN_CONFIGURATIONS = %W(type output_tag)
20
+ BUILTIN_CONFIGURATIONS = %W(type output_tag remove_keys renew_record enable_ruby)
18
21
 
19
22
  def configure(conf)
20
23
  super
@@ -22,9 +25,34 @@ module Fluent
22
25
  @map = {}
23
26
  conf.each_pair { |k, v|
24
27
  next if BUILTIN_CONFIGURATIONS.include?(k)
25
- conf.has_key?(k)
28
+ conf.has_key?(k) # to suppress unread configuration warning
26
29
  @map[k] = v
27
30
  }
31
+ # <record></record> directive
32
+ conf.elements.select { |element| element.name == 'record' }.each { |element|
33
+ element.each_pair { |k, v|
34
+ element.has_key?(k) # to suppress unread configuration warning
35
+ @map[k] = v
36
+ }
37
+ }
38
+
39
+ if @remove_keys
40
+ @remove_keys = @remove_keys.split(',')
41
+ end
42
+
43
+ @expand_placeholder_proc =
44
+ if @enable_ruby
45
+ Proc.new {|str, record, tag, tag_parts, time| expand_ruby_placeholder(str, record, tag, tag_parts, time) }
46
+ else
47
+ Proc.new {|str, record, tag, tag_parts, time| expand_placeholder(str, record, tag, tag_parts, time) }
48
+ end
49
+
50
+ @time_proc = # hmm, want to remove ${time} placeholder ...
51
+ if @enable_ruby
52
+ Proc.new {|time| Time.at(time) }
53
+ else
54
+ Proc.new {|time| time }
55
+ end
28
56
 
29
57
  @hostname = Socket.gethostname
30
58
  end
@@ -32,23 +60,58 @@ module Fluent
32
60
  def emit(tag, es, chain)
33
61
  tag_parts = tag.split('.')
34
62
  es.each { |time, record|
35
- t_time = Time.at(time)
36
- output_tag = expand_placeholder(@output_tag, record, tag, tag_parts, t_time)
63
+ t_time = @time_proc.call(time)
64
+ output_tag = @expand_placeholder_proc.call(@output_tag, record, tag, tag_parts, t_time)
37
65
  Engine.emit(output_tag, time, replace_record(record, tag, tag_parts, t_time))
38
66
  }
39
67
  chain.next
40
68
  rescue => e
41
- $log.warn e.message
42
- $log.warn e.backtrace.join(', ')
69
+ $log.warn "record_reformer: #{e.class} #{e.message} #{e.backtrace.join(', ')}"
43
70
  end
44
71
 
45
72
  private
46
73
 
47
74
  def replace_record(record, tag, tag_parts, time)
75
+ new_record = @renew_record ? {} : record.dup
48
76
  @map.each_pair { |k, v|
49
- record[k] = expand_placeholder(v, record, tag, tag_parts, time)
77
+ new_record[k] = @expand_placeholder_proc.call(v, record, tag, tag_parts, time)
50
78
  }
51
- record
79
+ @remove_keys.each { |k| new_record.delete(k) } if @remove_keys
80
+ new_record
81
+ end
82
+
83
+ def expand_placeholder(str, record, tag, tag_parts, time)
84
+ # referenced https://github.com/fluent/fluent-plugin-rewrite-tag-filter, thanks!
85
+ placeholders = get_placeholders(record, tag, tag_parts, time)
86
+ str.gsub(/(\${[a-z_]+(\[-?[0-9]+\])?}|__[A-Z_]+__)/) do
87
+ $log.warn "record_reformer: unknown placeholder `#{$1}` found in a tag `#{tag}`" unless placeholders.include?($1)
88
+ placeholders[$1]
89
+ end
90
+ end
91
+
92
+ def get_placeholders(record, tag, tag_parts, time)
93
+ placeholders = {
94
+ '${time}' => time,
95
+ '${tag}' => tag,
96
+ '${hostname}' => @hostname,
97
+ }
98
+
99
+ size = tag_parts.size
100
+ tag_parts.each_with_index do |t, idx|
101
+ placeholders.store("${tag_parts[#{idx}]}", t)
102
+ placeholders.store("${tag_parts[#{idx-size}]}", t) # support tag_parts[-1]
103
+ end
104
+ # tags is just for old version compatibility
105
+ tag_parts.each_with_index do |t, idx|
106
+ placeholders.store("${tags[#{idx}]}", t)
107
+ placeholders.store("${tags[#{idx-size}]}", t) # support tags[-1]
108
+ end
109
+
110
+ record.each {|k, v|
111
+ placeholders.store("${#{k}}", v)
112
+ }
113
+
114
+ return placeholders
52
115
  end
53
116
 
54
117
  # Replace placeholders in a string
@@ -58,7 +121,7 @@ module Fluent
58
121
  # @param [String] tag the tag
59
122
  # @param [Array] tag_parts the tag parts (tag splitted by .)
60
123
  # @param [Time] time the time
61
- def expand_placeholder(str, record, tag, tag_parts, time)
124
+ def expand_ruby_placeholder(str, record, tag, tag_parts, time)
62
125
  struct = UndefOpenStruct.new(record)
63
126
  struct.tag = tag
64
127
  struct.tags = struct.tag_parts = tag_parts # tags is for old version compatibility
@@ -75,5 +75,106 @@ describe Fluent::RecordReformerOutput do
75
75
  end
76
76
  it { emit }
77
77
  end
78
+
79
+ context 'record directive' do
80
+ let(:config) {%[
81
+ type reformed
82
+ output_tag reformed.${tag}
83
+
84
+ <record>
85
+ hostname ${hostname}
86
+ output_tag ${tag}
87
+ time ${time.strftime('%S')}
88
+ message ${hostname} ${tag_parts.last} ${message}
89
+ </record>
90
+ ]}
91
+ before do
92
+ Fluent::Engine.stub(:now).and_return(time)
93
+ Fluent::Engine.should_receive(:emit).with("reformed.#{tag}", time.to_i, {
94
+ 'foo' => 'bar',
95
+ 'hostname' => hostname,
96
+ 'output_tag' => tag,
97
+ 'time' => time.strftime('%S'),
98
+ 'message' => "#{hostname} #{tag_parts.last} 1",
99
+ })
100
+ Fluent::Engine.should_receive(:emit).with("reformed.#{tag}", time.to_i, {
101
+ 'foo' => 'bar',
102
+ 'hostname' => hostname,
103
+ 'output_tag' => tag,
104
+ 'time' => time.strftime('%S'),
105
+ 'message' => "#{hostname} #{tag_parts.last} 2",
106
+ })
107
+ end
108
+ it { emit }
109
+ end
110
+
111
+ context 'remove_keys' do
112
+ let(:config) { CONFIG + %[remove_keys foo,message] }
113
+ before do
114
+ Fluent::Engine.stub(:now).and_return(time)
115
+ Fluent::Engine.should_receive(:emit).with("reformed.#{tag}", time.to_i, {
116
+ 'hostname' => hostname,
117
+ 'tag' => tag,
118
+ 'time' => time.strftime('%S'),
119
+ })
120
+ Fluent::Engine.should_receive(:emit).with("reformed.#{tag}", time.to_i, {
121
+ 'hostname' => hostname,
122
+ 'tag' => tag,
123
+ 'time' => time.strftime('%S'),
124
+ })
125
+ end
126
+ it { emit }
127
+ end
128
+
129
+ context 'renew_record true' do
130
+ let(:config) { CONFIG + %[renew_record true] }
131
+ before do
132
+ Fluent::Engine.stub(:now).and_return(time)
133
+ Fluent::Engine.should_receive(:emit).with("reformed.#{tag}", time.to_i, {
134
+ 'hostname' => hostname,
135
+ 'tag' => tag,
136
+ 'time' => time.strftime('%S'),
137
+ 'message' => "#{hostname} #{tag_parts.last} 1",
138
+ })
139
+ Fluent::Engine.should_receive(:emit).with("reformed.#{tag}", time.to_i, {
140
+ 'hostname' => hostname,
141
+ 'tag' => tag,
142
+ 'time' => time.strftime('%S'),
143
+ 'message' => "#{hostname} #{tag_parts.last} 2",
144
+ })
145
+ end
146
+ it { emit }
147
+ end
148
+
149
+ context 'enable_ruby no' do
150
+ let(:config) {%[
151
+ type reformed
152
+ output_tag reformed.${tag}
153
+ enable_ruby no
154
+
155
+ hostname ${hostname}
156
+ tag ${tag}
157
+ time ${time}
158
+ message ${hostname} ${tag_parts[-1]} ${message}
159
+ ]}
160
+ before do
161
+ Fluent::Engine.stub(:now).and_return(time)
162
+ Fluent::Engine.should_receive(:emit).with("reformed.#{tag}", time.to_i, {
163
+ 'foo' => 'bar',
164
+ 'hostname' => hostname,
165
+ 'tag' => tag,
166
+ 'time' => time.to_i.to_s, # hmm, want to remove ${time} placeholder
167
+ 'message' => "#{hostname} #{tag_parts.last} 1",
168
+ })
169
+ Fluent::Engine.should_receive(:emit).with("reformed.#{tag}", time.to_i, {
170
+ 'foo' => 'bar',
171
+ 'hostname' => hostname,
172
+ 'tag' => tag,
173
+ 'time' => time.to_i.to_s, # hmm, want to remove ${time} placeholder
174
+ 'message' => "#{hostname} #{tag_parts.last} 2",
175
+ })
176
+ end
177
+ it { emit }
178
+ end
78
179
  end
79
180
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-record-reformer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naotoshi Seo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-17 00:00:00.000000000 Z
11
+ date: 2014-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-nav
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: Output filter plugin for reforming each event record
70
84
  email: sonots@gmail.com
71
85
  executables: []