grape-middleware-logger 1.7.1 → 1.8.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 +4 -0
- data/README.md +5 -1
- data/grape-middleware-logger.gemspec +1 -1
- data/lib/grape/middleware/logger.rb +15 -1
- data/spec/factories.rb +26 -2
- data/spec/integration/lib/grape/middleware/headers_option_spec.rb +65 -0
- data/spec/lib/grape/middleware/headers_option_spec.rb +57 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7c3e7ac5229767e264e6037c0a1af92946af940
|
4
|
+
data.tar.gz: b471c789e7ad5107630deea636a10594f623da02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85a21c6f2dd2c0376eb2db6968683e2444a75dfe982206450c707fdade2a2327811eddaca6aba516c64f01c86b26b5ae1115b4cc575930105192ea768113d423
|
7
|
+
data.tar.gz: 3d4510679704050630b392f1246843a37885fac14cd56621b527bfb27490e5a6439e0cf198ed7b966ade5cf76a7a7639fa15718b83fefa134012f13c39cebd62
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
1.8.0 (4/22/2017)
|
2
|
+
==================
|
3
|
+
* [#17] Add a `:headers` option, which can be either `:all` or an array of strings. (Thanks [@yamamotok](https://github.com/yamamotok))
|
4
|
+
|
1
5
|
1.7.1 (11/1/2016)
|
2
6
|
==================
|
3
7
|
* Log the error class name (https://github.com/ridiculous/grape-middleware-logger/pull/13)
|
data/README.md
CHANGED
@@ -53,13 +53,17 @@ The middleware logger can be customized with the following options:
|
|
53
53
|
|
54
54
|
* The `:logger` option can be any object that responds to `.info(String)`
|
55
55
|
* The `:filter` option can be any object that responds to `.filter(Hash)` and returns a hash.
|
56
|
+
* The `:headers` option can be either `:all` or array of strings.
|
57
|
+
+ If `:all`, all request headers will be output.
|
58
|
+
+ If array, output will be filtered by names in the array. (case-insensitive)
|
56
59
|
|
57
60
|
For example:
|
58
61
|
|
59
62
|
```ruby
|
60
63
|
insert_after Grape::Middleware::Formatter, Grape::Middleware::Logger, {
|
61
64
|
logger: Logger.new(STDERR),
|
62
|
-
filter: Class.new { def filter(opts) opts.reject { |k, _| k.to_s == 'password' } end }.new
|
65
|
+
filter: Class.new { def filter(opts) opts.reject { |k, _| k.to_s == 'password' } end }.new,
|
66
|
+
headers: %w(version cache-control)
|
63
67
|
}
|
64
68
|
```
|
65
69
|
|
@@ -7,7 +7,7 @@ class Grape::Middleware::Logger < Grape::Middleware::Globals
|
|
7
7
|
attr_reader :logger
|
8
8
|
|
9
9
|
class << self
|
10
|
-
attr_accessor :logger, :filter
|
10
|
+
attr_accessor :logger, :filter, :headers
|
11
11
|
|
12
12
|
def default_logger
|
13
13
|
default = Logger.new(STDOUT)
|
@@ -19,6 +19,7 @@ class Grape::Middleware::Logger < Grape::Middleware::Globals
|
|
19
19
|
def initialize(_, options = {})
|
20
20
|
super
|
21
21
|
@options[:filter] ||= self.class.filter
|
22
|
+
@options[:headers] ||= self.class.headers
|
22
23
|
@logger = options[:logger] || self.class.logger || self.class.default_logger
|
23
24
|
end
|
24
25
|
|
@@ -34,6 +35,7 @@ class Grape::Middleware::Logger < Grape::Middleware::Globals
|
|
34
35
|
]
|
35
36
|
logger.info %Q(Processing by #{processed_by})
|
36
37
|
logger.info %Q( Parameters: #{parameters})
|
38
|
+
logger.info %Q( Headers: #{headers}) if @options[:headers]
|
37
39
|
end
|
38
40
|
|
39
41
|
# @note Error and exception handling are required for the +after+ hooks
|
@@ -91,6 +93,18 @@ class Grape::Middleware::Logger < Grape::Middleware::Globals
|
|
91
93
|
end
|
92
94
|
end
|
93
95
|
|
96
|
+
def headers
|
97
|
+
request_headers = env[Grape::Env::GRAPE_REQUEST_HEADERS].to_hash
|
98
|
+
return Hash[request_headers.sort] if @options[:headers] == :all
|
99
|
+
|
100
|
+
headers_needed = Array(@options[:headers])
|
101
|
+
result = {}
|
102
|
+
headers_needed.each do |need|
|
103
|
+
result.merge!(request_headers.select { |key, value| need.to_s.casecmp(key).zero? })
|
104
|
+
end
|
105
|
+
Hash[result.sort]
|
106
|
+
end
|
107
|
+
|
94
108
|
def start_time
|
95
109
|
@start_time ||= Time.now
|
96
110
|
end
|
data/spec/factories.rb
CHANGED
@@ -32,8 +32,10 @@ FactoryGirl.define do
|
|
32
32
|
grape_request { build :grape_request }
|
33
33
|
grape_endpoint { build(:grape_endpoint) }
|
34
34
|
params { grape_request.params }
|
35
|
+
headers { grape_request.headers }
|
35
36
|
post_params { { 'secret' => 'key', 'customer' => [] } }
|
36
37
|
rails_post_params { { 'name' => 'foo', 'password' => 'access' } }
|
38
|
+
other_env_params { {} }
|
37
39
|
|
38
40
|
initialize_with do
|
39
41
|
new.merge(
|
@@ -42,10 +44,21 @@ FactoryGirl.define do
|
|
42
44
|
'action_dispatch.request.request_parameters' => rails_post_params,
|
43
45
|
Grape::Env::GRAPE_REQUEST => grape_request,
|
44
46
|
Grape::Env::GRAPE_REQUEST_PARAMS => params,
|
47
|
+
Grape::Env::GRAPE_REQUEST_HEADERS => headers,
|
45
48
|
Grape::Env::RACK_REQUEST_FORM_HASH => post_params,
|
46
49
|
Grape::Env::API_ENDPOINT => grape_endpoint
|
47
|
-
)
|
50
|
+
).merge(other_env_params)
|
48
51
|
end
|
52
|
+
|
53
|
+
trait :prefixed_basic_headers do
|
54
|
+
other_env_params { {
|
55
|
+
'HTTP_VERSION' => 'HTTP/1.1',
|
56
|
+
'HTTP_CACHE_CONTROL' => 'max-age=0',
|
57
|
+
'HTTP_USER_AGENT' => 'Mozilla/5.0',
|
58
|
+
'HTTP_ACCEPT_LANGUAGE' => 'en-US'
|
59
|
+
} }
|
60
|
+
end
|
61
|
+
|
49
62
|
end
|
50
63
|
|
51
64
|
factory :grape_endpoint, class: Grape::Endpoint do
|
@@ -84,9 +97,20 @@ FactoryGirl.define do
|
|
84
97
|
end
|
85
98
|
|
86
99
|
factory :grape_request, class: OpenStruct do
|
100
|
+
headers { {} }
|
101
|
+
|
87
102
|
initialize_with {
|
88
|
-
new(request_method: 'POST', path: '/api/1.0/users', headers:
|
103
|
+
new(request_method: 'POST', path: '/api/1.0/users', headers: headers, params: { 'id' => '101001' })
|
89
104
|
}
|
105
|
+
|
106
|
+
trait :basic_headers do
|
107
|
+
headers { {
|
108
|
+
'Version' => 'HTTP/1.1',
|
109
|
+
'Cache-Control' => 'max-age=0',
|
110
|
+
'User-Agent' => 'Mozilla/5.0',
|
111
|
+
'Accept-Language' => 'en-US'
|
112
|
+
} }
|
113
|
+
end
|
90
114
|
end
|
91
115
|
|
92
116
|
factory :app do
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grape::Middleware::Logger, type: :integration do
|
4
|
+
let(:app) { build :app }
|
5
|
+
|
6
|
+
subject { described_class.new(app, options) }
|
7
|
+
|
8
|
+
let(:grape_endpoint) { build(:grape_endpoint) }
|
9
|
+
let(:env) { build(:expected_env, :prefixed_basic_headers, grape_endpoint: grape_endpoint) }
|
10
|
+
|
11
|
+
context ':all option is set to option headers' do
|
12
|
+
let(:options) { {
|
13
|
+
filter: build(:param_filter),
|
14
|
+
headers: :all,
|
15
|
+
logger: Logger.new(Tempfile.new('logger'))
|
16
|
+
} }
|
17
|
+
it 'all headers will be shown, headers will be sorted by name' do
|
18
|
+
expect(subject.logger).to receive(:info).with ''
|
19
|
+
expect(subject.logger).to receive(:info).with %Q(Started POST "/api/1.0/users" at #{subject.start_time})
|
20
|
+
expect(subject.logger).to receive(:info).with %Q(Processing by TestAPI/users)
|
21
|
+
expect(subject.logger).to receive(:info).with %Q( Parameters: {"id"=>"101001", "secret"=>"[FILTERED]", "customer"=>[], "name"=>"foo", "password"=>"[FILTERED]"})
|
22
|
+
expect(subject.logger).to receive(:info).with %Q( Headers: {"Accept-Language"=>"en-US", "Cache-Control"=>"max-age=0", "User-Agent"=>"Mozilla/5.0", "Version"=>"HTTP/1.1"})
|
23
|
+
expect(subject.logger).to receive(:info).with /Completed 200 in \d+.\d+ms/
|
24
|
+
expect(subject.logger).to receive(:info).with ''
|
25
|
+
subject.call!(env)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'list of names ["User-Agent", "Cache-Control"] is set to option headers' do
|
30
|
+
let(:options) { {
|
31
|
+
filter: build(:param_filter),
|
32
|
+
headers: %w(User-Agent Cache-Control),
|
33
|
+
logger: Logger.new(Tempfile.new('logger'))
|
34
|
+
} }
|
35
|
+
it 'two headers will be shown' do
|
36
|
+
expect(subject.logger).to receive(:info).with ''
|
37
|
+
expect(subject.logger).to receive(:info).with %Q(Started POST "/api/1.0/users" at #{subject.start_time})
|
38
|
+
expect(subject.logger).to receive(:info).with %Q(Processing by TestAPI/users)
|
39
|
+
expect(subject.logger).to receive(:info).with %Q( Parameters: {"id"=>"101001", "secret"=>"[FILTERED]", "customer"=>[], "name"=>"foo", "password"=>"[FILTERED]"})
|
40
|
+
expect(subject.logger).to receive(:info).with %Q( Headers: {"Cache-Control"=>"max-age=0", "User-Agent"=>"Mozilla/5.0"})
|
41
|
+
expect(subject.logger).to receive(:info).with /Completed 200 in \d+.\d+ms/
|
42
|
+
expect(subject.logger).to receive(:info).with ''
|
43
|
+
subject.call!(env)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'a single string "Cache-Control" is set to option headers' do
|
48
|
+
let(:options) { {
|
49
|
+
filter: build(:param_filter),
|
50
|
+
headers: 'Cache-Control',
|
51
|
+
logger: Logger.new(Tempfile.new('logger'))
|
52
|
+
} }
|
53
|
+
it 'only Cache-Control header will be shown' do
|
54
|
+
expect(subject.logger).to receive(:info).with ''
|
55
|
+
expect(subject.logger).to receive(:info).with %Q(Started POST "/api/1.0/users" at #{subject.start_time})
|
56
|
+
expect(subject.logger).to receive(:info).with %Q(Processing by TestAPI/users)
|
57
|
+
expect(subject.logger).to receive(:info).with %Q( Parameters: {"id"=>"101001", "secret"=>"[FILTERED]", "customer"=>[], "name"=>"foo", "password"=>"[FILTERED]"})
|
58
|
+
expect(subject.logger).to receive(:info).with %Q( Headers: {"Cache-Control"=>"max-age=0"})
|
59
|
+
expect(subject.logger).to receive(:info).with /Completed 200 in \d+.\d+ms/
|
60
|
+
expect(subject.logger).to receive(:info).with ''
|
61
|
+
subject.call!(env)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grape::Middleware::Logger do
|
4
|
+
let(:app) { double('app') }
|
5
|
+
|
6
|
+
subject { described_class.new(app, options) }
|
7
|
+
|
8
|
+
describe '#headers' do
|
9
|
+
let(:grape_request) { build :grape_request, :basic_headers }
|
10
|
+
let(:env) { build :expected_env, grape_request: grape_request }
|
11
|
+
|
12
|
+
before { subject.instance_variable_set(:@env, env) }
|
13
|
+
|
14
|
+
context 'when @options[:headers] has a symbol :all' do
|
15
|
+
let(:options) { { headers: :all, logger: Object.new } }
|
16
|
+
it 'all request headers should be retrieved' do
|
17
|
+
expect(subject.headers.fetch('Accept-Language')).to eq('en-US')
|
18
|
+
expect(subject.headers.fetch('Cache-Control')).to eq('max-age=0')
|
19
|
+
expect(subject.headers.fetch('User-Agent')).to eq('Mozilla/5.0')
|
20
|
+
expect(subject.headers.fetch('Version')).to eq('HTTP/1.1')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when @options[:headers] is a string "user-agent"' do
|
25
|
+
let(:options) { { headers: 'user-agent', logger: Object.new } }
|
26
|
+
it 'only "User-Agent" should be retrieved' do
|
27
|
+
expect(subject.headers.fetch('User-Agent')).to eq('Mozilla/5.0')
|
28
|
+
expect(subject.headers.length).to eq(1)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when @options[:headers] is an array of ["user-agent", "Cache-Control", "Unknown"]' do
|
33
|
+
let(:options) { { headers: %w(user-agent Cache-Control Unknown), logger: Object.new } }
|
34
|
+
it '"User-Agent" and "Cache-Control" should be retrieved' do
|
35
|
+
expect(subject.headers.fetch('Cache-Control')).to eq('max-age=0')
|
36
|
+
expect(subject.headers.fetch('User-Agent')).to eq('Mozilla/5.0')
|
37
|
+
end
|
38
|
+
it '"Unknown" name does not make any effect' do
|
39
|
+
expect(subject.headers.length).to eq(2)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#headers if no request header' do
|
45
|
+
let(:env) { build :expected_env }
|
46
|
+
before { subject.instance_variable_set(:@env, env) }
|
47
|
+
|
48
|
+
context 'when @options[:headers] is set, but no request header is there' do
|
49
|
+
let(:options) { { headers: %w(user-agent Cache-Control), logger: Object.new } }
|
50
|
+
it 'subject.headers should return empty hash' do
|
51
|
+
expect(subject.headers.length).to eq(0)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grape-middleware-logger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Buckley
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: grape
|
@@ -112,8 +112,10 @@ files:
|
|
112
112
|
- lib/grape/middleware/logger/railtie.rb
|
113
113
|
- spec/factories.rb
|
114
114
|
- spec/fixtures/rails_app.rb
|
115
|
+
- spec/integration/lib/grape/middleware/headers_option_spec.rb
|
115
116
|
- spec/integration/lib/grape/middleware/logger_spec.rb
|
116
117
|
- spec/integration_rails/lib/grape/middleware/logger_spec.rb
|
118
|
+
- spec/lib/grape/middleware/headers_option_spec.rb
|
117
119
|
- spec/lib/grape/middleware/logger_spec.rb
|
118
120
|
- spec/rails_helper.rb
|
119
121
|
- spec/spec_helper.rb
|
@@ -146,8 +148,10 @@ summary: A logger for the Grape framework
|
|
146
148
|
test_files:
|
147
149
|
- spec/factories.rb
|
148
150
|
- spec/fixtures/rails_app.rb
|
151
|
+
- spec/integration/lib/grape/middleware/headers_option_spec.rb
|
149
152
|
- spec/integration/lib/grape/middleware/logger_spec.rb
|
150
153
|
- spec/integration_rails/lib/grape/middleware/logger_spec.rb
|
154
|
+
- spec/lib/grape/middleware/headers_option_spec.rb
|
151
155
|
- spec/lib/grape/middleware/logger_spec.rb
|
152
156
|
- spec/rails_helper.rb
|
153
157
|
- spec/spec_helper.rb
|