rack-request_logger 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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