rack-request_logger 0.0.4

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.
@@ -0,0 +1,187 @@
1
+ # Set Rack::RequestLogger.log_handler to an object with a write(params_hash) method
2
+ # This class can be extended and have the following methods overriden as desired:
3
+ #
4
+ # For logging more fields than the defaults, override:
5
+ # add_log_params(env_hash, status, response_headers, response_body, params_hash) # => modifies params_hash
6
+ #
7
+ # For filtering information from data to be logged, override:
8
+ # filter_request_headers(hash) # => returns hash with filtered values
9
+ # filter_request_body(string) # => returns filterd string
10
+ # filter_response_headers(hash) # => returns hash with filtered values
11
+ # filter_response_body(string) # => returns filterd string
12
+ #
13
+ # For special error handling, override:
14
+ # app_error(env_hash) # => returns an error to be logged
15
+ # The default app_error will handle errors thrown by Sinatra
16
+ # To set your own errors for logging,
17
+ # In Sintatra: env['request_logger.error'] = error
18
+ # In Rails: request.env['request_logger.error'] = error
19
+ # Or, override the method and handle it as desired.
20
+ #
21
+ # To control when logging happens, override:
22
+ # log_request?(env_hash, request, status, response_headers, response_body) # => returns boolean
23
+ # By default, this is always true
24
+
25
+ require 'rack'
26
+ require 'rack/tasks/request_log_readers'
27
+
28
+ module Rack
29
+ class RequestLogger
30
+ class << self
31
+ def log_handler=(log_handler)
32
+ @log_handler = log_handler
33
+ #Explicity set the logger on this class so everything works when this is inherited from
34
+ Rack::RequestLogger.instance_variable_set(:@log_handler, log_handler)
35
+ end
36
+
37
+ def log_handler
38
+ @log_handler
39
+ end
40
+ end
41
+
42
+ def initialize(app)
43
+ @app = app
44
+ end
45
+
46
+ def call(env)
47
+ begin
48
+ request_time = Time.now
49
+ request = Rack::Request.new env
50
+ status, response_headers, response_body = @app.call(env)
51
+ rescue => e
52
+ #TODO: Should return a better message, but this should basically never happen anyway,
53
+ # since @app.call won't throw execeptions, but rather catches and wraps them
54
+ status = 500
55
+ response_headers = {}
56
+ response_body = e.message
57
+ error = e
58
+ end
59
+
60
+ if log_handler.respond_to?(:write) && log_request?(env, request, status, response_headers, response_body)
61
+ begin
62
+ params = {
63
+ :url => request.url,
64
+ :method => request.request_method,
65
+ :request_headers => format_header_hash(filter_request_headers(request_headers(env))),
66
+ :request_body => filter_request_body(read_stream(request.body)),
67
+ :request_time => request_time,
68
+ :status => status,
69
+ :response_headers => format_header_hash(filter_response_headers(response_headers)),
70
+ :response_body => filter_response_body(response_body_to_s(response_body)),
71
+ :response_time => Time.now
72
+ }
73
+
74
+ add_log_params(env, status, response_headers, response_body, params)
75
+
76
+ remote_host = remote_host(env)
77
+ params[:remote_host] = remote_host if remote_host
78
+
79
+ error ||= app_error(env)
80
+ params[:error] = format_error(error) if error
81
+
82
+ log_handler.write params
83
+ rescue => e
84
+ begin
85
+ log_handler.write(
86
+ #TODO: Log more things that are safe, or ensure they are safe first
87
+ :error => format_error(e)
88
+ )
89
+ rescue
90
+ end
91
+ end
92
+ end
93
+
94
+ [status, response_headers, response_body]
95
+ end
96
+
97
+ protected
98
+
99
+ def log_handler
100
+ self.class.log_handler
101
+ end
102
+
103
+ def read_stream(data)
104
+ return nil unless data
105
+ string = data.read
106
+ data.rewind
107
+ string
108
+ end
109
+
110
+ def request_headers(env)
111
+ hash = {}
112
+ hash['Content-Type'] = env['CONTENT_TYPE'] if env['CONTENT_TYPE']
113
+ hash['Content-Length'] = env['CONTENT_LENGTH'] if env['CONTENT_LENGTH']
114
+
115
+ env.each do |key, value|
116
+ if header = key[/http_(.+)/i, 1]
117
+ hash[header.downcase.gsub('_','-')] = value
118
+ end
119
+ end
120
+
121
+ hash
122
+ end
123
+
124
+ def remote_host(env)
125
+ env['REMOTE_HOST'] || env['REMOTE_ADDR']
126
+ end
127
+
128
+ def format_header_hash(hash)
129
+ hash.map { |k, v| "#{k}: #{v}" }.join "\n" if hash
130
+ end
131
+
132
+ def format_error(error)
133
+ "#{error.class}: #{error.message}\n#{error.backtrace.join("\n") if error.backtrace}"
134
+ end
135
+
136
+ def response_body_to_s(response_body)
137
+ if sinatra? response_body
138
+ response_body.first
139
+ elsif rails? response_body
140
+ response_body.body
141
+ elsif response_body.is_a? StringIO
142
+ read_stream response_body
143
+ else
144
+ response_body
145
+ end
146
+ end
147
+
148
+ def sinatra?(response_body)
149
+ response_body.is_a?(Array) && response_body.first.is_a?(String)
150
+ end
151
+
152
+ #Check with string to avoid Rails dependency
153
+ def rails?(response_body)
154
+ response_body.class.to_s == 'ActionDispatch::Response'
155
+ end
156
+
157
+
158
+ #Template methods
159
+ def add_log_params(env, status, response_headers, response_body, params)
160
+ end
161
+
162
+ def filter_request_headers(hash)
163
+ hash
164
+ end
165
+
166
+ def filter_request_body(string)
167
+ string
168
+ end
169
+
170
+ def filter_response_headers(hash)
171
+ hash
172
+ end
173
+
174
+ def filter_response_body(string)
175
+ string
176
+ end
177
+
178
+ def app_error(env)
179
+ env['request_logger.error'] || env['sinatra.error']
180
+ end
181
+
182
+ def log_request?(env, request, status, response_headers, response_body)
183
+ true
184
+ end
185
+
186
+ end
187
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ class RequestLogger
3
+ VERSION = '0.0.4'
4
+ end
5
+ end
@@ -0,0 +1,111 @@
1
+ #Defines tasks for printing latest log entries
2
+ #Requires Rack::RequestLogger.log_handler to inherit from ActiveRecord::Base
3
+
4
+ if defined?(namespace)
5
+ namespace :log do
6
+ class Rack::RequestLogger
7
+ module TaskHelpers
8
+
9
+ class << self
10
+ def print_entry(entry)
11
+ unless entry
12
+ puts 'No matching log entry found!'
13
+ exit 1
14
+ end
15
+
16
+ #No guarantee of Ruby 1.9.x or greater, so hashes may not be ordered
17
+ #Use arrays and each_slice instead
18
+ small_fields = [
19
+ :id, 'ID',
20
+ :request_id, 'GUID',
21
+ :user_id, 'User ID',
22
+ [:method, :url], 'Request',
23
+ :remote_host, 'Remote host',
24
+ :request_time, 'Request time',
25
+ :response_time, 'Response time',
26
+ :status, 'Status'
27
+ ]
28
+ large_fields = [
29
+ :request_headers, 'Request headers',
30
+ :request_body, 'Request body',
31
+ :response_headers, 'Response headers',
32
+ :response_body, 'Response body',
33
+ :error, 'Error'
34
+ ]
35
+
36
+ name_size = 0
37
+ small_fields.each_slice(2) { |field, name| name_size = name.size if name.size > name_size }
38
+
39
+ puts
40
+ printed = []
41
+ small_fields.each_slice(2) do |field, name|
42
+ print_field entry, "#{name}:".ljust(name_size + 1), field, false, printed
43
+ end
44
+ large_fields.each_slice(2) do |field, name|
45
+ print_field entry, name, field, true, printed
46
+ end
47
+ puts
48
+
49
+ custom_fields = entry.class.columns.map(&:name) - printed.map(&:to_s)
50
+ custom_fields.each { |field| print_field entry, field + ':', field }
51
+ puts
52
+ end
53
+
54
+ def print_field(entry, field_name, field, large = nil, printed = [])
55
+ return unless entry
56
+
57
+ field = Array(field)
58
+ values = []
59
+ field.each do |f|
60
+ if entry.respond_to?(f)
61
+ values << entry.send(f)
62
+ printed << f
63
+ end
64
+ end
65
+ value = values.join(' ')
66
+
67
+ unless value.nil? || value.to_s.empty?
68
+ if large || (large.nil? && value.to_s.include?("\n"))
69
+ s = '-' * field_name.length
70
+ puts "\n#{s}\n#{field_name}\n#{s}\n#{value}\n#{s}\n\n"
71
+ else
72
+ puts "#{field_name} #{value}"
73
+ end
74
+ end
75
+ end
76
+
77
+ def request_logger
78
+ Rack::RequestLogger.log_handler.tap do |logger|
79
+ unless !logger.nil? && logger.respond_to?(:ancestors) && logger.ancestors.map { |a| a.to_s }.include?('ActiveRecord::Base')
80
+ puts 'Must have Rack::RequestLogger.log_handler set to an ActiveRecord based class to use this task!'
81
+ exit 1
82
+ end
83
+ end
84
+ end
85
+
86
+ def conditions(args, existing = nil)
87
+ conditions = []
88
+ conditions << "(#{existing})" if existing
89
+ conditions << "(#{args[:conditions]})" if args[:conditions]
90
+ conditions.empty? ? {} : { :conditions => conditions }
91
+ end
92
+ end
93
+
94
+ desc 'Print the most recent request'
95
+ task :request, [:conditions] => :environment do |task, args|
96
+ print_entry request_logger.last(conditions(args))
97
+ end
98
+
99
+ namespace :request do
100
+ %w(GET POST PUT DELETE).each do |method|
101
+ desc "Print the most recent #{method} request"
102
+ task method.downcase, [:conditions] => :environment do |task, args|
103
+ print_entry request_logger.last(conditions(args, "upper(method) = '#{method}'"))
104
+ end
105
+ end
106
+ end
107
+
108
+ end
109
+ end unless defined?(Rack::RequestLogger::TaskHelpers)
110
+ end
111
+ end
@@ -0,0 +1,395 @@
1
+ require 'spec_helper'
2
+
3
+ module Rack
4
+ describe RequestLogger do
5
+
6
+ class TestLogHandler
7
+ def self.write(params={}) end
8
+ end
9
+
10
+ class BadLogHandler
11
+ def self.write(params={}) raise 'Should not have called write!' end
12
+ def self.respond_to?(method) method == :write ? false : super end
13
+ end
14
+
15
+ before do
16
+ @log_handler = TestLogHandler
17
+ RequestLogger.log_handler = @log_handler
18
+
19
+ @app = Object.new
20
+ @logger = RequestLogger.new @app
21
+ end
22
+
23
+ describe 'call' do
24
+ def test_write_call(expected_hash)
25
+ @log_handler.should_receive(:write).with(hash_including(expected_hash))
26
+ @logger.call @env
27
+ end
28
+
29
+ before do
30
+ @user_id = 'someuser'
31
+ @request_id = 'somerequest'
32
+ @body = "user_id=#{@user_id}&other=stuff&request_id=#{@request_id}"
33
+
34
+ @url = 'http://this.server/path'
35
+
36
+ @env = {
37
+ 'rack.input' => StringIO.new(@body),
38
+ 'REQUEST_METHOD' => 'INFO',
39
+ 'rack.url_scheme' => 'http',
40
+ 'HTTP_HOST' => 'this.server',
41
+ 'PATH_INFO' => '/path',
42
+ 'SERVER_PORT' => 80
43
+ }
44
+
45
+ @status = 123
46
+ @response_headers = {:response => 'headers'}
47
+ @resopnse_body = 'the response'
48
+ @app.should_receive(:call).with(@env).and_return([@status, @response_headers, @response_body])
49
+
50
+ @logger.stub!(:log_request?).and_return(true)
51
+ end
52
+
53
+ it 'should return result of app.call' do
54
+ status, headers, body = @logger.call @env
55
+ status.should == @status
56
+ headers.should == @response_headers
57
+ body.should == @response_body
58
+ end
59
+
60
+ it 'should not log if the log_handler is not set' do
61
+ RequestLogger.log_handler = nil
62
+ @logger.call @env
63
+ #All is well if nothing blows up
64
+ end
65
+
66
+ it 'should not log if the log_handler does not respond to write' do
67
+ #Can't use expecatations for this, as using should_not_receive will define the method
68
+ RequestLogger.log_handler = BadLogHandler
69
+ @logger.call @env
70
+ #All is well if nothing blows up
71
+ end
72
+
73
+ it 'should not log if log_request? returns false' do
74
+ @log_handler.should_not_receive(:write)
75
+ @logger.should_receive(:log_request?).and_return(false)
76
+ @logger.call @env
77
+ end
78
+
79
+ it 'should call add_log_params with env, response results, and params' do
80
+ @logger.should_receive(:add_log_params).with(@env, @status, @response_headers, @response_body, hash_including(:url => @url))
81
+ @logger.call @env
82
+ end
83
+
84
+ it 'should log url' do
85
+ test_write_call :url => @url
86
+ end
87
+
88
+ it 'should log request_method' do
89
+ test_write_call :method => @env['REQUEST_METHOD']
90
+ end
91
+
92
+ it 'should log obfucated and formatted request headers' do
93
+ headers = { :some => 'headers' }
94
+ filtered_headers = { :some => '*****' }
95
+ formatted_headers = 'some formatted headers'
96
+
97
+ @logger.should_receive(:request_headers).with(@env).and_return(headers)
98
+ @logger.should_receive(:filter_request_headers).with(headers).and_return(filtered_headers)
99
+ @logger.should_receive(:format_header_hash).with(filtered_headers).and_return(formatted_headers)
100
+ @logger.stub!(:format_header_hash).with(@response_headers).and_return('other headers')
101
+
102
+ test_write_call :request_headers => formatted_headers
103
+ end
104
+
105
+ it 'should log filtered request body' do
106
+ filtered_body = 'some **** body'
107
+
108
+ @logger.should_receive(:read_stream).with(@env['rack.input']).and_return(@body)
109
+ @logger.should_receive(:filter_request_body).with(@body).and_return(filtered_body)
110
+
111
+ test_write_call :request_body => filtered_body
112
+ end
113
+
114
+ it 'should log request and response times' do
115
+ request, response = 1, 2
116
+ Time.should_receive(:now).and_return(request, response)
117
+ test_write_call :request_time => request, :response_time => response
118
+ end
119
+
120
+ it 'should log response status' do
121
+ test_write_call :status => @status
122
+ end
123
+
124
+ it 'should log filtered and formatted response headers' do
125
+ request_headers = { :other => 'request headers' }
126
+ @logger.stub!(:request_headers).and_return(request_headers)
127
+ @logger.stub!(:format_header_hash).with(request_headers).and_return('other headers')
128
+
129
+ filtered_headers = { :some => '*****' }
130
+ formatted_headers = 'some formatted headers'
131
+ @logger.should_receive(:filter_response_headers).with(@response_headers).and_return(filtered_headers)
132
+ @logger.should_receive(:format_header_hash).with(filtered_headers).and_return(formatted_headers)
133
+
134
+ test_write_call :response_headers => formatted_headers
135
+ end
136
+
137
+ it 'should log filtered response body' do
138
+ filtered_body = 'some **** body'
139
+ @logger.should_receive(:filter_response_body).with(@response_body).and_return(filtered_body)
140
+ test_write_call :response_body => filtered_body
141
+ end
142
+
143
+ it 'should not log remote host if not present' do
144
+ @logger.should_receive(:remote_host).and_return(nil)
145
+ @log_handler.should_not_receive(:write).with(hash_including(:remote_host => anything()))
146
+ @log_handler.should_receive(:write)
147
+
148
+ @logger.call @env
149
+ end
150
+
151
+ it 'should log remote host if present' do
152
+ remote_host = 'some.user.com'
153
+ @logger.should_receive(:remote_host).and_return(remote_host)
154
+ test_write_call :remote_host => remote_host
155
+ end
156
+
157
+ it 'should not log any error if none is present' do
158
+ @logger.should_receive(:app_error).and_return(nil)
159
+ @log_handler.should_not_receive(:write).with(hash_including(:error => anything()))
160
+ @log_handler.should_receive(:write)
161
+
162
+ @logger.call @env
163
+ end
164
+
165
+ it 'shoud format and log any present error' do
166
+ formatted_error = 'some formatted error'
167
+ error = RuntimeError.new 'some error'
168
+
169
+ @logger.should_receive(:app_error).and_return(error)
170
+ @logger.should_receive(:format_error).with(error).and_return(formatted_error)
171
+
172
+ test_write_call :error => formatted_error
173
+ end
174
+
175
+ it 'should not allow logging errors to propogate' do
176
+ @log_handler.should_receive(:write).twice.and_raise('some error')
177
+ @logger.call @env
178
+ #All is well if nothing blows up
179
+ end
180
+
181
+ it 'should attempt to format and log any logging errors' do
182
+ error = RuntimeError.new 'some error'
183
+
184
+ @log_handler.should_receive(:write).with(hash_including(:url => @url)).and_raise('some error')
185
+ @log_handler.should_receive(:write).with(instance_of(Hash)) do |params|
186
+ params[:error].message.should == error.message
187
+ end
188
+
189
+ @logger.call @env
190
+ end
191
+ end
192
+
193
+ describe 'read_stream' do
194
+ it 'should return nil if parameter is nil' do
195
+ @logger.send(:read_stream, nil).should be_nil
196
+ end
197
+
198
+ it 'should rewind stream' do
199
+ string = 'some data'
200
+ stream = StringIO.new string
201
+ value = @logger.send(:read_stream, stream)
202
+
203
+ value.should == string
204
+ stream.gets.should == string
205
+ end
206
+ end
207
+
208
+ describe 'filter_request_headers' do
209
+ it 'should return the same hash provided, since it is intended to be overridden' do
210
+ hash = { :login => 'login', :password => 'password' }
211
+ @logger.send(:filter_request_headers, nil).should be_nil
212
+ @logger.send(:filter_request_headers, hash).should == hash
213
+ end
214
+ end
215
+
216
+ describe 'filter_request_body' do
217
+ it 'should return the same string provided, since it is intended to be overridden' do
218
+ string = 'login=l&password=p&key=k&user=u'
219
+ @logger.send(:filter_request_body, nil).should be_nil
220
+ @logger.send(:filter_request_body, string).should == string
221
+ end
222
+ end
223
+
224
+ describe 'filter_response_headers' do
225
+ it 'should return the same hash provided, since it is intended to be overridden' do
226
+ hash = { :login => 'login', :password => 'password' }
227
+ @logger.send(:filter_response_headers, nil).should be_nil
228
+ @logger.send(:filter_response_headers, hash).should == hash
229
+ end
230
+ end
231
+
232
+ describe 'filter_response_body' do
233
+ it 'should return the same string provided, since it is intended to be overridden' do
234
+ string = 'login=l&password=p&key=k&user=u'
235
+ @logger.send(:filter_response_body, nil).should be_nil
236
+ @logger.send(:filter_response_body, string).should == string
237
+ end
238
+ end
239
+
240
+ describe 'request_headers' do
241
+ it 'should pull content type' do
242
+ content_type = 'some/type'
243
+ headers = @logger.send(:request_headers, 'CONTENT_TYPE' => content_type)
244
+ headers['Content-Type'].should == content_type
245
+ end
246
+
247
+ it 'should pull content length' do
248
+ content_length = 53188
249
+ headers = @logger.send(:request_headers, 'CONTENT_LENGTH' => content_length)
250
+ headers['Content-Length'].should == content_length
251
+ end
252
+
253
+ it 'should pull and format anything starting with "HTTP_"' do
254
+ env = {
255
+ 'HTTP_SOME_HEADER' => 'something',
256
+ 'HTTP_ANOTHER_HEADER' => 'another thing',
257
+ 'http_lowercase_header' => 'lowercase',
258
+ 'hTtp_CrAZy_HEadeR' => 'multicase'
259
+ }
260
+
261
+ headers = @logger.send(:request_headers, env)
262
+
263
+ env.each do |header, value|
264
+ formatted_header = header.downcase.sub('http_', '').gsub('_', '-')
265
+ headers[formatted_header].should == value
266
+ end
267
+ end
268
+
269
+ it 'should ignore anything not covered by tests above' do
270
+ @logger.send(:request_headers, 'IGNORED_VALUE' => 'JUNK').should be_empty
271
+ end
272
+ end
273
+
274
+ describe 'remote_host' do
275
+ before do
276
+ @host = 'some.host'
277
+ end
278
+
279
+ it 'should return remote host for Rails requests' do
280
+ @logger.send(:remote_host, 'REMOTE_ADDR' => @host).should == @host
281
+ end
282
+
283
+ it 'should return remote host for Sinatra requests' do
284
+ @logger.send(:remote_host, 'REMOTE_HOST' => @host).should == @host
285
+ end
286
+
287
+ it 'should return nil if nothing found' do
288
+ @logger.send(:remote_host, 'nothing' => 'useful').should be_nil
289
+ end
290
+ end
291
+
292
+ describe 'app_error' do
293
+ it 'should return sinatra.error if present in env' do
294
+ error = RuntimeError.new 'some sinatra-set error'
295
+ @logger.send(:app_error, 'sinatra.error' => error).should == error
296
+ end
297
+
298
+ it 'should return request_logger.error if present in env' do
299
+ error = RuntimeError.new 'some manually set error'
300
+ @logger.send(:app_error, 'request_logger.error' => error).should == error
301
+ end
302
+
303
+ it 'should let manually set errors take precedence over Sinatra set errors' do
304
+ sinatra_error = RuntimeError.new 'some sinatra-set error'
305
+ manual_error = RuntimeError.new 'some manually set error'
306
+ env = { 'sinatra.error' => sinatra_error, 'request_logger.error' => manual_error }
307
+ @logger.send(:app_error, env).should == manual_error
308
+ end
309
+
310
+ it 'should return nil if no error is found' do
311
+ @logger.send(:app_error, {}).should == nil
312
+ end
313
+ end
314
+
315
+ describe 'format_header_hash' do
316
+ it 'should return nil if hash is nil' do
317
+ @logger.send(:format_header_hash, nil).should be_nil
318
+ end
319
+
320
+ it 'should turn hash into a header string' do
321
+ hash = { :key1 => 'value1', :key2 => 'value2' }
322
+ string_possibilities = [[]]
323
+ hash.each do |k, v|
324
+ string_possibilities.first << "#{k}: #{v}"
325
+ end
326
+ string_possibilities << string_possibilities.first.reverse
327
+ string_possibilities.map! { |s| s.join "\n" }
328
+ string_possibilities.should include(@logger.send(:format_header_hash, hash))
329
+ end
330
+ end
331
+
332
+ describe 'format_error' do
333
+ before do
334
+ @message = 'the message'
335
+ @error = RuntimeError.new(@message)
336
+ end
337
+
338
+ it 'should include class' do
339
+ string = @logger.send(:format_error, @error)
340
+ string.should include(@error.class.to_s)
341
+ end
342
+
343
+ it 'should include message' do
344
+ string = @logger.send(:format_error, @error)
345
+ string.should include(@error.message)
346
+ end
347
+
348
+ it 'should include backtrace' do
349
+ begin
350
+ #Raise it to get a backtrace
351
+ raise @error
352
+ rescue => e
353
+ string = @logger.send(:format_error, e)
354
+ e.backtrace.each do |frame|
355
+ string.should include(frame)
356
+ end
357
+ end
358
+ end
359
+ end
360
+
361
+ describe 'response_body_to_s' do
362
+ it 'should handle Sinatra responses' do
363
+ body = 'An array with a single element'
364
+ sinatra_response = [ body ]
365
+ @logger.send(:response_body_to_s, sinatra_response).should == body
366
+ end
367
+
368
+ it 'should handle Rails responses' do
369
+ body = 'Part of an ActionDispatch::Response object'
370
+ hacked_rails_response = Object.new
371
+ hacked_rails_response.should_receive(:body).and_return(body)
372
+ hacked_rails_response.should_receive(:class).and_return('ActionDispatch::Response')
373
+ @logger.send(:response_body_to_s, hacked_rails_response).should == body
374
+ end
375
+
376
+ it 'should read streams' do
377
+ body = 'a stream'
378
+ stream = StringIO.new body
379
+ @logger.should_receive(:read_stream).with(stream).and_return(body)
380
+ @logger.send(:response_body_to_s, stream).should == body
381
+ end
382
+
383
+ it 'should simply return the object if it is a string' do
384
+ body = 'a string'
385
+ @logger.send(:response_body_to_s, body).should == body
386
+ end
387
+
388
+ it 'should simply return the object if it is an unknown type' do
389
+ object = { :a => 'hash' }
390
+ @logger.send(:response_body_to_s, object).should == object
391
+ end
392
+ end
393
+
394
+ end
395
+ end
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
3
+
4
+ require 'rspec'
5
+ require 'rspec/autorun'
6
+ require 'stringio'
7
+
8
+ require 'rack/request_logger'
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-request_logger
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 4
9
+ version: 0.0.4
10
+ platform: ruby
11
+ authors:
12
+ - Mike Marion
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-08-25 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rack
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 0
30
+ version: "1.0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: rake
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ type: :development
44
+ version_requirements: *id002
45
+ - !ruby/object:Gem::Dependency
46
+ name: rspec
47
+ prerelease: false
48
+ requirement: &id003 !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 2
54
+ - 6
55
+ version: "2.6"
56
+ type: :development
57
+ version_requirements: *id003
58
+ description: |-
59
+ This gem is Rack middleware that gathers information about
60
+ all requests and responses, allowing for detailed logging.
61
+ email: mike.marion@gmail.com
62
+ executables: []
63
+
64
+ extensions: []
65
+
66
+ extra_rdoc_files: []
67
+
68
+ files:
69
+ - lib/rack/request_logger.rb
70
+ - lib/rack/request_logger_version.rb
71
+ - lib/rack/tasks/request_log_readers.rb
72
+ has_rdoc: true
73
+ homepage: https://github.com/BLC/rack-request_logger
74
+ licenses: []
75
+
76
+ post_install_message:
77
+ rdoc_options: []
78
+
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ requirements: []
96
+
97
+ rubyforge_project:
98
+ rubygems_version: 1.3.6
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: Rack Request Logger
102
+ test_files:
103
+ - spec/rack/request_logger_spec.rb
104
+ - spec/spec_helper.rb