fluent-plugin-record-reformer 0.8.3 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/CHANGELOG.md +6 -0
- data/README.md +8 -2
- data/fluent-plugin-record-reformer.gemspec +1 -1
- data/lib/fluent/plugin/out_record_reformer.rb +6 -355
- data/lib/fluent/plugin/out_record_reformer/core.rb +345 -0
- data/lib/fluent/plugin/out_record_reformer/v12.rb +32 -0
- data/lib/fluent/plugin/out_record_reformer/v14.rb +22 -0
- data/test/helper.rb +45 -0
- data/test/test_out_record_reformer.rb +20 -24
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 224873397bd762ffdf8b4256c727f0d274c0f39b
|
4
|
+
data.tar.gz: 3c2f1c849c49d690c1e583ac03ecd3817ba670ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8dbc917cf34ea266ec33e4a39c59e87536856bf43af2ea1889714b71eb3d1145dc03f45789d7af99b6c89f9d36b581fd171ca94188c1afe25d19bcf3153464a
|
7
|
+
data.tar.gz: 9c47cd0a33f18d0b3f62ecc43077df7c1a2710aca5e110d39225a4c2a66e89823826ba3685f9f444f921098897fb67c1b71941575d3580d578e0817f9c4ee9ae
|
data/.travis.yml
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
rvm:
|
2
|
-
- 2.0.*
|
3
2
|
- 2.1.*
|
4
3
|
- 2.2.*
|
5
4
|
- 2.3.0
|
5
|
+
- 2.4.0
|
6
6
|
gemfile:
|
7
7
|
- Gemfile
|
8
8
|
- Gemfile.fluentd.0.12
|
9
9
|
- Gemfile.fluentd.0.10
|
10
10
|
matrix:
|
11
11
|
exclude:
|
12
|
-
- rvm: 2.0
|
13
|
-
gemfile: Gemfile
|
12
|
+
- rvm: 2.4.0
|
13
|
+
gemfile: Gemfile.fluentd.0.10
|
14
14
|
before_install: gem update bundler
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -4,6 +4,12 @@
|
|
4
4
|
|
5
5
|
Fluentd plugin to add or replace fields of a event record
|
6
6
|
|
7
|
+
## Requirements
|
8
|
+
|
9
|
+
See [.travis.yml](.travis.yml)
|
10
|
+
|
11
|
+
Note that `fluent-plugin-record-reformer` supports both v0.14 API and v0.12 API in one gem.
|
12
|
+
|
7
13
|
## Installation
|
8
14
|
|
9
15
|
Use RubyGems:
|
@@ -25,7 +31,7 @@ Example:
|
|
25
31
|
hostname ${hostname}
|
26
32
|
input_tag ${tag}
|
27
33
|
last_tag ${tag_parts[-1]}
|
28
|
-
message ${message}, yay!
|
34
|
+
message ${record['message']}, yay!
|
29
35
|
</record>
|
30
36
|
</match>
|
31
37
|
|
@@ -65,7 +71,7 @@ Example:
|
|
65
71
|
hostname ${hostname}
|
66
72
|
input_tag ${tag}
|
67
73
|
last_tag ${tag_parts[-1]}
|
68
|
-
message ${message}, yay!
|
74
|
+
message ${record['message']}, yay!
|
69
75
|
</match>
|
70
76
|
|
71
77
|
This results in same, but please note that following option parameters are reserved, so can not be used as a record key.
|
@@ -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.
|
6
|
+
gem.version = "0.9.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"
|
@@ -1,356 +1,7 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
require 'socket'
|
9
|
-
super
|
10
|
-
end
|
11
|
-
|
12
|
-
config_param :output_tag, :string, :default => nil, # obsolete
|
13
|
-
:desc => 'The output tag name. This option is deprecated. Use `tag` option instead.'
|
14
|
-
config_param :tag, :string, :default => nil,
|
15
|
-
:desc => 'The output tag name.'
|
16
|
-
config_param :remove_keys, :string, :default => nil,
|
17
|
-
:desc => 'Specify record keys to be removed by a string separated by , (comma).'
|
18
|
-
config_param :keep_keys, :string, :default => nil,
|
19
|
-
:desc => 'Specify record keys to be kept by a string separated by , (comma).'
|
20
|
-
config_param :renew_record, :bool, :default => false,
|
21
|
-
:desc => 'Creates an output record newly without extending (merging) the input record fields.'
|
22
|
-
config_param :renew_time_key, :string, :default => nil,
|
23
|
-
:desc => 'Overwrites the time of events with a value of the record field.'
|
24
|
-
config_param :enable_ruby, :bool, :default => true, # true for lower version compatibility
|
25
|
-
:desc => 'Enable to use ruby codes in placeholders.'
|
26
|
-
config_param :auto_typecast, :bool, :default => false, # false for lower version compatibility
|
27
|
-
:desc => 'Automatically cast the field types.'
|
28
|
-
|
29
|
-
BUILTIN_CONFIGURATIONS = %W(@id @type @label type tag output_tag remove_keys renew_record keep_keys enable_ruby renew_time_key auto_typecast)
|
30
|
-
|
31
|
-
# To support log_level option implemented by Fluentd v0.10.43
|
32
|
-
unless method_defined?(:log)
|
33
|
-
define_method("log") { $log }
|
34
|
-
end
|
35
|
-
|
36
|
-
# Define `router` method of v0.12 to support v0.10 or earlier
|
37
|
-
unless method_defined?(:router)
|
38
|
-
define_method("router") { Fluent::Engine }
|
39
|
-
end
|
40
|
-
|
41
|
-
def configure(conf)
|
42
|
-
super
|
43
|
-
|
44
|
-
map = {}
|
45
|
-
conf.each_pair { |k, v|
|
46
|
-
next if BUILTIN_CONFIGURATIONS.include?(k)
|
47
|
-
conf.has_key?(k) # to suppress unread configuration warning
|
48
|
-
map[k] = parse_value(v)
|
49
|
-
}
|
50
|
-
# <record></record> directive
|
51
|
-
conf.elements.select { |element| element.name == 'record' }.each { |element|
|
52
|
-
element.each_pair { |k, v|
|
53
|
-
element.has_key?(k) # to suppress unread configuration warning
|
54
|
-
map[k] = parse_value(v)
|
55
|
-
}
|
56
|
-
}
|
57
|
-
|
58
|
-
if @remove_keys
|
59
|
-
@remove_keys = @remove_keys.split(',')
|
60
|
-
end
|
61
|
-
|
62
|
-
if @keep_keys
|
63
|
-
raise Fluent::ConfigError, "out_record_reformer: `renew_record` must be true to use `keep_keys`" unless @renew_record
|
64
|
-
@keep_keys = @keep_keys.split(',')
|
65
|
-
end
|
66
|
-
|
67
|
-
if @output_tag and @tag.nil? # for lower version compatibility
|
68
|
-
log.warn "out_record_reformer: `output_tag` is deprecated. Use `tag` option instead."
|
69
|
-
@tag = @output_tag
|
70
|
-
end
|
71
|
-
if @tag.nil?
|
72
|
-
raise Fluent::ConfigError, "out_record_reformer: `tag` must be specified"
|
73
|
-
end
|
74
|
-
|
75
|
-
placeholder_expander_params = {
|
76
|
-
:log => log,
|
77
|
-
:auto_typecast => @auto_typecast,
|
78
|
-
}
|
79
|
-
@placeholder_expander =
|
80
|
-
if @enable_ruby
|
81
|
-
# require utilities which would be used in ruby placeholders
|
82
|
-
require 'pathname'
|
83
|
-
require 'uri'
|
84
|
-
require 'cgi'
|
85
|
-
RubyPlaceholderExpander.new(placeholder_expander_params)
|
86
|
-
else
|
87
|
-
PlaceholderExpander.new(placeholder_expander_params)
|
88
|
-
end
|
89
|
-
@map = @placeholder_expander.preprocess_map(map)
|
90
|
-
@tag = @placeholder_expander.preprocess_map(@tag)
|
91
|
-
|
92
|
-
@hostname = Socket.gethostname
|
93
|
-
end
|
94
|
-
|
95
|
-
def emit(tag, es, chain)
|
96
|
-
tag_parts = tag.split('.')
|
97
|
-
tag_prefix = tag_prefix(tag_parts)
|
98
|
-
tag_suffix = tag_suffix(tag_parts)
|
99
|
-
placeholder_values = {
|
100
|
-
'tag' => tag,
|
101
|
-
'tags' => tag_parts, # for old version compatibility
|
102
|
-
'tag_parts' => tag_parts,
|
103
|
-
'tag_prefix' => tag_prefix,
|
104
|
-
'tag_suffix' => tag_suffix,
|
105
|
-
'hostname' => @hostname,
|
106
|
-
}
|
107
|
-
last_record = nil
|
108
|
-
es.each {|time, record|
|
109
|
-
last_record = record # for debug log
|
110
|
-
placeholder_values.merge!({
|
111
|
-
'time' => @placeholder_expander.time_value(time),
|
112
|
-
'record' => record,
|
113
|
-
})
|
114
|
-
new_tag, new_record = reform(@tag, record, placeholder_values)
|
115
|
-
if new_tag
|
116
|
-
if @renew_time_key && new_record.has_key?(@renew_time_key)
|
117
|
-
time = new_record[@renew_time_key].to_i
|
118
|
-
end
|
119
|
-
@remove_keys.each {|k| new_record.delete(k) } if @remove_keys
|
120
|
-
router.emit(new_tag, time, new_record)
|
121
|
-
end
|
122
|
-
}
|
123
|
-
chain.next
|
124
|
-
rescue => e
|
125
|
-
log.warn "record_reformer: #{e.class} #{e.message} #{e.backtrace.first}"
|
126
|
-
log.debug "record_reformer: tag:#{@tag} map:#{@map} record:#{last_record} placeholder_values:#{placeholder_values}"
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
def parse_value(value_str)
|
132
|
-
if value_str.start_with?('{', '[')
|
133
|
-
JSON.parse(value_str)
|
134
|
-
else
|
135
|
-
value_str
|
136
|
-
end
|
137
|
-
rescue => e
|
138
|
-
log.warn "failed to parse #{value_str} as json. Assuming #{value_str} is a string", :error_class => e.class, :error => e.message
|
139
|
-
value_str # emit as string
|
140
|
-
end
|
141
|
-
|
142
|
-
def reform(tag, record, placeholder_values)
|
143
|
-
placeholders = @placeholder_expander.prepare_placeholders(placeholder_values)
|
144
|
-
|
145
|
-
new_tag = expand_placeholders(tag, placeholders)
|
146
|
-
|
147
|
-
new_record = @renew_record ? {} : record.dup
|
148
|
-
@keep_keys.each {|k| new_record[k] = record[k]} if @keep_keys and @renew_record
|
149
|
-
new_record.merge!(expand_placeholders(@map, placeholders))
|
150
|
-
|
151
|
-
[new_tag, new_record]
|
152
|
-
end
|
153
|
-
|
154
|
-
def expand_placeholders(value, placeholders)
|
155
|
-
if value.is_a?(String)
|
156
|
-
new_value = @placeholder_expander.expand(value, placeholders)
|
157
|
-
elsif value.is_a?(Hash)
|
158
|
-
new_value = {}
|
159
|
-
value.each_pair do |k, v|
|
160
|
-
new_key = @placeholder_expander.expand(k, placeholders, true)
|
161
|
-
new_value[new_key] = expand_placeholders(v, placeholders)
|
162
|
-
end
|
163
|
-
elsif value.is_a?(Array)
|
164
|
-
new_value = []
|
165
|
-
value.each_with_index do |v, i|
|
166
|
-
new_value[i] = expand_placeholders(v, placeholders)
|
167
|
-
end
|
168
|
-
else
|
169
|
-
new_value = value
|
170
|
-
end
|
171
|
-
new_value
|
172
|
-
end
|
173
|
-
|
174
|
-
def tag_prefix(tag_parts)
|
175
|
-
return [] if tag_parts.empty?
|
176
|
-
tag_prefix = [tag_parts.first]
|
177
|
-
1.upto(tag_parts.size-1).each do |i|
|
178
|
-
tag_prefix[i] = "#{tag_prefix[i-1]}.#{tag_parts[i]}"
|
179
|
-
end
|
180
|
-
tag_prefix
|
181
|
-
end
|
182
|
-
|
183
|
-
def tag_suffix(tag_parts)
|
184
|
-
return [] if tag_parts.empty?
|
185
|
-
rev_tag_parts = tag_parts.reverse
|
186
|
-
rev_tag_suffix = [rev_tag_parts.first]
|
187
|
-
1.upto(tag_parts.size-1).each do |i|
|
188
|
-
rev_tag_suffix[i] = "#{rev_tag_parts[i]}.#{rev_tag_suffix[i-1]}"
|
189
|
-
end
|
190
|
-
rev_tag_suffix.reverse!
|
191
|
-
end
|
192
|
-
|
193
|
-
# THIS CLASS MUST BE THREAD-SAFE
|
194
|
-
class PlaceholderExpander
|
195
|
-
attr_reader :placeholders, :log
|
196
|
-
|
197
|
-
def initialize(params)
|
198
|
-
@log = params[:log]
|
199
|
-
@auto_typecast = params[:auto_typecast]
|
200
|
-
end
|
201
|
-
|
202
|
-
def time_value(time)
|
203
|
-
Time.at(time).to_s
|
204
|
-
end
|
205
|
-
|
206
|
-
def preprocess_map(value, force_stringify = false)
|
207
|
-
value
|
208
|
-
end
|
209
|
-
|
210
|
-
def prepare_placeholders(placeholder_values)
|
211
|
-
placeholders = {}
|
212
|
-
|
213
|
-
placeholder_values.each do |key, value|
|
214
|
-
if value.kind_of?(Array) # tag_parts, etc
|
215
|
-
size = value.size
|
216
|
-
value.each_with_index do |v, idx|
|
217
|
-
placeholders.store("${#{key}[#{idx}]}", v)
|
218
|
-
placeholders.store("${#{key}[#{idx-size}]}", v) # support [-1]
|
219
|
-
end
|
220
|
-
elsif value.kind_of?(Hash) # record, etc
|
221
|
-
value.each do |k, v|
|
222
|
-
unless placeholder_values.has_key?(k) # prevent overwriting the reserved keys such as tag
|
223
|
-
placeholders.store("${#{k}}", v)
|
224
|
-
end
|
225
|
-
placeholders.store(%Q[${#{key}["#{k}"]}], v) # record["foo"]
|
226
|
-
end
|
227
|
-
else # string, interger, float, and others?
|
228
|
-
placeholders.store("${#{key}}", value)
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
placeholders
|
233
|
-
end
|
234
|
-
|
235
|
-
# Expand string with placeholders
|
236
|
-
#
|
237
|
-
# @param [String] str
|
238
|
-
# @param [Boolean] force_stringify the value must be string, used for hash key
|
239
|
-
def expand(str, placeholders, force_stringify = false)
|
240
|
-
if @auto_typecast and !force_stringify
|
241
|
-
single_placeholder_matched = str.match(/\A(\${[^}]+}|__[A-Z_]+__)\z/)
|
242
|
-
if single_placeholder_matched
|
243
|
-
log_if_unknown_placeholder($1, placeholders)
|
244
|
-
return placeholders[single_placeholder_matched[1]]
|
245
|
-
end
|
246
|
-
end
|
247
|
-
str.gsub(/(\${[^}]+}|__[A-Z_]+__)/) {
|
248
|
-
log_if_unknown_placeholder($1, placeholders)
|
249
|
-
placeholders[$1]
|
250
|
-
}
|
251
|
-
end
|
252
|
-
|
253
|
-
private
|
254
|
-
|
255
|
-
def log_if_unknown_placeholder(placeholder, placeholders)
|
256
|
-
unless placeholders.include?(placeholder)
|
257
|
-
log.warn "record_reformer: unknown placeholder `#{placeholder}` found"
|
258
|
-
end
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
# THIS CLASS MUST BE THREAD-SAFE
|
263
|
-
class RubyPlaceholderExpander
|
264
|
-
attr_reader :log
|
265
|
-
|
266
|
-
def initialize(params)
|
267
|
-
@log = params[:log]
|
268
|
-
@auto_typecast = params[:auto_typecast]
|
269
|
-
@cleanroom_expander = CleanroomExpander.new
|
270
|
-
end
|
271
|
-
|
272
|
-
def time_value(time)
|
273
|
-
Time.at(time)
|
274
|
-
end
|
275
|
-
|
276
|
-
# Preprocess record map to convert into ruby string expansion
|
277
|
-
#
|
278
|
-
# @param [Hash|String|Array] value record map config
|
279
|
-
# @param [Boolean] force_stringify the value must be string, used for hash key
|
280
|
-
def preprocess_map(value, force_stringify = false)
|
281
|
-
new_value = nil
|
282
|
-
if value.is_a?(String)
|
283
|
-
if @auto_typecast and !force_stringify
|
284
|
-
num_placeholders = value.scan('${').size
|
285
|
-
if num_placeholders == 1 and value.start_with?('${') && value.end_with?('}')
|
286
|
-
new_value = value[2..-2] # ${..} => ..
|
287
|
-
end
|
288
|
-
end
|
289
|
-
unless new_value
|
290
|
-
new_value = "%Q[#{value.gsub('${', '#{')}]" # xx${..}xx => %Q[xx#{..}xx]
|
291
|
-
end
|
292
|
-
elsif value.is_a?(Hash)
|
293
|
-
new_value = {}
|
294
|
-
value.each_pair do |k, v|
|
295
|
-
new_value[preprocess_map(k, true)] = preprocess_map(v)
|
296
|
-
end
|
297
|
-
elsif value.is_a?(Array)
|
298
|
-
new_value = []
|
299
|
-
value.each_with_index do |v, i|
|
300
|
-
new_value[i] = preprocess_map(v)
|
301
|
-
end
|
302
|
-
else
|
303
|
-
new_value = value
|
304
|
-
end
|
305
|
-
new_value
|
306
|
-
end
|
307
|
-
|
308
|
-
def prepare_placeholders(placeholder_values)
|
309
|
-
placeholder_values
|
310
|
-
end
|
311
|
-
|
312
|
-
# Expand string with placeholders
|
313
|
-
#
|
314
|
-
# @param [String] str
|
315
|
-
def expand(str, placeholders, force_stringify = false)
|
316
|
-
@cleanroom_expander.expand(
|
317
|
-
str,
|
318
|
-
placeholders['tag'],
|
319
|
-
placeholders['time'],
|
320
|
-
placeholders['record'],
|
321
|
-
placeholders['tag_parts'],
|
322
|
-
placeholders['tag_prefix'],
|
323
|
-
placeholders['tag_suffix'],
|
324
|
-
placeholders['hostname'],
|
325
|
-
)
|
326
|
-
rescue => e
|
327
|
-
log.warn "record_reformer: failed to expand `#{str}`", :error_class => e.class, :error => e.message
|
328
|
-
log.warn_backtrace
|
329
|
-
nil
|
330
|
-
end
|
331
|
-
|
332
|
-
class CleanroomExpander
|
333
|
-
def expand(__str_to_eval__, tag, time, record, tag_parts, tag_prefix, tag_suffix, hostname)
|
334
|
-
tags = tag_parts # for old version compatibility
|
335
|
-
Thread.current[:record_reformer_record] = record # for old version compatibility
|
336
|
-
instance_eval(__str_to_eval__)
|
337
|
-
end
|
338
|
-
|
339
|
-
# for old version compatibility
|
340
|
-
def method_missing(name)
|
341
|
-
key = name.to_s
|
342
|
-
record = Thread.current[:record_reformer_record]
|
343
|
-
if record.has_key?(key)
|
344
|
-
record[key]
|
345
|
-
else
|
346
|
-
raise NameError, "undefined local variable or method `#{key}'"
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
(Object.instance_methods).each do |m|
|
351
|
-
undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
|
352
|
-
end
|
353
|
-
end
|
354
|
-
end
|
355
|
-
end
|
1
|
+
require 'fluent/version'
|
2
|
+
major, minor, patch = Fluent::VERSION.split('.').map(&:to_i)
|
3
|
+
if major > 0 || (major == 0 && minor >= 14)
|
4
|
+
require_relative 'out_record_reformer/v14'
|
5
|
+
else
|
6
|
+
require_relative 'out_record_reformer/v12'
|
356
7
|
end
|
@@ -0,0 +1,345 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
module Fluent
|
5
|
+
module RecordReformerOutputCore
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.included(klass)
|
11
|
+
klass.config_param :output_tag, :string, :default => nil, # obsolete
|
12
|
+
:desc => 'The output tag name. This option is deprecated. Use `tag` option instead.'
|
13
|
+
klass.config_param :tag, :string, :default => nil,
|
14
|
+
:desc => 'The output tag name.'
|
15
|
+
klass.config_param :remove_keys, :string, :default => nil,
|
16
|
+
:desc => 'Specify record keys to be removed by a string separated by , (comma).'
|
17
|
+
klass.config_param :keep_keys, :string, :default => nil,
|
18
|
+
:desc => 'Specify record keys to be kept by a string separated by , (comma).'
|
19
|
+
klass.config_param :renew_record, :bool, :default => false,
|
20
|
+
:desc => 'Creates an output record newly without extending (merging) the input record fields.'
|
21
|
+
klass.config_param :renew_time_key, :string, :default => nil,
|
22
|
+
:desc => 'Overwrites the time of events with a value of the record field.'
|
23
|
+
klass.config_param :enable_ruby, :bool, :default => true, # true for lower version compatibility
|
24
|
+
:desc => 'Enable to use ruby codes in placeholders.'
|
25
|
+
klass.config_param :auto_typecast, :bool, :default => false, # false for lower version compatibility
|
26
|
+
:desc => 'Automatically cast the field types.'
|
27
|
+
end
|
28
|
+
|
29
|
+
BUILTIN_CONFIGURATIONS = %W(@id @type @label type tag output_tag remove_keys renew_record keep_keys enable_ruby renew_time_key auto_typecast)
|
30
|
+
|
31
|
+
def configure(conf)
|
32
|
+
super
|
33
|
+
|
34
|
+
map = {}
|
35
|
+
conf.each_pair { |k, v|
|
36
|
+
next if BUILTIN_CONFIGURATIONS.include?(k)
|
37
|
+
conf.has_key?(k) # to suppress unread configuration warning
|
38
|
+
map[k] = parse_value(v)
|
39
|
+
}
|
40
|
+
# <record></record> directive
|
41
|
+
conf.elements.select { |element| element.name == 'record' }.each { |element|
|
42
|
+
element.each_pair { |k, v|
|
43
|
+
element.has_key?(k) # to suppress unread configuration warning
|
44
|
+
map[k] = parse_value(v)
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
if @remove_keys
|
49
|
+
@remove_keys = @remove_keys.split(',')
|
50
|
+
end
|
51
|
+
|
52
|
+
if @keep_keys
|
53
|
+
raise Fluent::ConfigError, "out_record_reformer: `renew_record` must be true to use `keep_keys`" unless @renew_record
|
54
|
+
@keep_keys = @keep_keys.split(',')
|
55
|
+
end
|
56
|
+
|
57
|
+
if @output_tag and @tag.nil? # for lower version compatibility
|
58
|
+
log.warn "out_record_reformer: `output_tag` is deprecated. Use `tag` option instead."
|
59
|
+
@tag = @output_tag
|
60
|
+
end
|
61
|
+
if @tag.nil?
|
62
|
+
raise Fluent::ConfigError, "out_record_reformer: `tag` must be specified"
|
63
|
+
end
|
64
|
+
|
65
|
+
placeholder_expander_params = {
|
66
|
+
:log => log,
|
67
|
+
:auto_typecast => @auto_typecast,
|
68
|
+
}
|
69
|
+
@placeholder_expander =
|
70
|
+
if @enable_ruby
|
71
|
+
# require utilities which would be used in ruby placeholders
|
72
|
+
require 'pathname'
|
73
|
+
require 'uri'
|
74
|
+
require 'cgi'
|
75
|
+
RubyPlaceholderExpander.new(placeholder_expander_params)
|
76
|
+
else
|
77
|
+
PlaceholderExpander.new(placeholder_expander_params)
|
78
|
+
end
|
79
|
+
@map = @placeholder_expander.preprocess_map(map)
|
80
|
+
@tag = @placeholder_expander.preprocess_map(@tag)
|
81
|
+
|
82
|
+
@hostname = Socket.gethostname
|
83
|
+
end
|
84
|
+
|
85
|
+
def process(tag, es)
|
86
|
+
tag_parts = tag.split('.')
|
87
|
+
tag_prefix = tag_prefix(tag_parts)
|
88
|
+
tag_suffix = tag_suffix(tag_parts)
|
89
|
+
placeholder_values = {
|
90
|
+
'tag' => tag,
|
91
|
+
'tags' => tag_parts, # for old version compatibility
|
92
|
+
'tag_parts' => tag_parts,
|
93
|
+
'tag_prefix' => tag_prefix,
|
94
|
+
'tag_suffix' => tag_suffix,
|
95
|
+
'hostname' => @hostname,
|
96
|
+
}
|
97
|
+
last_record = nil
|
98
|
+
es.each {|time, record|
|
99
|
+
last_record = record # for debug log
|
100
|
+
placeholder_values.merge!({
|
101
|
+
'time' => @placeholder_expander.time_value(time),
|
102
|
+
'record' => record,
|
103
|
+
})
|
104
|
+
new_tag, new_record = reform(@tag, record, placeholder_values)
|
105
|
+
if new_tag
|
106
|
+
if @renew_time_key && new_record.has_key?(@renew_time_key)
|
107
|
+
time = new_record[@renew_time_key].to_i
|
108
|
+
end
|
109
|
+
@remove_keys.each {|k| new_record.delete(k) } if @remove_keys
|
110
|
+
router.emit(new_tag, time, new_record)
|
111
|
+
end
|
112
|
+
}
|
113
|
+
rescue => e
|
114
|
+
log.warn "record_reformer: #{e.class} #{e.message} #{e.backtrace.first}"
|
115
|
+
log.debug "record_reformer: tag:#{@tag} map:#{@map} record:#{last_record} placeholder_values:#{placeholder_values}"
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def parse_value(value_str)
|
121
|
+
if value_str.start_with?('{', '[')
|
122
|
+
JSON.parse(value_str)
|
123
|
+
else
|
124
|
+
value_str
|
125
|
+
end
|
126
|
+
rescue => e
|
127
|
+
log.warn "failed to parse #{value_str} as json. Assuming #{value_str} is a string", :error_class => e.class, :error => e.message
|
128
|
+
value_str # emit as string
|
129
|
+
end
|
130
|
+
|
131
|
+
def reform(tag, record, placeholder_values)
|
132
|
+
placeholders = @placeholder_expander.prepare_placeholders(placeholder_values)
|
133
|
+
|
134
|
+
new_tag = expand_placeholders(tag, placeholders)
|
135
|
+
|
136
|
+
new_record = @renew_record ? {} : record.dup
|
137
|
+
@keep_keys.each {|k| new_record[k] = record[k]} if @keep_keys and @renew_record
|
138
|
+
new_record.merge!(expand_placeholders(@map, placeholders))
|
139
|
+
|
140
|
+
[new_tag, new_record]
|
141
|
+
end
|
142
|
+
|
143
|
+
def expand_placeholders(value, placeholders)
|
144
|
+
if value.is_a?(String)
|
145
|
+
new_value = @placeholder_expander.expand(value, placeholders)
|
146
|
+
elsif value.is_a?(Hash)
|
147
|
+
new_value = {}
|
148
|
+
value.each_pair do |k, v|
|
149
|
+
new_key = @placeholder_expander.expand(k, placeholders, true)
|
150
|
+
new_value[new_key] = expand_placeholders(v, placeholders)
|
151
|
+
end
|
152
|
+
elsif value.is_a?(Array)
|
153
|
+
new_value = []
|
154
|
+
value.each_with_index do |v, i|
|
155
|
+
new_value[i] = expand_placeholders(v, placeholders)
|
156
|
+
end
|
157
|
+
else
|
158
|
+
new_value = value
|
159
|
+
end
|
160
|
+
new_value
|
161
|
+
end
|
162
|
+
|
163
|
+
def tag_prefix(tag_parts)
|
164
|
+
return [] if tag_parts.empty?
|
165
|
+
tag_prefix = [tag_parts.first]
|
166
|
+
1.upto(tag_parts.size-1).each do |i|
|
167
|
+
tag_prefix[i] = "#{tag_prefix[i-1]}.#{tag_parts[i]}"
|
168
|
+
end
|
169
|
+
tag_prefix
|
170
|
+
end
|
171
|
+
|
172
|
+
def tag_suffix(tag_parts)
|
173
|
+
return [] if tag_parts.empty?
|
174
|
+
rev_tag_parts = tag_parts.reverse
|
175
|
+
rev_tag_suffix = [rev_tag_parts.first]
|
176
|
+
1.upto(tag_parts.size-1).each do |i|
|
177
|
+
rev_tag_suffix[i] = "#{rev_tag_parts[i]}.#{rev_tag_suffix[i-1]}"
|
178
|
+
end
|
179
|
+
rev_tag_suffix.reverse!
|
180
|
+
end
|
181
|
+
|
182
|
+
# THIS CLASS MUST BE THREAD-SAFE
|
183
|
+
class PlaceholderExpander
|
184
|
+
attr_reader :placeholders, :log
|
185
|
+
|
186
|
+
def initialize(params)
|
187
|
+
@log = params[:log]
|
188
|
+
@auto_typecast = params[:auto_typecast]
|
189
|
+
end
|
190
|
+
|
191
|
+
def time_value(time)
|
192
|
+
Time.at(time).to_s
|
193
|
+
end
|
194
|
+
|
195
|
+
def preprocess_map(value, force_stringify = false)
|
196
|
+
value
|
197
|
+
end
|
198
|
+
|
199
|
+
def prepare_placeholders(placeholder_values)
|
200
|
+
placeholders = {}
|
201
|
+
|
202
|
+
placeholder_values.each do |key, value|
|
203
|
+
if value.kind_of?(Array) # tag_parts, etc
|
204
|
+
size = value.size
|
205
|
+
value.each_with_index do |v, idx|
|
206
|
+
placeholders.store("${#{key}[#{idx}]}", v)
|
207
|
+
placeholders.store("${#{key}[#{idx-size}]}", v) # support [-1]
|
208
|
+
end
|
209
|
+
elsif value.kind_of?(Hash) # record, etc
|
210
|
+
value.each do |k, v|
|
211
|
+
unless placeholder_values.has_key?(k) # prevent overwriting the reserved keys such as tag
|
212
|
+
placeholders.store("${#{k}}", v)
|
213
|
+
end
|
214
|
+
placeholders.store(%Q[${#{key}["#{k}"]}], v) # record["foo"]
|
215
|
+
end
|
216
|
+
else # string, interger, float, and others?
|
217
|
+
placeholders.store("${#{key}}", value)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
placeholders
|
222
|
+
end
|
223
|
+
|
224
|
+
# Expand string with placeholders
|
225
|
+
#
|
226
|
+
# @param [String] str
|
227
|
+
# @param [Boolean] force_stringify the value must be string, used for hash key
|
228
|
+
def expand(str, placeholders, force_stringify = false)
|
229
|
+
if @auto_typecast and !force_stringify
|
230
|
+
single_placeholder_matched = str.match(/\A(\${[^}]+}|__[A-Z_]+__)\z/)
|
231
|
+
if single_placeholder_matched
|
232
|
+
log_if_unknown_placeholder($1, placeholders)
|
233
|
+
return placeholders[single_placeholder_matched[1]]
|
234
|
+
end
|
235
|
+
end
|
236
|
+
str.gsub(/(\${[^}]+}|__[A-Z_]+__)/) {
|
237
|
+
log_if_unknown_placeholder($1, placeholders)
|
238
|
+
placeholders[$1]
|
239
|
+
}
|
240
|
+
end
|
241
|
+
|
242
|
+
private
|
243
|
+
|
244
|
+
def log_if_unknown_placeholder(placeholder, placeholders)
|
245
|
+
unless placeholders.include?(placeholder)
|
246
|
+
log.warn "record_reformer: unknown placeholder `#{placeholder}` found"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# THIS CLASS MUST BE THREAD-SAFE
|
252
|
+
class RubyPlaceholderExpander
|
253
|
+
attr_reader :log
|
254
|
+
|
255
|
+
def initialize(params)
|
256
|
+
@log = params[:log]
|
257
|
+
@auto_typecast = params[:auto_typecast]
|
258
|
+
@cleanroom_expander = CleanroomExpander.new
|
259
|
+
end
|
260
|
+
|
261
|
+
def time_value(time)
|
262
|
+
Time.at(time)
|
263
|
+
end
|
264
|
+
|
265
|
+
# Preprocess record map to convert into ruby string expansion
|
266
|
+
#
|
267
|
+
# @param [Hash|String|Array] value record map config
|
268
|
+
# @param [Boolean] force_stringify the value must be string, used for hash key
|
269
|
+
def preprocess_map(value, force_stringify = false)
|
270
|
+
new_value = nil
|
271
|
+
if value.is_a?(String)
|
272
|
+
if @auto_typecast and !force_stringify
|
273
|
+
num_placeholders = value.scan('${').size
|
274
|
+
if num_placeholders == 1 and value.start_with?('${') && value.end_with?('}')
|
275
|
+
new_value = value[2..-2] # ${..} => ..
|
276
|
+
end
|
277
|
+
end
|
278
|
+
unless new_value
|
279
|
+
new_value = "%Q[#{value.gsub('${', '#{')}]" # xx${..}xx => %Q[xx#{..}xx]
|
280
|
+
end
|
281
|
+
elsif value.is_a?(Hash)
|
282
|
+
new_value = {}
|
283
|
+
value.each_pair do |k, v|
|
284
|
+
new_value[preprocess_map(k, true)] = preprocess_map(v)
|
285
|
+
end
|
286
|
+
elsif value.is_a?(Array)
|
287
|
+
new_value = []
|
288
|
+
value.each_with_index do |v, i|
|
289
|
+
new_value[i] = preprocess_map(v)
|
290
|
+
end
|
291
|
+
else
|
292
|
+
new_value = value
|
293
|
+
end
|
294
|
+
new_value
|
295
|
+
end
|
296
|
+
|
297
|
+
def prepare_placeholders(placeholder_values)
|
298
|
+
placeholder_values
|
299
|
+
end
|
300
|
+
|
301
|
+
# Expand string with placeholders
|
302
|
+
#
|
303
|
+
# @param [String] str
|
304
|
+
def expand(str, placeholders, force_stringify = false)
|
305
|
+
@cleanroom_expander.expand(
|
306
|
+
str,
|
307
|
+
placeholders['tag'],
|
308
|
+
placeholders['time'],
|
309
|
+
placeholders['record'],
|
310
|
+
placeholders['tag_parts'],
|
311
|
+
placeholders['tag_prefix'],
|
312
|
+
placeholders['tag_suffix'],
|
313
|
+
placeholders['hostname'],
|
314
|
+
)
|
315
|
+
rescue => e
|
316
|
+
log.warn "record_reformer: failed to expand `#{str}`", :error_class => e.class, :error => e.message
|
317
|
+
log.warn_backtrace
|
318
|
+
nil
|
319
|
+
end
|
320
|
+
|
321
|
+
class CleanroomExpander
|
322
|
+
def expand(__str_to_eval__, tag, time, record, tag_parts, tag_prefix, tag_suffix, hostname)
|
323
|
+
tags = tag_parts # for old version compatibility
|
324
|
+
Thread.current[:record_reformer_record] = record # for old version compatibility
|
325
|
+
instance_eval(__str_to_eval__)
|
326
|
+
end
|
327
|
+
|
328
|
+
# for old version compatibility
|
329
|
+
def method_missing(name)
|
330
|
+
key = name.to_s
|
331
|
+
record = Thread.current[:record_reformer_record]
|
332
|
+
if record.has_key?(key)
|
333
|
+
record[key]
|
334
|
+
else
|
335
|
+
raise NameError, "undefined local variable or method `#{key}'"
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
(Object.instance_methods).each do |m|
|
340
|
+
undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'core'
|
2
|
+
|
3
|
+
module Fluent
|
4
|
+
class RecordReformerOutput < Output
|
5
|
+
Fluent::Plugin.register_output('record_reformer', self)
|
6
|
+
|
7
|
+
include ::Fluent::RecordReformerOutputCore
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
# To support log_level option implemented by Fluentd v0.10.43
|
14
|
+
unless method_defined?(:log)
|
15
|
+
define_method("log") { $log }
|
16
|
+
end
|
17
|
+
|
18
|
+
# Define `router` method of v0.12 to support v0.10 or earlier
|
19
|
+
unless method_defined?(:router)
|
20
|
+
define_method("router") { Fluent::Engine }
|
21
|
+
end
|
22
|
+
|
23
|
+
def configure(conf)
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def emit(tag, es, chain)
|
28
|
+
process(tag, es)
|
29
|
+
chain.next
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'core'
|
2
|
+
|
3
|
+
module Fluent
|
4
|
+
class Plugin::RecordReformerOutput < Plugin::Output
|
5
|
+
Fluent::Plugin.register_output('record_reformer', self)
|
6
|
+
|
7
|
+
helpers :event_emitter
|
8
|
+
include ::Fluent::RecordReformerOutputCore
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def configure(conf)
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def process(tag, es)
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/test/helper.rb
CHANGED
@@ -28,3 +28,48 @@ module Fluent
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
require 'fluent/version'
|
33
|
+
major, minor, patch = Fluent::VERSION.split('.').map(&:to_i)
|
34
|
+
if major > 0 || (major == 0 && minor >= 14)
|
35
|
+
require 'fluent/test/driver/output'
|
36
|
+
require 'fluent/test/helpers'
|
37
|
+
include Fluent::Test::Helpers
|
38
|
+
|
39
|
+
# I do not want to use Fluent::Test::OutputTestDriver, but
|
40
|
+
# want to have a test driver whose interface is compatible with of v0.12
|
41
|
+
class RecordReformerOutputTestDriver < Fluent::Test::Driver::Output
|
42
|
+
def initialize(klass, tag)
|
43
|
+
super(klass)
|
44
|
+
@tag = tag
|
45
|
+
end
|
46
|
+
|
47
|
+
def configure(conf, use_v1)
|
48
|
+
super(conf, syntax: use_v1 ? :v1 : :v0)
|
49
|
+
end
|
50
|
+
|
51
|
+
def run(&block)
|
52
|
+
super(default_tag: @tag, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
def emit(record, time)
|
56
|
+
feed(time, record)
|
57
|
+
end
|
58
|
+
|
59
|
+
def emits
|
60
|
+
events
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_driver(conf, use_v1)
|
65
|
+
RecordReformerOutputTestDriver.new(Fluent::Plugin::RecordReformerOutput, @tag).configure(conf, use_v1)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
def event_time(str)
|
69
|
+
Time.parse(str)
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_driver(conf, use_v1)
|
73
|
+
Fluent::Test::OutputTestDriver.new(Fluent::RecordReformerOutput, @tag).configure(conf, use_v1)
|
74
|
+
end
|
75
|
+
end
|
@@ -5,22 +5,6 @@ require 'fluent/plugin/out_record_reformer'
|
|
5
5
|
Fluent::Test.setup
|
6
6
|
|
7
7
|
class RecordReformerOutputTest < Test::Unit::TestCase
|
8
|
-
setup do
|
9
|
-
@hostname = Socket.gethostname.chomp
|
10
|
-
@tag = 'test.tag'
|
11
|
-
@tag_parts = @tag.split('.')
|
12
|
-
@time = Time.local(1,2,3,4,5,2010,nil,nil,nil,nil)
|
13
|
-
Timecop.freeze(@time)
|
14
|
-
end
|
15
|
-
|
16
|
-
teardown do
|
17
|
-
Timecop.return
|
18
|
-
end
|
19
|
-
|
20
|
-
def create_driver(conf, use_v1)
|
21
|
-
Fluent::Test::OutputTestDriver.new(Fluent::RecordReformerOutput, @tag).configure(conf, use_v1)
|
22
|
-
end
|
23
|
-
|
24
8
|
def emit(config, use_v1, msgs = [''])
|
25
9
|
d = create_driver(config, use_v1)
|
26
10
|
d.run do
|
@@ -37,6 +21,18 @@ class RecordReformerOutputTest < Test::Unit::TestCase
|
|
37
21
|
d.emits
|
38
22
|
end
|
39
23
|
|
24
|
+
setup do
|
25
|
+
@hostname = Socket.gethostname.chomp
|
26
|
+
@tag = 'test.tag'
|
27
|
+
@tag_parts = @tag.split('.')
|
28
|
+
@time = event_time("2010-05-04 03:02:01")
|
29
|
+
Timecop.freeze(@time)
|
30
|
+
end
|
31
|
+
|
32
|
+
teardown do
|
33
|
+
Timecop.return
|
34
|
+
end
|
35
|
+
|
40
36
|
CONFIG = %[
|
41
37
|
tag reformed.${tag}
|
42
38
|
|
@@ -77,7 +73,7 @@ class RecordReformerOutputTest < Test::Unit::TestCase
|
|
77
73
|
assert_equal('bar', record['eventType0'])
|
78
74
|
assert_equal(@hostname, record['hostname'])
|
79
75
|
assert_equal(@tag, record['input_tag'])
|
80
|
-
assert_equal(@time.to_s, record['time'])
|
76
|
+
assert_equal(Time.at(@time).localtime.to_s, record['time'])
|
81
77
|
assert_equal("#{@hostname} #{@tag_parts[-1]} #{msgs[i]}", record['message'])
|
82
78
|
end
|
83
79
|
end
|
@@ -109,7 +105,7 @@ class RecordReformerOutputTest < Test::Unit::TestCase
|
|
109
105
|
assert_equal('bar', record['eventType0'])
|
110
106
|
assert_equal(@hostname, record['hostname'])
|
111
107
|
assert_equal(@tag, record['tag'])
|
112
|
-
assert_equal(@time.to_s, record['time'])
|
108
|
+
assert_equal(Time.at(@time).localtime.to_s, record['time'])
|
113
109
|
assert_equal("#{@hostname} #{@tag_parts[-1]} #{msgs[i]}", record['message'])
|
114
110
|
end
|
115
111
|
end
|
@@ -122,7 +118,7 @@ class RecordReformerOutputTest < Test::Unit::TestCase
|
|
122
118
|
assert_not_include(record, 'eventType0')
|
123
119
|
assert_equal(@hostname, record['hostname'])
|
124
120
|
assert_equal(@tag, record['input_tag'])
|
125
|
-
assert_equal(@time.to_s, record['time'])
|
121
|
+
assert_equal(Time.at(@time).localtime.to_s, record['time'])
|
126
122
|
assert_not_include(record, 'message')
|
127
123
|
end
|
128
124
|
end
|
@@ -136,13 +132,13 @@ class RecordReformerOutputTest < Test::Unit::TestCase
|
|
136
132
|
assert_not_include(record, 'eventType0')
|
137
133
|
assert_equal(@hostname, record['hostname'])
|
138
134
|
assert_equal(@tag, record['input_tag'])
|
139
|
-
assert_equal(@time.to_s, record['time'])
|
135
|
+
assert_equal(Time.at(@time).localtime.to_s, record['time'])
|
140
136
|
assert_equal("#{@hostname} #{@tag_parts[-1]} #{msgs[i]}", record['message'])
|
141
137
|
end
|
142
138
|
end
|
143
139
|
|
144
140
|
test 'renew_time_key' do
|
145
|
-
times = [ Time.
|
141
|
+
times = [ Time.at(event_time("2010-05-04 03:02:02")), Time.at(event_time("2010-05-04 03:02:03")) ]
|
146
142
|
config = <<EOC
|
147
143
|
tag reformed.${tag}
|
148
144
|
enable_ruby true
|
@@ -170,7 +166,7 @@ EOC
|
|
170
166
|
event_time_key ${Time.parse(record["message"]).to_i}
|
171
167
|
</record>
|
172
168
|
EOC
|
173
|
-
times = [ Time.
|
169
|
+
times = [ Time.at(event_time("2010-05-04 03:02:02")), Time.at(event_time("2010-05-04 03:02:03")) ]
|
174
170
|
msgs = times.map{|t| t.to_s }
|
175
171
|
emits = emit(config, use_v1, msgs)
|
176
172
|
emits.each_with_index do |(tag, time, record), i|
|
@@ -295,7 +291,7 @@ EOC
|
|
295
291
|
]
|
296
292
|
emits = emit(config, use_v1)
|
297
293
|
emits.each do |(tag, time, record)|
|
298
|
-
assert_equal(
|
294
|
+
assert_equal(Time.at(time).localtime.to_s, record['message'])
|
299
295
|
end
|
300
296
|
end
|
301
297
|
|
@@ -335,7 +331,7 @@ EOC
|
|
335
331
|
assert_not_equal('tag', record['new_tag'])
|
336
332
|
assert_equal(@tag, record['new_tag'])
|
337
333
|
assert_not_equal('time', record['new_time'])
|
338
|
-
assert_equal(@time.to_s, record['new_time'])
|
334
|
+
assert_equal(Time.at(@time).localtime.to_s, record['new_time'])
|
339
335
|
assert_equal('tag', record['new_record_tag'])
|
340
336
|
assert_equal('time', record['new_record_time'])
|
341
337
|
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.
|
4
|
+
version: 0.9.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: 2017-
|
11
|
+
date: 2017-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -127,6 +127,9 @@ files:
|
|
127
127
|
- example.conf
|
128
128
|
- fluent-plugin-record-reformer.gemspec
|
129
129
|
- lib/fluent/plugin/out_record_reformer.rb
|
130
|
+
- lib/fluent/plugin/out_record_reformer/core.rb
|
131
|
+
- lib/fluent/plugin/out_record_reformer/v12.rb
|
132
|
+
- lib/fluent/plugin/out_record_reformer/v14.rb
|
130
133
|
- test/bench_out_record_reformer.rb
|
131
134
|
- test/helper.rb
|
132
135
|
- test/test_out_record_reformer.rb
|
@@ -150,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
153
|
version: '0'
|
151
154
|
requirements: []
|
152
155
|
rubyforge_project:
|
153
|
-
rubygems_version: 2.
|
156
|
+
rubygems_version: 2.6.8
|
154
157
|
signing_key:
|
155
158
|
specification_version: 4
|
156
159
|
summary: Fluentd plugin to add or replace fields of a event record
|