fluent-plugin-datacounter 0.5.0 → 1.0.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: 91d0b353b01ecba75105027f3ea432cb54659dda
4
- data.tar.gz: 07d98018128765756fb478638531f778c5138f50
3
+ metadata.gz: 658db36e09471b16f21cba480b36b5168818daf4
4
+ data.tar.gz: e798289a5f33cd2bf8a85f3e8c0efa941d2b1439
5
5
  SHA512:
6
- metadata.gz: 3a765c1d921fa731f6fdfb5beca42e6522a52585542b1d23a6ad2f07b859e2f2756d8b1407379169c20709ce2ecf07a49446248b78b9f32b674a9d8d26954c24
7
- data.tar.gz: 8f4dc5d9acc4ff7f325647c3da6c0af16b36ca0574d990e0b79d34fa6de6e22d08aac8863b2df73e994df20ef058515be6f025ea142f8434dda7ef1b454e6073
6
+ metadata.gz: 77682c560a84a722ec7b2edb6eb831295ffdfca1d0ba228cd79fefc33ae9a3d93f35ffc26d95a49cd66b54f2b6ecb1215b8527852f0b4a4834f75a56731c34b1
7
+ data.tar.gz: a575acce7199476d09caff16a83a7323134b869e88f534bc11c9e9c83af5090d11ab0508a2494084a51f3717a81061ce49b86ca79cda2d22e99a87eab81f0357
@@ -1,6 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0.0
4
3
  - 2.1.8
5
4
  - 2.2.4
6
-
5
+ - 2.3.3
6
+ before_install:
7
+ - gem update bundler
data/Rakefile CHANGED
@@ -7,5 +7,5 @@ Rake::TestTask.new(:test) do |test|
7
7
  test.verbose = true
8
8
  end
9
9
 
10
- task :default => :test
10
+ task default: :test
11
11
 
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |gem|
3
3
  gem.name = "fluent-plugin-datacounter"
4
- gem.version = "0.5.0"
4
+ gem.version = "1.0.0"
5
5
  gem.authors = ["TAGOMORI Satoshi"]
6
6
  gem.email = ["tagomoris@gmail.com"]
7
7
  gem.homepage = "https://github.com/tagomoris/fluent-plugin-datacounter"
@@ -14,10 +14,10 @@ Gem::Specification.new do |gem|
14
14
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
15
  gem.require_paths = ["lib"]
16
16
 
17
- gem.add_runtime_dependency "fluentd", "< 0.14.0"
17
+ gem.add_runtime_dependency "fluentd", [">= 0.14.8", "< 2"]
18
18
 
19
19
  gem.add_development_dependency "bundler"
20
20
  gem.add_development_dependency "rake"
21
21
  gem.add_development_dependency "test-unit"
22
- gem.add_development_dependency "delorean"
22
+ gem.add_development_dependency "timecop"
23
23
  end
@@ -1,52 +1,51 @@
1
- class Fluent::DataCounterOutput < Fluent::Output
1
+ require 'pathname'
2
+ require 'fluent/plugin/output'
3
+
4
+ class Fluent::Plugin::DataCounterOutput < Fluent::Plugin::Output
2
5
  Fluent::Plugin.register_output('datacounter', self)
3
6
 
4
- # Define `log` method for v0.10.42 or earlier
5
- unless method_defined?(:log)
6
- define_method("log") { $log }
7
- end
8
-
9
- # Define `router` method of v0.12 to support v0.10 or earlier
10
- unless method_defined?(:router)
11
- define_method("router") { Fluent::Engine }
12
- end
13
-
14
- def initialize
15
- super
16
- require 'pathname'
17
- end
7
+ helpers :event_emitter, :storage, :timer
18
8
 
9
+ DEFAULT_STORAGE_TYPE = 'local'
19
10
  PATTERN_MAX_NUM = 20
20
11
 
21
- config_param :count_interval, :time, :default => nil,
22
- :desc => 'The interval time to count in seconds.'
23
- config_param :unit, :string, :default => 'minute',
24
- :desc => 'The interval time to monitor specified an unit (either of minute, hour, or day).'
25
- config_param :output_per_tag, :bool, :default => false,
26
- :desc => 'Emit for each input tag. tag_prefix must be specified together.'
27
- config_param :aggregate, :string, :default => 'tag',
28
- :desc => 'Calculate in each input tag separetely, or all records in a mass.'
29
- config_param :tag, :string, :default => 'datacount',
30
- :desc => 'The output tag.'
31
- config_param :tag_prefix, :string, :default => nil,
32
- :desc => 'The prefix string which will be added to the input tag.'
33
- config_param :input_tag_remove_prefix, :string, :default => nil,
34
- :desc => 'The prefix string which will be removed from the input tag.'
12
+ config_param :count_interval, :time, default: nil,
13
+ desc: 'The interval time to count in seconds.'
14
+ config_param :unit, :enum, list: [:minute, :hour, :day], default: :minute,
15
+ desc: 'The interval time to monitor specified an unit (either of minute, hour, or day).'
16
+ config_param :output_per_tag, :bool, default: false,
17
+ desc: 'Emit for each input tag. tag_prefix must be specified together.'
18
+ config_param :aggregate, :enum, list: [:tag, :all], default: :tag,
19
+ desc: 'Calculate in each input tag separetely, or all records in a mass.'
20
+ config_param :tag, :string, default: 'datacount',
21
+ desc: 'The output tag.'
22
+ config_param :tag_prefix, :string, default: nil,
23
+ desc: 'The prefix string which will be added to the input tag.'
24
+ config_param :input_tag_remove_prefix, :string, default: nil,
25
+ desc: 'The prefix string which will be removed from the input tag.'
35
26
  config_param :count_key, :string,
