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 +4 -4
- data/README.md +86 -0
- data/fluent-plugin-growthforecast.gemspec +1 -1
- data/lib/fluent/plugin/out_growthforecast.rb +73 -7
- data/test/plugin/test_out_growthforecast.rb +153 -0
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce309fd9162a5d30d1a24cfaed6c72feb607ecbe
|
4
|
+
data.tar.gz: 649824e492f0132967303c1d0f7400c1bdcab98c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
185
|
-
if record[name]
|
186
|
-
events.push({:tag => tag, :name => name, :value =>
|
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 @
|
200
|
-
|
260
|
+
if @thread
|
261
|
+
@mutex.synchronize do
|
262
|
+
@queue += events
|
263
|
+
end
|
201
264
|
else
|
202
|
-
|
203
|
-
|
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.
|
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-
|
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.
|
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:
|