fluent-plugin-growthforecast 0.2.2 → 0.2.3

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: 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: