fluent-plugin-growthforecast 0.2.2 → 0.2.3

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: 4e4201bfd9823a61a81953e23c02a50ab12cf654
4
- data.tar.gz: 6fcb119c643d549cd18e962207cad1c9c0d890c7
3
+ metadata.gz: ce309fd9162a5d30d1a24cfaed6c72feb607ecbe
4
+ data.tar.gz: 649824e492f0132967303c1d0f7400c1bdcab98c
5
5
  SHA512:
6
- metadata.gz: 1a4f51b1fac0d9490ce105641baa1cf3ff49ce7d897eed6015153fcce9db804866ff19f443e0a73ad32919e9ed788feede39edce5d9824f9b1a7447eb0ac8ead
7
- data.tar.gz: 05aff06da6206939ab35f19584507f1f453058bea42c4758337da7b998392b4af198966b7eacaa728da1f3ba2886981cc748855dfbba4b54b6b1f6032a299da5
6
+ metadata.gz: 2301b6ce097f7ff46d55a0e972574a5d8b0ba57f2555be7d575bc936b40cfa8f2c394e3d6c2196c3dc77c97339a3cf90c5dbbe8f60fc1d959ed52e393c6e9f72
7
+ data.tar.gz: 16de04d7a45a0810db0da6de6bb521082899cf488808baa60aa8cd1af2d20ba3693c57191b2bfc77170b82572d4d5357b6991a93a0a07768b09a32e5999bcdf6
data/README.md CHANGED
@@ -82,6 +82,92 @@ Version v0.2.0 or later, this plugin uses HTTP connection keep-alive for a batch
82
82
  keepalive no
83
83
  </match>
84
84
 
85
+ ## Parameters
86
+
87
+ * gfapi\_url (required)
88
+
89
+ The URL of a GrowthForecast API endpoint like `http://growth.forecast.local/api/`.
90
+
91
+ * tag\_for
92
+
93
+ Either of `name_prefix`, `section`, `service`, or `ignore`. Default is `name_prefix`.
94
+
95
+ * `name_prefix` uses the tag name as a graph\_name prefix.
96
+ * `section` uses the tag name as a section\_name.
97
+ * `service` uses the tag name as a service\_name.
98
+ * `ignore` uses the tag name for nothing.
99
+
100
+ * remove\_prefix
101
+
102
+ The prefix string which will be removed from the tag. This option would be useful using with the `tag_for` option.
103
+
104
+ * service
105
+
106
+ The service\_name of graphs to create.
107
+
108
+ * section
109
+
110
+ The section\_name of graphs to create.
111
+
112
+ * name\_keys
113
+
114
+ Specify field names of the input record. Separate by , (comma).
115
+ The values of these fields are posted as numbers, and names of thease fields are used as parts of grame\_names.
116
+ Either of `name_keys` or `name_key_pattern` is required.
117
+
118
+ * name\_key\_pattern
119
+
120
+ Specify the field names of the input record by a regular expression.
121
+ The values of these fields are posted as numbers, and names of thease fields are used as parts of grame\_names.
122
+ Either of `name_keys` or `name_key_pattern` is required.
123
+
124
+ * graphs
125
+
126
+ You may use this option to specify graph names correspond to each of `name_keys`. Separate by , (comma).
127
+ The number of graph names must be same with the number of `name_keys`.
128
+
129
+ * mode
130
+
131
+ The graph mode (either of `gauge`, `count`, or `modified`). Just same as `mode` of GrowthForecast POST parameter. Default is `gauge`.
132
+
133
+ * keepalive
134
+
135
+ Use a keepalive HTTP connection. Default is false.
136
+
137
+ NOTE: To effectively use this, you may need to give a parameter `max_keepalive_reqs` (default: 1) to Starlet in `growthforecast.pl`.
138
+
139
+ * background_post
140
+
141
+ Post to GrowthForecast in background thread, without retries for failures (Default: false)
142
+
143
+ * timeout
144
+
145
+ Read/Write timeout seconds (Default: 60)
146
+
147
+ * retry
148
+
149
+ Do retry for HTTP request failures, or not. This feature will be set as false for `background_post yes` automatically. (Default: true)
150
+
151
+ * ssl
152
+
153
+ Use SSL (https) or not. Default is false.
154
+
155
+ * verify\_ssl
156
+
157
+ Do SSL verification or not. Default is false (ignore the SSL verification).
158
+
159
+ * authentication
160
+
161
+ Specify `basic` if your GrowthForecast protected with basic authentication. Default is 'none' (no authentication).
162
+
163
+ * username
164
+
165
+ The username for authentication.
166
+
167
+ * password
168
+
169
+ The password for authentication.
170
+
85
171
  ## TODO
86
172
 
