http_event_logger 0.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/lib/http_event_logger/adapter/ethon.rb +56 -0
- data/lib/http_event_logger/adapter/excon.rb +64 -0
- data/lib/http_event_logger/adapter/httpclient.rb +60 -0
- data/lib/http_event_logger/adapter/net_http.rb +65 -0
- data/lib/http_event_logger/adapter/patron.rb +40 -0
- data/lib/http_event_logger/configuration.rb +9 -0
- data/lib/http_event_logger/event/connection.rb +21 -0
- data/lib/http_event_logger/event/headers.rb +21 -0
- data/lib/http_event_logger/event/observer.rb +13 -0
- data/lib/http_event_logger/event/request.rb +24 -0
- data/lib/http_event_logger/event/response.rb +47 -0
- data/lib/http_event_logger/logger.rb +47 -0
- data/lib/http_event_logger/version.rb +3 -0
- data/lib/http_event_logger.rb +43 -0
- data/spec/http_event_logger_integration_spec.rb +151 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/support/custom_logger.rb +25 -0
- data/spec/support/driver/base.rb +48 -0
- data/spec/support/driver/ethon.rb +29 -0
- data/spec/support/driver/excon.rb +21 -0
- data/spec/support/driver/faraday.rb +36 -0
- data/spec/support/driver/httparty.rb +21 -0
- data/spec/support/driver/httpclient.rb +29 -0
- data/spec/support/driver/net_http.rb +24 -0
- data/spec/support/driver/open_uri.rb +19 -0
- data/spec/support/driver/patron.rb +27 -0
- data/spec/support/driver/typhoeus.rb +34 -0
- data/spec/support/index.html +8 -0
- data/spec/support/server.rb +28 -0
- metadata +299 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d1c6e13a02bf58df078b6db91d89d34e04a3ab46
|
4
|
+
data.tar.gz: 8743f10e8bc7672991d0447cf8dad126d84d7e7f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5827ef887a7b2a13a9d9d29a684eb1b75963047ed30c7a4c9717c5346a2268ad94521dd363f8c57b84311306242e52d4e732f091f0aa9882ea0fccfeea9f169c
|
7
|
+
data.tar.gz: 27e747db5d476fbc7fc9db0adf5a759ca1ea5d750c4b70ddf8219a60956b7bf8bea9cdda18aeabbd0c0cc3bc9f1f95f3d0fd8ebc56021954dfcf966512809079
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 Thilo Rusche
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Ethon
|
2
|
+
|
3
|
+
class Easy
|
4
|
+
|
5
|
+
module Http
|
6
|
+
|
7
|
+
def http_request_with_logging(url, action_name, options={})
|
8
|
+
create_request_event(url, action_name, options)
|
9
|
+
http_request_without_logging(url, action_name, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method_chain :http_request, :logging
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def create_request_event(url, action_name, options)
|
17
|
+
@request_event = HttpEventLogger::Event::Request.new(
|
18
|
+
method: action_name,
|
19
|
+
uri: url,
|
20
|
+
headers: options[:headers],
|
21
|
+
body: options[:body]
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
module Operations
|
28
|
+
|
29
|
+
def perform_with_logging
|
30
|
+
result = nil
|
31
|
+
time_taken_in_seconds = ::Benchmark.realtime do
|
32
|
+
result = perform_without_logging
|
33
|
+
end
|
34
|
+
create_response_event(time_taken_in_seconds)
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
alias_method_chain :perform, :logging
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def create_response_event(time_taken_in_seconds)
|
43
|
+
HttpEventLogger::Event::Response.new(
|
44
|
+
request: @request_event,
|
45
|
+
time_taken_in_seconds: time_taken_in_seconds,
|
46
|
+
status: response_code,
|
47
|
+
headers: response_headers,
|
48
|
+
body: response_body
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end if defined?(Ethon)
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Excon
|
2
|
+
|
3
|
+
class Socket
|
4
|
+
|
5
|
+
def connect_with_logging
|
6
|
+
host = @data[:proxy] ? @data[:proxy][:host] : @data[:host]
|
7
|
+
port = @data[:proxy] ? @data[:proxy][:port] : @data[:port]
|
8
|
+
HttpEventLogger::Event::Connection.new(host, port)
|
9
|
+
connect_without_logging
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method_chain :connect, :logging
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class Connection
|
17
|
+
|
18
|
+
def request_with_logging(params, &block)
|
19
|
+
request_datum = @data.merge(params)
|
20
|
+
request_datum[:headers] = @data[:headers].merge(request_datum[:headers] || {})
|
21
|
+
request_event = create_request_event(request_datum)
|
22
|
+
result = nil
|
23
|
+
time_taken_in_seconds = ::Benchmark.realtime do
|
24
|
+
result = request_without_logging(params, &block)
|
25
|
+
end
|
26
|
+
response = result.is_a?(Excon::Response) ? result : Excon::Response.new(response(result)[:response])
|
27
|
+
create_response_event(request_event, time_taken_in_seconds, response)
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method_chain :request, :logging
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def create_request_event(datum)
|
36
|
+
HttpEventLogger::Event::Request.new(
|
37
|
+
method: method_from(datum),
|
38
|
+
uri: absolute_url_from(datum),
|
39
|
+
headers: datum[:headers],
|
40
|
+
body: datum[:body]
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
def method_from(datum)
|
45
|
+
datum[:method] ? datum[:method].to_s.upcase : "UNKNOWN"
|
46
|
+
end
|
47
|
+
|
48
|
+
def absolute_url_from(datum)
|
49
|
+
"#{datum[:scheme]}://#{datum[:host]}:#{datum[:port]}#{datum[:path]}#{datum[:query]}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_response_event(request_event, time_taken_in_seconds, response)
|
53
|
+
HttpEventLogger::Event::Response.new(
|
54
|
+
request: request_event,
|
55
|
+
time_taken_in_seconds: time_taken_in_seconds,
|
56
|
+
status: response.status,
|
57
|
+
headers: response.headers,
|
58
|
+
body: response.body
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end if defined?(Excon)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class HTTPClient
|
2
|
+
|
3
|
+
private
|
4
|
+
|
5
|
+
class Session
|
6
|
+
|
7
|
+
def create_socket_with_logging(site)
|
8
|
+
HttpEventLogger::Event::Connection.new(site.host, site.port)
|
9
|
+
create_socket_without_logging(site)
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method_chain :create_socket, :logging
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
def do_get_block_with_logging(req, proxy, conn, &block)
|
17
|
+
request_event = create_request_event(req)
|
18
|
+
retryable_response_error = nil
|
19
|
+
time_taken_in_seconds = ::Benchmark.realtime do
|
20
|
+
begin
|
21
|
+
do_get_block_without_logging(req, proxy, conn, &block)
|
22
|
+
rescue RetryableResponse => exc
|
23
|
+
retryable_response_error = exc
|
24
|
+
end
|
25
|
+
end
|
26
|
+
res = conn.pop
|
27
|
+
create_response_event(request_event, res, time_taken_in_seconds)
|
28
|
+
conn.push(res)
|
29
|
+
raise retryable_response_error unless retryable_response_error.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
alias_method_chain :do_get_block, :logging
|
33
|
+
|
34
|
+
def create_request_event(req)
|
35
|
+
HttpEventLogger::Event::Request.new(
|
36
|
+
method: req.header.request_method,
|
37
|
+
uri: req.header.request_uri,
|
38
|
+
headers: req.headers,
|
39
|
+
body: req.body
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_response_event(request_event, res, time_taken_in_seconds)
|
44
|
+
HttpEventLogger::Event::Response.new(
|
45
|
+
request: request_event,
|
46
|
+
time_taken_in_seconds: time_taken_in_seconds,
|
47
|
+
status: res.status_code,
|
48
|
+
headers: response_headers_from(res),
|
49
|
+
body: res.body
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
def response_headers_from(res)
|
54
|
+
res.header.all.reduce({}) do |result, header|
|
55
|
+
result[header[0]] = header[1]
|
56
|
+
result
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end if defined?(::HTTPClient)
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Net
|
2
|
+
|
3
|
+
class HTTP
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
HIDDEN_PORTS = [ 80, 443 ].freeze
|
8
|
+
|
9
|
+
public
|
10
|
+
|
11
|
+
def connect_with_logging
|
12
|
+
HttpEventLogger::Event::Connection.new(@address, @port) unless started?
|
13
|
+
connect_without_logging
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_method_chain :connect, :logging
|
17
|
+
|
18
|
+
def request_with_logging(req, body = nil, &block)
|
19
|
+
create_request_event(req, body) if started?
|
20
|
+
response = nil
|
21
|
+
time_taken_in_seconds = ::Benchmark.realtime do
|
22
|
+
response = request_without_logging(req, body, &block)
|
23
|
+
end
|
24
|
+
create_response_event(time_taken_in_seconds, response) if started?
|
25
|
+
response
|
26
|
+
end
|
27
|
+
|
28
|
+
alias_method_chain :request, :logging
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def create_request_event(req, body)
|
33
|
+
@request_event = HttpEventLogger::Event::Request.new(
|
34
|
+
method: req.method,
|
35
|
+
uri: absolute_url_from(req),
|
36
|
+
headers: req.each_header.collect,
|
37
|
+
body: request_body_from(req, body)
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def absolute_url_from(req)
|
42
|
+
protocol = @use_ssl ? "https" : "http"
|
43
|
+
port_indicator = HIDDEN_PORTS.include?(@port) ? "" : ":#{@port}"
|
44
|
+
hostname = "#{@address}#{port_indicator}"
|
45
|
+
"#{protocol}://#{hostname}#{req.path}"
|
46
|
+
end
|
47
|
+
|
48
|
+
# A bit convoluted because post_form uses form_data= to assign the data, so in that case req.body will be empty
|
49
|
+
def request_body_from(req, body)
|
50
|
+
req.body.nil? || req.body.size == 0 ? body : req.body
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_response_event(time_taken_in_seconds, response)
|
54
|
+
HttpEventLogger::Event::Response.new(
|
55
|
+
request: @request_event,
|
56
|
+
time_taken_in_seconds: time_taken_in_seconds,
|
57
|
+
status: response.code,
|
58
|
+
headers: response.each_header.collect,
|
59
|
+
body: response.body
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Patron
|
2
|
+
|
3
|
+
class Session
|
4
|
+
|
5
|
+
def request_with_logging(action_name, url, headers, options={})
|
6
|
+
create_request_event(action_name, headers, options, url)
|
7
|
+
response = nil
|
8
|
+
time_taken_in_seconds = ::Benchmark.realtime do
|
9
|
+
response = request_without_logging(action_name, url, headers, options)
|
10
|
+
end
|
11
|
+
create_response_event(response, time_taken_in_seconds)
|
12
|
+
response
|
13
|
+
end
|
14
|
+
|
15
|
+
alias_method_chain :request, :logging
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def create_response_event(response, time_taken_in_seconds)
|
20
|
+
HttpEventLogger::Event::Response.new(
|
21
|
+
request: @request_event,
|
22
|
+
time_taken_in_seconds: time_taken_in_seconds,
|
23
|
+
status: response.status,
|
24
|
+
headers: response.headers,
|
25
|
+
body: response.body
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_request_event(action_name, headers, options, url)
|
30
|
+
@request_event = HttpEventLogger::Event::Request.new(
|
31
|
+
method: action_name,
|
32
|
+
uri: url,
|
33
|
+
headers: headers,
|
34
|
+
body: options[:data]
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end if defined?(Patron)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module HttpEventLogger
|
2
|
+
module Event
|
3
|
+
|
4
|
+
class Connection
|
5
|
+
|
6
|
+
attr_reader :host, :port
|
7
|
+
|
8
|
+
def initialize(host, port)
|
9
|
+
@host = host
|
10
|
+
@port = port ? port.to_s : nil
|
11
|
+
HttpEventLogger::Event::Observer.observe(:connected, self)
|
12
|
+
end
|
13
|
+
|
14
|
+
def uri
|
15
|
+
@port.present? ? "#{@host}:#{@port}" : @host
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module HttpEventLogger
|
2
|
+
module Event
|
3
|
+
|
4
|
+
class Headers
|
5
|
+
|
6
|
+
def initialize(headers)
|
7
|
+
@headers = headers || ""
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](name)
|
11
|
+
@headers.is_a?(Hash) ? @headers[name] : nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
@headers.is_a?(String) ? @headers : @headers.map { |key, value| "#{key}: #{value}" }.join(", ")
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module HttpEventLogger
|
2
|
+
module Event
|
3
|
+
|
4
|
+
class Request
|
5
|
+
|
6
|
+
attr_reader :method, :uri, :headers, :body
|
7
|
+
|
8
|
+
def initialize(args)
|
9
|
+
@method = args[:method].to_s.upcase
|
10
|
+
@uri = args[:uri].to_s
|
11
|
+
@headers = HttpEventLogger::Event::Headers.new(args[:headers])
|
12
|
+
@body = args[:body]
|
13
|
+
HttpEventLogger::Event::Observer.observe(:sent, self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def base_uri
|
17
|
+
matcher = @uri.match(/\/\/([^\/\?]*)/)
|
18
|
+
matcher ? matcher[1] : ""
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module HttpEventLogger
|
2
|
+
module Event
|
3
|
+
|
4
|
+
class Response
|
5
|
+
|
6
|
+
attr_reader :request, :time_taken_in_seconds, :status, :headers
|
7
|
+
|
8
|
+
delegate :base_uri, :uri, to: :request
|
9
|
+
|
10
|
+
def initialize(args)
|
11
|
+
@request = args[:request]
|
12
|
+
@time_taken_in_seconds = args[:time_taken_in_seconds]
|
13
|
+
@status = args[:status].to_s
|
14
|
+
@headers = HttpEventLogger::Event::Headers.new(args[:headers])
|
15
|
+
@raw_body = args[:body]
|
16
|
+
HttpEventLogger::Event::Observer.observe(:received, self)
|
17
|
+
end
|
18
|
+
|
19
|
+
def body_with_formatting
|
20
|
+
body.include?("\n") ? "\n#{body}" : body
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def body
|
26
|
+
if body_read_deferred?
|
27
|
+
"[not available]"
|
28
|
+
elsif body_gzip_encoded?
|
29
|
+
Zlib::GzipReader.new(StringIO.new(@raw_body.to_s)).read
|
30
|
+
else
|
31
|
+
@raw_body.to_s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# open-uri wraps the response in a Net::ReadAdapter, so the response body is not available yet
|
36
|
+
def body_read_deferred?
|
37
|
+
@raw_body.is_a?(Net::ReadAdapter)
|
38
|
+
end
|
39
|
+
|
40
|
+
def body_gzip_encoded?
|
41
|
+
@headers["Content-Encoding"] =~ /gzip/
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module HttpEventLogger
|
2
|
+
|
3
|
+
class Logger
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
DEFAULT_LOGGER = ::Logger.new($stdout).freeze
|
8
|
+
DEFAULT_SEVERITY = ::Logger::Severity::DEBUG.freeze
|
9
|
+
|
10
|
+
public
|
11
|
+
|
12
|
+
def initialize(options={})
|
13
|
+
@logger = options[:logger] || DEFAULT_LOGGER
|
14
|
+
@severity = options[:severity] || DEFAULT_SEVERITY
|
15
|
+
@blacklist_pattern = options[:blacklist_pattern] || nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def logs?(uri)
|
19
|
+
@blacklist_pattern.nil? || @blacklist_pattern !~ uri
|
20
|
+
end
|
21
|
+
|
22
|
+
def connected(connection)
|
23
|
+
log "[#{connection.uri}] Connected"
|
24
|
+
end
|
25
|
+
|
26
|
+
def sent(request)
|
27
|
+
log "[#{request.base_uri}] Sent - #{request.method} #{request.uri}"
|
28
|
+
log "[#{request.base_uri}] Sent - Headers: #{request.headers}"
|
29
|
+
log "[#{request.base_uri}] Sent - Body: #{request.body}" if request.body.present?
|
30
|
+
end
|
31
|
+
|
32
|
+
def received(response)
|
33
|
+
log "[#{response.base_uri}] Benchmark: #{response.time_taken_in_seconds} seconds"
|
34
|
+
log "[#{response.base_uri}] Received - Status: #{response.status}"
|
35
|
+
log "[#{response.base_uri}] Received - Headers: #{response.headers}"
|
36
|
+
log "[#{response.base_uri}] Received - Body:#{response.body_with_formatting}"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def log(message)
|
42
|
+
@logger.add(@severity) { message }
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'logger'
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
require 'active_support/core_ext/object/blank'
|
6
|
+
require 'active_support/core_ext/module/aliasing'
|
7
|
+
require 'active_support/core_ext/module/delegation'
|
8
|
+
require 'active_support/core_ext/string/inflections'
|
9
|
+
|
10
|
+
require_relative 'http_event_logger/configuration'
|
11
|
+
require_relative 'http_event_logger/event/connection'
|
12
|
+
require_relative 'http_event_logger/event/headers'
|
13
|
+
require_relative 'http_event_logger/event/request'
|
14
|
+
require_relative 'http_event_logger/event/response'
|
15
|
+
require_relative 'http_event_logger/logger'
|
16
|
+
require_relative 'http_event_logger/event/observer'
|
17
|
+
require_relative 'http_event_logger/adapter/net_http'
|
18
|
+
require_relative 'http_event_logger/adapter/httpclient'
|
19
|
+
require_relative 'http_event_logger/adapter/excon'
|
20
|
+
require_relative 'http_event_logger/adapter/ethon'
|
21
|
+
require_relative 'http_event_logger/adapter/patron'
|
22
|
+
|
23
|
+
module HttpEventLogger
|
24
|
+
|
25
|
+
class << self
|
26
|
+
|
27
|
+
attr_reader :configuration
|
28
|
+
|
29
|
+
def configure(&block)
|
30
|
+
@configuration = HttpEventLogger::Configuration.new
|
31
|
+
block.call @configuration
|
32
|
+
end
|
33
|
+
|
34
|
+
def logger
|
35
|
+
@configuration.logger
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
# Establish default configuration
|
43
|
+
HttpEventLogger.configure { |config| config.logger = HttpEventLogger::Logger.new }
|