fluent-plugin-numeric-monitor 0.1.4 → 0.1.5

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f0e34e02fb3c60ee05565ff9e7ed9c31bbf1f677
4
+ data.tar.gz: b74595ed3a9194bb3da3f21d8d47749b97059bcd
5
+ SHA512:
6
+ metadata.gz: 9031f88688412a012a965d9240639e51c65716bcc5248085c8bdff1e85bcde52b8b12d3703df11442464427a5b9c1459c26d8bfec907a60ec18fdfe62d72e21f
7
+ data.tar.gz: 9ee81f7dfbe2483631df14dbea7553cced143f62c5631d23c25386cc1dcd6c669aa7b92fd59870b23a1c380090293031d44a9c6a9ee9c68ca2e71c22c8d8e31b
data/README.md CHANGED
@@ -26,6 +26,54 @@ Output messages like:
26
26
 
27
27
  {"min":3012,"max":913243,"avg":100123.51,"percentile_90":154390,"percentile_95":223110,"num":50012}
28
28
 
29
+
30
+ ## Parameters
31
+
32
+ * monitor\_key (required)
33
+
34
+ The key to monitor in the event record.
35
+
36
+ * percentiles
37
+
38
+ Activate the percentile monitoring. Must be specified between `1` and `99` by integer separeted by , (comma).
39
+
40
+ * tag
41
+
42
+ The output tag. Default is `monitor`.
43
+
44
+ * tag\_prefix
45
+
46
+ The prefix string which will be added to the input tag. `output_per_tag yes` must be specified together.
47
+
48
+ * input\_tag\_remove\_prefix
49
+
50
+ The prefix string which will be removed from the input tag.
51
+
52
+ * count\_interval
53
+
54
+ The interval time to monitor in seconds. Default is `60`.
55
+
56
+ * unit
57
+
58
+ The interval time to monitor specified an unit (either of `minute`, `hour`, or `day`).
59
+ Use either of `count_interval` or `unit`.
60
+
61
+ * aggregate
62
+
63
+ Calculate in each input `tag` separetely, or `all` records in a mass. Default is `tag`
64
+
65
+ * ouput\_per\_tag
66
+
67
+ Emit for each input tag. `tag_prefix` must be specified together. Default is `no`.
68
+
69
+ * output\_key\_prefix
70
+
71
+ The prefix string which will be added to the output key.
72
+
73
+ * samples\_limit
74
+
75
+ The limit number of sampling. Default is `1000000`.
76
+
29
77
  ## TODO
30
78
 
31
79
  * more tests
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |gem|
3
3
  gem.name = "fluent-plugin-numeric-monitor"
4
- gem.version = "0.1.4"
4
+ gem.version = "0.1.5"
5
5
  gem.authors = ["TAGOMORI Satoshi"]
6
6
  gem.email = ["tagomoris@gmail.com"]
7
7
  gem.description = %q{Fluentd plugin to calculate min/max/avg/Xpercentile values, and emit these data as message}
@@ -6,7 +6,9 @@ class Fluent::NumericMonitorOutput < Fluent::Output
6
6
  config_param :count_interval, :time, :default => 60
7
7
  config_param :unit, :string, :default => nil
8
8
  config_param :tag, :string, :default => 'monitor'
9
+ config_param :tag_prefix, :string, :default => nil
9
10
 
11
+ config_param :output_per_tag, :bool, :default => false
10
12
  config_param :aggregate, :default => 'tag' do |val|
11
13
  case val
12
14
  when 'tag' then :tag
@@ -17,6 +19,7 @@ class Fluent::NumericMonitorOutput < Fluent::Output
17
19
  end
18
20
  config_param :input_tag_remove_prefix, :string, :default => nil
19
21
  config_param :monitor_key, :string
22
+ config_param :output_key_prefix, :string, :default => nil
20
23
  config_param :percentiles, :default => nil do |val|
21
24
  values = val.split(",").map(&:to_i)
22
25
  if values.select{|i| i < 1 or i > 99 }.size > 0
@@ -46,6 +49,16 @@ class Fluent::NumericMonitorOutput < Fluent::Output
46
49
  @removed_prefix_string = @input_tag_remove_prefix + '.'
47
50
  @removed_length = @removed_prefix_string.length
48
51
  end
