fluent-plugin-datacounter 0.5.0 → 1.0.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: 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
  - - ">="