36
- :desc => 'The key to count in the event record.'
37
- config_param :outcast_unmatched, :bool, :default => false,
38
- :desc => 'Specify yes if you do not want to include \'unmatched\' counts into percentage. '
39
- config_param :output_messages, :bool, :default => false,
40
- :desc => 'Specify yes if you want to get tested messages.'
41
- config_param :store_file, :string, :default => nil,
42
- :desc => 'Store internal data into a file of the given path on shutdown, and load on starting.'
27
+ desc: 'The key to count in the event record.'
28
+ config_param :outcast_unmatched, :bool, default: false,
29
+ desc: 'Specify yes if you do not want to include \'unmatched\' counts into percentage. '
30
+ config_param :output_messages, :bool, default: false,
31
+ desc: 'Specify yes if you want to get tested messages.'
32
+ config_param :store_file, :string, default: nil,
33
+ obsoleted: 'Use store_storage parameter instead.',
34
+ desc: 'Store internal data into a file of the given path on shutdown, and load on starting.'
35
+ config_param :store_storage, :bool, default: false,
36
+ desc: 'Store internal data into a storage on shutdown, and load on starting.'
43
37
 
44
38
  # pattern0 reserved as unmatched counts
45
39
  config_param :pattern1, :string, # string: NAME REGEXP
46
- :desc => 'Specify RegexpName and Regexp. format: NAME REGEXP'
40
+ desc: 'Specify RegexpName and Regexp. format: NAME REGEXP'
47
41
  (2..PATTERN_MAX_NUM).each do |i|
48
- config_param ('pattern' + i.to_s).to_sym, :string, :default => nil, # NAME REGEXP
49
- :desc => "Specify RegexpName and Regexp. format: NAME REGEXP"
42
+ config_param ('pattern' + i.to_s).to_sym, :string, default: nil, # NAME REGEXP
43
+ desc: "Specify RegexpName and Regexp. format: NAME REGEXP"
44
+ end
45
+
46
+ config_section :storage do
47
+ config_set_default :usage, 'resume'
48
+ config_set_default :@type, DEFAULT_STORAGE_TYPE
50
49
  end
51
50
 
52
51
  attr_accessor :tick
@@ -62,28 +61,21 @@ class Fluent::DataCounterOutput < Fluent::Output
62
61
  @tick = @count_interval.to_i
63
62
  else
64
63
  @tick = case @unit
65
- when 'minute' then 60
66
- when 'hour' then 3600
67
- when 'day' then 86400
64
+ when :minute then 60
65
+ when :hour then 3600
66
+ when :day then 86400
68
67
  else
69
- raise RuntimeError, "@unit must be one of minute/hour/day"
68
+ raise RuntimeError, "BUG: unknown unit: #{@unit}"
70
69
  end
71
70
  end
72
71
 
73
- @aggregate = case @aggregate
74
- when 'tag' then :tag
75
- when 'all' then :all
76
- else
77
- raise Fluent::ConfigError, "datacounter aggregate allows tag/all"
78
- end
79
-
80
72
  @patterns = [[0, 'unmatched', nil]]
81
73
  pattern_names = ['unmatched']
82
74
 
83
75
  pattern_keys = conf.keys.select{|k| k =~ /^pattern(\d+)$/}
84
76
  invalids = pattern_keys.select{|arg| arg =~ /^pattern(\d+)/ and not (1..PATTERN_MAX_NUM).include?($1.to_i)}
85
77
  if invalids.size > 0
86
- log.warn "invalid number patterns (valid pattern number:1-20):" + invalids.join(",")
78
+ log.warn "invalid number patterns (valid pattern number:1-20)", invalids: invalids
87
79
  end
88
80
  (1..PATTERN_MAX_NUM).each do |i|
89
81
  next unless conf["pattern#{i}"]
@@ -109,28 +101,34 @@ class Fluent::DataCounterOutput < Fluent::Output
109
101
  @removed_length = @removed_prefix_string.length
110
102
  end
111
103
 
112
- if @store_file
113
- f = Pathname.new(@store_file)
114
- if (f.exist? && !f.writable_real?) || (!f.exist? && !f.parent.writable_real?)
115
- raise Fluent::ConfigError, "#{@store_file} is not writable"
116
- end
104
+ if @store_storage
105
+ @storage = storage_create(usage: 'resume')
106
+ end
107
+
108
+ if system_config.workers > 1
109
+ log.warn "Fluentd is now working with multi process workers, and datacounter plugin will produce counter results in each separeted processes."
117
110
  end
118
111
 
119
112
  @counts = count_initialized
120
113
  @mutex = Mutex.new
121
114
  end
122
115
 
116
+ def multi_workers_ready?
117
+ true
118
+ end
119
+
123
120
  def start
124
121
  super