87
173
  * patches welcome!
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = "fluent-plugin-growthforecast"
5
- gem.version = "0.2.2"
5
+ gem.version = "0.2.3"
6
6
  gem.authors = ["TAGOMORI Satoshi"]
7
7
  gem.email = ["tagomoris@gmail.com"]
8
8
  gem.summary = %q{Fluentd output plugin to post numbers to GrowthForecast (by kazeburo)}
@@ -11,6 +11,7 @@ class Fluent::GrowthForecastOutput < Fluent::Output
11
11
  config_param :gfapi_url, :string # growth.forecast.local/api/
12
12
  config_param :service, :string, :default => nil
13
13
  config_param :section, :string, :default => nil
14
+ config_param :graphs, :string, :default => nil
14
15
 
15
16
  config_param :ssl, :bool, :default => false
16
17
  config_param :verify_ssl, :bool, :default => false
@@ -23,6 +24,10 @@ class Fluent::GrowthForecastOutput < Fluent::Output
23
24
  config_param :remove_prefix, :string, :default => nil
24
25
  config_param :tag_for, :string, :default => 'name_prefix' # or 'ignore' or 'section' or 'service'
25
26
 
27
+ config_param :background_post, :bool, :default => false
28
+
29
+ config_param :timeout, :integer, :default => nil # default 60secs
30
+ config_param :retry, :bool, :default => true
26
31
  config_param :keepalive, :bool, :default => true
27
32
 
28
33
  config_param :authentication, :string, :default => nil # nil or 'none' or 'basic'
@@ -42,6 +47,10 @@ class Fluent::GrowthForecastOutput < Fluent::Output
42
47
  if not @name_keys.nil? and not @name_key_pattern.nil?
43
48
  raise Fluent::ConfigError, "cannot specify both of name_keys and name_key_pattern"
44
49
  end
50
+ if not @graphs.nil? and @name_keys.nil?
51
+ raise Fluent::ConfigError, "graphs must be specified with name_keys"
52
+ end
53
+
45
54
  if @name_keys
46
55
  @name_keys = @name_keys.split(',')
47
56
  end
@@ -49,6 +58,13 @@ class Fluent::GrowthForecastOutput < Fluent::Output
49
58
  @name_key_pattern = Regexp.new(@name_key_pattern)
50
59
  end
51
60
 
61
+ if @graphs
62
+ @graphs = @graphs.split(',')
63
+ end
64
+ if @name_keys and @graphs and @name_keys.size != @graphs.size
65
+ raise Fluent::ConfigError, "sizes of name_keys and graphs do not match"
66
+ end
67
+
52
68
  @mode = case @mode
53
69
  when 'count' then :count
54
70
  when 'modified' then :modified
@@ -84,12 +100,43 @@ class Fluent::GrowthForecastOutput < Fluent::Output
84
100
 
85
101
  def start
86
102
  super
103
+
104
+ @running = true
105
+ @thread = nil
106
+ @queue = nil
107
+ @mutex = nil
108
+ if @background_post
109
+ @mutex = Mutex.new
110
+ @queue = []
111
+ @thread = Thread.new(&method(:poster))
112
+ end
87
113
  end
88
114
 
89
115
  def shutdown
116
+ @running = false
117
+ @thread.join if @thread
90
118
  super
91
119
  end
92
120
 
121
+ def poster
122
+ while @running
123
+ if @queue.size < 1
124
+ sleep(0.2)
125
+ next
126
+ end
127
+
128
+ events = @mutex.synchronize {
129
+ es,@queue = @queue,[]
130
+ es
131
+ }
132
+ begin
133
+ post_events(events) if events.size > 0
134
+ rescue => e
135
+ $log.warn "HTTP POST Error occures to growthforecast server", :error_class => e.class, :error => e.message
136
+ end
137
+ end
138
+ end
139
+
93
140
  def format_url(tag, name)
94
141
  if @remove_prefix and
95
142
  ( (tag.start_with?(@removed_prefix_string) and tag.length > @removed_length) or tag == @remove_prefix)
@@ -115,6 +162,10 @@ class Fluent::GrowthForecastOutput < Fluent::Output
115
162
 
116
163
  def http_connection(host, port)
117
164
  http = Net::HTTP.new(@resolver.getaddress(host), port)
165
+ if @timeout
166
+ http.open_timeout = @timeout
167
+ http.read_timeout = @timeout
168
+ end
118
169
  if @ssl
119
170
  http.use_ssl = true
120
171
  unless @verify_ssl
@@ -177,13 +228,23 @@ class Fluent::GrowthForecastOutput < Fluent::Output
177
228
  end
178
229
  end
179
230
 
231
+ def post_events(events)
232
+ if @keepalive
233
+ post_keepalive(events)
234
+ else
235
+ events.each do |event|
236
+ post(event[:tag], event[:name], event[:value])
237
+ end
238
+ end
239
+ end
240
+
180
241
  def emit(tag, es, chain)
