fluent-plugin-records-merger 0.1.0 → 0.1.1

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
  SHA256:
3
- metadata.gz: 5c802733686b3da60f4482bac6f209bbb8852f21a93c8adacf770c24e10cc8ab
4
- data.tar.gz: 4c6157e2bc485d422e2debe7a988169682375af12a6e48df6a906ff361cafe77
3
+ metadata.gz: 8eb7fbf8e02b7ce0c3f820c4ddbaa27526d6d43e409912d14f19ce5807220787
4
+ data.tar.gz: 192ade91d03b5233185f84dae69a206efb4a211ecc9bb87ed8c728d34ccfdeea
5
5
  SHA512:
6
- metadata.gz: 0d2078ded6a41d434291ae41468fa76784c09f64a57123148c96452a7f73cc6ccfcab53e7d7e0997df12aa7bce8812236a98dccf03a37a3e2992569ffa568a97
7
- data.tar.gz: 3ce73da1351c592ee3a7f1cb6d7a3a8c2ae598aaee31337d251331f32ccd1233c21273a87bf954fb60068aaf7e6812b3a8c7e5c62704a510c20a9b6d951c7f4e
6
+ metadata.gz: cc2af7b4a0929a32fce8b0fbc296428cdc81da53153e31ba92928865698e9dcfd58fb11780b836899ff00d01e1e8a5189093ceeab203674420ac4203ebc50688
7
+ data.tar.gz: 5c0f1ea3554704a93b4987767b51b88c8141c6463266fb644b766fc094b55caa35122d379119278895299df6ca12c9ef5bb0d125e3e6ed92d1188cd0c91141de
data/.rubocop.yml ADDED
@@ -0,0 +1,18 @@
1
+ Style/AsciiComments:
2
+ Enabled: false
3
+ Metrics/LineLength:
4
+ Max: 140
5
+ Naming/MethodParameterName:
6
+ Enabled: false
7
+ Metrics/AbcSize:
8
+ Max: 30
9
+ Metrics/MethodLength:
10
+ Max: 30
11
+ Metrics/PerceivedComplexity:
12
+ Max: 10
13
+ Metrics/CyclomaticComplexity:
14
+ Max: 10
15
+ Metrics/BlockLength:
16
+ Max: 45
17
+ Metrics/ClassLength:
18
+ Max: 250
data/example/README.md ADDED
@@ -0,0 +1,22 @@
1
+ ## 動かす
2
+
3
+
4
+ ```cassandraql
5
+ fluentd -c example/fluent.conf -p lib/fluent/plugin
6
+ ```
7
+
8
+ ## 動作を確認する
9
+
10
+ ```cassandraql
11
+ cat worw2.json | fluent-cat w.sub_word1
12
+ cat word1.json | fluent-cat w.main_word
13
+
14
+ # 条件にマッチするのでemitされる
15
+
16
+
17
+ cat worw3.json | fluent-cat w.sub_word1
18
+ cat word1.json | fluent-cat w.main_word
19
+
20
+ # 条件にマッチしないのでemitされない
21
+
22
+ ```
@@ -0,0 +1,22 @@
1
+ <source>
2
+ @type forward
3
+ port 24224
4
+ </source>
5
+
6
+ <match w.**>
7
+ @type records_merger
8
+ tag result
9
+ merge_timing before
10
+ main_tag w.main_word
11
+ sub_tag1 w.sub_word1
12
+ condition sub1["word"] == "hello"
13
+ <record>
14
+ main ${main["word"]}
15
+ sub ${sub1["word"]}
16
+ </record>
17
+ </match>
18
+
19
+
20
+ <match result>
21
+ @type stdout
22
+ </match>
@@ -0,0 +1 @@
1
+ {"word": "aaaaaaaaa"}
@@ -0,0 +1 @@
1
+ {"word": "hello"}
@@ -0,0 +1 @@
1
+ {"word": "not_hello"}
@@ -5,13 +5,13 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'fluent-plugin-records-merger'
8
- spec.version = '0.1.0'
8
+ spec.version = '0.1.1'
9
9
  spec.authors = ['Nobuyuki Oishi', 'WallyNegima']
10
10
  spec.email = ['u.str.gm@gmail.com']