125
- load_status(@store_file, @tick) if @store_file
126
- start_watch
122
+
123
+ load_status(@tick) if @store_storage
124
+
125
+ @last_checked = Fluent::Engine.now
126
+ timer_execute(:out_datacounter_timer, @tick, &method(:watch))
127
127
  end
128
128
 
129
129
  def shutdown
130
+ save_status() if @store_storage
130
131
  super
131
- @watcher.terminate
132
- @watcher.join
133
- save_status(@store_file) if @store_file
134
132
  end
135
133
 
136
134
  def count_initialized(keys=nil)
@@ -235,39 +233,28 @@ class Fluent::DataCounterOutput < Fluent::Output
235
233
  end
236
234
 
237
235
  def flush_emit(step)
236
+ time = Fluent::Engine.now
238
237
  if @output_per_tag
239
238
  # tag - message maps
240
- time = Fluent::Engine.now
241
239
  flush_per_tags(step).each do |tag,message|
242
240
  router.emit(@tag_prefix_string + tag, time, message)
243
241
  end
244
242
  else
245
243
  message = flush(step)
246
244
  if message.keys.size > 0
247
- router.emit(@tag, Fluent::Engine.now, message)
245
+ router.emit(@tag, time, message)
248
246
  end
249
247
  end
250
248
  end
251
249
 
252
- def start_watch
253
- # for internal, or tests only
254
- @watcher = Thread.new(&method(:watch))
255
- end
256
-
257
250
  def watch
258
251
  # instance variable, and public accessable, for test
259
- @last_checked ||= Fluent::Engine.now
260
- while true
261
- sleep 0.5
262
- if Fluent::Engine.now - @last_checked >= @tick
263
- now = Fluent::Engine.now
264
- flush_emit(now - @last_checked)
265
- @last_checked = now
266
- end
267
- end
252
+ now = Fluent::Engine.now
253
+ flush_emit(now - @last_checked)
254
+ @last_checked = now
268
255
  end
269
256
 
270
- def emit(tag, es, chain)
257
+ def process(tag, es)
271
258
  c = [0] * @patterns.length
272
259
 
273
260
  es.each do |time,record|
@@ -285,65 +272,72 @@ class Fluent::DataCounterOutput < Fluent::Output
285
272
  c[0] += 1 unless matched
286
273
  end
287
274
  countups(tag, c)
288
-
289
- chain.next
290
275
  end
291
276
 
292
- # Store internal status into a file
277
+ # Store internal status into a storage
293
278
  #
294
- # @param [String] file_path
295
- def save_status(file_path)
279
+ def save_status()
296
280
  begin
297
- Pathname.new(file_path).open('wb') do |f|
298
- @saved_at = Fluent::Engine.now
299
- @saved_duration = @saved_at - @last_checked
300
- Marshal.dump({
301
- :counts => @counts,
302
- :saved_at => @saved_at,
303
- :saved_duration => @saved_duration,
304
- :aggregate => @aggregate,
305
- :count_key => @count_key,
306
- :patterns => @patterns,
307
- }, f)
308
- end
281
+ @saved_at = Fluent::Engine.now
282
+ @saved_duration = @saved_at - @last_checked
283
+ patterns = @patterns.map{|idx, label, regexp|
284
+ if regexp
285
+ [idx, label, regexp.source]
286
+ else
287
+ [idx, label, regexp]
288
+ end
289
+ }
290
+ value = {
291
+ "counts" => @counts,
292
+ "saved_at" => @saved_at,
293
+ "saved_duration" => @saved_duration,
294
+ "aggregate" => @aggregate,
295
+ "count_key" => @count_key.to_s,
296
+ "patterns" => patterns,
297
+ }
298
+ @storage.put(:stored_value, value)
309
299
  rescue => e
310
- log.warn "out_datacounter: Can't write store_file #{e.class} #{e.message}"
300
+ log.warn "Can't write store_storage", error: e
311
301
  end
312
302
  end
313
303
 
314
- # Load internal status from a file
304
+ # Load internal status from a storage
315
305
  #
316
- # @param [String] file_path
317
306
  # @param [Interger] tick The count interval
318
- def load_status(file_path, tick)
319
- return unless (f = Pathname.new(file_path)).exist?
307
+ def load_status(tick)
308
+ stored = @storage.get(:stored_value)
309
+ return unless stored
320
310
 
321
311
  begin
