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.
@@ -1,2 +1,2 @@
1
- service_name: travis-pro
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.6"
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| http.request(req) }
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
- raise warning if @raise_on_http_failure
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.6
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: 2015-12-16 00:00:00.000000000 Z
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: 2.4.8
158
+ rubygems_version: 1.8.23
145
159
  signing_key:
146
- specification_version: 4
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