fluent-plugin-out-http-ext 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.coveralls.yml +1 -1
- data/README.md +3 -0
- data/fluent-plugin-out-http-ext.gemspec +1 -1
- data/lib/fluent/plugin/out_http_ext.rb +66 -4
- data/test/plugin/test_out_http_ext.rb +169 -0
- metadata +31 -17
- checksums.yaml +0 -7
data/.coveralls.yml
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
service_name: travis-
|
1
|
+
service_name: travis-ci
|
2
2
|
repo_token: 9tG18WMwC1xpPdDBEGznon01RCp9NusHL
|
data/README.md
CHANGED
@@ -15,8 +15,11 @@ A generic [fluentd][1] output plugin for sending logs to an HTTP endpoint
|
|
15
15
|
http_method put # default: post
|
16
16
|
serializer json # default: form
|
17
17
|
rate_limit_msec 100 # default: 0 = no rate limiting
|
18
|
+
open_timeout 5 # default: nil = no timeout
|
19
|
+
read_timeout 10 # default: 60
|
18
20
|
raise_on_error false # default: true
|
19
21
|
raise_on_http_failure true # default: false
|
22
|
+
ignore_http_status_code 300,400..499 # default: nil # do not raise on these http_hstatus codes
|
20
23
|
authentication basic # default: none
|
21
24
|
username alice # default: ''
|
22
25
|
password bobpop # default: '', secret: true
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = "fluent-plugin-out-http-ext"
|
5
|
-
gem.version = "0.1.
|
5
|
+
gem.version = "0.1.7"
|
6
6
|
gem.authors = ["Toshiya Kawasaki"]
|
7
7
|
gem.email = ["kawasakitoshiya@gmail.com"]
|
8
8
|
gem.summary = %q{A generic Fluentd output plugin to send logs to an HTTP endpoint with SSL and Header option}
|
@@ -1,3 +1,12 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
class Array
|
4
|
+
def to_set
|
5
|
+
Set.new(self)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
|
1
10
|
class Hash
|
2
11
|
"""
|
3
12
|
each traverse in hash
|
@@ -19,6 +28,39 @@ class Hash
|
|
19
28
|
|
20
29
|
end
|
21
30
|
|
31
|
+
class StatusCodeParser
|
32
|
+
"""
|
33
|
+
parse status code string to array of codes
|
34
|
+
"""
|
35
|
+
def self.range?(str)
|
36
|
+
# i.e. 200..399 => return true
|
37
|
+
return /^\d{3}..\d{3}$/ =~ str ? true : false
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.number?(str)
|
41
|
+
return /^\d{3}$/ =~ str ? true : false
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.get_array(str)
|
45
|
+
if self.range?(str)
|
46
|
+
ends = str.split('..').map{|d| Integer(d)}
|
47
|
+
return (ends[0]..ends[1]).to_a
|
48
|
+
elsif self.number?(str)
|
49
|
+
return [str.to_i]
|
50
|
+
else
|
51
|
+
raise "invalid status code range format"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.convert(range_str)
|
56
|
+
elems = range_str.split(',')
|
57
|
+
status_codes = elems.flat_map do |elem|
|
58
|
+
self.get_array(elem)
|
59
|
+
end
|
60
|
+
return status_codes.to_set
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
22
64
|
class Fluent::HTTPOutput < Fluent::Output
|
23
65
|
Fluent::Plugin.register_output('http_ext', self)
|
24
66
|
|
@@ -27,6 +69,7 @@ class Fluent::HTTPOutput < Fluent::Output
|
|
27
69
|
require 'net/http'
|
28
70
|
require 'uri'
|
29
71
|
require 'yajl'
|
72
|
+
require 'set'
|
30
73
|
end
|
31
74
|
|
32
75
|
# Endpoint URL ex. localhost.local/api/
|
@@ -41,6 +84,9 @@ class Fluent::HTTPOutput < Fluent::Output
|
|
41
84
|
# true | false
|
42
85
|
config_param :use_ssl, :bool, :default => false
|
43
86
|
|
87
|
+
config_param :open_timeout, :integer, :default => nil
|
88
|
+
config_param :read_timeout, :integer, :default => 60
|
89
|
+
|
44
90
|
# Simple rate limiting: ignore any records within `rate_limit_msec`
|
45
91
|
# since the last one.
|
46
92
|
config_param :rate_limit_msec, :integer, :default => 0
|
@@ -50,8 +96,7 @@ class Fluent::HTTPOutput < Fluent::Output
|
|
50
96
|
|
51
97
|
# Raise errors when HTTP response code was not successful.
|
52
98
|
config_param :raise_on_http_failure, :bool, :default => false
|
53
|
-
|
54
|
-
|
99
|
+
config_param :ignore_http_status_code, :string, :default => nil
|
55
100
|
# nil | 'none' | 'basic'
|
56
101
|
config_param :authentication, :string, :default => nil
|
57
102
|
config_param :username, :string, :default => ''
|
@@ -74,6 +119,12 @@ class Fluent::HTTPOutput < Fluent::Output
|
|
74
119
|
:post
|
75
120
|
end
|
76
121
|
|
122
|
+
@ignore_http_status_code = if @ignore_http_status_code.nil?
|
123
|
+
[].to_set
|
124
|
+
else
|
125
|
+
StatusCodeParser.convert(@ignore_http_status_code)
|
126
|
+
end
|
127
|
+
|
77
128
|
@auth = case @authentication
|
78
129
|
when 'basic' then :basic
|
79
130
|
else
|
@@ -158,7 +209,11 @@ class Fluent::HTTPOutput < Fluent::Output
|
|
158
209
|
client.use_ssl = true
|
159
210
|
client.ca_file = OpenSSL::X509::DEFAULT_CERT_FILE
|
160
211
|
end
|
161
|
-
res = client.start {|http|
|
212
|
+
res = client.start {|http|
|
213
|
+
http.open_timeout = @open_timeout
|
214
|
+
http.read_timeout = @read_timeout
|
215
|
+
http.request(req)
|
216
|
+
}
|
162
217
|
rescue => e # rescue all StandardErrors
|
163
218
|
# server didn't respond
|
164
219
|
$log.warn "Net::HTTP.#{req.method.capitalize} raises exception: #{e.class}, '#{e.message}'"
|
@@ -172,7 +227,14 @@ class Fluent::HTTPOutput < Fluent::Output
|
|
172
227
|
end
|
173
228
|
warning = "failed to #{req.method} #{uri} (#{res_summary})"
|
174
229
|
$log.warn warning
|
175
|
-
|
230
|
+
if @raise_on_http_failure
|
231
|
+
unless @ignore_http_status_code.include?(res.code.to_i)
|
232
|
+
raise warning
|
233
|
+
else
|
234
|
+
$log.debug "ignore http status code #{req.method}"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
176
238
|
end #end unless
|
177
239
|
end # end begin
|
178
240
|
end # end send_request
|
@@ -59,6 +59,23 @@ class HTTPOutputTestBase < Test::Unit::TestCase
|
|
59
59
|
res.status = 200
|
60
60
|
res.body = 'running'
|
61
61
|
}
|
62
|
+
srv.mount_proc('/slow_5') { |req,res|
|
63
|
+
sleep 5
|
64
|
+
res.status = 200
|
65
|
+
res.body = 'slow_5'
|
66
|
+
}
|
67
|
+
srv.mount_proc('/slow_10') { |req,res|
|
68
|
+
sleep 10
|
69
|
+
res.status = 200
|
70
|
+
res.body = 'slow_10'
|
71
|
+
}
|
72
|
+
srv.mount_proc('/status_code') { |req,res|
|
73
|
+
r = Yajl.load(req.body)
|
74
|
+
code = r["code"]
|
75
|
+
res.status = code.to_s
|
76
|
+
res.body = ''
|
77
|
+
}
|
78
|
+
|
62
79
|
srv.start
|
63
80
|
ensure
|
64
81
|
srv.shutdown
|
@@ -169,6 +186,38 @@ class HTTPOutputTest < HTTPOutputTestBase
|
|
169
186
|
rate_limit_msec #{RATE_LIMIT_MSEC}
|
170
187
|
]
|
171
188
|
|
189
|
+
CONFIG_NOT_READ_TIMEOUT = %[
|
190
|
+
endpoint_url http://127.0.0.1:#{TEST_LISTEN_PORT}/slow_5/
|
191
|
+
read_timeout 7
|
192
|
+
]
|
193
|
+
CONFIG_READ_TIMEOUT = %[
|
194
|
+
endpoint_url http://127.0.0.1:#{TEST_LISTEN_PORT}/slow_10/
|
195
|
+
read_timeout 7
|
196
|
+
]
|
197
|
+
CONFIG_IGNORE_NONE = %[
|
198
|
+
endpoint_url http://127.0.0.1:#{TEST_LISTEN_PORT}/status_code/
|
199
|
+
serializer json
|
200
|
+
raise_on_http_failure true
|
201
|
+
]
|
202
|
+
CONFIG_IGNORE_409 = %[
|
203
|
+
endpoint_url http://127.0.0.1:#{TEST_LISTEN_PORT}/status_code/
|
204
|
+
serializer json
|
205
|
+
raise_on_http_failure true
|
206
|
+
ignore_http_status_code 409
|
207
|
+
]
|
208
|
+
CONFIG_IGNORE_4XX = %[
|
209
|
+
endpoint_url http://127.0.0.1:#{TEST_LISTEN_PORT}/status_code/
|
210
|
+
serializer json
|
211
|
+
raise_on_http_failure true
|
212
|
+
ignore_http_status_code 400..499
|
213
|
+
]
|
214
|
+
CONFIG_IGNORE_4XX_5XX = %[
|
215
|
+
endpoint_url http://127.0.0.1:#{TEST_LISTEN_PORT}/status_code/
|
216
|
+
serializer json
|
217
|
+
raise_on_http_failure true
|
218
|
+
ignore_http_status_code 400..599
|
219
|
+
]
|
220
|
+
|
172
221
|
def create_driver(conf=CONFIG, tag='test.metrics')
|
173
222
|
Fluent::Test::OutputTestDriver.new(Fluent::HTTPOutput, tag).configure(conf)
|
174
223
|
end
|
@@ -302,6 +351,93 @@ class HTTPOutputTest < HTTPOutputTestBase
|
|
302
351
|
assert_equal 2, @posts.size
|
303
352
|
end
|
304
353
|
|
354
|
+
def test_read_timeout
|
355
|
+
d = create_driver CONFIG_READ_TIMEOUT
|
356
|
+
assert_equal 7, d.instance.read_timeout
|
357
|
+
err = Net.const_defined?(:ReadTimeout) ? Net::ReadTimeout : Timeout::Error
|
358
|
+
assert_raise err do
|
359
|
+
d.emit({})
|
360
|
+
d.run
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
def test_not_read_timeout
|
365
|
+
d = create_driver CONFIG_NOT_READ_TIMEOUT
|
366
|
+
assert_equal 7, d.instance.read_timeout
|
367
|
+
assert_nothing_raised do
|
368
|
+
d.emit({})
|
369
|
+
d.run
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def test_ignore_none
|
374
|
+
d = create_driver CONFIG_IGNORE_NONE
|
375
|
+
assert_equal [].to_set, d.instance.ignore_http_status_code
|
376
|
+
|
377
|
+
assert_raise do
|
378
|
+
d.emit({:code=> 409})
|
379
|
+
d.run
|
380
|
+
end
|
381
|
+
|
382
|
+
assert_raise do
|
383
|
+
d.emit({:code => 500})
|
384
|
+
d.run
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
def test_ignore_409
|
389
|
+
d = create_driver CONFIG_IGNORE_409
|
390
|
+
assert_equal [409].to_set, d.instance.ignore_http_status_code
|
391
|
+
|
392
|
+
assert_nothing_raised do
|
393
|
+
d.emit({:code => 409})
|
394
|
+
d.run
|
395
|
+
end
|
396
|
+
assert_raise do
|
397
|
+
d.emit({:code => 404})
|
398
|
+
d.run
|
399
|
+
end
|
400
|
+
assert_raise do
|
401
|
+
d.emit({:code => 500})
|
402
|
+
d.run
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def test_ignore_4XX
|
407
|
+
d = create_driver CONFIG_IGNORE_4XX
|
408
|
+
assert_equal (400..499).to_a.to_set, d.instance.ignore_http_status_code
|
409
|
+
|
410
|
+
assert_nothing_raised do
|
411
|
+
d.emit({:code => 409})
|
412
|
+
d.run
|
413
|
+
end
|
414
|
+
assert_nothing_raised do
|
415
|
+
d.emit({:code => 404})
|
416
|
+
d.run
|
417
|
+
end
|
418
|
+
assert_raise do
|
419
|
+
d.emit({:code => 500})
|
420
|
+
d.run
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
def test_ignore_4XX_5XX
|
425
|
+
d = create_driver CONFIG_IGNORE_4XX_5XX
|
426
|
+
assert_equal (400..599).to_a.to_set, d.instance.ignore_http_status_code
|
427
|
+
assert_nothing_raised do
|
428
|
+
d.emit({:code => 409})
|
429
|
+
d.run
|
430
|
+
end
|
431
|
+
assert_nothing_raised do
|
432
|
+
d.emit({:code => 404})
|
433
|
+
d.run
|
434
|
+
end
|
435
|
+
assert_nothing_raised do
|
436
|
+
d.emit({:code => 500})
|
437
|
+
d.run
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
305
441
|
def _current_msec
|
306
442
|
Time.now.to_f * 1000
|
307
443
|
end
|
@@ -339,4 +475,37 @@ class HTTPOutputTest < HTTPOutputTestBase
|
|
339
475
|
assert_equal 2, @prohibited
|
340
476
|
end
|
341
477
|
|
478
|
+
def test_status_code_parser()
|
479
|
+
assert_equal (400..409).to_a.to_set, StatusCodeParser.convert("400..409")
|
480
|
+
assert_equal ((400..409).to_a + [300]).to_set, StatusCodeParser.convert("400..409,300")
|
481
|
+
assert_equal ((400..409).to_a + [300]).to_set, StatusCodeParser.convert("300,400..409")
|
482
|
+
assert_equal [404, 409].to_set, StatusCodeParser.convert("404,409")
|
483
|
+
assert_equal [404, 409, 300, 301, 302, 303].to_set, StatusCodeParser.convert("404,409,300..303")
|
484
|
+
assert_equal [409].to_set, StatusCodeParser.convert("409")
|
485
|
+
assert_equal [].to_set, StatusCodeParser.convert("")
|
486
|
+
assert_raise do
|
487
|
+
StatusCodeParser.convert("400...499")
|
488
|
+
end
|
489
|
+
assert_raise do
|
490
|
+
StatusCodeParser.convert("10..20")
|
491
|
+
end
|
492
|
+
assert_raise do
|
493
|
+
StatusCodeParser.convert("4XX")
|
494
|
+
end
|
495
|
+
assert_raise do
|
496
|
+
StatusCodeParser.convert("4XX..5XX")
|
497
|
+
end
|
498
|
+
assert_raise do
|
499
|
+
StatusCodeParser.convert("200.0..400")
|
500
|
+
end
|
501
|
+
assert_raise do
|
502
|
+
StatusCodeParser.convert("-200..400")
|
503
|
+
end
|
504
|
+
|
505
|
+
end
|
506
|
+
|
507
|
+
def test_array_extend
|
508
|
+
assert_equal [].to_set, Set.new([])
|
509
|
+
assert_equal [1, 2].to_set, Set.new([1, 2])
|
510
|
+
end
|
342
511
|
end
|
metadata
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-out-http-ext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Toshiya Kawasaki
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2016-01-14 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: yajl-ruby
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
19
|
- - ~>
|
18
20
|
- !ruby/object:Gem::Version
|
@@ -20,6 +22,7 @@ dependencies:
|
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
23
26
|
requirements:
|
24
27
|
- - ~>
|
25
28
|
- !ruby/object:Gem::Version
|
@@ -27,8 +30,9 @@ dependencies:
|
|
27
30
|
- !ruby/object:Gem::Dependency
|
28
31
|
name: fluentd
|
29
32
|
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
30
34
|
requirements:
|
31
|
-
- - '>='
|
35
|
+
- - ! '>='
|
32
36
|
- !ruby/object:Gem::Version
|
33
37
|
version: 0.10.0
|
34
38
|
- - <
|
@@ -37,8 +41,9 @@ dependencies:
|
|
37
41
|
type: :runtime
|
38
42
|
prerelease: false
|
39
43
|
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
40
45
|
requirements:
|
41
|
-
- - '>='
|
46
|
+
- - ! '>='
|
42
47
|
- !ruby/object:Gem::Version
|
43
48
|
version: 0.10.0
|
44
49
|
- - <
|
@@ -47,57 +52,65 @@ dependencies:
|
|
47
52
|
- !ruby/object:Gem::Dependency
|
48
53
|
name: bundler
|
49
54
|
requirement: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
50
56
|
requirements:
|
51
|
-
- - '>='
|
57
|
+
- - ! '>='
|
52
58
|
- !ruby/object:Gem::Version
|
53
59
|
version: '0'
|
54
60
|
type: :development
|
55
61
|
prerelease: false
|
56
62
|
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
57
64
|
requirements:
|
58
|
-
- - '>='
|
65
|
+
- - ! '>='
|
59
66
|
- !ruby/object:Gem::Version
|
60
67
|
version: '0'
|
61
68
|
- !ruby/object:Gem::Dependency
|
62
69
|
name: rake
|
63
70
|
requirement: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
64
72
|
requirements:
|
65
|
-
- - '>='
|
73
|
+
- - ! '>='
|
66
74
|
- !ruby/object:Gem::Version
|
67
75
|
version: '0'
|
68
76
|
type: :development
|
69
77
|
prerelease: false
|
70
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
71
80
|
requirements:
|
72
|
-
- - '>='
|
81
|
+
- - ! '>='
|
73
82
|
- !ruby/object:Gem::Version
|
74
83
|
version: '0'
|
75
84
|
- !ruby/object:Gem::Dependency
|
76
85
|
name: test-unit
|
77
86
|
requirement: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
78
88
|
requirements:
|
79
|
-
- - '>='
|
89
|
+
- - ! '>='
|
80
90
|
- !ruby/object:Gem::Version
|
81
91
|
version: 3.1.0
|
82
92
|
type: :development
|
83
93
|
prerelease: false
|
84
94
|
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
85
96
|
requirements:
|
86
|
-
- - '>='
|
97
|
+
- - ! '>='
|
87
98
|
- !ruby/object:Gem::Version
|
88
99
|
version: 3.1.0
|
89
100
|
- !ruby/object:Gem::Dependency
|
90
101
|
name: coveralls
|
91
102
|
requirement: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
92
104
|
requirements:
|
93
|
-
- - '>='
|
105
|
+
- - ! '>='
|
94
106
|
- !ruby/object:Gem::Version
|
95
107
|
version: '0'
|
96
108
|
type: :development
|
97
109
|
prerelease: false
|
98
110
|
version_requirements: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
99
112
|
requirements:
|
100
|
-
- - '>='
|
113
|
+
- - ! '>='
|
101
114
|
- !ruby/object:Gem::Version
|
102
115
|
version: '0'
|
103
116
|
description: A generic Fluentd output plugin to send logs to an HTTP endpoint with
|
@@ -124,26 +137,27 @@ files:
|
|
124
137
|
homepage:
|
125
138
|
licenses:
|
126
139
|
- Apache-2.0
|
127
|
-
metadata: {}
|
128
140
|
post_install_message:
|
129
141
|
rdoc_options: []
|
130
142
|
require_paths:
|
131
143
|
- lib
|
132
144
|
required_ruby_version: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
133
146
|
requirements:
|
134
|
-
- - '>='
|
147
|
+
- - ! '>='
|
135
148
|
- !ruby/object:Gem::Version
|
136
149
|
version: '0'
|
137
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
|
+
none: false
|
138
152
|
requirements:
|
139
|
-
- - '>='
|
153
|
+
- - ! '>='
|
140
154
|
- !ruby/object:Gem::Version
|
141
155
|
version: '0'
|
142
156
|
requirements: []
|
143
157
|
rubyforge_project:
|
144
|
-
rubygems_version:
|
158
|
+
rubygems_version: 1.8.23
|
145
159
|
signing_key:
|
146
|
-
specification_version:
|
160
|
+
specification_version: 3
|
147
161
|
summary: A generic Fluentd output plugin to send logs to an HTTP endpoint with SSL
|
148
162
|
and Header option
|
149
163
|
test_files:
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: 3e9c08d1a809ddd3df73b5ab13fe55ac7ed79305
|
4
|
-
data.tar.gz: 2af17adfcbb3375ab1079dfcc56d51d2a64d0b06
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: 4c445f8eb6d35bf52705eeb683ff48f15d96b5eadc8625736ce98cd2b52d9f207a4e08ba6abd2ac8306b025d0626eae55e3204ab3806638fdd4468c19b7699d4
|
7
|
-
data.tar.gz: 66977734544084539b681b6690e82fef9cb595badfb57cd509f97f1cdf196afd3e314e0697bda3a25175f119bdb78b278237ee8ee1c7d2e3e515bb50d99f7bb6
|