52
+
53
+ @key_prefix_string = ''
54
+ if @output_key_prefix
55
+ @key_prefix_string = @output_key_prefix + '_'
56
+ end
57
+
58
+ if (@output_per_tag || @tag_prefix) && (!@output_per_tag || !@tag_prefix)
59
+ raise Fluent::ConfigError, 'Specify both of output_per_tag and tag_prefix'
60
+ end
61
+ @tag_prefix_string = @tag_prefix + '.' if @output_per_tag
49
62
 
50
63
  @count = count_initialized
51
64
  @mutex = Mutex.new
@@ -106,42 +119,46 @@ class Fluent::NumericMonitorOutput < Fluent::Output
106
119
  tag
107
120
  end
108
121
 
109
- def generate_output(count)
110
- output = {}
111
- if @aggregate == :all
112
- c = count['all']
113
- if c[:num] then output['num'] = c[:num] end
114
- if c[:min] then output['min'] = c[:min] end
115
- if c[:max] then output['max'] = c[:max] end
116
- if c[:num] > 0 then output['avg'] = (c[:sum] * 100.0 / (c[:num] * 1.0)).round / 100.0 end
117
- if @percentiles
118
- sorted = c[:sample].sort
119
- @percentiles.each do |p|
120
- i = (c[:num] * p / 100).floor
121
- if i > 0
122
- i -= 1
123
- end
124
- output["percentile_#{p}"] = sorted[i]
122
+ def generate_fields(count, key_prefix = '', output = {})
123
+ output[key_prefix + 'num'] = count[:num] if count[:num]
124
+ output[key_prefix + 'min'] = count[:min] if count[:min]
125
+ output[key_prefix + 'max'] = count[:max] if count[:max]
126
+ output[key_prefix + 'avg'] = (count[:sum] / (count[:num] * 1.0)) if count[:num] > 0
127
+ if @percentiles
128
+ sorted = count[:sample].sort
129
+ @percentiles.each do |p|
130
+ i = (count[:num] * p / 100).floor
131
+ if i > 0
132
+ i -= 1
125
133
  end
134
+ output[key_prefix + "percentile_#{p}"] = sorted[i]
126
135
  end
127
- return output
128
136
  end
137
+ output
138
+ end
129
139
 
130
- count.keys.each do |tag|
131
- t = stripped_tag(tag)
132
- c = count[tag]
133
- if c[:num] then output[t + '_num'] = c[:num] end
134
- if c[:min] then output[t + '_min'] = c[:min] end
135
- if c[:max] then output[t + '_max'] = c[:max] end
136
- if c[:num] > 0 then output[t + '_avg'] = (c[:sum] * 100.0 / (c[:num] * 1.0)).round / 100.0 end
137
- if @percentiles
138
- sorted = c[:sample].sort
139
- @percentiles.each do |p|
140
- i = (c[:num] * p / 100).floor
141
- if i > 0
142
- i -= 1
143
- end
144
- output[t + "_percentile_#{p}"] = sorted[i]
140
+ def generate_output(count)
141
+ if @aggregate == :all
142
+ if @output_per_tag
143
+ # tag_prefix_all: { 'key_prefix_min' => -10, 'key_prefix_max' => 10, ... } }
144
+ output = {'all' => generate_fields(count['all'], @key_prefix_string)}
145
+ else
146
+ # tag: { 'key_prefix_min' => -10, 'key_prefix_max' => 10, ... }
147
+ output = generate_fields(count['all'], @key_prefix_string)
148
+ end
149
+ else
150
+ output = {}
151
+ if @output_per_tag
152
+ # tag_prefix_tag1: { 'key_prefix_min' => -10, 'key_prefix_max' => 10, ... }
153
+ # tag_prefix_tag2: { 'key_prefix_min' => -10, 'key_prefix_max' => 10, ... }
154
+ count.keys.each do |tag|
155
+ output[stripped_tag(tag)] = generate_fields(count[tag], @key_prefix_string)
156
+ end
157
+ else
158
+ # tag: { 'key_prefix_tag1_min' => -10, 'key_prefix_tag1_max' => 10, ..., 'key_prefix_tag2_min' => -10, 'key_prefix_tag2_max' => 10, ... }
159
+ count.keys.each do |tag|
160
+ key_prefix = @key_prefix_string + stripped_tag(tag) + '_'
161
+ generate_fields(count[tag], key_prefix, output)
145
162
  end