11
11
 
12
12
  spec.summary = 'this is fluentd plugin. some records merge and out.'
13
13
  spec.description = 'Parallels data is merged and out.'
14
- spec.homepage = "https://github.com/WallyNegima/fluent-plugin-records-merger"
14
+ spec.homepage = 'https://github.com/WallyNegima/fluent-plugin-records-merger'
15
15
  spec.license = 'Apache-2.0'
16
16
 
17
17
  test_files, files = `git ls-files -z`.split("\x0").partition do |f|
@@ -19,6 +19,7 @@ require 'fluent/plugin/output'
19
19
 
20
20
  module Fluent
21
21
  module Plugin
22
+ # fluentd records merger
22
23
  class RecordsMergerOutput < Fluent::Plugin::Output
23
24
  Fluent::Plugin.register_output('records_merger', self)
24
25
  helpers :event_emitter
@@ -28,67 +29,56 @@ module Fluent
28
29
  desc: 'Specify the output tag'
29
30
  config_param :main_tag, :string,
30
31
  desc: 'Specify main_tag name'
31
- config_param :sub_tag1, :string, # string: NAME REGEXP
32
- desc: 'Specify sub_tag name'
33
- (2..PATTERN_MAX_NUM).each do |i|
32
+ (1..PATTERN_MAX_NUM).each do |i|
34
33
  config_param ('sub_tag' + i.to_s).to_sym, :string, default: nil, # NAME REGEXP
35
34
  desc: 'Specify sub_tag name'
36
35
  end
37
36
  config_param :auto_typecast, :bool, default: true, # false for lower version compatibility
38
37
  desc: 'Automatically cast the field types.'
39
- config_param :merge_timing, :enum, list: %i[before after simple], default: 'before',
38
+ config_param :merge_timing, :enum, list: %i[before after simple], default: 'simple',
40
39
  desc: 'Choose merge timing before/after'
41
40
  # ↓ これ、なんかエラー出てるっぽい。修正する。
42
41
  config_param :tolerable_time_range, :integer, default: nil,
43
42
  desc: 'Specify tolerable time range for merging'
43
+
44
+ config_param :condition, :string, default: nil, desc: 'emit if condition is true '
45
+
44
46
  # 以下、未実装
45
47
  config_param :force_emit, :bool, default: false,
46
48
  desc: 'Specify to emit or not when exceeded the tolerable_time_range'
47
49
 
48
50
  def configure(conf)
49
51
  super
50
- # p 'in configure()'
51
- # p conf
52
52
  # conf: {"@type"=>"records_merger", "tag"=>"merged1", "main_tag"=>"accesslog.1.main", "sub_tag1"=>"accesslog.1.sub1", "sub_tag2"=>"accesslog.1.sub2"}, []
53
53
  @tag = conf['tag'] # これも,結局 ${tag} とかを有効にする関係で使わなくなりそう.
54
54
  # set the tags set by the user
55
+ @last_records = {}
55
56
  @main_tag = conf['main_tag']
57
+
56
58
  @sub_tags = []
57
59
  (1..PATTERN_MAX_NUM).each do |i|
58
60
  next unless conf["sub_tag#{i}"]
59
61
 
60
62
  @sub_tags.push(conf["sub_tag#{i}"])
61
63
  end
64
+
62
65
  if conf['merge_timing']
63
66
  @merge_timing = conf['merge_timing']
64
- p '@merge_timing is ' + @merge_timing.to_s
65
- else
66
- p 'Specify merge_timing before/after'
67
67
  end
68
68
 
69
69
  @tolerable_time_range = conf['tolerable_time_range'].to_i
70
70
 
71
- @last_records = {} # main を流した後に削除する? (未実装)
72
-
73
- p 'size of @sub_tags is ' + @sub_tags.size.to_s
74
71
  @flags4merge = Array.new(@sub_tags.size + 1, 0)
75
- # p @flags4merge # [0, 0,..., 0]
76
-
77
72
  @force_emit = conf['force_emit']
78
73
 
79
74
  # from out-record-reformer
80
75
  map = {}
81
- # load <record></record> directive
82
76
  conf.elements.select { |element| element.name == 'record' }.each do |element|
