httplog 1.4.3 → 1.6.0
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/CHANGELOG.md +8 -0
- data/README.md +6 -13
- data/httplog.gemspec +6 -4
- data/lib/httplog/adapters/ethon.rb +33 -15
- data/lib/httplog/adapters/net_http.rb +11 -1
- data/lib/httplog/configuration.rb +1 -1
- data/lib/httplog/http_log.rb +15 -10
- data/lib/httplog/version.rb +1 -1
- metadata +38 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b45410a66dcec431137326ea3402d5f7aa46aec70ad5bd826dc3fe24021c4dfe
|
4
|
+
data.tar.gz: a7fb94896bd9456ca53f83c78a9b0ed025e9dffd537bf531b56350488334ee1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4abf19d31bcf87d0f4f5cdf4eab1eee36f1974581310077be364a3a89d9f5dae956b7cd5fa021b2711606ac6657ce904a293119a3da8738d95e45d52fc98d50b
|
7
|
+
data.tar.gz: 567406b24ed46bf14bec3960ad246c8ca866f9f96160fcb3578c99969548d2720a5dde179eb69ac129c787cd9121839560914900bd9eef7f68986cd545c93438
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 1.5.0 - 2021-05-20
|
2
|
+
|
3
|
+
* Support for Ruby 2.7 and frozen strings
|
4
|
+
* Development dependency updates
|
5
|
+
* Dropped support for net/http v3
|
6
|
+
* Performance tweaks
|
7
|
+
* Fix for RestClient body read issue (WARNING: this may be reverted, see [#105](https://github.com/trusche/httplog/issues/105))
|
8
|
+
|
1
9
|
## 1.4.3 - 2020-06-10
|
2
10
|
|
3
11
|
* Masking `password` parameter by default... doh.
|
data/README.md
CHANGED
@@ -1,18 +1,15 @@
|
|
1
1
|
## httplog
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
[](http://badge.fury.io/rb/httplog) [](https://travis-ci.org/trusche/httplog) [](https://codeclimate.com/github/trusche/httplog)
|
3
|
+
[](http://badge.fury.io/rb/httplog) [](https://travis-ci.org/trusche/httplog) [](https://codeclimate.com/github/trusche/httplog)
|
6
4
|
[](https://img.shields.io/github/release/trusche/httplog.svg)
|
7
|
-
<a href="https://www.bearer.sh?ref=httplog"><img src="/bearer-badge.png" height="20px"/></a>
|
8
5
|
|
9
6
|
Log outgoing HTTP requests made from your application. Helps with debugging pesky API error responses, or just generally understanding what's going on under the hood.
|
10
7
|
|
11
|
-
Requires ruby >= 2.
|
8
|
+
Requires ruby >= 2.6
|
12
9
|
|
13
10
|
This gem works with the following ruby modules and libraries:
|
14
11
|
|
15
|
-
* [Net::HTTP](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/index.html)
|
12
|
+
* [Net::HTTP](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/index.html) v4+
|
16
13
|
* [Ethon](https://github.com/typhoeus/ethon)
|
17
14
|
* [Excon](https://github.com/geemus/excon)
|
18
15
|
* [OpenURI](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/open-uri/rdoc/index.html)
|
@@ -32,10 +29,6 @@ This is very much a development and debugging tool; it is **not recommended** to
|
|
32
29
|
use this in a production environment as it is monkey-patching the respective HTTP implementations.
|
33
30
|
You have been warned - use at your own risk.
|
34
31
|
|
35
|
-
Httplog is kindly sponsored by <a href="https://www.bearer.sh?ref=httplog">Bearer.sh</a> - go check them out please!
|
36
|
-
|
37
|
-
<a href="https://www.bearer.sh?ref=httplog"><img src="/bearer-sponsor.png" height="72px" /></a>
|
38
|
-
|
39
32
|
### Installation
|
40
33
|
|
41
34
|
gem install httplog
|
@@ -103,6 +96,9 @@ HttpLog.configure do |config|
|
|
103
96
|
|
104
97
|
# Mask the values of sensitive request parameters
|
105
98
|
config.filter_parameters = %w[password]
|
99
|
+
|
100
|
+
# Customize the prefix with a proc or lambda
|
101
|
+
config.prefix = ->{ "[httplog] #{Time.now} " }
|
106
102
|
end
|
107
103
|
```
|
108
104
|
|
@@ -267,9 +263,6 @@ a suggestion for a fix, please open an issue or, even better, submit a pull requ
|
|
267
263
|
|
268
264
|
* Benchmarking only covers the time between starting the HTTP request and receiving the response. It does *not* cover the time it takes to establish the TCP connection.
|
269
265
|
|
270
|
-
* When using [REST Client](https://github.com/rest-client/rest-client), POST requests might be missing the requests
|
271
|
-
data. See #54 for details.
|
272
|
-
|
273
266
|
### Running the specs
|
274
267
|
|
275
268
|
Make sure you have the necessary dependencies installed by running `bundle install`.
|
data/httplog.gemspec
CHANGED
@@ -22,23 +22,25 @@ Gem::Specification.new do |gem|
|
|
22
22
|
gem.test_files = `git ls-files -- test/*`.split("\n")
|
23
23
|
gem.require_paths = ['lib']
|
24
24
|
|
25
|
-
gem.required_ruby_version = '>= 2.
|
25
|
+
gem.required_ruby_version = '>= 2.6'
|
26
26
|
|
27
27
|
gem.add_development_dependency 'ethon', ['~> 0.11']
|
28
28
|
gem.add_development_dependency 'excon', ['~> 0.60']
|
29
|
-
gem.add_development_dependency 'faraday', ['~>
|
29
|
+
gem.add_development_dependency 'faraday', ['~> 1.3']
|
30
30
|
gem.add_development_dependency 'guard-rspec', ['~> 4.7']
|
31
31
|
gem.add_development_dependency 'http', ['~> 4.0']
|
32
32
|
gem.add_development_dependency 'httparty', ['~> 0.16']
|
33
33
|
gem.add_development_dependency 'httpclient', ['~> 2.8']
|
34
|
+
gem.add_development_dependency 'rest-client', ['~> 2.0']
|
35
|
+
gem.add_development_dependency 'typhoeus', ['~> 1.4']
|
34
36
|
gem.add_development_dependency 'listen', ['~> 3.0']
|
35
37
|
gem.add_development_dependency 'patron', ['~> 0.12']
|
36
|
-
gem.add_development_dependency 'rake', ['~>
|
38
|
+
gem.add_development_dependency 'rake', ['~> 13.0']
|
37
39
|
gem.add_development_dependency 'rspec', ['~> 3.7']
|
38
40
|
gem.add_development_dependency 'simplecov', ['~> 0.15']
|
39
41
|
gem.add_development_dependency 'thin', ['~> 1.7']
|
40
42
|
gem.add_development_dependency 'oj', ['>= 3.9.2']
|
41
43
|
|
42
|
-
gem.add_dependency 'rack', ['>=
|
44
|
+
gem.add_dependency 'rack', ['>= 2.0']
|
43
45
|
gem.add_dependency 'rainbow', ['>= 2.0.0']
|
44
46
|
end
|
@@ -8,7 +8,7 @@ if defined?(Ethon)
|
|
8
8
|
module Http
|
9
9
|
alias orig_http_request http_request
|
10
10
|
def http_request(url, action_name, options = {})
|
11
|
-
@http_log = options.merge(method: action_name) # remember this for compact logging
|
11
|
+
@http_log = options.merge(method: action_name, url: url) # remember this for compact logging
|
12
12
|
orig_http_request(url, action_name, options)
|
13
13
|
end
|
14
14
|
end
|
@@ -18,32 +18,50 @@ if defined?(Ethon)
|
|
18
18
|
def perform
|
19
19
|
return orig_perform unless HttpLog.url_approved?(url)
|
20
20
|
|
21
|
-
|
21
|
+
httplog_add_callback
|
22
22
|
|
23
|
-
|
24
|
-
# extract it from the response header.
|
25
|
-
encoding = response_headers.scan(/Content-Encoding: (\S+)/).flatten.first
|
26
|
-
content_type = response_headers.scan(/Content-Type: (\S+(; charset=\S+)?)/).flatten.first
|
23
|
+
bm = Benchmark.realtime { orig_perform }
|
27
24
|
|
28
|
-
|
29
|
-
|
30
|
-
headers = response_headers.split(/\r?\n/).drop(1)
|
25
|
+
url = @http_log[:url]
|
26
|
+
url = "#{url}?#{@http_log[:params]}" if @http_log[:params]
|
31
27
|
|
32
28
|
HttpLog.call(
|
33
29
|
method: @http_log[:method],
|
34
|
-
url:
|
30
|
+
url: url,
|
35
31
|
request_body: @http_log[:body],
|
36
32
|
request_headers: @http_log[:headers],
|
37
33
|
response_code: @return_code,
|
38
|
-
response_body: response_body,
|
39
|
-
response_headers:
|
34
|
+
response_body: @http_log[:response_body],
|
35
|
+
response_headers: @http_log[:response_headers].map { |header| header.split(/:\s/) }.to_h,
|
40
36
|
benchmark: bm,
|
41
|
-
encoding: encoding,
|
42
|
-
content_type: content_type,
|
43
|
-
mask_body: HttpLog.masked_body_url?(url)
|
37
|
+
encoding: @http_log[:encoding],
|
38
|
+
content_type: @http_log[:content_type],
|
39
|
+
mask_body: HttpLog.masked_body_url?(@http_log[:url])
|
44
40
|
)
|
45
41
|
return_code
|
46
42
|
end
|
43
|
+
|
44
|
+
def httplog_add_callback
|
45
|
+
# Hack to perform this callback before the cleanup
|
46
|
+
@on_complete ||= []
|
47
|
+
@on_complete.unshift -> (*) do
|
48
|
+
# Not sure where the actual status code is stored - so let's
|
49
|
+
# extract it from the response header.
|
50
|
+
encoding = response_headers.scan(/Content-Encoding: (\S+)/).flatten.first
|
51
|
+
content_type = response_headers.scan(/Content-Type: (\S+(; charset=\S+)?)/).flatten.first
|
52
|
+
|
53
|
+
# Hard to believe that Ethon wouldn't parse out the headers into
|
54
|
+
# an array; probably overlooked it. Anyway, let's do it ourselves:
|
55
|
+
headers = response_headers.split(/\r?\n/).drop(1)
|
56
|
+
|
57
|
+
@http_log.merge!(
|
58
|
+
encoding: encoding,
|
59
|
+
content_type: content_type,
|
60
|
+
response_headers: headers,
|
61
|
+
response_body: response_body
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
47
65
|
end
|
48
66
|
end
|
49
67
|
end
|
@@ -11,12 +11,22 @@ module Net
|
|
11
11
|
bm = Benchmark.realtime do
|
12
12
|
@response = orig_request(req, body, &block)
|
13
13
|
end
|
14
|
+
body_stream = req.body_stream
|
15
|
+
request_body = if body_stream
|
16
|
+
body_stream.to_s # read and rewind for RestClient::Payload::Base
|
17
|
+
body_stream.rewind if body_stream.respond_to?(:rewind) # RestClient::Payload::Base has no method rewind
|
18
|
+
body_stream.read
|
19
|
+
elsif req.body.nil? || req.body.empty?
|
20
|
+
body
|
21
|
+
else
|
22
|
+
req.body
|
23
|
+
end
|
14
24
|
|
15
25
|
if HttpLog.url_approved?(url) && started?
|
16
26
|
HttpLog.call(
|
17
27
|
method: req.method,
|
18
28
|
url: url,
|
19
|
-
request_body:
|
29
|
+
request_body: request_body,
|
20
30
|
request_headers: req.each_header.collect,
|
21
31
|
response_code: @response.code,
|
22
32
|
response_body: @response.body,
|
data/lib/httplog/http_log.rb
CHANGED
@@ -26,6 +26,7 @@ module HttpLog
|
|
26
26
|
|
27
27
|
def configure
|
28
28
|
yield(configuration)
|
29
|
+
configuration.json_parser ||= ::JSON if configuration.json_log || configuration.url_masked_body_pattern
|
29
30
|
end
|
30
31
|
|
31
32
|
def call(options = {})
|
@@ -121,22 +122,24 @@ module HttpLog
|
|
121
122
|
raise BodyParsingError, '(not available yet)'
|
122
123
|
end
|
123
124
|
|
124
|
-
|
125
|
-
|
125
|
+
body_copy = body.dup
|
126
|
+
body_copy = body.to_s if defined?(HTTP::Response::Body) && body.is_a?(HTTP::Response::Body)
|
127
|
+
return nil if body_copy.nil? || body_copy.empty?
|
126
128
|
|
127
|
-
|
129
|
+
|
130
|
+
if encoding =~ /gzip/
|
128
131
|
begin
|
129
|
-
sio = StringIO.new(
|
132
|
+
sio = StringIO.new(body_copy.to_s)
|
130
133
|
gz = Zlib::GzipReader.new(sio)
|
131
|
-
|
134
|
+
body_copy = gz.read
|
132
135
|
rescue Zlib::GzipFile::Error
|
133
136
|
log("(gzip decompression failed)")
|
134
137
|
end
|
135
138
|
end
|
136
139
|
|
137
|
-
result = utf_encoded(
|
140
|
+
result = utf_encoded(body_copy.to_s, content_type)
|
138
141
|
|
139
|
-
if mask_body
|
142
|
+
if mask_body
|
140
143
|
if content_type =~ /json/
|
141
144
|
result = begin
|
142
145
|
masked_data config.json_parser.load(result)
|
@@ -259,12 +262,14 @@ module HttpLog
|
|
259
262
|
# in its entirety.
|
260
263
|
return (config.filter_parameters.include?(key.downcase) ? PARAM_MASK : msg) if key
|
261
264
|
|
262
|
-
# Otherwise, we'll parse Strings for key=
|
265
|
+
# Otherwise, we'll parse Strings for key=value pairs,
|
266
|
+
# for name="key"\n value...
|
263
267
|
case msg
|
264
268
|
when *string_classes
|
265
269
|
config.filter_parameters.reduce(msg) do |m,key|
|
266
270
|
scrubbed = m.to_s.encode('UTF-8', invalid: :replace, undef: :replace)
|
267
|
-
scrubbed.gsub(/(#{key})=[^&]+/i, "#{key}=#{PARAM_MASK}")
|
271
|
+
scrubbed.to_s.gsub(/(#{key})=[^&]+/i, "#{key}=#{PARAM_MASK}")
|
272
|
+
.gsub(/name="#{key}"\s+\K[\s\w]+/, "#{PARAM_MASK}\r\n") # multi-part Faraday
|
268
273
|
end
|
269
274
|
# ...and recurse over hashes
|
270
275
|
when *hash_classes
|
@@ -345,7 +350,7 @@ module HttpLog
|
|
345
350
|
end
|
346
351
|
|
347
352
|
def log_data_lines(data)
|
348
|
-
data.each_line.with_index do |line, row|
|
353
|
+
data.to_s.each_line.with_index do |line, row|
|
349
354
|
if config.prefix_line_numbers
|
350
355
|
log("#{row + 1}: #{line.chomp}")
|
351
356
|
else
|
data/lib/httplog/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httplog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thilo Rusche
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ethon
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '1.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '1.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: guard-rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +108,34 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '2.8'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rest-client
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '2.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '2.0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: typhoeus
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.4'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.4'
|
111
139
|
- !ruby/object:Gem::Dependency
|
112
140
|
name: listen
|
113
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,14 +170,14 @@ dependencies:
|
|
142
170
|
requirements:
|
143
171
|
- - "~>"
|
144
172
|
- !ruby/object:Gem::Version
|
145
|
-
version: '
|
173
|
+
version: '13.0'
|
146
174
|
type: :development
|
147
175
|
prerelease: false
|
148
176
|
version_requirements: !ruby/object:Gem::Requirement
|
149
177
|
requirements:
|
150
178
|
- - "~>"
|
151
179
|
- !ruby/object:Gem::Version
|
152
|
-
version: '
|
180
|
+
version: '13.0'
|
153
181
|
- !ruby/object:Gem::Dependency
|
154
182
|
name: rspec
|
155
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -212,14 +240,14 @@ dependencies:
|
|
212
240
|
requirements:
|
213
241
|
- - ">="
|
214
242
|
- !ruby/object:Gem::Version
|
215
|
-
version: '
|
243
|
+
version: '2.0'
|
216
244
|
type: :runtime
|
217
245
|
prerelease: false
|
218
246
|
version_requirements: !ruby/object:Gem::Requirement
|
219
247
|
requirements:
|
220
248
|
- - ">="
|
221
249
|
- !ruby/object:Gem::Version
|
222
|
-
version: '
|
250
|
+
version: '2.0'
|
223
251
|
- !ruby/object:Gem::Dependency
|
224
252
|
name: rainbow
|
225
253
|
requirement: !ruby/object:Gem::Requirement
|
@@ -267,14 +295,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
267
295
|
requirements:
|
268
296
|
- - ">="
|
269
297
|
- !ruby/object:Gem::Version
|
270
|
-
version: '2.
|
298
|
+
version: '2.6'
|
271
299
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
272
300
|
requirements:
|
273
301
|
- - ">="
|
274
302
|
- !ruby/object:Gem::Version
|
275
303
|
version: '0'
|
276
304
|
requirements: []
|
277
|
-
rubygems_version: 3.
|
305
|
+
rubygems_version: 3.3.7
|
278
306
|
signing_key:
|
279
307
|
specification_version: 4
|
280
308
|
summary: Log outgoing HTTP requests.
|