322
- f.open('rb') do |f|
323
- stored = Marshal.load(f)
324
- if stored[:aggregate] == @aggregate and
325
- stored[:count_key] == @count_key and
326
- stored[:patterns] == @patterns
327
-
328
- if Fluent::Engine.now <= stored[:saved_at] + tick
329
- @mutex.synchronize {
330
- @counts = stored[:counts]
331
- @saved_at = stored[:saved_at]
332
- @saved_duration = stored[:saved_duration]
333
-
334
- # skip the saved duration to continue counting
335
- @last_checked = Fluent::Engine.now - @saved_duration
336
- }
337
- else
338
- log.warn "out_datacounter: stored data is outdated. ignore stored data"
339
- end
312
+ patterns = stored["patterns"].map{|idx, label, regexp|
313
+ if regexp
314
+ [idx, label, Regexp.compile(regexp)]
340
315
  else
341
- log.warn "out_datacounter: configuration param was changed. ignore stored data"
316
+ [idx, label, regexp]
342
317
  end
318
+ }
319
+
320
+ if stored["aggregate"] == @aggregate.to_s and
321
+ stored["count_key"] == @count_key and
322
+ patterns == @patterns
323
+
324
+ if Fluent::Engine.now <= stored["saved_at"] + tick
325
+ @mutex.synchronize {
326
+ @counts = stored["counts"]
327
+ @saved_at = stored["saved_at"]
328
+ @saved_duration = stored["saved_duration"]
329
+
330
+ # skip the saved duration to continue counting
331
+ @last_checked = Fluent::Engine.now - @saved_duration
332
+ }
333
+ else
334
+ log.warn "stored data is outdated. ignore stored data"
335
+ end
336
+ else
337
+ log.warn "configuration param was changed. ignore stored data"
343
338
  end
344
339
  rescue => e
345
- log.warn "out_datacounter: Can't load store_file #{e.class} #{e.message}"
340
+ log.warn "Can't load store_storage", error: e
346
341
  end
347
342
  end
348
-
349
343
  end
@@ -22,7 +22,6 @@ unless ENV.has_key?('VERBOSE')
22
22
  $log = nulllogger
23
23
  end
24
24
 
25
- require 'delorean'
26
25
  require 'fluent/plugin/out_datacounter'
27
26
 
28
27
  class Test::Unit::TestCase
@@ -1,10 +1,22 @@
1
1
  require 'helper'
2
+ require 'fluent/test/driver/output'
3
+ require 'fileutils'
4
+ require 'timecop'
5
+
2
6
 
3
7
  class DataCounterOutputTest < Test::Unit::TestCase
4
8
  def setup
5
9
  Fluent::Test.setup
6
10
  end
7
11
 
12
+ def teardown
13
+ Timecop.return
14
+ end
15
+
16
+ def config_element(name = 'test', argument = '', params = {}, elements = [])
17
+ Fluent::Config::Element.new(name, argument, params, elements)
18
+ end
19
+
8
20
  CONFIG = %[
9
21
  unit minute
10
22
  aggregate tag
@@ -30,39 +42,39 @@ class DataCounterOutputTest < Test::Unit::TestCase
30
42
  output_messages yes
31
43
  ]
32
44
 
33
- def create_driver(conf = CONFIG, tag='test.input')
34
- Fluent::Test::OutputTestDriver.new(Fluent::DataCounterOutput, tag).configure(conf)
45
+ def create_driver(conf = CONFIG)
46
+ Fluent::Test::Driver::Output.new(Fluent::Plugin::DataCounterOutput).configure(conf)
35
47
  end
36
48
 
37
49
  def test_configure
38
50
  assert_raise(Fluent::ConfigError) {
39
- d = create_driver('')
51
+ create_driver('')
40
52
  }
