clogger 0.6.0 → 0.7.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.
- 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
|