146
163
  end
147
164
  end
@@ -154,7 +171,14 @@ class Fluent::NumericMonitorOutput < Fluent::Output
154
171
  end
155
172
 
156
173
  def flush_emit
157
- Fluent::Engine.emit(@tag, Fluent::Engine.now, flush)
174
+ if @output_per_tag
175
+ time = Fluent::Engine.now
176
+ flush.each do |tag, message|
177
+ Fluent::Engine.emit(@tag_prefix_string + tag, time, message)
178
+ end
179
+ else
180
+ Fluent::Engine.emit(@tag, Fluent::Engine.now, flush)
181
+ end
158
182
  end
159
183
 
160
184
  def countups(tag, min, max, sum, num, sample)
@@ -18,6 +18,19 @@ class NumericMonitorOutputTest < Test::Unit::TestCase
18
18
  end
19
19
 
20
20
  def test_configure
21
+ assert_raise(Fluent::ConfigError) {
22
+ d = create_driver('')
23
+ }
24
+ assert_raise(Fluent::ConfigError) {
25
+ d = create_driver CONFIG + %[
26
+ output_per_tag true
27
+ ]
28
+ }
29
+ assert_raise(Fluent::ConfigError) {
30
+ d = create_driver CONFIG + %[
31
+ tag_prefix prefix
32
+ ]
33
+ }
21
34
  #TODO
22
35
  end
23
36
 
@@ -115,4 +128,228 @@ class NumericMonitorOutputTest < Test::Unit::TestCase
115
128
  assert_equal 2, r['test_avg']
116
129
  assert_equal 3, r['test_num']
117
130
  end