41
53
  assert_raise(Fluent::ConfigError) {
42
- d = create_driver %[
54
+ create_driver %[
43
55
  count_key field
44
56
  ]
45
57
  }
46
58
  assert_raise(Fluent::ConfigError) {
47
- d = create_driver %[
59
+ create_driver %[
48
60
  pattern1 hoge ^1\\d\\d$
49
61
  ]
50
62
  }
51
63
  assert_raise(Fluent::ConfigError) {
52
- d = create_driver %[
64
+ create_driver %[
53
65
  count_key field
54
66
  pattern2 hoge ^1\\d\\d$
55
67
  ]
56
68
  }
57
69
  assert_raise(Fluent::ConfigError) {
58
- d = create_driver %[
70
+ create_driver %[
59
71
  count_key field
60
72
  pattern1 hoge ^1\\d\\d$
61
73
  pattern4 pos ^4\\d\\d$
62
74
  ]
63
75
  }
64
76
  assert_raise(Fluent::ConfigError) {
65
- d = create_driver %[
77
+ create_driver %[
66
78
  count_key field
67
79
  pattern1 hoge ^1\\d\\d$
68
80
  pattern2 hoge ^4\\d\\d$
@@ -91,7 +103,7 @@ class DataCounterOutputTest < Test::Unit::TestCase
91
103
  pattern1 ok ^2\\d\\d$
92
104
  ]
93
105
  assert_equal d1.instance.tick, d2.instance.tick
94
-
106
+
95
107
  d = create_driver %[
96
108
  count_interval 5m
97
109
  count_key field
@@ -296,7 +308,7 @@ class DataCounterOutputTest < Test::Unit::TestCase
296
308
  end
297
309
 
298
310
  def test_pattern_num
299
- assert_equal 20, Fluent::DataCounterOutput::PATTERN_MAX_NUM
311
+ assert_equal 20, Fluent::Plugin::DataCounterOutput::PATTERN_MAX_NUM
300
312
 
301
313
  conf = %[
302
314
  aggregate all
@@ -305,10 +317,10 @@ class DataCounterOutputTest < Test::Unit::TestCase
305
317
  (1..20).each do |i|
306
318
  conf += "pattern#{i} name#{i} ^#{i}$\n"
307
319
  end
308
- d = create_driver(conf, 'test.max')
309
- d.run do
320
+ d = create_driver(conf)
321
+ d.run(default_tag: 'test.max') do
310
322
  (1..20).each do |j|
311
- d.emit({'field' => j})
323
+ d.feed({'field' => j})
312
324
  end
313
325
  end
314
326
  r = d.instance.flush(60)
@@ -335,13 +347,13 @@ class DataCounterOutputTest < Test::Unit::TestCase
335
347
  end
336
348
 
337
349
  def test_emit
338
- d1 = create_driver(CONFIG, 'test.tag1')
339
- d1.run do
350
+ d1 = create_driver(CONFIG)
351
+ d1.run(default_tag: 'test.tag1') do
340
352
  60.times do
341
- d1.emit({'target' => '200'})
342
- d1.emit({'target' => '100'})
343
- d1.emit({'target' => '200'})
344
- d1.emit({'target' => '400'})
353
+ d1.feed({'target' => '200'})
354
+ d1.feed({'target' => '100'})
355
+ d1.feed({'target' => '200'})
356
+ d1.feed({'target' => '400'})
345
357
  end
346
358
  end
347
359
  r1 = d1.instance.flush(60)
@@ -352,11 +364,11 @@ class DataCounterOutputTest < Test::Unit::TestCase
352
364
  assert_equal 60, r1['tag1_status4xx_count']
353
365
  assert_equal 1.0, r1['tag1_status4xx_rate']
354
366
  assert_equal 25.0, r1['tag1_status4xx_percentage']
355
-
367
+
356
368
  assert_equal 60, r1['tag1_unmatched_count']
357
369
  assert_equal 1.0, r1['tag1_unmatched_rate']
358
370
  assert_equal 25.0, r1['tag1_unmatched_percentage']
359
-
371
+
360
372
  assert_equal 0, r1['tag1_status3xx_count']
361
373
  assert_equal 0.0, r1['tag1_status3xx_rate']
362
374
  assert_equal 0.0, r1['tag1_status3xx_percentage']
@@ -370,17 +382,17 @@ class DataCounterOutputTest < Test::Unit::TestCase
370
382
  pattern1 ok 2\\d\\d
371
383
  pattern2 redirect 3\\d\\d
372
384
  output_messages yes
373
- ], 'test.tag2')
374
- d2.run do
385
+ ])
386
+ d2.run(default_tag: 'test.tag2') do
375
387
  60.times do
376
- d2.emit({'target' => '200'})
377
- d2.emit({'target' => '300 200'})
388
+ d2.feed({'target' => '200'})
389
+ d2.feed({'target' => '300 200'})
378
390
  end
391
+ d2.instance.flush_emit(120)
379
392
  end
380
- d2.instance.flush_emit(120)
381
- emits = d2.emits
382
- assert_equal 1, emits.length
383
- data = emits[0]
393
+ events = d2.events
394
+ assert_equal 1, events.length
395
+ data = events[0]
384
396
  assert_equal 'datacount', data[0] # tag
385
397
  assert_equal 120, data[2]['ok_count']
386
398
  assert_equal 1.0, data[2]['ok_rate']
@@ -399,18 +411,18 @@ class DataCounterOutputTest < Test::Unit::TestCase
399
411
  pattern1 ok 2\\d\\d
400
412
  pattern2 redirect 3\\d\\d
401
413
  outcast_unmatched yes
402
- ], 'test.tag2')
403
- d3.run do
414
+ ])
415
+ d3.run(default_tag: 'test.tag2') do
404
416
  60.times do
405
- d3.emit({'target' => '200'})
406
- d3.emit({'target' => '300'})
407
- d3.emit({'target' => '400'})
417
+ d3.feed({'target' => '200'})
418
+ d3.feed({'target' => '300'})
419
+ d3.feed({'target' => '400'})
408
420
  end
421
+ d3.instance.flush_emit(180)
409
422
  end
410
- d3.instance.flush_emit(180)
411
- emits = d3.emits
412
- assert_equal 1, emits.length
413
- data = emits[0]
423
+ events = d3.events
424
+ assert_equal 1, events.length
425
+ data = events[0]
414
426
  assert_equal 'datacount', data[0] # tag
415
427
  assert_equal 60, data[2]['tag2_unmatched_count']
416
428
  assert_nil data[2]['tag2_unmatched_percentage']
@@ -426,18 +438,18 @@ class DataCounterOutputTest < Test::Unit::TestCase
426
438
  pattern2 redirect 3\\d\\d
427
439
  outcast_unmatched true
428
440
  output_messages true
429
- ], 'test.tag2')
430
- d3.run do
441
+ ])
442
+ d3.run(default_tag: 'test.tag2') do
431
443
  60.times do
432
- d3.emit({'target' => '200'})
433
- d3.emit({'target' => '300'})
434
- d3.emit({'target' => '400'})
444
+ d3.feed({'target' => '200'})
445
+ d3.feed({'target' => '300'})
446
+ d3.feed({'target' => '400'})
435
447
  end
448
+ d3.instance.flush_emit(180)
436
449
  end
437
- d3.instance.flush_emit(180)
438
- emits = d3.emits
439
- assert_equal 1, emits.length
440
- data = emits[0]
450
+ events = d3.events
451
+ assert_equal 1, events.length
452
+ data = events[0]
441
453
  assert_equal 'datacount', data[0] # tag
