grape-middleware-logger 1.3.0 → 1.4.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/Gemfile +1 -0
- data/README.md +8 -1
- data/grape-middleware-logger.gemspec +2 -2
- data/lib/grape/middleware/logger.rb +25 -4
- data/spec/factories.rb +90 -0
- data/spec/integration/lib/grape/middleware/logger_spec.rb +52 -0
- data/spec/lib/grape/middleware/logger_spec.rb +8 -37
- data/spec/spec_helper.rb +5 -0
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c6903ab2693fd8f2192bcdf3a3d56353cb5954b
|
4
|
+
data.tar.gz: bf21e7e9fe1d0730288c412e88ac1c011238316d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2682ddacc69dbd6f7300b12d29f05e0350bb0d4b33b4bab108f46abe0b14d652a1f6963a141a9cb31cbdfd11eee4c5e4867af5e088449e5a3df4bc829a70466
|
7
|
+
data.tar.gz: d6b82afc9f5f2e2adb7a41eaa1ea81363aefd54da2dbaef4d4bb5b30c7411e7f8cbeedf62e7402719bbd8f4940b34e14bd8388d3db673d4dd32630224f9d1633
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -9,13 +9,14 @@ Simple logger for Grape apps. Logs request path, parameters, status and time tak
|
|
9
9
|
Add this line to your application's Gemfile:
|
10
10
|
|
11
11
|
```ruby
|
12
|
-
gem 'grape', '>= 0.
|
12
|
+
gem 'grape', '>= 0.14.0'
|
13
13
|
gem 'grape-middleware-logger'
|
14
14
|
```
|
15
15
|
|
16
16
|
## Usage
|
17
17
|
```ruby
|
18
18
|
class API < Grape::API
|
19
|
+
# @note Make sure this above you're first +mount+
|
19
20
|
use Grape::Middleware::Logger
|
20
21
|
end
|
21
22
|
```
|
@@ -41,17 +42,23 @@ The `filter` option can be any object that responds to `.filter(params_hash)`
|
|
41
42
|
Get
|
42
43
|
```
|
43
44
|
Started GET "/v1/reports/101" at 2015-12-11 15:40:51 -0800
|
45
|
+
Processing by ReportsAPI#reports/:id
|
44
46
|
Parameters: {"id"=>"101"}
|
45
47
|
Completed 200 in 6.29ms
|
46
48
|
```
|
47
49
|
Error
|
48
50
|
```
|
49
51
|
Started POST "/v1/reports" at 2015-12-11 15:42:33 -0800
|
52
|
+
Processing by ReportsAPI#reports
|
50
53
|
Parameters: {"name"=>"foo", "password"=>"[FILTERED]"}
|
51
54
|
Error: {:error=>"undefined something something bad", :detail=>"Whoops"}
|
52
55
|
Completed 422 in 6.29ms
|
53
56
|
```
|
54
57
|
|
58
|
+
## Rack
|
59
|
+
|
60
|
+
If you're using the `rackup` command to run your server in development, pass the `-q` flag to silence the default rack logger.
|
61
|
+
|
55
62
|
## Credits
|
56
63
|
|
57
64
|
Big thanks to jadent's question/answer on [stackoverflow](http://stackoverflow.com/questions/25048163/grape-using-error-and-grapemiddleware-after-callback)
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = 'grape-middleware-logger'
|
5
|
-
spec.version = '1.
|
5
|
+
spec.version = '1.4.0'
|
6
6
|
spec.platform = Gem::Platform::RUBY
|
7
7
|
spec.authors = ['Ryan Buckley']
|
8
8
|
spec.email = ['arebuckley@gmail.com']
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
17
|
spec.require_paths = ['lib']
|
18
18
|
|
19
|
-
spec.add_dependency 'grape', '>= 0.
|
19
|
+
spec.add_dependency 'grape', '>= 0.14', '< 1'
|
20
20
|
|
21
21
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
22
22
|
spec.add_development_dependency 'rake', '~> 10.0'
|
@@ -8,7 +8,7 @@ class Grape::Middleware::Logger < Grape::Middleware::Globals
|
|
8
8
|
super
|
9
9
|
@logger = options[:logger]
|
10
10
|
@logger ||= Rails.logger if defined?(Rails) && Rails.logger.present?
|
11
|
-
@logger ||=
|
11
|
+
@logger ||= default_logger
|
12
12
|
end
|
13
13
|
|
14
14
|
def before
|
@@ -16,10 +16,11 @@ class Grape::Middleware::Logger < Grape::Middleware::Globals
|
|
16
16
|
super # sets env['grape.*']
|
17
17
|
logger.info ''
|
18
18
|
logger.info %Q(Started %s "%s" at %s) % [
|
19
|
-
env[
|
20
|
-
env[
|
19
|
+
env[Grape::Env::GRAPE_REQUEST].request_method,
|
20
|
+
env[Grape::Env::GRAPE_REQUEST].path,
|
21
21
|
start_time.to_s
|
22
22
|
]
|
23
|
+
logger.info %Q(Processing by #{processed_by})
|
23
24
|
logger.info %Q( Parameters: #{parameters})
|
24
25
|
end
|
25
26
|
|
@@ -73,7 +74,7 @@ class Grape::Middleware::Logger < Grape::Middleware::Globals
|
|
73
74
|
end
|
74
75
|
|
75
76
|
def parameters
|
76
|
-
request_params = env[
|
77
|
+
request_params = env[Grape::Env::GRAPE_REQUEST_PARAMS].to_hash
|
77
78
|
request_params.merge!(env['action_dispatch.request.request_parameters'] || {}) # for Rails
|
78
79
|
if @options[:filter]
|
79
80
|
@options[:filter].filter(request_params)
|
@@ -85,4 +86,24 @@ class Grape::Middleware::Logger < Grape::Middleware::Globals
|
|
85
86
|
def start_time
|
86
87
|
@start_time ||= Time.now
|
87
88
|
end
|
89
|
+
|
90
|
+
def processed_by
|
91
|
+
endpoint = env[Grape::Env::API_ENDPOINT]
|
92
|
+
parts = endpoint.options[:for].to_s
|
93
|
+
parts << endpoint.namespace if endpoint.namespace != '/'
|
94
|
+
parts << '#' << endpoint.options[:path].map { |path| path.to_s.sub('/', '') }.join('/')
|
95
|
+
parts
|
96
|
+
end
|
97
|
+
|
98
|
+
def default_logger
|
99
|
+
default = Logger.new(STDOUT)
|
100
|
+
default.formatter = LogFormatter.new
|
101
|
+
default
|
102
|
+
end
|
103
|
+
|
104
|
+
class LogFormatter
|
105
|
+
def call(*args)
|
106
|
+
args.last.to_s << "\n"
|
107
|
+
end
|
108
|
+
end
|
88
109
|
end
|
data/spec/factories.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
class ExpectedEnv < Hash
|
3
|
+
attr_accessor :grape_request, :params, :post_params, :grape_endpoint
|
4
|
+
end
|
5
|
+
|
6
|
+
class ParamFilter
|
7
|
+
def filter(opts)
|
8
|
+
opts.each_pair { |key, val| val[0..-1] = '[FILTERED]' if key == 'password' }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class TestAPI
|
13
|
+
end
|
14
|
+
|
15
|
+
class App
|
16
|
+
attr_accessor :response
|
17
|
+
|
18
|
+
def call(_env)
|
19
|
+
response
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
factory :param_filter
|
24
|
+
|
25
|
+
require 'rack/rewindable_input'
|
26
|
+
|
27
|
+
factory :expected_env do
|
28
|
+
grape_request { build :grape_request }
|
29
|
+
params { grape_request.params }
|
30
|
+
post_params { { 'name' => 'foo', 'password' => 'access' } }
|
31
|
+
grape_endpoint { build(:grape_endpoint) }
|
32
|
+
|
33
|
+
initialize_with do
|
34
|
+
new.merge(
|
35
|
+
'REQUEST_METHOD' => 'POST',
|
36
|
+
'PATH_INFO' => '/api/1.0/users',
|
37
|
+
'action_dispatch.request.request_parameters' => post_params,
|
38
|
+
Grape::Env::GRAPE_REQUEST => grape_request,
|
39
|
+
Grape::Env::GRAPE_REQUEST_PARAMS => params,
|
40
|
+
Grape::Env::API_ENDPOINT => grape_endpoint
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
factory :grape_endpoint, class: Grape::Endpoint do
|
46
|
+
settings { Grape::Util::InheritableSetting.new }
|
47
|
+
options {
|
48
|
+
{
|
49
|
+
path: [:users],
|
50
|
+
method: 'get',
|
51
|
+
for: TestAPI
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
initialize_with { new(settings, options) }
|
56
|
+
|
57
|
+
trait :complex do
|
58
|
+
options {
|
59
|
+
{
|
60
|
+
path: ['/users/:name/profile'],
|
61
|
+
method: 'put',
|
62
|
+
for: TestAPI
|
63
|
+
}
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
factory :namespaced_endpoint, parent: :grape_endpoint do
|
69
|
+
initialize_with do
|
70
|
+
new(settings, options).tap do |me|
|
71
|
+
me.namespace_stackable(:namespace, Grape::Namespace.new('/admin', {}))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
factory :app_response, class: Rack::Response do
|
77
|
+
initialize_with { new('Hello World', 200, {}) }
|
78
|
+
end
|
79
|
+
|
80
|
+
factory :grape_request, class: OpenStruct do
|
81
|
+
initialize_with {
|
82
|
+
new(request_method: 'POST', path: '/api/1.0/users', headers: {}, params: { 'id' => '101001' })
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
factory :app do
|
87
|
+
response { build :app_response }
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'grape/middleware/logger'
|
3
|
+
|
4
|
+
describe Grape::Middleware::Logger, type: :integration do
|
5
|
+
let(:app) { build :app }
|
6
|
+
let(:options) { { filter: build(:param_filter), logger: Logger.new(Tempfile.new('logger')) } }
|
7
|
+
|
8
|
+
subject { described_class.new(app, options) }
|
9
|
+
|
10
|
+
let(:app_response) { build :app_response }
|
11
|
+
let(:grape_request) { build :grape_request }
|
12
|
+
let(:grape_endpoint) { build(:grape_endpoint) }
|
13
|
+
let(:env) { build(:expected_env, grape_endpoint: grape_endpoint) }
|
14
|
+
|
15
|
+
it 'logs all parts of the request' do
|
16
|
+
expect(subject.logger).to receive(:info).with ''
|
17
|
+
expect(subject.logger).to receive(:info).with %Q(Started POST "/api/1.0/users" at #{subject.start_time})
|
18
|
+
expect(subject.logger).to receive(:info).with %Q(Processing by TestAPI#users)
|
19
|
+
expect(subject.logger).to receive(:info).with %Q( Parameters: {"id"=>"101001", "name"=>"foo", "password"=>"[FILTERED]"})
|
20
|
+
expect(subject.logger).to receive(:info).with /Completed 200 in \d.\d+ms/
|
21
|
+
expect(subject.logger).to receive(:info).with ''
|
22
|
+
subject.call!(env)
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'the "processing by" section' do
|
26
|
+
before { subject.call!(env) }
|
27
|
+
|
28
|
+
context 'namespacing' do
|
29
|
+
let(:grape_endpoint) { build(:namespaced_endpoint) }
|
30
|
+
|
31
|
+
it 'designates the namespace with a slash' do
|
32
|
+
expect(subject.processed_by).to eq 'TestAPI/admin#users'
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'with more complex route' do
|
36
|
+
let(:grape_endpoint) { build(:namespaced_endpoint, :complex) }
|
37
|
+
|
38
|
+
it 'only escapes the first slash and leaves the rest of the untouched' do
|
39
|
+
expect(subject.processed_by).to eq 'TestAPI/admin#users/:name/profile'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'with more complex route' do
|
45
|
+
let(:grape_endpoint) { build(:grape_endpoint, :complex) }
|
46
|
+
|
47
|
+
it 'only escapes the first slash and leaves the rest of the untouched' do
|
48
|
+
expect(subject.processed_by).to eq 'TestAPI#users/:name/profile'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,25 +1,14 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'grape/middleware/logger'
|
3
2
|
|
4
3
|
describe Grape::Middleware::Logger do
|
5
4
|
let(:app) { double('app') }
|
6
|
-
let(:options) { { filter:
|
5
|
+
let(:options) { { filter: build(:param_filter), logger: Object.new } }
|
7
6
|
|
8
7
|
subject { described_class.new(app, options) }
|
9
8
|
|
10
|
-
let(:app_response) {
|
11
|
-
let(:grape_request) {
|
12
|
-
let(:env) {
|
13
|
-
{
|
14
|
-
'grape.request' => grape_request,
|
15
|
-
'grape.request.params' => grape_request.params,
|
16
|
-
'action_dispatch.request.request_parameters' => {
|
17
|
-
'name' => 'foo',
|
18
|
-
'password' => 'access'
|
19
|
-
},
|
20
|
-
'rack.input' => OpenStruct.new
|
21
|
-
}
|
22
|
-
}
|
9
|
+
let(:app_response) { build :app_response }
|
10
|
+
let(:grape_request) { build :grape_request }
|
11
|
+
let(:env) { build(:expected_env) }
|
23
12
|
|
24
13
|
describe '#call!' do
|
25
14
|
context 'when calling the app results in an error response' do
|
@@ -128,6 +117,10 @@ describe Grape::Middleware::Logger do
|
|
128
117
|
expect(subject.logger).to be_a(Logger)
|
129
118
|
end
|
130
119
|
|
120
|
+
it 'logs each message in the correct format' do
|
121
|
+
expect(subject.logger.formatter.call('foo')).to eq "foo\n"
|
122
|
+
end
|
123
|
+
|
131
124
|
context 'when Rails.logger is defined' do
|
132
125
|
before do
|
133
126
|
Rails.logger = double('rails_logger')
|
@@ -154,26 +147,4 @@ describe Grape::Middleware::Logger do
|
|
154
147
|
end
|
155
148
|
end
|
156
149
|
end
|
157
|
-
|
158
|
-
describe 'integration' do
|
159
|
-
it 'properly logs requests' do
|
160
|
-
expect(app).to receive(:call).with(env).and_return(app_response)
|
161
|
-
expect(Grape::Request).to receive(:new).and_return(grape_request)
|
162
|
-
expect(subject.logger).to receive(:info).with('')
|
163
|
-
expect(subject.logger).to receive(:info).with(%Q(Started POST "/api/1.0/users" at #{subject.start_time}))
|
164
|
-
expect(subject.logger).to receive(:info).with(%Q( Parameters: {"id"=>"101001", "name"=>"foo", "password"=>"[FILTERED]"}))
|
165
|
-
expect(subject.logger).to receive(:info).with(/Completed 200 in \d.\d+ms/)
|
166
|
-
expect(subject.logger).to receive(:info).with('')
|
167
|
-
subject.call!(env)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
#
|
172
|
-
# Test class
|
173
|
-
#
|
174
|
-
class ParamFilter
|
175
|
-
def filter(opts)
|
176
|
-
opts.each_pair { |key, val| val[0..-1] = '[FILTERED]' if key == 'password' }
|
177
|
-
end
|
178
|
-
end
|
179
150
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,7 +2,12 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
2
2
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
3
|
|
4
4
|
require 'ostruct'
|
5
|
+
require 'factory_girl'
|
6
|
+
require 'grape/middleware/logger'
|
7
|
+
|
8
|
+
FactoryGirl.find_definitions
|
5
9
|
|
6
10
|
RSpec.configure do |config|
|
7
11
|
config.raise_errors_for_deprecations!
|
12
|
+
config.include FactoryGirl::Syntax::Methods
|
8
13
|
end
|
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.4.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: 2015-12-
|
11
|
+
date: 2015-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: grape
|
@@ -16,7 +16,7 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.14'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '1'
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '0.
|
29
|
+
version: '0.14'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '1'
|
@@ -93,6 +93,8 @@ files:
|
|
93
93
|
- Rakefile
|
94
94
|
- grape-middleware-logger.gemspec
|
95
95
|
- lib/grape/middleware/logger.rb
|
96
|
+
- spec/factories.rb
|
97
|
+
- spec/integration/lib/grape/middleware/logger_spec.rb
|
96
98
|
- spec/lib/grape/middleware/logger_spec.rb
|
97
99
|
- spec/spec_helper.rb
|
98
100
|
homepage: ''
|
@@ -120,5 +122,7 @@ signing_key:
|
|
120
122
|
specification_version: 4
|
121
123
|
summary: A logger for the Grape framework
|
122
124
|
test_files:
|
125
|
+
- spec/factories.rb
|
126
|
+
- spec/integration/lib/grape/middleware/logger_spec.rb
|
123
127
|
- spec/lib/grape/middleware/logger_spec.rb
|
124
128
|
- spec/spec_helper.rb
|