fluent-plugin-out-http-ext 0.1.6 → 0.1.7
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.
- 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
|