442
454
  assert_equal 60, data[2]['unmatched_count']
443
455
  assert_nil data[2]['unmatched_percentage']
@@ -449,13 +461,13 @@ class DataCounterOutputTest < Test::Unit::TestCase
449
461
  end
450
462
 
451
463
  def test_emit_output_per_tag
452
- d1 = create_driver(CONFIG_OUTPUT_PER_TAG, 'test.tag1')
453
- d1.run do
464
+ d1 = create_driver(CONFIG_OUTPUT_PER_TAG)
465
+ d1.run(default_tag: 'test.tag1') do
454
466
  60.times do
455
- d1.emit({'target' => '200'})
456
- d1.emit({'target' => '100'})
457
- d1.emit({'target' => '200'})
458
- d1.emit({'target' => '400'})
467
+ d1.feed({'target' => '200'})
468
+ d1.feed({'target' => '100'})
469
+ d1.feed({'target' => '200'})
470
+ d1.feed({'target' => '400'})
459
471
  end
460
472
  end
461
473
  r1 = d1.instance.flush_per_tags(60)
@@ -468,11 +480,11 @@ class DataCounterOutputTest < Test::Unit::TestCase
468
480
  assert_equal 60, r['status4xx_count']
469
481
  assert_equal 1.0, r['status4xx_rate']
470
482
  assert_equal 25.0, r['status4xx_percentage']
471
-
483
+
472
484
  assert_equal 60, r['unmatched_count']
473
485
  assert_equal 1.0, r['unmatched_rate']
474
486
  assert_equal 25.0, r['unmatched_percentage']
475
-
487
+
476
488
  assert_equal 0, r['status3xx_count']
477
489
  assert_equal 0.0, r['status3xx_rate']
478
490
  assert_equal 0.0, r['status3xx_percentage']
@@ -489,17 +501,17 @@ class DataCounterOutputTest < Test::Unit::TestCase
489
501
  pattern2 redirect 3\\d\\d
490
502
  output_per_tag yes
491
503
  tag_prefix d
492
- ], 'test.tag2')
493
- d2.run do
504
+ ])
505
+ d2.run(default_tag: 'test.tag2') do
494
506
  60.times do
495
- d2.emit({'target' => '200'})
496
- d2.emit({'target' => '300 200'})
507
+ d2.feed({'target' => '200'})
508
+ d2.feed({'target' => '300 200'})
497
509
  end
510
+ d2.instance.flush_emit(120)
498
511
  end
499
- d2.instance.flush_emit(120)
500
- emits = d2.emits
501
- assert_equal 1, emits.length
502
- data = emits[0]
512
+ events = d2.events
513
+ assert_equal 1, events.length
514
+ data = events[0]
503
515
  assert_equal 'd.all', data[0] # tag
504
516
  assert_equal 120, data[2]['ok_count']
505
517
  assert_equal 1.0, data[2]['ok_rate']
@@ -519,18 +531,18 @@ class DataCounterOutputTest < Test::Unit::TestCase
519
531
  outcast_unmatched yes
520
532
  output_per_tag yes
521
533
  tag_prefix d
522
- ], 'test.tag2')
523
- d3.run do
534
+ ])
535
+ d3.run(default_tag: 'test.tag2') do
524
536
  60.times do
525
- d3.emit({'target' => '200'})
526
- d3.emit({'target' => '300'})
527
- d3.emit({'target' => '400'})
537
+ d3.feed({'target' => '200'})
538
+ d3.feed({'target' => '300'})
539
+ d3.feed({'target' => '400'})
528
540
  end
541
+ d3.instance.flush_emit(180)
529
542
  end
530
- d3.instance.flush_emit(180)
531
- emits = d3.emits
532
- assert_equal 1, emits.length
533
- data = emits[0]
543
+ events = d3.events
544
+ assert_equal 1, events.length
545
+ data = events[0]
534
546
  assert_equal 'd.tag2', data[0] # tag
535
547
  assert_equal 60, data[2]['unmatched_count']
536
548
  assert_nil data[2]['unmatched_percentage']
@@ -547,18 +559,18 @@ class DataCounterOutputTest < Test::Unit::TestCase
547
559
  outcast_unmatched true
548
560
  output_per_tag yes
549
561
  tag_prefix ddd
550
- ], 'test.tag2')
551
- d3.run do
562
+ ])
563
+ d3.run(default_tag: 'test.tag2') do
552
564
  60.times do
553
- d3.emit({'target' => '200'})
554
- d3.emit({'target' => '300'})
555
- d3.emit({'target' => '400'})
565
+ d3.feed({'target' => '200'})
566
+ d3.feed({'target' => '300'})
567
+ d3.feed({'target' => '400'})
556
568
  end
569
+ d3.instance.flush_emit(180)
557
570
  end
558
- d3.instance.flush_emit(180)
559
- emits = d3.emits
560
- assert_equal 1, emits.length
561
- data = emits[0]
571
+ events = d3.events
572
+ assert_equal 1, events.length
573
+ data = events[0]
562
574
  assert_equal 'ddd.all', data[0] # tag
563
575
  assert_equal 60, data[2]['unmatched_count']
564
576
  assert_nil data[2]['unmatched_percentage']
