grape-middleware-logger 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|