83
77
  element.each_pair do |k, v|
84
- # p k
85
- # p v
86
78
  element.key?(k) # to suppress unread configuration warning
87
79
  map[k] = parse_value(v)
88
80
  end
89
81
  end
90
- # p 'print map below'
91
- # p map
92
82
 
93
83
  placeholder_expander_params = {
94
84
  log: log,
@@ -98,6 +88,7 @@ module Fluent
98
88
  @map = @placeholder_expander.preprocess_map(map)
99
89
  @tag = @placeholder_expander.preprocess_map(@tag)
100
90
  @hostname = Socket.gethostname
91
+ @condition = conf['condition']
101
92
  end
102
93
 
103
94
  def start
@@ -109,18 +100,12 @@ module Fluent
109
100
  end
110
101
 
111
102
  def process(tag, es)
112
- # p 'in process(), merge_timing is '+@merge_timing.to_s
113
103
  if @merge_timing == 'before'
114
- # p 'merge timing is before'
115
104
  if @main_tag == tag
116
- # p 'main tag has come'
117
105
  store_to_lastrecords(tag, es)
118
106
  @flags4merge[0] = 1
119
- # p 'store_to_lastrecords() seems to have no problems'
120
107
  check_timegap if @tolerable_time_range > 0
121
- # pp @flags4merge
122
108
  if @flags4merge.all? { |flag| flag == 1 }
123
- # pp 'Great! Now you can omit merged event!'
124
109
  emit_new_event(es)
125
110
  else
126
111
  (0..@flags4merge.length - 1).each do |i|
@@ -131,53 +116,35 @@ module Fluent
131
116
  store_to_lastrecords(tag, es)
132
117
  @flags4merge[@sub_tags.index(tag) + 1] = 1
133
118
  check_timegap if @tolerable_time_range > 0
134
- # p @flags4merge
135
119
  end
136
120
  elsif @merge_timing == 'after'
137
- # p 'merge timing is after'
138
121
  if @main_tag == tag
139
122
  store_to_lastrecords(tag, es)
140
123
  @flags4merge[0] = 1
141
124
  check_timegap if @tolerable_time_range > 0
142
- # pp @flags4merge
143
125
  elsif @sub_tags.include?(tag)
144
126
  if @flags4merge[0] == 1
145
127
  store_to_lastrecords(tag, es)
146
128
  @flags4merge[@sub_tags.index(tag) + 1] = 1
147
129
  check_timegap if @tolerable_time_range > 0
148
- # p @flags4merge
149
- if @flags4merge.all? { |flag| flag == 1 }
150
- # pp 'Great! Now you can omit merged event!'
151
- emit_new_event(es)
152
- end
130
+ emit_new_event(es) if @flags4merge.all? {|flag| flag == 1}
153
131
  else
154
132
  (0..@flags4merge.length - 1).each do |i|
155
133
  @flags4merge[i] = 0
156
134
  end
157
- # p @flags4merge
158
135
  end
159
136
  else
160
137
  p 'something else has come! check it!' + tag.to_s
161
138
  end
162
139
  elsif @merge_timing == 'simple'
163
- # p 'merge timing is simple'
164
140
  if @main_tag == tag
165
- # p "main_tag_came"
166
141
  store_to_lastrecords(tag, es)
167
- # p 'after store_to_lastrecords()'
168
142
  @flags4merge[0] = 1
169
143
  check_timegap if @tolerable_time_range > 0
170
- # pp @flags4merge
171
- if @flags4merge.all? { |flag| flag == 1 }
172
- # p 'before emit_new event()'
173
- emit_new_event(es)
174
- # p 'after emit_new event()'
175
-
176
- end
144
+ emit_new_event(es) if @flags4merge.all? { |flag| flag == 1 }
177
145
  elsif @sub_tags.include?(tag)
178
146
  store_to_lastrecords(tag, es)
179
147
  @flags4merge[@sub_tags.index(tag) + 1] = 1
180
- # p @flags4merge
181
148
  check_timegap if @tolerable_time_range > 0
182
149
  emit_new_event(es) if @flags4merge.all? { |flag| flag == 1 }
183
150
  else
@@ -186,7 +153,7 @@ module Fluent
186
153
  end
187
154
  rescue StandardError => e
188
155
  log.warn "record_reformer: #{e.class} #{e.message} #{e.backtrace.first}"
189
- log.debug "record_reformer: tag:#{@tag} map:#{@map} record:#{last_records} placeholder_values:#{placeholder_values}"
156
+ log.debug "record_reformer: tag:#{@tag} map:#{@map} record:#{@last_records} placeholder_values"
190
157
  end
191
158
 
192
159
  # そのまま持ってきてしまっているので,rewriteしたほうが良さそう?
@@ -195,26 +162,17 @@ module Fluent
195
162
 
196
163
  def store_to_lastrecords(tag, es)
197
164
  es.each do |time, record|
198
- # p 'in store_to_lastrecords()'
199
- # print 'time: '
200
- # p time
201
- # print 'record: '
202
- # p record
203
165
  record.store('time', time)
204
166
  @last_records.store(tag, record)
205
- # これで,last_recordsにはsub_tagの情報がそのまま入ってる.ちなみに,storeはkey, valueの形でハッシュに値を入れるために使う.
206
- # ここはそのままでも問題なくて,mainが来たときにまとめて調整すれば良い.
167
+ # これで,last_recordsにはsub_tagの情報がそのまま入ってる.ちなみに,storeはkey, valueの形でハッシュに値を入れるために使う.´
207
168
  end
208
169
  end
209
170
 
210
171
  def generate_placeholders
211
172
  # here, tag can be used directly only because it is the main tag
212
173
  main_tag_parts = @main_tag.split('.')
213
- # p tag_parts
214
174
  main_tag_prefix = tag_prefix(main_tag_parts)
215
- # p tag_prefix
216
175
  main_tag_suffix = tag_suffix(main_tag_parts)
217
- # p tag_suffix
218
176
 
219
177
  placeholder_values = {
220
178
  'main' => @last_records[@main_tag],
@@ -248,46 +206,43 @@ module Fluent
248
206
  end
249
207
 
250
208
  def emit_new_event(es)
251
- # p "in emit_new_event"
252
209
  es.each do |time, _record|
253
210
  placeholder_values = generate_placeholders
254
211
  message = @last_records
255
- # print "message:"
256
- # p @last_records
257
212
  next if message.keys.empty?
258
213
 
259
214
  new_tag, new_record = reform(@tag, @last_records, placeholder_values)
260
215
  next unless new_tag
261
216
 
217
+ unless @condition.nil?
218
+ # conditionがOKじゃなければemiしない
219
+ next unless condition_is_ok?(placeholder_values)
220
+ end
221
+
262
222
  router.emit(new_tag, time, new_record)
263
223
  # flagの初期化
264
224
  (0..@flags4merge.length - 1).each do |i|
265
225
  @flags4merge[i] = 0
266
226
  end
267
- # p @flags4merge
268
- # router.emit(@tag, time, message)
269
227
  end
270
228
  end
271
229
 
230
+ def condition_is_ok?(placeholder_values)
231
+ placeholders = @placeholder_expander.prepare_placeholders(placeholder_values)
232
+ instance_eval(@condition.gsub(/((main\["\w+"\])|(sub[0-9]{1,2}\["\w+"\]))/, 'placeholders[\'${\1}\']'))
233
+ end
234
+
272
235
  def check_timegap
273
- p @last_records.size
274
236
  tag_time_hash = {}
275
237
  if @last_records.size > 1
276
238
  @last_records.each do |k, v|
277
- # p k
278
- # p v['time'].sec
279
- # p v['time'].nsec # ナノセカンドでの比較は余裕があったら実装する
280
239
  tag_time_hash.store(k, v['time'].sec)
281
240
  end
282
241
  # ここでtag_nameと一緒に保持しておきたい
283
242
  latest = tag_time_hash.max { |a, b| a[1] <=> b[1] }
284
- # p latest
285
243
  oldest = tag_time_hash.min { |a, b| a[1] <=> b[1] }
286
- # p oldest
287
- # p @last_records
288
244
 
289
245
  if latest[1] - oldest[1] > @tolerable_time_range
290
- p oldest[0].to_s + ' is too old! so deleted'
291
246
  @last_records.delete(oldest[0])
292
247
  if oldest[0] == @main_tag
293
248
  @flags4merge[0] = 0
@@ -310,37 +265,21 @@ module Fluent
310
265
  end
311
266
 
312
267
  def reform(tag, _record, placeholder_values)
313
- # p 'in reform()'
314
- # p 'tag: '
315
- # pp tag
316
- # p 'record'
317
- # pp record
318
268
  placeholders = @placeholder_expander.prepare_placeholders(placeholder_values)
319
- # p 'placeholders'
320
- # pp placeholders
321
269
 
322
270
  new_tag = expand_placeholders(tag, placeholders) # 新しいtagを生成してる
323
- # p 'new_tag'
324
- # p new_tag
325
271
 
326
272
  # 基本的に,全部ゼロから作るからここでdupする必要はない.
327
273
  # new_record = @renew_record ? {} : record.dup # dupは新しいのを作ってコピーするやつ
328
274
  # @keep_keys.each {|k| new_record[k] = record[k]} if @keep_keys and @renew_record
329
275
 
330
276
  new_record = {}
331
- # p '@map' # ここには,<record></record>で指定したものが入ってる.
332
- # pp @map
333
277
  new_record.merge!(expand_placeholders(@map, placeholders))
334
- # p 'new_record'
335
- # pp new_record
336
278
 
337
279
  [new_tag, new_record]
338
280
  end
339
281
 
340
282
  def expand_placeholders(value, placeholders)
341
- # p 'in expand_placeholders()'
342
- # pp value
343
- # pp placeholders
344
283
  if value.is_a?(String)
345
284
  new_value = @placeholder_expander.expand(value, placeholders)
346
285
  elsif value.is_a?(Hash)
@@ -403,11 +342,9 @@ module Fluent
403
342
  end
404
343
 
405
344
  def prepare_placeholders(placeholder_values)
406
- # p 'in prepare_placeholders()'
407
345
  placeholders = {}
408
346
 
409
347
  placeholder_values.each do |key, value|
410
- # p key
411
348
  if value.is_a?(Array) # tag_parts, etc
412
349
  size = value.size
413
350
  value.each_with_index do |v, idx|
@@ -416,17 +353,13 @@ module Fluent
416
353
  end
417
354
  elsif value.is_a?(Hash) # record, etc
418
355
  value.each do |k, v|
419
- unless placeholder_values.key?(k) # prevent overwriting the reserved keys such as tag
420
- placeholders.store("${#{k}}", v)
421
- end
356
+ placeholders.store("${#{k}}", v) unless placeholder_values.key?(k) # prevent overwriting the reserved keys such as tag
422
357
  placeholders.store(%(${#{key}["#{k}"]}), v) # record["foo"]
423
358
  end
424
359
  else # string, interger, float, and others?
425
360
  placeholders.store("${#{key}}", value)
426
361
  end
427
362
  end
428
- # pp placeholders
429
- # p 'end of prepare_placeholders()'
430
363
  placeholders
431
364
  end
432
365
 
@@ -451,9 +384,7 @@ module Fluent
451
384
  private
452
385
 
453
386
  def log_if_unknown_placeholder(placeholder, placeholders)
454
- unless placeholders.include?(placeholder)
455
- log.warn "record_reformer: unknown placeholder `#{placeholder}` found"
456
- end
387
+ log.warn "record_reformer: unknown placeholder `#{placeholder}` found" unless placeholders.include?(placeholder)
457
388
  end
458
389
  end
459
390
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-records-merger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nobuyuki Oishi
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-02-28 00:00:00.000000000 Z
12
+ date: 2020-03-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -81,10 +81,16 @@ extensions: []
81
81
  extra_rdoc_files: []
82
82
  files:
83
83
  - ".gitignore"
84
+ - ".rubocop.yml"
84
85
  - Gemfile
85
86
  - LICENSE
86
87
  - README.md
87
88
  - Rakefile
89
+ - example/README.md
90
+ - example/fluent.conf
91
+ - example/word1.json
92
+ - example/word2.json
93
+ - example/word3.json
88
94
  - fluent-plugin-records-merger.gemspec
89
95
  - lib/fluent/plugin/out_records_merger.rb
90
96
  - test/helper.rb