@@ -576,7 +588,7 @@ class DataCounterOutputTest < Test::Unit::TestCase
576
588
  ['count', 'rate'].map{|a| p + '_' + a}
577
589
  }.flatten
578
590
 
579
- d = create_driver(CONFIG, 'test.tag1')
591
+ d = create_driver(CONFIG)
580
592
  # CONFIG = %[
581
593
  # unit minute
582
594
  # aggregate tag
@@ -587,27 +599,27 @@ class DataCounterOutputTest < Test::Unit::TestCase
587
599
  # pattern3 status4xx ^4\\d\\d$
588
600
  # pattern4 status5xx ^5\\d\\d$
589
601
  # ]
590
- d.run do
602
+ d.run(default_tag: 'test.tag1') do
591
603
  60.times do
592
- d.emit({'target' => '200'})
593
- d.emit({'target' => '100'})
594
- d.emit({'target' => '200'})
595
- d.emit({'target' => '400'})
604
+ d.feed({'target' => '200'})
605
+ d.feed({'target' => '100'})
606
+ d.feed({'target' => '200'})
607
+ d.feed({'target' => '400'})
596
608
  end
609
+ d.instance.flush_emit(60)
610
+ assert_equal 1, d.events.size
611
+ r1 = d.events[0][2]
612
+ assert_equal fields, r1.keys
613
+
614
+ d.instance.flush_emit(60)
615
+ assert_equal 2, d.events.size # +1
616
+ r2 = d.events[1][2]
617
+ assert_equal fields_without_percentage, r2.keys
618
+ assert_equal [0]*10, r2.values
619
+
620
+ d.instance.flush_emit(60)
621
+ assert_equal 2, d.events.size # +0
597
622
  end
598
- d.instance.flush_emit(60)
599
- assert_equal 1, d.emits.size
600
- r1 = d.emits[0][2]
601
- assert_equal fields, r1.keys
602
-
603
- d.instance.flush_emit(60)
604
- assert_equal 2, d.emits.size # +1
605
- r2 = d.emits[1][2]
606
- assert_equal fields_without_percentage, r2.keys
607
- assert_equal [0]*10, r2.values
608
-
609
- d.instance.flush_emit(60)
610
- assert_equal 2, d.emits.size # +0
611
623
  end
612
624
  def test_zer_tags_per_tag
613
625
  fields = (['unmatched','status2xx','status3xx','status4xx','status5xx'].map{|p|
@@ -617,7 +629,7 @@ class DataCounterOutputTest < Test::Unit::TestCase
617
629
  ['count', 'rate'].map{|a| p + '_' + a}
618
630
  }.flatten + ['messages']).sort
619
631
 
620
- d = create_driver(CONFIG_OUTPUT_PER_TAG, 'test.tag1')
632
+ d = create_driver(CONFIG_OUTPUT_PER_TAG)
621
633
  # CONFIG_OUTPUT_PER_TAG = %[
622
634
  # unit minute
623
635
  # aggregate tag
@@ -631,84 +643,99 @@ class DataCounterOutputTest < Test::Unit::TestCase
631
643
  # pattern4 status5xx ^5\\d\\d$
632
644
  # output_messages yes
633
645
  # ]
634
- d.run do
646
+ d.run(default_tag: 'test.tag1') do
635
647
  60.times do
636
- d.emit({'target' => '200'})
637
- d.emit({'target' => '100'})
638
- d.emit({'target' => '200'})
639
- d.emit({'target' => '400'})
648
+ d.feed({'target' => '200'})
649
+ d.feed({'target' => '100'})
650
+ d.feed({'target' => '200'})
651
+ d.feed({'target' => '400'})
640
652
  end
653
+ d.instance.flush_emit(60)
654
+ assert_equal 1, d.events.size
655
+ r1 = d.events[0][2]
656
+ assert_equal fields, r1.keys.sort
657
+
658
+ d.instance.flush_emit(60)
659
+ assert_equal 2, d.events.size # +1
660
+ r2 = d.events[1][2]
661
+ assert_equal fields_without_percentage, r2.keys.sort
662
+ assert_equal [0]*11, r2.values # (_count, _rate)x5 + messages
663
+
664
+ d.instance.flush_emit(60)
665
+ assert_equal 2, d.events.size # +0
641
666
  end
642
- d.instance.flush_emit(60)
643
- assert_equal 1, d.emits.size
644
- r1 = d.emits[0][2]
645
- assert_equal fields, r1.keys.sort
646
-
647
- d.instance.flush_emit(60)
648
- assert_equal 2, d.emits.size # +1
649
- r2 = d.emits[1][2]
650
- assert_equal fields_without_percentage, r2.keys.sort
651
- assert_equal [0]*11, r2.values # (_count, _rate)x5 + messages
652
-
653
- d.instance.flush_emit(60)
654
- assert_equal 2, d.emits.size # +0
655
667
  end
656
668
 
657
- def test_store_file
669
+ def test_store_storage
658
670
  dir = "test/tmp"
659
671
  Dir.mkdir dir unless Dir.exist? dir
