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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 590ce26a5ad8498e9a23d0d04fb67d145839c3d2
4
- data.tar.gz: 3b14c745464c253f07dc3f1d3114670ef69498f4
3
+ metadata.gz: 5c6903ab2693fd8f2192bcdf3a3d56353cb5954b
4
+ data.tar.gz: bf21e7e9fe1d0730288c412e88ac1c011238316d
5
5
  SHA512:
6
- metadata.gz: 52bbc22b98b568a93abca85bb5037d5c01d21e791d15ed484ea8f03a3a895d15f6a251fd02bbe33d64b0b507db8850a07e52cb8c1244ae162fff67ef2328b94f
7
- data.tar.gz: 2f7471095ee5ac2a94e9f98ca55e23d6656d6ff84126eb3860998b909484442e5adc97eb8b18217880cd10a4c849b7a14c72d68a85750751670f8ed8e51413bb
6
+ metadata.gz: e2682ddacc69dbd6f7300b12d29f05e0350bb0d4b33b4bab108f46abe0b14d652a1f6963a141a9cb31cbdfd11eee4c5e4867af5e088449e5a3df4bc829a70466
7
+ data.tar.gz: d6b82afc9f5f2e2adb7a41eaa1ea81363aefd54da2dbaef4d4bb5b30c7411e7f8cbeedf62e7402719bbd8f4940b34e14bd8388d3db673d4dd32630224f9d1633
data/Gemfile CHANGED
@@ -5,4 +5,5 @@ gemspec
5
5
 
6
6
  group :test do
7
7
  gem 'rake'
8
+ gem "factory_girl", "~> 4.0"
8
9
  end
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.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.3.0'
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.12', '< 1'
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 ||= Logger.new(STDOUT)
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['grape.request'].request_method,
20
- env['grape.request'].path,
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['grape.request.params'].to_hash
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
@@ -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: ParamFilter.new, logger: Object.new } }
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) { Rack::Response.new 'Hello World', 200, {} }
11
- let(:grape_request) { OpenStruct.new(request_method: 'POST', path: '/api/1.0/users', headers: {}, params: { 'id' => '101001' }) }
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
@@ -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.3.0
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 00:00:00.000000000 Z
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.12'
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.12'
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