181
242
  events = []
182
243
  if @name_keys
183
244
  es.each {|time,record|
184
- @name_keys.each {|name|
185
- if record[name]
186
- events.push({:tag => tag, :name => name, :value => record[name]})
245
+ @name_keys.each_with_index {|name, i|
246
+ if value = record[name]
247
+ events.push({:tag => tag, :name => (@graphs ? @graphs[i] : name), :value => value})
187
248
  end
188
249
  }
189
250
  }
@@ -196,11 +257,16 @@ class Fluent::GrowthForecastOutput < Fluent::Output
196
257
  }
197
258
  }
198
259
  end
199
- if @keepalive
200
- post_keepalive(events)
260
+ if @thread
261
+ @mutex.synchronize do
262
+ @queue += events
263
+ end
201
264
  else
202
- events.each do |event|
203
- post(event[:tag], event[:name], event[:value])
265
+ begin
266
+ post_events(events)
267
+ rescue => e
268
+ $log.warn "HTTP POST Error occures to growthforecast server", :error_class => e.class, :error => e.message
269
+ raise if @retry
204
270
  end
205
271
  end
206
272
 
@@ -55,6 +55,54 @@ class GrowthForecastOutputTest < Test::Unit::TestCase
55
55
  keepalive false
56
56
  ]
57
57
 
58
+ CONFIG_THREADING_KEEPALIVE = %[
59
+ gfapi_url http://127.0.0.1:5125/api/
60
+ service service
61
+ section metrics
62
+ name_keys field1,field2,otherfield
63
+ tag_for name_prefix
64
+ background_post true
65
+ keepalive true
66
+ timeout 120
67
+ ]
68
+
69
+ CONFIG_THREADING_NON_KEEPALIVE = %[
70
+ gfapi_url http://127.0.0.1:5125/api/
71
+ service service
72
+ section metrics
73
+ name_keys field1,field2,otherfield
74
+ tag_for name_prefix
75
+ background_post true
76
+ keepalive false
77
+ ]
78
+
79
+ CONFIG_BAD_GRAPHS = %[
80
+ gfapi_url http://127.0.0.1:5125/api/
81
+ service service
82
+ section metrics
83
+ name_keys field1,field2,otherfield
84
+ graphs graph1,graph2
85
+ tag_for name_prefix
86
+ ]
87
+
88
+ CONFIG_GRAPHS_WITHOUT_NAME_KEYS = %[
89
+ gfapi_url http://127.0.0.1:5125/api/
90
+ service service
91
+ section metrics
92
+ name_key_pattern ^(field|key)\\d+$
93
+ graphs graph1,graph2
94
+ tag_for name_prefix
95
+ ]
96
+
97
+ CONFIG_GRAPHS = %[
98
+ gfapi_url http://127.0.0.1:5125/api/
99
+ service service
100
+ section metrics
101
+ name_keys field1,field2,otherfield
102
+ graphs graph1,graph2,othergraph
103
+ tag_for name_prefix
104
+ ]
105
+
58
106
  def create_driver(conf=CONFIG1, tag='test.metrics')
59
107
  Fluent::Test::OutputTestDriver.new(Fluent::GrowthForecastOutput, tag).configure(conf)
60
108
  end
@@ -93,6 +141,9 @@ class GrowthForecastOutputTest < Test::Unit::TestCase
93
141
  assert_equal :modified, d.instance.mode
94
142
 
95
143
  assert_equal 'http://127.0.0.1:5125/api/service/data1/field1', d.instance.format_url('test.data1', 'field1')
144
+
145
+ assert_raise(Fluent::ConfigError) { d = create_driver(CONFIG_BAD_GRAPHS) }
146
+ assert_raise(Fluent::ConfigError) { d = create_driver(CONFIG_GRAPHS_WITHOUT_NAME_KEYS) }
96
147
  end
97
148
 
98
149
  # CONFIG1 = %[
@@ -319,6 +370,108 @@ class GrowthForecastOutputTest < Test::Unit::TestCase
319
370
  assert_equal 'test.metrics_otherfield', v3rd[:name]
320
371
  end
321
372
 