660
- file = "#{dir}/test.dat"
661
- File.unlink file if File.exist? file
662
-
672
+ storage_path = "#{dir}/test.dat"
673
+ FileUtils.rm_rf(storage_path)
674
+
675
+ config = {
676
+ "unit" => "minute",
677
+ "aggregate" => "tag",
678
+ "input_tag_remove_prefix" => "test",
679
+ "count_key" => " target",
680
+ "pattern1" => "status2xx ^2\\d\\d$",
681
+ "pattern2" => "status3xx ^3\\d\\d$",
682
+ "pattern3" => "status4xx ^4\\d\\d$",
683
+ "pattern4" => "status5xx ^5\\d\\d$",
684
+ "store_storage" => true
685
+ }
686
+ storage_conf = config_element('storage', 'resume', {'@type' => 'local', '@id' => 'test-01', 'path' => storage_path, 'persistent' => 'true'})
687
+ conf = config_element('ROOT', '', config, [storage_conf])
663
688
  # test store
664
- d = create_driver(CONFIG + %[store_file #{file}])
665
- d.run do
689
+ d = create_driver(conf)
690
+ time = Fluent::Engine.now
691
+ d.run(default_tag: 'test.input') do
666
692
  d.instance.flush_emit(60)
667
- d.emit({'target' => 1})
668
- d.emit({'target' => 1})
669
- d.emit({'target' => 1})
670
- d.instance.shutdown
693
+ d.feed(time, {'target' => 1})
694
+ d.feed(time, {'target' => 1})
695
+ d.feed(time, {'target' => 1})
671
696
  end
672
697
  stored_counts = d.instance.counts
673
698
  stored_saved_at = d.instance.saved_at
674
699
  stored_saved_duration = d.instance.saved_duration
675
- assert File.exist? file
700
+ assert File.exist?(storage_path)
676
701
 
677
702
  # test load
678
- d = create_driver(CONFIG + %[store_file #{file}])
679
- d.run do
703
+ d = create_driver(conf)
704
+ loaded_counts = {}
705
+ loaded_saved_at = nil
706
+ loaded_saved_duration = nil
707
+ d.run(default_tag: 'test.input') do
680
708
  loaded_counts = d.instance.counts
681
709
  loaded_saved_at = d.instance.saved_at
682
710
  loaded_saved_duration = d.instance.saved_duration
683
- assert_equal stored_counts, loaded_counts
684
- assert_equal stored_saved_at, loaded_saved_at
685
- assert_equal stored_saved_duration, loaded_saved_duration
686
711
  end
712
+ assert_equal stored_counts, loaded_counts
713
+ assert_equal stored_saved_at, loaded_saved_at
714
+ assert_equal stored_saved_duration, loaded_saved_duration
687
715
 
688
716
  # test not to load if config is changed
689
- d = create_driver(CONFIG + %[count_key foobar store_file #{file}])
690
- d.run do
717
+ d = create_driver(conf.merge("count_key" => "foobar", "store_storage" => true))
718
+ d.run(default_tag: 'test.input') do
691
719
  loaded_counts = d.instance.counts
692
720
  loaded_saved_at = d.instance.saved_at
693
721
  loaded_saved_duration = d.instance.saved_duration
694
- assert_equal({}, loaded_counts)
695
- assert_equal(nil, loaded_saved_at)
696
- assert_equal(nil, loaded_saved_duration)
697
722
  end
723
+ assert_equal({}, loaded_counts)
724
+ assert_equal(nil, loaded_saved_at)
725
+ assert_equal(nil, loaded_saved_duration)
698
726
 
699
727
  # test not to load if stored data is outdated.
700
- Delorean.jump 61 # jump more than count_interval
701
- d = create_driver(CONFIG + %[store_file #{file}])
702
- d.run do
728
+ Timecop.freeze(Time.now + 61) # jump more than count_interval
729
+ d = create_driver(conf.merge("store_storage" => true))
730
+ d.run(default_tag: 'test.input') do
703
731
  loaded_counts = d.instance.counts
704
732
  loaded_saved_at = d.instance.saved_at
705
733
  loaded_saved_duration = d.instance.saved_duration
706
- assert_equal({}, loaded_counts)
707
- assert_equal(nil, loaded_saved_at)
708
- assert_equal(nil, loaded_saved_duration)
709
734
  end
710
- Delorean.back_to_the_present
735
+ assert_equal({}, loaded_counts)
736
+ assert_equal(nil, loaded_saved_at)
737
+ assert_equal(nil, loaded_saved_duration)
711
738
 
712
- File.unlink file
739
+ FileUtils.rm_rf(storage_path)
713
740
  end
714
741
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-datacounter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - TAGOMORI Satoshi
@@ -14,16 +14,22 @@ dependencies:
14
14
  name: fluentd
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.14.8
17
20
  - - "<"
18
21
  - !ruby/object:Gem::Version
19
- version: 0.14.0
22
+ version: '2'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 0.14.8
24
30
  - - "<"
25
31
  - !ruby/object:Gem::Version
26
- version: 0.14.0
32
+ version: '2'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: bundler
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -67,7 +73,7 @@ dependencies:
67
73
  - !ruby/object:Gem::Version
68
74
  version: '0'
69
75
  - !ruby/object:Gem::Dependency
70
- name: delorean
76
+ name: timecop
71
77
  requirement: !ruby/object:Gem::Requirement
72
78
  requirements:
73
79
  - - ">="