clogger 0.0.1

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,349 @@
1
+ # -*- encoding: binary -*-
2
+ $stderr.sync = $stdout.sync = true
3
+ require "test/unit"
4
+ require "date"
5
+ require "stringio"
6
+
7
+ require "rack"
8
+
9
+ require "clogger"
10
+ class TestClogger < Test::Unit::TestCase
11
+ include Clogger::Format
12
+
13
+ def setup
14
+ @req = {
15
+ "REQUEST_METHOD" => "GET",
16
+ "HTTP_VERSION" => "HTTP/1.0",
17
+ "HTTP_USER_AGENT" => 'echo and socat \o/',
18
+ "PATH_INFO" => "/hello",
19
+ "QUERY_STRING" => "goodbye=true",
20
+ "rack.errors" => $stderr,
21
+ "rack.input" => File.open('/dev/null', 'rb'),
22
+ "REMOTE_ADDR" => 'home',
23
+ }
24
+ end
25
+
26
+ def test_init_basic
27
+ Clogger.new(lambda { |env| [ 0, {}, [] ] })
28
+ end
29
+
30
+ def test_init_noargs
31
+ assert_raise(ArgumentError) { Clogger.new }
32
+ end
33
+
34
+ def test_init_stderr
35
+ cl = Clogger.new(lambda { |env| [ 0, {}, [] ] }, :logger => $stderr)
36
+ assert_kind_of(Integer, cl.fileno)
37
+ assert_equal $stderr.fileno, cl.fileno
38
+ end
39
+
40
+ def test_init_stringio
41
+ cl = Clogger.new(lambda { |env| [ 0, {}, [] ] }, :logger => StringIO.new)
42
+ assert_nil cl.fileno
43
+ end
44
+
45
+ def test_write_stringio
46
+ start = DateTime.now - 1
47
+ str = StringIO.new
48
+ cl = Clogger.new(lambda { |env| [ "302 Found", {}, [] ] }, :logger => str)
49
+ status, headers, body = cl.call(@req)
50
+ assert_equal("302 Found", status)
51
+ assert_equal({}, headers)
52
+ body.each { |part| assert false }
53
+ str = str.string
54
+ r = %r{\Ahome - - \[[^\]]+\] "GET /hello\?goodbye=true HTTP/1.0" 302 -\n\z}
55
+ assert_match r, str
56
+ %r{\[([^\]]+)\]} =~ str
57
+ tmp = nil
58
+ assert_nothing_raised {
59
+ tmp = DateTime.strptime($1, "%d/%b/%Y:%H:%M:%S %z")
60
+ }
61
+ assert tmp >= start
62
+ assert tmp <= DateTime.now
63
+ end
64
+
65
+ def test_clen_stringio
66
+ start = DateTime.now - 1
67
+ str = StringIO.new
68
+ app = lambda { |env| [ 301, {'Content-Length' => '5'}, ['abcde'] ] }
69
+ format = Common.dup
70
+ assert format.gsub!(/response_length/, 'sent_http_content_length')
71
+ cl = Clogger.new(app, :logger => str, :format => format)
72
+ status, headers, body = cl.call(@req)
73
+ assert_equal(301, status)
74
+ assert_equal({'Content-Length' => '5'}, headers)
75
+ body.each { |part| assert_equal('abcde', part) }
76
+ str = str.string
77
+ r = %r{\Ahome - - \[[^\]]+\] "GET /hello\?goodbye=true HTTP/1.0" 301 5\n\z}
78
+ assert_match r, str
79
+ %r{\[([^\]]+)\]} =~ str
80
+ tmp = nil
81
+ assert_nothing_raised {
82
+ tmp = DateTime.strptime($1, "%d/%b/%Y:%H:%M:%S %z")
83
+ }
84
+ assert tmp >= start
85
+ assert tmp <= DateTime.now
86
+ end
87
+
88
+ def test_compile_ambiguous
89
+ cl = Clogger.new(nil, :logger => $stderr)
90
+ ary = nil
91
+ cl.instance_eval {
92
+ ary = compile_format(
93
+ '$remote_addr $$$$pid' \
94
+ "\n")
95
+ }
96
+ expect = [
97
+ [ Clogger::OP_REQUEST, "REMOTE_ADDR" ],
98
+ [ Clogger::OP_LITERAL, " " ],
99
+ [ Clogger::OP_LITERAL, "$$$" ],
100
+ [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:pid] ],
101
+ [ Clogger::OP_LITERAL, "\n" ],
102
+ ]
103
+ assert_equal expect, ary
104
+ end
105
+
106
+ def test_compile_auto_newline
107
+ cl = Clogger.new(nil, :logger => $stderr)
108
+ ary = nil
109
+ cl.instance_eval { ary = compile_format('$remote_addr $request') }
110
+ expect = [
111
+ [ Clogger::OP_REQUEST, "REMOTE_ADDR" ],
112
+ [ Clogger::OP_LITERAL, " " ],
113
+ [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:request] ],
114
+ [ Clogger::OP_LITERAL, "\n" ],
115
+ ]
116
+ assert_equal expect, ary
117
+ end
118
+
119
+ def test_big_log
120
+ str = StringIO.new
121
+ fmt = '$remote_addr $pid $remote_user [$time_local] ' \
122
+ '"$request" $status $body_bytes_sent "$http_referer" ' \
123
+ '"$http_user_agent" "$http_cookie" $request_time $http_host'
124
+ app = lambda { |env| [ 302, {}, [] ] }
125
+ cl = Clogger.new(app, :logger => str, :format => fmt)
126
+ cookie = "foo=bar#{'f' * 256}".freeze
127
+ req = {
128
+ 'HTTP_HOST' => 'example.com:12345',
129
+ 'HTTP_COOKIE' => cookie,
130
+ }
131
+ req = @req.merge(req)
132
+ cl.call(req).last.each { |part| part }
133
+ str = str.string
134
+ assert(str.size > 128)
135
+ assert_match %r["echo and socat \\o/" "#{cookie}" \d+\.\d{3}], str
136
+ assert_match %r["#{cookie}" \d+\.\d{3} example\.com:12345\n\z], str
137
+ end
138
+
139
+ def test_compile
140
+ cl = Clogger.new(nil, :logger => $stderr)
141
+ ary = nil
142
+ cl.instance_eval {
143
+ ary = compile_format(
144
+ '$remote_addr - $remote_user [$time_local] ' \
145
+ '"$request" $status $body_bytes_sent "$http_referer" ' \
146
+ '"$http_user_agent" "$http_cookie" $request_time ' \
147
+ '$env{rack.url_scheme}' \
148
+ "\n")
149
+ }
150
+ expect = [
151
+ [ Clogger::OP_REQUEST, "REMOTE_ADDR" ],
152
+ [ Clogger::OP_LITERAL, " - " ],
153
+ [ Clogger::OP_REQUEST, "REMOTE_USER" ],
154
+ [ Clogger::OP_LITERAL, " [" ],
155
+ [ Clogger::OP_TIME_LOCAL, '%d/%b/%Y:%H:%M:%S %z' ],
156
+ [ Clogger::OP_LITERAL, "] \"" ],
157
+ [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:request] ],
158
+ [ Clogger::OP_LITERAL, "\" "],
159
+ [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:status] ],
160
+ [ Clogger::OP_LITERAL, " "],
161
+ [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:body_bytes_sent] ],
162
+ [ Clogger::OP_LITERAL, " \"" ],
163
+ [ Clogger::OP_REQUEST, "HTTP_REFERER" ],
164
+ [ Clogger::OP_LITERAL, "\" \"" ],
165
+ [ Clogger::OP_REQUEST, "HTTP_USER_AGENT" ],
166
+ [ Clogger::OP_LITERAL, "\" \"" ],
167
+ [ Clogger::OP_REQUEST, "HTTP_COOKIE" ],
168
+ [ Clogger::OP_LITERAL, "\" " ],
169
+ [ Clogger::OP_REQUEST_TIME, '%d.%03d', 1000 ],
170
+ [ Clogger::OP_LITERAL, " " ],
171
+ [ Clogger::OP_REQUEST, "rack.url_scheme" ],
172
+ [ Clogger::OP_LITERAL, "\n" ],
173
+ ]
174
+ assert_equal expect, ary
175
+ end
176
+
177
+ def test_eval
178
+ current = Thread.current.to_s
179
+ str = StringIO.new
180
+ app = lambda { |env| [ 302, {}, [] ] }
181
+ cl = Clogger.new(app,
182
+ :logger => str,
183
+ :format => "-$e{Thread.current}-\n")
184
+ status, headers, body = cl.call(@req)
185
+ assert_equal "-#{current}-\n", str.string
186
+ end
187
+
188
+ def test_pid
189
+ str = StringIO.new
190
+ app = lambda { |env| [ 302, {}, [] ] }
191
+ cl = Clogger.new(app, :logger => str, :format => "[$pid]\n")
192
+ status, headers, body = cl.call(@req)
193
+ assert_equal "[#$$]\n", str.string
194
+ end
195
+
196
+ def test_rack_xff
197
+ str = StringIO.new
198
+ app = lambda { |env| [ 302, {}, [] ] }
199
+ cl = Clogger.new(app, :logger => str, :format => "$ip")
200
+ req = @req.merge("HTTP_X_FORWARDED_FOR" => '192.168.1.1')
201
+ status, headers, body = cl.call(req)
202
+ assert_equal "192.168.1.1\n", str.string
203
+ str.rewind
204
+ str.truncate(0)
205
+ status, headers, body = cl.call(@req)
206
+ assert_equal "home\n", str.string
207
+ str.rewind
208
+ str.truncate(0)
209
+ end
210
+
211
+ def test_rack_1_0
212
+ start = DateTime.now - 1
213
+ str = StringIO.new
214
+ app = lambda { |env| [ 200, {'Content-Length'=>'0'}, %w(a b c)] }
215
+ cl = Clogger.new(app, :logger => str, :format => Rack_1_0)
216
+ status, headers, body = cl.call(@req)
217
+ tmp = []
218
+ body.each { |s| tmp << s }
219
+ assert_equal %w(a b c), tmp
220
+ str = str.string
221
+ assert_match %r[" 200 3 \d+\.\d{4}\n\z], str
222
+ tmp = nil
223
+ %r{\[(\d+/\w+/\d+ \d+:\d+:\d+)\]} =~ str
224
+ assert $1
225
+ assert_nothing_raised { tmp = DateTime.strptime($1, "%d/%b/%Y %H:%M:%S") }
226
+ assert tmp >= start
227
+ assert tmp <= DateTime.now
228
+ end
229
+
230
+ def test_msec
231
+ str = StringIO.new
232
+ app = lambda { |env| [ 200, {}, [] ] }
233
+ cl = Clogger.new(app, :logger => str, :format => '$msec')
234
+ status, header, bodies = cl.call(@req)
235
+ assert_match %r(\A\d+\.\d{3}\n\z), str.string
236
+ end
237
+
238
+ def test_usec
239
+ str = StringIO.new
240
+ app = lambda { |env| [ 200, {}, [] ] }
241
+ cl = Clogger.new(app, :logger => str, :format => '$usec')
242
+ status, header, bodies = cl.call(@req)
243
+ assert_match %r(\A\d+\.\d{6}\n\z), str.string
244
+ end
245
+
246
+ def test_time_0
247
+ str = StringIO.new
248
+ app = lambda { |env| [ 200, {}, [] ] }
249
+ cl = Clogger.new(app, :logger => str, :format => '$time{0}')
250
+ status, header, bodies = cl.call(@req)
251
+ assert_match %r(\A\d+\n\z), str.string
252
+ end
253
+
254
+ def test_time_1
255
+ str = StringIO.new
256
+ app = lambda { |env| [ 200, {}, [] ] }
257
+ cl = Clogger.new(app, :logger => str, :format => '$time{1}')
258
+ status, header, bodies = cl.call(@req)
259
+ assert_match %r(\A\d+\.\d\n\z), str.string
260
+ end
261
+
262
+ def test_request_length
263
+ str = StringIO.new
264
+ input = StringIO.new('.....')
265
+ app = lambda { |env| [ 200, {}, [] ] }
266
+ cl = Clogger.new(app, :logger => str, :format => '$request_length')
267
+ status, header, bodies = cl.call(@req.merge('rack.input' => input))
268
+ assert_equal "5\n", str.string
269
+ end
270
+
271
+ def test_response_length_0
272
+ str = StringIO.new
273
+ app = lambda { |env| [ 200, {}, [] ] }
274
+ cl = Clogger.new(app, :logger => str, :format => '$response_length')
275
+ status, header, bodies = cl.call(@req)
276
+ bodies.each { |part| part }
277
+ assert_equal "-\n", str.string
278
+ end
279
+
280
+ def test_combined
281
+ start = DateTime.now - 1
282
+ str = StringIO.new
283
+ app = lambda { |env| [ 200, {'Content-Length'=>'3'}, %w(a b c)] }
284
+ cl = Clogger.new(app, :logger => str, :format => Combined)
285
+ status, headers, body = cl.call(@req)
286
+ tmp = []
287
+ body.each { |s| tmp << s }
288
+ assert_equal %w(a b c), tmp
289
+ str = str.string
290
+ assert_match %r[" 200 3 "-" "echo and socat \\o/"\n\z], str
291
+ tmp = nil
292
+ %r{\[(\d+/\w+/\d+:\d+:\d+:\d+ .+)\]} =~ str
293
+ assert $1
294
+ assert_nothing_raised {
295
+ tmp = DateTime.strptime($1, "%d/%b/%Y:%H:%M:%S %z")
296
+ }
297
+ assert tmp >= start
298
+ assert tmp <= DateTime.now
299
+ end
300
+
301
+ def test_rack_errors_fallback
302
+ err = StringIO.new
303
+ app = lambda { |env| [ 200, {'Content-Length'=>'3'}, %w(a b c)] }
304
+ cl = Clogger.new(app, :format => '$pid')
305
+ req = @req.merge('rack.errors' => err)
306
+ status, headers, body = cl.call(req)
307
+ assert_equal "#$$\n", err.string
308
+ end
309
+
310
+ def test_body_close
311
+ s_body = StringIO.new(%w(a b c).join("\n"))
312
+ app = lambda { |env| [ 200, {'Content-Length'=>'5'}, s_body] }
313
+ cl = Clogger.new(app, :logger => [], :format => '$pid')
314
+ status, headers, body = cl.call(@req)
315
+ assert ! s_body.closed?
316
+ assert_nothing_raised { body.close }
317
+ assert s_body.closed?
318
+ end
319
+
320
+ def test_escape
321
+ str = StringIO.new
322
+ app = lambda { |env| [ 200, {'Content-Length'=>'5'}, [] ] }
323
+ cl = Clogger.new(app,
324
+ :logger => str,
325
+ :format => '$http_user_agent "$request"')
326
+ bad = {
327
+ 'HTTP_USER_AGENT' => '"asdf"',
328
+ 'QUERY_STRING' => 'sdf=bar"',
329
+ 'PATH_INFO' => '/"<>"',
330
+ }
331
+ status, headers, body = cl.call(@req.merge(bad))
332
+ expect = '\x22asdf\x22 "GET /\x22<>\x22?sdf=bar\x22 HTTP/1.0"' << "\n"
333
+ assert_equal expect, str.string
334
+ end
335
+
336
+ def test_cookies
337
+ str = StringIO.new
338
+ app = lambda { |env|
339
+ req = Rack::Request.new(env).cookies
340
+ [ 302, {}, [] ]
341
+ }
342
+ cl = Clogger.new(app,
343
+ :format => '$cookie_foo $cookie_quux',
344
+ :logger => str)
345
+ req = @req.merge('HTTP_COOKIE' => "foo=bar;quux=h&m")
346
+ status, headers, body = cl.call(req)
347
+ assert_equal "bar h&m\n", str.string
348
+ end
349
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clogger
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Eric Wong
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-28 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.3.3
24
+ version:
25
+ description: |-
26
+ Clogger is Rack middleware for logging HTTP requests. The log format
27
+ is customizable so you can specify exactly which fields to log.
28
+ email: clogger@librelist.com
29
+ executables: []
30
+
31
+ extensions: []
32
+
33
+ extra_rdoc_files:
34
+ - History.txt
35
+ - Manifest.txt
36
+ - README.txt
37
+ files:
38
+ - .gitignore
39
+ - COPYING
40
+ - GNUmakefile
41
+ - History.txt
42
+ - Manifest.txt
43
+ - README.txt
44
+ - Rakefile
45
+ - ext/clogger_ext/clogger.c
46
+ - ext/clogger_ext/extconf.rb
47
+ - ext/clogger_ext/ruby_1_9_compat.h
48
+ - lib/clogger.rb
49
+ - lib/clogger/format.rb
50
+ - lib/clogger/pure.rb
51
+ - setup.rb
52
+ - test/test_clogger.rb
53
+ has_rdoc: true
54
+ homepage: http://clogger.rubyforge.org/
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options:
59
+ - --title
60
+ - Clogger - configurable request logging for Rack
61
+ require_paths:
62
+ - lib
63
+ - ext
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ requirements: []
77
+
78
+ rubyforge_project: clogger
79
+ rubygems_version: 1.3.5
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: configurable request logging for Rack
83
+ test_files:
84
+ - test/test_clogger.rb