131
+
132
+ def test_output_per_tag
133
+ d = create_driver(CONFIG + %[
134
+ aggregate tag
135
+ output_per_tag true
136
+ tag_prefix tag_prefix
137
+ ], 'tag')
138
+ d.run do
139
+ d.tag = 'tag1'
140
+ d.emit({'field1' => 1})
141
+ d.emit({'field1' => 2})
142
+ d.emit({'field1' => 3})
143
+ d.tag = 'tag2'
144
+ d.emit({'field1' => 1})
145
+ d.emit({'field1' => 2})
146
+ d.emit({'field1' => 3})
147
+ end
148
+ d.instance.flush_emit
149
+ assert_equal 2, d.emits.size
150
+ tag, r = d.emits[0][0], d.emits[0][2]
151
+ assert_equal 'tag_prefix.tag1', tag
152
+ assert_equal 1, r['min']
153
+ assert_equal 3, r['max']
154
+ assert_equal 2, r['avg']
155
+ assert_equal 3, r['num']
156
+ tag, r = d.emits[1][0], d.emits[1][2]
157
+ assert_equal 'tag_prefix.tag2', tag
158
+ assert_equal 1, r['min']
159
+ assert_equal 3, r['max']
160
+ assert_equal 2, r['avg']
161
+ assert_equal 3, r['num']
162
+
163
+ d = create_driver(CONFIG + %[
164
+ aggregate tag
165
+ output_per_tag false
166
+ tag output_tag
167
+ ], 'tag')
168
+ d.run do
169
+ d.tag = 'tag1'
170
+ d.emit({'field1' => 1})
171
+ d.emit({'field1' => 2})
172
+ d.emit({'field1' => 3})
173
+ d.tag = 'tag2'
174
+ d.emit({'field1' => 1})
175
+ d.emit({'field1' => 2})
176
+ d.emit({'field1' => 3})
177
+ end
178
+ d.instance.flush_emit
179
+ assert_equal 1, d.emits.size
180
+ tag, r = d.emits[0][0], d.emits[0][2]
181
+ assert_equal 'output_tag', tag
182
+ assert_equal 1, r['tag1_min']
183
+ assert_equal 3, r['tag1_max']
184
+ assert_equal 2, r['tag1_avg']
185
+ assert_equal 3, r['tag1_num']
186
+ assert_equal 1, r['tag2_min']
187
+ assert_equal 3, r['tag2_max']
188
+ assert_equal 2, r['tag2_avg']
189
+ assert_equal 3, r['tag2_num']
190
+
191
+ d = create_driver(CONFIG + %[
192
+ aggregate all
193
+ output_per_tag true
194
+ tag_prefix tag_prefix
195
+ ], 'tag')
196
+ d.run do
197
+ d.tag = 'tag1'
198
+ d.emit({'field1' => 1})
199
+ d.emit({'field1' => 2})
200
+ d.emit({'field1' => 3})
201
+ d.tag = 'tag2'
202
+ d.emit({'field1' => 1})
203
+ d.emit({'field1' => 2})
204
+ d.emit({'field1' => 3})
205
+ end
206
+ d.instance.flush_emit
207
+ assert_equal 1, d.emits.size
208
+ tag = d.emits[0][0]
209
+ r = d.emits[0][2]
210
+ assert_equal 'tag_prefix.all', tag
211
+ assert_equal 1, r['min']
212
+ assert_equal 3, r['max']
213
+ assert_equal 2, r['avg']
214
+ assert_equal 6, r['num']
215
+
216
+ d = create_driver(CONFIG + %[
217
+ aggregate all
218
+ output_per_tag false
219
+ tag output_tag
220
+ ], 'tag')
221
+ d.run do
222
+ d.tag = 'tag1'
223
+ d.emit({'field1' => 1})
224
+ d.emit({'field1' => 2})
225
+ d.emit({'field1' => 3})
226
+ d.tag = 'tag2'
227
+ d.emit({'field1' => 1})
228
+ d.emit({'field1' => 2})
229
+ d.emit({'field1' => 3})
230
+ end
231
+ d.instance.flush_emit
232
+ assert_equal 1, d.emits.size
233
+ tag = d.emits[0][0]
234
+ r = d.emits[0][2]
235
+ assert_equal 'output_tag', tag
236
+ assert_equal 1, r['min']
237
+ assert_equal 3, r['max']
238
+ assert_equal 2, r['avg']
239
+ assert_equal 6, r['num']
240
+ end
241
+
242
+ def test_output_key_prefix
243
+ d = create_driver(CONFIG + %[
244
+ aggregate tag
245
+ output_per_tag true
246
+ tag_prefix tag_prefix
247
+ output_key_prefix key_prefix
248
+ ], 'tag')
249
+ d.run do
250
+ d.tag = 'tag1'
251
+ d.emit({'field1' => 1})
252
+ d.emit({'field1' => 2})
253
+ d.emit({'field1' => 3})
254
+ d.tag = 'tag2'
255
+ d.emit({'field1' => 1})
256
+ d.emit({'field1' => 2})
257
+ d.emit({'field1' => 3})
258
+ end
259
+ d.instance.flush_emit
260
+ assert_equal 2, d.emits.size
261
+ tag, r = d.emits[0][0], d.emits[0][2]
262
+ assert_equal 'tag_prefix.tag1', tag
263
+ assert_equal 1, r['key_prefix_min']
264
+ assert_equal 3, r['key_prefix_max']
265
+ assert_equal 2, r['key_prefix_avg']
266
+ assert_equal 3, r['key_prefix_num']
267
+ tag, r = d.emits[1][0], d.emits[1][2]
268
+ assert_equal 'tag_prefix.tag2', tag
269
+ assert_equal 1, r['key_prefix_min']
270
+ assert_equal 3, r['key_prefix_max']
271
+ assert_equal 2, r['key_prefix_avg']
272
+ assert_equal 3, r['key_prefix_num']
273
+
274
+ d = create_driver(CONFIG + %[
275
+ aggregate tag
276
+ output_per_tag false
277
+ tag output_tag
278
+ output_key_prefix key_prefix
279
+ ], 'tag')
280
+ d.run do
281
+ d.tag = 'tag1'
282
+ d.emit({'field1' => 1})
283
+ d.emit({'field1' => 2})
284
+ d.emit({'field1' => 3})
285
+ d.tag = 'tag2'
286
+ d.emit({'field1' => 1})
287
+ d.emit({'field1' => 2})
288
+ d.emit({'field1' => 3})
289
+ end
290
+ d.instance.flush_emit
291
+ assert_equal 1, d.emits.size
292
+ tag, r = d.emits[0][0], d.emits[0][2]
293
+ assert_equal 'output_tag', tag
294
+ assert_equal 1, r['key_prefix_tag1_min']
295
+ assert_equal 3, r['key_prefix_tag1_max']
296
+ assert_equal 2, r['key_prefix_tag1_avg']
297
+ assert_equal 3, r['key_prefix_tag1_num']
298
+ assert_equal 1, r['key_prefix_tag2_min']
299
+ assert_equal 3, r['key_prefix_tag2_max']
300
+ assert_equal 2, r['key_prefix_tag2_avg']
301
+ assert_equal 3, r['key_prefix_tag2_num']
302
+
303
+ d = create_driver(CONFIG + %[
304
+ aggregate all
305
+ output_per_tag true
306
+ tag_prefix tag_prefix
307
+ output_key_prefix key_prefix
308
+ ], 'tag')
309
+ d.run do
310
+ d.tag = 'tag1'
311
+ d.emit({'field1' => 1})
312
+ d.emit({'field1' => 2})
313
+ d.emit({'field1' => 3})
314
+ d.tag = 'tag2'
315
+ d.emit({'field1' => 1})
316
+ d.emit({'field1' => 2})
317
+ d.emit({'field1' => 3})
318
+ end
319
+ d.instance.flush_emit
320
+ assert_equal 1, d.emits.size
321
+ tag = d.emits[0][0]
322
+ r = d.emits[0][2]
323
+ assert_equal 'tag_prefix.all', tag
324
+ assert_equal 1, r['key_prefix_min']
325
+ assert_equal 3, r['key_prefix_max']
326
+ assert_equal 2, r['key_prefix_avg']
327
+ assert_equal 6, r['key_prefix_num']
328
+
329
+ d = create_driver(CONFIG + %[
330
+ aggregate all
331
+ output_per_tag false
332
+ tag output_tag
333
+ output_key_prefix key_prefix
334
+ ], 'tag')
335
+ d.run do
336
+ d.tag = 'tag1'
337
+ d.emit({'field1' => 1})
338
+ d.emit({'field1' => 2})
339
+ d.emit({'field1' => 3})
340
+ d.tag = 'tag2'
341
+ d.emit({'field1' => 1})
342
+ d.emit({'field1' => 2})
343
+ d.emit({'field1' => 3})
344
+ end
345
+ d.instance.flush_emit
346
+ assert_equal 1, d.emits.size
347
+ tag = d.emits[0][0]
348
+ r = d.emits[0][2]
349
+ assert_equal 'output_tag', tag
350
+ assert_equal 1, r['key_prefix_min']
351
+ assert_equal 3, r['key_prefix_max']
352
+ assert_equal 2, r['key_prefix_avg']
353
+ assert_equal 6, r['key_prefix_num']
354
+ end
118
355
  end