373
+ # CONFIG_THREADING_KEEPALIVE = %[
374
+ # gfapi_url http://127.0.0.1:5125/api/
375
+ # service service
376
+ # section metrics
377
+ # name_keys field1,field2,otherfield
378
+ # tag_for name_prefix
379
+ # background_post true
380
+ # keepalive true
381
+ # timeout 120
382
+ # ]
383
+ def test_threading
384
+ d = create_driver(CONFIG_THREADING_KEEPALIVE, 'test.metrics')
385
+ d.emit({ 'field1' => 50, 'field2' => 20, 'field3' => 10, 'otherfield' => 1 })
386
+ d.run
387
+ sleep 0.5 # wait internal posting thread loop
388
+
389
+ assert_equal 3, @posted.size
390
+ v1st = @posted[0]
391
+ v2nd = @posted[1]
392
+ v3rd = @posted[2]
393
+
394
+ assert_equal 50, v1st[:data][:number]
395
+ assert_equal 'gauge', v1st[:data][:mode]
396
+ assert_nil v1st[:auth]
397
+ assert_equal 'service', v1st[:service]
398
+ assert_equal 'metrics', v1st[:section]
399
+ assert_equal 'test.metrics_field1', v1st[:name]
400
+
401
+ assert_equal 20, v2nd[:data][:number]
402
+ assert_equal 'test.metrics_field2', v2nd[:name]
403
+
404
+ assert_equal 1, v3rd[:data][:number]
405
+ assert_equal 'test.metrics_otherfield', v3rd[:name]
406
+ end
407
+
408
+ # CONFIG_THREADING_NON_KEEPALIVE = %[
409
+ # gfapi_url http://127.0.0.1:5125/api/
410
+ # service service
411
+ # section metrics
412
+ # name_keys field1,field2,otherfield
413
+ # tag_for name_prefix
414
+ # background_post true
415
+ # keepalive false
416
+ # ]
417
+ def test_threading_non_keepalive
418
+ d = create_driver(CONFIG_THREADING_NON_KEEPALIVE, 'test.metrics')
419
+ d.emit({ 'field1' => 50, 'field2' => 20, 'field3' => 10, 'otherfield' => 1 })
420
+ d.run
421
+ sleep 0.5 # wait internal posting thread loop
422
+
423
+ assert_equal 3, @posted.size
424
+ v1st = @posted[0]
425
+ v2nd = @posted[1]
426
+ v3rd = @posted[2]
427
+
428
+ assert_equal 50, v1st[:data][:number]
429
+ assert_equal 'gauge', v1st[:data][:mode]
430
+ assert_nil v1st[:auth]
431
+ assert_equal 'service', v1st[:service]
432
+ assert_equal 'metrics', v1st[:section]
433
+ assert_equal 'test.metrics_field1', v1st[:name]
434
+
435
+ assert_equal 20, v2nd[:data][:number]
436
+ assert_equal 'test.metrics_field2', v2nd[:name]
437
+
438
+ assert_equal 1, v3rd[:data][:number]
439
+ assert_equal 'test.metrics_otherfield', v3rd[:name]
440
+ end
441
+
442
+
443
+ # CONFIG_GRAPHS = %[
444
+ # gfapi_url http://127.0.0.1:5125/api/
445
+ # service service
446
+ # section metrics
447
+ # name_keys field1,field2,otherfield
448
+ # graphs graph1,graph2,othergraph
449
+ # tag_for name_prefix
450
+ # ]
451
+ def test_graphs
452
+ d = create_driver(CONFIG_GRAPHS, 'test.metrics')
453
+ d.emit({ 'field1' => 50, 'field2' => 20, 'field3' => 10, 'otherfield' => 1 })
454
+ d.run
455
+
456
+ assert_equal 3, @posted.size
457
+ v1st = @posted[0]
458
+ v2nd = @posted[1]
459
+ v3rd = @posted[2]
460
+
461
+ assert_equal 50, v1st[:data][:number]
462
+ assert_equal 'gauge', v1st[:data][:mode]
463
+ assert_nil v1st[:auth]
464
+ assert_equal 'service', v1st[:service]
465
+ assert_equal 'metrics', v1st[:section]
466
+ assert_equal 'test.metrics_graph1', v1st[:name]
467
+
468
+ assert_equal 20, v2nd[:data][:number]
469
+ assert_equal 'test.metrics_graph2', v2nd[:name]
470
+
471
+ assert_equal 1, v3rd[:data][:number]
472
+ assert_equal 'test.metrics_othergraph', v3rd[:name]
473
+ end
474
+
322
475
  # setup / teardown for servers
323
476
  def setup
324
477
  Fluent::Test.setup
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-growthforecast
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - TAGOMORI Satoshi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-16 00:00:00.000000000 Z
11
+ date: 2013-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -104,11 +104,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
104
  version: '0'
105
105
  requirements: []
106
106
  rubyforge_project:
107
- rubygems_version: 2.0.2
107
+ rubygems_version: 2.0.3
108
108
  signing_key:
109
109
  specification_version: 4
110
110
  summary: Fluentd output plugin to post numbers to GrowthForecast (by kazeburo)
111
111
  test_files:
112
112
  - test/helper.rb
113
113
  - test/plugin/test_out_growthforecast.rb
114
- has_rdoc: