clogger 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +1 -0
- data/README +1 -3
- data/Rakefile +19 -6
- data/ext/clogger_ext/broken_system_compat.h +36 -0
- data/ext/clogger_ext/clogger.c +91 -42
- data/ext/clogger_ext/extconf.rb +4 -2
- data/ext/clogger_ext/ruby_1_9_compat.h +0 -8
- data/lib/clogger.rb +8 -13
- data/lib/clogger/pure.rb +13 -14
- data/test/test_clogger.rb +21 -1
- data/test/test_clogger_to_path.rb +17 -3
- metadata +8 -5
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
@@ -133,6 +133,7 @@ release: verify package $(release_notes) $(release_changes)
|
|
133
133
|
gem push $(pkggem)
|
134
134
|
rubyforge add_file \
|
135
135
|
$(rfproject) $(rfpackage) $(VERSION) $(pkggem)
|
136
|
+
$(RAKE) publish_news VERSION=$(VERSION)
|
136
137
|
else
|
137
138
|
gem install-gem: GIT-VERSION-FILE
|
138
139
|
$(MAKE) $@ VERSION=$(GIT_VERSION)
|
data/README
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
= \Clogger - configurable request logging for Rack
|
2
2
|
|
3
|
-
== DESCRIPTION
|
4
|
-
|
5
3
|
\Clogger is Rack middleware for logging HTTP requests. The log format
|
6
4
|
is customizable so you can specify exactly which fields to log.
|
7
5
|
|
@@ -26,7 +24,7 @@ is customizable so you can specify exactly which fields to log.
|
|
26
24
|
|
27
25
|
* Pure Ruby version for non-MRI versions of Ruby (or via CLOGGER_PURE=1
|
28
26
|
in the environment). The optional C extension is loaded by default
|
29
|
-
and supported under MRI 1.8.7, 1.9.1,
|
27
|
+
and supported under MRI 1.8.7, 1.9.1, 1.9.2 and Rubinius.
|
30
28
|
|
31
29
|
== SYNOPSIS
|
32
30
|
|
data/Rakefile
CHANGED
@@ -5,11 +5,27 @@ rescue LoadError
|
|
5
5
|
warn "rake-compiler not available, cross compiling disabled"
|
6
6
|
end
|
7
7
|
|
8
|
-
|
8
|
+
cgit_url = "http://git.bogomips.org/cgit/clogger.git"
|
9
|
+
git_url = 'git://git.bogomips.org/clogger.git'
|
10
|
+
|
11
|
+
desc "post news article to rubyforge"
|
9
12
|
task :publish_news do
|
10
13
|
require 'rubyforge'
|
11
|
-
|
12
|
-
|
14
|
+
spec = Gem::Specification.load('clogger.gemspec')
|
15
|
+
tmp = Tempfile.new('rf-news')
|
16
|
+
_, subject, body = `git cat-file tag v#{spec.version}`.split(/\n\n/, 3)
|
17
|
+
tmp.puts subject
|
18
|
+
tmp.puts
|
19
|
+
tmp.puts spec.description.strip
|
20
|
+
tmp.puts ""
|
21
|
+
tmp.puts "* #{spec.homepage}"
|
22
|
+
tmp.puts "* #{spec.email}"
|
23
|
+
tmp.puts "* #{git_url}"
|
24
|
+
tmp.print "\nChanges:\n\n"
|
25
|
+
tmp.puts body
|
26
|
+
tmp.flush
|
27
|
+
system(ENV["VISUAL"], tmp.path) or abort "#{ENV["VISUAL"]} failed: #$?"
|
28
|
+
msg = File.readlines(tmp.path)
|
13
29
|
subject = msg.shift
|
14
30
|
blank = msg.shift
|
15
31
|
blank == "\n" or abort "no newline after subject!"
|
@@ -21,9 +37,6 @@ task :publish_news do
|
|
21
37
|
rf.post_news('clogger', subject, body)
|
22
38
|
end
|
23
39
|
|
24
|
-
cgit_url = "http://git.bogomips.org/cgit/clogger.git"
|
25
|
-
git_url = 'git://git.bogomips.org/clogger.git'
|
26
|
-
|
27
40
|
desc "post to RAA"
|
28
41
|
task :raa_update do
|
29
42
|
require 'rubygems'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
/*
|
2
|
+
* this header includes functions to support broken systems
|
3
|
+
* without clock_gettime() or CLOCK_MONOTONIC
|
4
|
+
*/
|
5
|
+
|
6
|
+
#ifndef HAVE_TYPE_CLOCKID_T
|
7
|
+
typedef int clockid_t;
|
8
|
+
#endif
|
9
|
+
|
10
|
+
#ifndef HAVE_CLOCK_GETTIME
|
11
|
+
# ifndef CLOCK_REALTIME
|
12
|
+
# define CLOCK_REALTIME 0 /* whatever */
|
13
|
+
# endif
|
14
|
+
static int fake_clock_gettime(clockid_t clk_id, struct timespec *res)
|
15
|
+
{
|
16
|
+
struct timeval tv;
|
17
|
+
int r = gettimeofday(&tv, NULL);
|
18
|
+
|
19
|
+
assert(0 == r && "gettimeofday() broke!?");
|
20
|
+
res->tv_sec = tv.tv_sec;
|
21
|
+
res->tv_nsec = tv.tv_usec * 1000;
|
22
|
+
|
23
|
+
return r;
|
24
|
+
}
|
25
|
+
# define clock_gettime fake_clock_gettime
|
26
|
+
#endif /* broken systems w/o clock_gettime() */
|
27
|
+
|
28
|
+
/*
|
29
|
+
* UGH
|
30
|
+
* CLOCK_MONOTONIC is not guaranteed to be a macro, either
|
31
|
+
*/
|
32
|
+
#ifndef CLOCK_MONOTONIC
|
33
|
+
# if (!defined(_POSIX_MONOTONIC_CLOCK) || !defined(HAVE_CLOCK_MONOTONIC))
|
34
|
+
# define CLOCK_MONOTONIC CLOCK_REALTIME
|
35
|
+
# endif
|
36
|
+
#endif
|
data/ext/clogger_ext/clogger.c
CHANGED
@@ -13,9 +13,39 @@
|
|
13
13
|
#ifdef HAVE_FCNTL_H
|
14
14
|
# include <fcntl.h>
|
15
15
|
#endif
|
16
|
-
#
|
16
|
+
#ifndef _POSIX_C_SOURCE
|
17
|
+
# define _POSIX_C_SOURCE 200112L
|
18
|
+
#endif
|
17
19
|
#include <time.h>
|
18
20
|
#include "ruby_1_9_compat.h"
|
21
|
+
#include "broken_system_compat.h"
|
22
|
+
|
23
|
+
/*
|
24
|
+
* Availability of a monotonic clock needs to be detected at runtime
|
25
|
+
* since we could've been built on a different system than we're run
|
26
|
+
* under.
|
27
|
+
*/
|
28
|
+
static clockid_t hopefully_CLOCK_MONOTONIC;
|
29
|
+
|
30
|
+
static void check_clock(void)
|
31
|
+
{
|
32
|
+
struct timespec now;
|
33
|
+
|
34
|
+
hopefully_CLOCK_MONOTONIC = CLOCK_MONOTONIC;
|
35
|
+
|
36
|
+
/* we can't check this reliably at compile time */
|
37
|
+
if (clock_gettime(CLOCK_MONOTONIC, &now) == 0)
|
38
|
+
return;
|
39
|
+
|
40
|
+
if (clock_gettime(CLOCK_REALTIME, &now) == 0) {
|
41
|
+
hopefully_CLOCK_MONOTONIC = CLOCK_REALTIME;
|
42
|
+
rb_warn("CLOCK_MONOTONIC not available, "
|
43
|
+
"falling back to CLOCK_REALTIME");
|
44
|
+
}
|
45
|
+
rb_warn("clock_gettime() totally broken, " \
|
46
|
+
"falling back to pure Ruby Clogger");
|
47
|
+
rb_raise(rb_eLoadError, "clock_gettime() broken");
|
48
|
+
}
|
19
49
|
|
20
50
|
static void clock_diff(struct timespec *a, const struct timespec *b)
|
21
51
|
{
|
@@ -94,8 +124,8 @@ static ID sq_brace_id;
|
|
94
124
|
static ID new_id;
|
95
125
|
static ID to_path_id;
|
96
126
|
static ID to_io_id;
|
127
|
+
static ID respond_to_id;
|
97
128
|
static VALUE cClogger;
|
98
|
-
static VALUE cToPath;
|
99
129
|
static VALUE mFormat;
|
100
130
|
static VALUE cHeaderHash;
|
101
131
|
|
@@ -205,11 +235,6 @@ static struct clogger *clogger_get(VALUE self)
|
|
205
235
|
return c;
|
206
236
|
}
|
207
237
|
|
208
|
-
static VALUE obj_fileno(VALUE obj)
|
209
|
-
{
|
210
|
-
return rb_funcall(obj, rb_intern("fileno"), 0);
|
211
|
-
}
|
212
|
-
|
213
238
|
/* only for writing to regular files, not stupid crap like NFS */
|
214
239
|
static void write_full(int fd, const void *buf, size_t count)
|
215
240
|
{
|
@@ -350,11 +375,8 @@ static void append_ts(struct clogger *c, const VALUE *op, struct timespec *ts)
|
|
350
375
|
static void append_request_time_fmt(struct clogger *c, const VALUE *op)
|
351
376
|
{
|
352
377
|
struct timespec now;
|
353
|
-
int r = clock_gettime(CLOCK_MONOTONIC, &now);
|
354
|
-
|
355
|
-
if (unlikely(r != 0))
|
356
|
-
rb_sys_fail("clock_gettime(CLOCK_MONONTONIC)");
|
357
378
|
|
379
|
+
clock_gettime(hopefully_CLOCK_MONOTONIC, &now);
|
358
380
|
clock_diff(&now, &c->ts_start);
|
359
381
|
append_ts(c, op, &now);
|
360
382
|
}
|
@@ -420,10 +442,11 @@ static void append_request_length(struct clogger *c)
|
|
420
442
|
}
|
421
443
|
}
|
422
444
|
|
423
|
-
static void
|
445
|
+
static void
|
446
|
+
append_time(struct clogger *c, enum clogger_opcode op, VALUE fmt, VALUE buf)
|
424
447
|
{
|
425
|
-
|
426
|
-
|
448
|
+
char *buf_ptr = RSTRING_PTR(buf);
|
449
|
+
size_t buf_size = RSTRING_LEN(buf) + 1; /* "\0" */
|
427
450
|
size_t nr;
|
428
451
|
struct tm tmp;
|
429
452
|
time_t t = time(NULL);
|
@@ -435,11 +458,9 @@ static void append_time(struct clogger *c, enum clogger_opcode op, VALUE fmt)
|
|
435
458
|
else
|
436
459
|
assert(0 && "unknown op");
|
437
460
|
|
438
|
-
nr = strftime(
|
439
|
-
|
440
|
-
|
441
|
-
else
|
442
|
-
rb_str_buf_cat(c->log_buf, buf, nr);
|
461
|
+
nr = strftime(buf_ptr, buf_size, RSTRING_PTR(fmt), &tmp);
|
462
|
+
assert(nr < buf_size && "time format too small!");
|
463
|
+
rb_str_buf_cat(c->log_buf, buf_ptr, nr);
|
443
464
|
}
|
444
465
|
|
445
466
|
static void append_pid(struct clogger *c)
|
@@ -559,7 +580,7 @@ static VALUE cwrite(struct clogger *c)
|
|
559
580
|
break;
|
560
581
|
case CL_OP_TIME_LOCAL:
|
561
582
|
case CL_OP_TIME_UTC:
|
562
|
-
append_time(c, opcode, op[1]);
|
583
|
+
append_time(c, opcode, op[1], op[2]);
|
563
584
|
break;
|
564
585
|
case CL_OP_REQUEST_TIME:
|
565
586
|
append_request_time_fmt(c, op);
|
@@ -728,7 +749,7 @@ static VALUE ccall(struct clogger *c, VALUE env)
|
|
728
749
|
{
|
729
750
|
VALUE rv;
|
730
751
|
|
731
|
-
clock_gettime(
|
752
|
+
clock_gettime(hopefully_CLOCK_MONOTONIC, &c->ts_start);
|
732
753
|
c->env = env;
|
733
754
|
c->cookies = Qfalse;
|
734
755
|
rv = rb_funcall(c->app, call_id, 1, env);
|
@@ -785,9 +806,6 @@ static VALUE clogger_call(VALUE self, VALUE env)
|
|
785
806
|
|
786
807
|
rv = ccall(c, env);
|
787
808
|
assert(!OBJ_FROZEN(rv) && "frozen response array");
|
788
|
-
|
789
|
-
if (rb_respond_to(c->body, to_path_id))
|
790
|
-
self = rb_funcall(cToPath, new_id, 1, self);
|
791
809
|
rb_ary_store(rv, 2, self);
|
792
810
|
|
793
811
|
return rv;
|
@@ -799,7 +817,24 @@ static VALUE clogger_call(VALUE self, VALUE env)
|
|
799
817
|
return rv;
|
800
818
|
}
|
801
819
|
|
802
|
-
|
820
|
+
static void duplicate_buffers(VALUE ops)
|
821
|
+
{
|
822
|
+
long i = RARRAY_LEN(ops);
|
823
|
+
VALUE *ary = RARRAY_PTR(ops);
|
824
|
+
|
825
|
+
for ( ; --i >= 0; ary++) {
|
826
|
+
VALUE *op = RARRAY_PTR(*ary);
|
827
|
+
enum clogger_opcode opcode = FIX2INT(op[0]);
|
828
|
+
|
829
|
+
if (opcode == CL_OP_TIME_LOCAL || opcode == CL_OP_TIME_UTC) {
|
830
|
+
Check_Type(op[2], T_STRING);
|
831
|
+
op[2] = rb_str_dup(op[2]);
|
832
|
+
rb_str_modify(op[2]); /* trigger copy-on-write */
|
833
|
+
}
|
834
|
+
}
|
835
|
+
}
|
836
|
+
|
837
|
+
/* :nodoc: */
|
803
838
|
static VALUE clogger_init_copy(VALUE clone, VALUE orig)
|
804
839
|
{
|
805
840
|
struct clogger *a = clogger_get(orig);
|
@@ -807,6 +842,7 @@ static VALUE clogger_init_copy(VALUE clone, VALUE orig)
|
|
807
842
|
|
808
843
|
memcpy(b, a, sizeof(struct clogger));
|
809
844
|
init_buffers(b);
|
845
|
+
duplicate_buffers(b->fmt_ops);
|
810
846
|
|
811
847
|
return clone;
|
812
848
|
}
|
@@ -818,25 +854,38 @@ static VALUE clogger_init_copy(VALUE clone, VALUE orig)
|
|
818
854
|
|
819
855
|
#define CONST_GLOBAL_STR(val) CONST_GLOBAL_STR2(val, #val)
|
820
856
|
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
857
|
+
/*
|
858
|
+
* call-seq:
|
859
|
+
* clogger.respond_to?(:to_path) => true or false
|
860
|
+
* clogger.respond_to?(:close) => true
|
861
|
+
*
|
862
|
+
* used to delegate +:to_path+ checks for Rack webservers that optimize
|
863
|
+
* static file serving
|
864
|
+
*/
|
865
|
+
static VALUE respond_to(VALUE self, VALUE method)
|
866
|
+
{
|
867
|
+
struct clogger *c = clogger_get(self);
|
868
|
+
ID id = rb_to_id(method);
|
869
|
+
|
870
|
+
if (close_id == id)
|
871
|
+
return Qtrue;
|
872
|
+
return rb_respond_to(c->body, id);
|
873
|
+
}
|
827
874
|
|
875
|
+
/*
|
876
|
+
* call-seq:
|
877
|
+
* clogger.to_path
|
878
|
+
*
|
879
|
+
* used to proxy +:to_path+ method calls to the wrapped response body.
|
880
|
+
*/
|
828
881
|
static VALUE to_path(VALUE self)
|
829
882
|
{
|
830
|
-
|
831
|
-
struct clogger *c = clogger_get(my_clogger);
|
883
|
+
struct clogger *c = clogger_get(self);
|
832
884
|
VALUE path = rb_funcall(c->body, to_path_id, 0);
|
833
885
|
struct stat sb;
|
834
886
|
int rv;
|
835
887
|
unsigned devfd;
|
836
|
-
const char *cpath;
|
837
|
-
|
838
|
-
Check_Type(path, T_STRING);
|
839
|
-
cpath = RSTRING_PTR(path);
|
888
|
+
const char *cpath = StringValuePtr(path);
|
840
889
|
|
841
890
|
/* try to avoid an extra path lookup */
|
842
891
|
if (rb_respond_to(c->body, to_io_id))
|
@@ -863,6 +912,8 @@ void Init_clogger_ext(void)
|
|
863
912
|
{
|
864
913
|
VALUE tmp;
|
865
914
|
|
915
|
+
check_clock();
|
916
|
+
|
866
917
|
ltlt_id = rb_intern("<<");
|
867
918
|
call_id = rb_intern("call");
|
868
919
|
each_id = rb_intern("each");
|
@@ -874,6 +925,7 @@ void Init_clogger_ext(void)
|
|
874
925
|
new_id = rb_intern("new");
|
875
926
|
to_path_id = rb_intern("to_path");
|
876
927
|
to_io_id = rb_intern("to_io");
|
928
|
+
respond_to_id = rb_intern("respond_to?");
|
877
929
|
cClogger = rb_define_class("Clogger", rb_cObject);
|
878
930
|
mFormat = rb_define_module_under(cClogger, "Format");
|
879
931
|
rb_define_alloc_func(cClogger, clogger_alloc);
|
@@ -885,6 +937,8 @@ void Init_clogger_ext(void)
|
|
885
937
|
rb_define_method(cClogger, "fileno", clogger_fileno, 0);
|
886
938
|
rb_define_method(cClogger, "wrap_body?", clogger_wrap_body, 0);
|
887
939
|
rb_define_method(cClogger, "reentrant?", clogger_reentrant, 0);
|
940
|
+
rb_define_method(cClogger, "to_path", to_path, 0);
|
941
|
+
rb_define_method(cClogger, "respond_to?", respond_to, 1);
|
888
942
|
CONST_GLOBAL_STR(REMOTE_ADDR);
|
889
943
|
CONST_GLOBAL_STR(HTTP_X_FORWARDED_FOR);
|
890
944
|
CONST_GLOBAL_STR(REQUEST_METHOD);
|
@@ -903,9 +957,4 @@ void Init_clogger_ext(void)
|
|
903
957
|
tmp = rb_const_get(rb_cObject, rb_intern("Rack"));
|
904
958
|
tmp = rb_const_get(tmp, rb_intern("Utils"));
|
905
959
|
cHeaderHash = rb_const_get(tmp, rb_intern("HeaderHash"));
|
906
|
-
cToPath = rb_const_get(cClogger, rb_intern("ToPath"));
|
907
|
-
rb_define_method(cToPath, "to_path", to_path, 0);
|
908
|
-
#ifndef RSTRUCT_PTR
|
909
|
-
clogger_id = rb_intern("clogger");
|
910
|
-
#endif
|
911
960
|
}
|
data/ext/clogger_ext/extconf.rb
CHANGED
@@ -13,10 +13,12 @@ begin
|
|
13
13
|
have_macro('O_NONBLOCK', %w(unistd.h fcntl.h))
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
$CPPFLAGS += '-D_POSIX_C_SOURCE=200112L'
|
17
|
+
unless have_macro('CLOCK_MONOTONIC', 'time.h')
|
18
18
|
have_func('CLOCK_MONOTONIC', 'time.h')
|
19
19
|
end
|
20
|
+
have_type('clockid_t', 'time.h')
|
21
|
+
have_func('clock_gettime', 'time.h')
|
20
22
|
have_func('localtime_r', 'time.h') or raise "localtime_r needed"
|
21
23
|
have_func('gmtime_r', 'time.h') or raise "gmtime_r needed"
|
22
24
|
have_func('rb_str_set_len', 'ruby.h')
|
@@ -11,14 +11,6 @@
|
|
11
11
|
#ifndef RARRAY_LEN
|
12
12
|
# define RARRAY_LEN(s) (RARRAY(s)->len)
|
13
13
|
#endif
|
14
|
-
#ifndef RUBINIUS
|
15
|
-
# ifndef RSTRUCT_PTR
|
16
|
-
# define RSTRUCT_PTR(s) (RSTRUCT(s)->ptr)
|
17
|
-
# endif
|
18
|
-
# ifndef RSTRUCT_LEN
|
19
|
-
# define RSTRUCT_LEN(s) (RSTRUCT(s)->len)
|
20
|
-
# endif
|
21
|
-
#endif
|
22
14
|
|
23
15
|
#ifndef HAVE_RB_STR_SET_LEN
|
24
16
|
/* this is taken from Ruby 1.8.7, 1.8.6 may not have it */
|
data/lib/clogger.rb
CHANGED
@@ -4,8 +4,8 @@ require 'rack'
|
|
4
4
|
# See the README for usage instructions
|
5
5
|
class Clogger
|
6
6
|
|
7
|
-
# the version of Clogger, currently 0.
|
8
|
-
VERSION = '0.
|
7
|
+
# the version of Clogger, currently 0.7.0
|
8
|
+
VERSION = '0.7.0'
|
9
9
|
|
10
10
|
# :stopdoc:
|
11
11
|
OP_LITERAL = 0
|
@@ -23,6 +23,7 @@ class Clogger
|
|
23
23
|
ALIASES = {
|
24
24
|
'$request_time' => '$request_time{3}',
|
25
25
|
'$time_local' => '$time_local{%d/%b/%Y:%H:%M:%S %z}',
|
26
|
+
'$time_utc' => '$time_utc{%d/%b/%Y:%H:%M:%S %z}',
|
26
27
|
'$msec' => '$time{3}',
|
27
28
|
'$usec' => '$time{6}',
|
28
29
|
'$http_content_length' => '$content_length',
|
@@ -40,15 +41,6 @@ class Clogger
|
|
40
41
|
:request_uri => 7
|
41
42
|
}
|
42
43
|
|
43
|
-
# proxy class to avoid clobbering the +to_path+ optimization when
|
44
|
-
# using static files
|
45
|
-
class ToPath < Struct.new(:clogger)
|
46
|
-
def each(&block); clogger.each(&block); end
|
47
|
-
def close; clogger.close; end
|
48
|
-
|
49
|
-
# to_path is defined in Clogger::Pure or the C extension
|
50
|
-
end
|
51
|
-
|
52
44
|
private
|
53
45
|
|
54
46
|
CGI_ENV = Regexp.new('\A\$(' <<
|
@@ -66,6 +58,7 @@ private
|
|
66
58
|
\w*))?([^$]*)/x
|
67
59
|
|
68
60
|
def compile_format(str, opt = {})
|
61
|
+
longest_day = Time.at(26265600) # "Saturday, November 01, 1970 00:00:00"
|
69
62
|
rv = []
|
70
63
|
opt ||= {}
|
71
64
|
str.scan(SCAN).each do |pre,tok,post|
|
@@ -92,9 +85,11 @@ private
|
|
92
85
|
when /\A\$sent_http_(\w+)\z/
|
93
86
|
rv << [ OP_RESPONSE, $1.downcase.tr('_','-') ]
|
94
87
|
when /\A\$time_local\{([^\}]+)\}\z/
|
95
|
-
|
88
|
+
fmt = $1
|
89
|
+
rv << [ OP_TIME_LOCAL, fmt, longest_day.strftime(fmt) ]
|
96
90
|
when /\A\$time_utc\{([^\}]+)\}\z/
|
97
|
-
|
91
|
+
fmt = $1
|
92
|
+
rv << [ OP_TIME_UTC, fmt, longest_day.strftime(fmt) ]
|
98
93
|
when /\A\$time\{(\d+)\}\z/
|
99
94
|
rv << [ OP_TIME, *usec_conv_pair(tok, $1.to_i) ]
|
100
95
|
when /\A\$request_time\{(\d+)\}\z/
|
data/lib/clogger/pure.rb
CHANGED
@@ -43,7 +43,6 @@ class Clogger
|
|
43
43
|
wbody.status = status
|
44
44
|
wbody.headers = headers
|
45
45
|
wbody.body = body
|
46
|
-
wbody = Clogger::ToPath.new(wbody) if body.respond_to?(:to_path)
|
47
46
|
return [ status, headers, wbody ]
|
48
47
|
end
|
49
48
|
log(env, status, headers)
|
@@ -77,6 +76,19 @@ class Clogger
|
|
77
76
|
@logger.respond_to?(:fileno) ? @logger.fileno : nil
|
78
77
|
end
|
79
78
|
|
79
|
+
def respond_to?(m)
|
80
|
+
:close == m.to_sym || @body.respond_to?(m)
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_path
|
84
|
+
rv = @body.to_path
|
85
|
+
# try to avoid unnecessary path lookups with to_io.stat instead of
|
86
|
+
# File.size
|
87
|
+
@body_bytes_sent =
|
88
|
+
@body.respond_to?(:to_io) ? @body.to_io.stat.size : File.size(rv)
|
89
|
+
rv
|
90
|
+
end
|
91
|
+
|
80
92
|
private
|
81
93
|
|
82
94
|
def byte_xs(s)
|
@@ -151,17 +163,4 @@ private
|
|
151
163
|
end
|
152
164
|
}.join('')
|
153
165
|
end
|
154
|
-
|
155
|
-
class ToPath
|
156
|
-
def to_path
|
157
|
-
rv = (body = clogger.body).to_path
|
158
|
-
|
159
|
-
# try to avoid unnecessary path lookups with to_io.stat instead of
|
160
|
-
# File.stat
|
161
|
-
clogger.body_bytes_sent =
|
162
|
-
(body.respond_to?(:to_io) ? body.to_io.stat : File.stat(rv)).size
|
163
|
-
rv
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
166
|
end
|
data/test/test_clogger.rb
CHANGED
@@ -156,12 +156,13 @@ class TestClogger < Test::Unit::TestCase
|
|
156
156
|
'$env{rack.url_scheme}' \
|
157
157
|
"\n")
|
158
158
|
}
|
159
|
+
longest_day = Time.at(26265600).strftime('%d/%b/%Y:%H:%M:%S %z')
|
159
160
|
expect = [
|
160
161
|
[ Clogger::OP_REQUEST, "REMOTE_ADDR" ],
|
161
162
|
[ Clogger::OP_LITERAL, " - " ],
|
162
163
|
[ Clogger::OP_REQUEST, "REMOTE_USER" ],
|
163
164
|
[ Clogger::OP_LITERAL, " [" ],
|
164
|
-
[ Clogger::OP_TIME_LOCAL, '%d/%b/%Y:%H:%M:%S %z' ],
|
165
|
+
[ Clogger::OP_TIME_LOCAL, '%d/%b/%Y:%H:%M:%S %z', longest_day ],
|
165
166
|
[ Clogger::OP_LITERAL, "] \"" ],
|
166
167
|
[ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:request] ],
|
167
168
|
[ Clogger::OP_LITERAL, "\" "],
|
@@ -677,4 +678,23 @@ class TestClogger < Test::Unit::TestCase
|
|
677
678
|
assert s[-1].to_f >= 0.100
|
678
679
|
assert s[-1].to_f <= 0.110
|
679
680
|
end
|
681
|
+
|
682
|
+
def test_insanely_long_time_format
|
683
|
+
s = []
|
684
|
+
app = lambda { |env| [200, [], [] ] }
|
685
|
+
fmt = '%Y' * 100
|
686
|
+
expect = Time.now.utc.strftime(fmt) << "\n"
|
687
|
+
assert_equal 100 * 4 + 1, expect.size
|
688
|
+
cl = Clogger.new(app, :logger => s, :format => "$time_utc{#{fmt}}")
|
689
|
+
status, headers, body = cl.call(@req)
|
690
|
+
assert_equal expect, s[0]
|
691
|
+
end
|
692
|
+
|
693
|
+
def test_time_utc
|
694
|
+
s = []
|
695
|
+
app = lambda { |env| [200, [], [] ] }
|
696
|
+
cl = Clogger.new(app, :logger => s, :format => "$time_utc")
|
697
|
+
status, headers, body = cl.call(@req)
|
698
|
+
assert %r!\A\d+/\w+/\d{4}:\d\d:\d\d:\d\d \+0000\n\z! =~ s[0], s.inspect
|
699
|
+
end
|
680
700
|
end
|
@@ -31,6 +31,14 @@ class TestCloggerToPath < Test::Unit::TestCase
|
|
31
31
|
}
|
32
32
|
end
|
33
33
|
|
34
|
+
def check_body(body)
|
35
|
+
assert body.respond_to?(:to_path)
|
36
|
+
assert body.respond_to?("to_path")
|
37
|
+
|
38
|
+
assert ! body.respond_to?(:to_Path)
|
39
|
+
assert ! body.respond_to?("to_Path")
|
40
|
+
end
|
41
|
+
|
34
42
|
def test_wraps_to_path
|
35
43
|
logger = StringIO.new
|
36
44
|
tmp = Tempfile.new('')
|
@@ -49,7 +57,8 @@ class TestCloggerToPath < Test::Unit::TestCase
|
|
49
57
|
end.to_app
|
50
58
|
|
51
59
|
status, headers, body = app.call(@req)
|
52
|
-
assert_instance_of(Clogger
|
60
|
+
assert_instance_of(Clogger, body)
|
61
|
+
check_body(body)
|
53
62
|
assert logger.string.empty?
|
54
63
|
assert_equal tmp.path, body.to_path
|
55
64
|
body.close
|
@@ -75,7 +84,8 @@ class TestCloggerToPath < Test::Unit::TestCase
|
|
75
84
|
end.to_app
|
76
85
|
|
77
86
|
status, headers, body = app.call(@req)
|
78
|
-
assert_instance_of(Clogger
|
87
|
+
assert_instance_of(Clogger, body)
|
88
|
+
check_body(body)
|
79
89
|
assert logger.string.empty?
|
80
90
|
assert_equal "/dev/fd/#{tmp.fileno}", body.to_path
|
81
91
|
body.close
|
@@ -107,7 +117,9 @@ class TestCloggerToPath < Test::Unit::TestCase
|
|
107
117
|
end.to_app
|
108
118
|
|
109
119
|
status, headers, body = app.call(@req)
|
110
|
-
assert_instance_of(Clogger
|
120
|
+
assert_instance_of(Clogger, body)
|
121
|
+
check_body(body)
|
122
|
+
|
111
123
|
body.to_path
|
112
124
|
assert_kind_of IO, tmp.instance_variable_get(:@to_io_called)
|
113
125
|
assert logger.string.empty?
|
@@ -132,6 +144,8 @@ class TestCloggerToPath < Test::Unit::TestCase
|
|
132
144
|
end.to_app
|
133
145
|
status, headers, body = app.call(@req)
|
134
146
|
assert_instance_of(Clogger, body)
|
147
|
+
assert ! body.respond_to?(:to_path)
|
148
|
+
assert ! body.respond_to?("to_path")
|
135
149
|
assert logger.string.empty?
|
136
150
|
body.close
|
137
151
|
assert ! logger.string.empty?
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clogger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 7
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.7.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- cloggers
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-01-15 00:00:00 +00:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -48,7 +48,9 @@ dependencies:
|
|
48
48
|
version: "1.0"
|
49
49
|
type: :development
|
50
50
|
version_requirements: *id002
|
51
|
-
description:
|
51
|
+
description: |-
|
52
|
+
\Clogger is Rack middleware for logging HTTP requests. The log format
|
53
|
+
is customizable so you can specify exactly which fields to log.
|
52
54
|
email: clogger@librelist.com
|
53
55
|
executables: []
|
54
56
|
|
@@ -80,6 +82,7 @@ files:
|
|
80
82
|
- README
|
81
83
|
- Rakefile
|
82
84
|
- clogger.gemspec
|
85
|
+
- ext/clogger_ext/broken_system_compat.h
|
83
86
|
- ext/clogger_ext/clogger.c
|
84
87
|
- ext/clogger_ext/extconf.rb
|
85
88
|
- ext/clogger_ext/ruby_1_9_compat.h
|