metadata CHANGED
@@ -1,46 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-numeric-monitor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
5
- prerelease:
4
+ version: 0.1.5
6
5
  platform: ruby
7
6
  authors:
8
7
  - TAGOMORI Satoshi
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-04-08 00:00:00.000000000 Z
11
+ date: 2013-06-07 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rake
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: fluentd
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  description: Fluentd plugin to calculate min/max/avg/Xpercentile values, and emit
@@ -62,27 +57,26 @@ files:
62
57
  - test/plugin/test_out_numeric_monitor.rb
63
58
  homepage: https://github.com/tagomoris/fluent-plugin-numeric-monitor
64
59
  licenses: []
60
+ metadata: {}
65
61
  post_install_message:
66
62
  rdoc_options: []
67
63
  require_paths:
68
64
  - lib
69
65
  required_ruby_version: !ruby/object:Gem::Requirement
70
- none: false
71
66
  requirements:
72
- - - ! '>='
67
+ - - '>='
73
68
  - !ruby/object:Gem::Version
74
69
  version: '0'
75
70
  required_rubygems_version: !ruby/object:Gem::Requirement
76
- none: false
77
71
  requirements:
78
- - - ! '>='
72
+ - - '>='
79
73
  - !ruby/object:Gem::Version
80
74
  version: '0'
81
75
  requirements: []
82
76
  rubyforge_project:
83
- rubygems_version: 1.8.23
77
+ rubygems_version: 2.0.2
84
78
  signing_key:
85
- specification_version: 3
79
+ specification_version: 4
86
80
  summary: Fluentd plugin to calculate min/max/avg/Xpercentile values
87
81
  test_files:
88
82
  - test/helper.rb