fluent-plugin-record-reformer 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: []