clogger 0.5.0 → 0.6.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/.document +1 -0
- data/.gitignore +1 -0
- data/.wrongdoc.yml +5 -0
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +21 -40
- data/README +9 -3
- data/Rakefile +1 -94
- data/clogger.gemspec +10 -26
- data/ext/clogger_ext/clogger.c +66 -37
- data/ext/clogger_ext/extconf.rb +4 -0
- data/ext/clogger_ext/ruby_1_9_compat.h +7 -5
- data/lib/clogger.rb +12 -12
- data/lib/clogger/format.rb +4 -4
- data/lib/clogger/pure.rb +8 -3
- data/test/test_clogger.rb +48 -0
- metadata +48 -14
data/.document
CHANGED
data/.gitignore
CHANGED
data/.wrongdoc.yml
ADDED
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
all:: test
|
2
2
|
RUBY = ruby
|
3
3
|
RAKE = rake
|
4
|
-
|
4
|
+
RSYNC = rsync
|
5
5
|
|
6
6
|
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
7
7
|
@./GIT-VERSION-GEN
|
@@ -26,24 +26,24 @@ test_unit := $(wildcard test/test_*.rb)
|
|
26
26
|
test-unit: $(test_unit)
|
27
27
|
|
28
28
|
ifeq ($(CLOGGER_PURE),)
|
29
|
-
$(test_unit):
|
29
|
+
$(test_unit): mylib := ext/clogger_ext:lib
|
30
30
|
$(test_unit): ext/clogger_ext/clogger.$(DLEXT)
|
31
31
|
else
|
32
|
-
$(test_unit):
|
32
|
+
$(test_unit): mylib := lib
|
33
33
|
endif
|
34
34
|
|
35
35
|
$(test_unit):
|
36
|
-
$(RUBY) $@
|
36
|
+
$(RUBY) -I $(mylib) $@
|
37
37
|
|
38
38
|
test-ext:
|
39
|
-
CLOGGER_PURE=
|
39
|
+
CLOGGER_PURE= $(MAKE) test-unit
|
40
40
|
|
41
41
|
test-pure:
|
42
42
|
CLOGGER_PURE=1 $(MAKE) test-unit
|
43
43
|
|
44
44
|
test: test-ext test-pure
|
45
45
|
|
46
|
-
pkg_extra := GIT-VERSION-FILE NEWS ChangeLog
|
46
|
+
pkg_extra := GIT-VERSION-FILE NEWS ChangeLog LATEST
|
47
47
|
manifest: $(pkg_extra)
|
48
48
|
$(RM) .manifest
|
49
49
|
$(MAKE) .manifest
|
@@ -55,44 +55,25 @@ manifest: $(pkg_extra)
|
|
55
55
|
cmp $@+ $@ || mv $@+ $@
|
56
56
|
$(RM) $@+
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
mv $@+ $@
|
61
|
-
|
62
|
-
SINCE = 0.4.0
|
63
|
-
ChangeLog: log_range = $(shell test -n "$(SINCE)" && echo v$(SINCE)..)
|
64
|
-
ChangeLog: GIT-VERSION-FILE
|
65
|
-
@echo "ChangeLog from $(GIT_URL) ($(SINCE)..$(GIT_VERSION))" > $@+
|
66
|
-
@echo >> $@+
|
67
|
-
git log $(log_range) | sed -e 's/^/ /' >> $@+
|
68
|
-
mv $@+ $@
|
58
|
+
ChangeLog: GIT-VERSION-FILE .wrongdoc.yml
|
59
|
+
wrongdoc prepare
|
69
60
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
doc: .document NEWS ChangeLog
|
76
|
-
rdoc -a -t "$(shell sed -ne '1s/^= //p' README)"
|
61
|
+
doc: .document .wrongdoc.yml
|
62
|
+
find lib ext -type f -name '*.rbc' -exec rm -f '{}' ';'
|
63
|
+
$(RM) -r doc
|
64
|
+
wrongdoc all
|
77
65
|
install -m644 COPYING doc/COPYING
|
78
|
-
install -m644 $(shell grep '^[A-Z]' .document)
|
79
|
-
$(RUBY) -i -p -e \
|
80
|
-
'$$_.gsub!("</title>",%q{\&$(call atom,$(cgit_atom))})' \
|
81
|
-
doc/ChangeLog.html
|
82
|
-
$(RUBY) -i -p -e \
|
83
|
-
'$$_.gsub!("</title>",%q{\&$(call atom,$(news_atom))})' \
|
84
|
-
doc/NEWS.html doc/README.html
|
85
|
-
$(RAKE) -s news_atom > doc/NEWS.atom.xml
|
86
|
-
cd doc && ln README.html tmp && mv tmp index.html
|
66
|
+
install -m644 $(shell grep '^[A-Z]' .document) doc/
|
87
67
|
|
88
68
|
# publishes docs to http://clogger.rubyforge.org/
|
89
69
|
# this preserves timestamps as best as possible to help HTTP caches out
|
90
70
|
# git set-file-times is here: http://git-scm.org/gitwiki/ExampleScripts
|
91
71
|
publish_doc:
|
92
|
-
git set-file-times
|
93
|
-
$(RM) -r doc
|
72
|
+
-git set-file-times
|
94
73
|
$(MAKE) doc
|
95
|
-
|
74
|
+
-find doc/images -type f | \
|
75
|
+
TZ=UTC xargs touch -d '1970-01-01 00:00:03' doc/rdoc.css
|
76
|
+
$(RSYNC) -av doc/ rubyforge.org:/var/www/gforge-projects/clogger/
|
96
77
|
git ls-files | xargs touch
|
97
78
|
|
98
79
|
ifneq ($(VERSION),)
|
@@ -106,10 +87,10 @@ release_changes := release_changes-$(VERSION)
|
|
106
87
|
release-notes: $(release_notes)
|
107
88
|
release-changes: $(release_changes)
|
108
89
|
$(release_changes):
|
109
|
-
|
90
|
+
wrongdoc release_changes > $@+
|
110
91
|
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
111
92
|
$(release_notes):
|
112
|
-
|
93
|
+
wrongdoc release_notes > $@+
|
113
94
|
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
114
95
|
|
115
96
|
# ensures we're actually on the tagged $(VERSION), only used for release
|
@@ -140,8 +121,8 @@ $(pkgtgz): manifest fix-perms
|
|
140
121
|
@test -n "$(distdir)"
|
141
122
|
$(RM) -r $(distdir)
|
142
123
|
mkdir -p $(distdir)
|
143
|
-
tar
|
144
|
-
cd pkg && tar
|
124
|
+
tar cf - `cat .manifest` | (cd $(distdir) && tar xf -)
|
125
|
+
cd pkg && tar cf - $(basename $(@F)) | gzip -9 > $(@F)+
|
145
126
|
mv $@+ $@
|
146
127
|
|
147
128
|
package: $(pkgtgz) $(pkggem)
|
data/README
CHANGED
@@ -10,7 +10,7 @@ is customizable so you can specify exactly which fields to log.
|
|
10
10
|
* highly customizable with easy-to-read nginx-like log format variables.
|
11
11
|
|
12
12
|
* pre-defines Apache Common Log Format, Apache Combined Log Format and
|
13
|
-
Rack::CommonLogger (as distributed by Rack 1.0) formats.
|
13
|
+
Rack::CommonLogger (as distributed by Rack 1.0 and 1.1) formats.
|
14
14
|
See Clogger::Format for the predefined formats.
|
15
15
|
|
16
16
|
* Untrusted values are escaped (all HTTP headers, request URI components)
|
@@ -36,7 +36,7 @@ is customizable so you can specify exactly which fields to log.
|
|
36
36
|
require "clogger"
|
37
37
|
use Clogger,
|
38
38
|
:format => Clogger::Format::Combined,
|
39
|
-
:
|
39
|
+
:path => "/path/to/log",
|
40
40
|
:reentrant => true
|
41
41
|
run YourApplication.new
|
42
42
|
|
@@ -45,9 +45,15 @@ somewhere inside the "Rails::Initializer.run do |config|" block:
|
|
45
45
|
|
46
46
|
config.middleware.use 'Clogger',
|
47
47
|
:format => Clogger::Format::Combined,
|
48
|
-
:
|
48
|
+
:path => "/path/to/log",
|
49
49
|
:reentrant => false
|
50
50
|
|
51
|
+
Instead of specifying a :path, you may also specify a :logger object
|
52
|
+
that receives a "<<" method:
|
53
|
+
|
54
|
+
use Clogger, :logger=> $stdout, :reentrant => true
|
55
|
+
run YourApplication.new
|
56
|
+
|
51
57
|
== VARIABLES
|
52
58
|
|
53
59
|
* $http_* - HTTP request headers (e.g. $http_user_agent)
|
data/Rakefile
CHANGED
@@ -21,101 +21,8 @@ task :publish_news do
|
|
21
21
|
rf.post_news('clogger', subject, body)
|
22
22
|
end
|
23
23
|
|
24
|
-
def tags
|
25
|
-
timefmt = '%Y-%m-%dT%H:%M:%SZ'
|
26
|
-
@tags ||= `git tag -l`.split(/\n/).map do |tag|
|
27
|
-
next if tag == "v0.0.0"
|
28
|
-
if %r{\Av[\d\.]+\z} =~ tag
|
29
|
-
header, subject, body = `git cat-file tag #{tag}`.split(/\n\n/, 3)
|
30
|
-
header = header.split(/\n/)
|
31
|
-
tagger = header.grep(/\Atagger /).first
|
32
|
-
body ||= "initial"
|
33
|
-
{
|
34
|
-
:time => Time.at(tagger.split(/ /)[-2].to_i).utc.strftime(timefmt),
|
35
|
-
:tagger_name => %r{^tagger ([^<]+)}.match(tagger)[1],
|
36
|
-
:tagger_email => %r{<([^>]+)>}.match(tagger)[1],
|
37
|
-
:id => `git rev-parse refs/tags/#{tag}`.chomp!,
|
38
|
-
:tag => tag,
|
39
|
-
:subject => subject,
|
40
|
-
:body => body,
|
41
|
-
}
|
42
|
-
end
|
43
|
-
end.compact.sort { |a,b| b[:time] <=> a[:time] }
|
44
|
-
end
|
45
|
-
|
46
24
|
cgit_url = "http://git.bogomips.org/cgit/clogger.git"
|
47
|
-
git_url =
|
48
|
-
|
49
|
-
desc 'prints news as an Atom feed'
|
50
|
-
task :news_atom do
|
51
|
-
require 'nokogiri'
|
52
|
-
new_tags = tags[0,10]
|
53
|
-
puts(Nokogiri::XML::Builder.new do
|
54
|
-
feed :xmlns => "http://www.w3.org/2005/Atom" do
|
55
|
-
id! "http://clogger.rubyforge.org/NEWS.atom.xml"
|
56
|
-
title "Clogger news"
|
57
|
-
subtitle "configurable request logging for Rack"
|
58
|
-
link! :rel => 'alternate', :type => 'text/html',
|
59
|
-
:href => 'http://clogger.rubyforge.org/NEWS.html'
|
60
|
-
updated new_tags.first[:time]
|
61
|
-
new_tags.each do |tag|
|
62
|
-
entry do
|
63
|
-
title tag[:subject]
|
64
|
-
updated tag[:time]
|
65
|
-
published tag[:time]
|
66
|
-
author {
|
67
|
-
name tag[:tagger_name]
|
68
|
-
email tag[:tagger_email]
|
69
|
-
}
|
70
|
-
url = "#{cgit_url}/tag/?id=#{tag[:tag]}"
|
71
|
-
link! :rel => "alternate", :type => "text/html", :href =>url
|
72
|
-
id! url
|
73
|
-
content(:type => 'text') { tag[:body] }
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end.to_xml)
|
78
|
-
end
|
79
|
-
|
80
|
-
desc 'prints RDoc-formatted news'
|
81
|
-
task :news_rdoc do
|
82
|
-
tags.each do |tag|
|
83
|
-
time = tag[:time].tr!('T', ' ').gsub!(/:\d\dZ/, ' UTC')
|
84
|
-
puts "=== #{tag[:tag].sub(/^v/, '')} / #{time}"
|
85
|
-
puts ""
|
86
|
-
|
87
|
-
body = tag[:body]
|
88
|
-
puts tag[:body].gsub(/^/sm, " ").gsub(/[ \t]+$/sm, "")
|
89
|
-
puts ""
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
desc "print release changelog for Rubyforge"
|
94
|
-
task :release_changes do
|
95
|
-
version = ENV['VERSION'] or abort "VERSION= needed"
|
96
|
-
version = "v#{version}"
|
97
|
-
vtags = tags.map { |tag| tag[:tag] =~ /\Av/ and tag[:tag] }.sort
|
98
|
-
prev = vtags[vtags.index(version) - 1]
|
99
|
-
system('git', 'diff', '--stat', prev, version) or abort $?
|
100
|
-
puts ""
|
101
|
-
system('git', 'log', "#{prev}..#{version}") or abort $?
|
102
|
-
end
|
103
|
-
|
104
|
-
desc "print release notes for Rubyforge"
|
105
|
-
task :release_notes do
|
106
|
-
require 'rubygems'
|
107
|
-
|
108
|
-
spec = Gem::Specification.load('clogger.gemspec')
|
109
|
-
puts spec.description.strip
|
110
|
-
puts ""
|
111
|
-
puts "* #{spec.homepage}"
|
112
|
-
puts "* #{spec.email}"
|
113
|
-
puts "* #{git_url}"
|
114
|
-
|
115
|
-
_, _, body = `git cat-file tag v#{spec.version}`.split(/\n\n/, 3)
|
116
|
-
print "\nChanges:\n\n"
|
117
|
-
puts body
|
118
|
-
end
|
25
|
+
git_url = 'git://git.bogomips.org/clogger.git'
|
119
26
|
|
120
27
|
desc "post to RAA"
|
121
28
|
task :raa_update do
|
data/clogger.gemspec
CHANGED
@@ -1,44 +1,28 @@
|
|
1
1
|
ENV["VERSION"] or abort "VERSION= must be specified"
|
2
2
|
manifest = File.readlines('.manifest').map! { |x| x.chomp! }
|
3
|
+
require 'wrongdoc'
|
4
|
+
extend Wrongdoc::Gemspec
|
5
|
+
name, summary, title = readme_metadata
|
3
6
|
|
4
7
|
Gem::Specification.new do |s|
|
5
8
|
s.name = %q{clogger}
|
6
|
-
s.version = ENV["VERSION"]
|
7
|
-
|
8
|
-
if s.respond_to? :required_rubygems_version=
|
9
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0")
|
10
|
-
end
|
11
|
-
s.homepage = 'http://clogger.rubyforge.org/'
|
9
|
+
s.version = ENV["VERSION"].dup
|
10
|
+
s.homepage = Wrongdoc.config[:rdoc_url]
|
12
11
|
s.authors = ["cloggers"]
|
13
12
|
s.date = Time.now.utc.strftime('%Y-%m-%d')
|
14
|
-
s.description =
|
15
|
-
Clogger is Rack middleware for logging HTTP requests. The log format
|
16
|
-
is customizable so you can specify exactly which fields to log.
|
17
|
-
}.strip
|
13
|
+
s.description = readme_description
|
18
14
|
s.email = %q{clogger@librelist.com}
|
19
|
-
|
20
|
-
s.extra_rdoc_files = File.readlines('.document').map! do |x|
|
21
|
-
x.chomp!
|
22
|
-
if File.directory?(x)
|
23
|
-
manifest.grep(%r{\A#{x}/})
|
24
|
-
elsif File.file?(x)
|
25
|
-
x
|
26
|
-
else
|
27
|
-
nil
|
28
|
-
end
|
29
|
-
end.flatten.compact
|
30
|
-
|
15
|
+
s.extra_rdoc_files = extra_rdoc_files(manifest)
|
31
16
|
s.files = manifest
|
32
|
-
s.rdoc_options =
|
33
|
-
"-t", "Clogger - configurable request logging for Rack"
|
34
|
-
]
|
17
|
+
s.rdoc_options = rdoc_options
|
35
18
|
s.require_paths = %w(lib ext)
|
36
19
|
s.rubyforge_project = %q{clogger}
|
37
|
-
s.summary =
|
20
|
+
s.summary = summary
|
38
21
|
s.test_files = %w(test/test_clogger.rb test/test_clogger_to_path.rb)
|
39
22
|
|
40
23
|
# HeaderHash wasn't case-insensitive in old versions
|
41
24
|
s.add_dependency(%q<rack>, ["> 0.9"])
|
25
|
+
s.add_development_dependency(%q<wrongdoc>, "~> 1.0")
|
42
26
|
s.extensions = %w(ext/clogger_ext/extconf.rb)
|
43
27
|
|
44
28
|
# s.license = "LGPLv2.1+" # disabled for compatibility with older RubyGems
|
data/ext/clogger_ext/clogger.c
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
#define _BSD_SOURCE
|
2
1
|
#include <ruby.h>
|
3
2
|
#ifdef HAVE_RUBY_IO_H
|
4
3
|
# include <ruby/io.h>
|
@@ -10,25 +9,23 @@
|
|
10
9
|
#include <sys/types.h>
|
11
10
|
#include <sys/stat.h>
|
12
11
|
#include <sys/time.h>
|
13
|
-
#include <time.h>
|
14
12
|
#include <errno.h>
|
15
13
|
#ifdef HAVE_FCNTL_H
|
16
14
|
# include <fcntl.h>
|
17
15
|
#endif
|
16
|
+
#define _POSIX_C_SOURCE 200112L
|
17
|
+
#include <time.h>
|
18
18
|
#include "ruby_1_9_compat.h"
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
} \
|
30
|
-
} while (0)
|
31
|
-
#endif
|
20
|
+
static void clock_diff(struct timespec *a, const struct timespec *b)
|
21
|
+
{
|
22
|
+
a->tv_sec -= b->tv_sec;
|
23
|
+
a->tv_nsec -= b->tv_nsec;
|
24
|
+
if (a->tv_nsec < 0) {
|
25
|
+
--a->tv_sec;
|
26
|
+
a->tv_nsec += 1000000000;
|
27
|
+
}
|
28
|
+
}
|
32
29
|
|
33
30
|
/* give GCC hints for better branch prediction
|
34
31
|
* (we layout branches so that ASCII characters are handled faster) */
|
@@ -78,7 +75,7 @@ struct clogger {
|
|
78
75
|
VALUE body;
|
79
76
|
|
80
77
|
off_t body_bytes_sent;
|
81
|
-
struct
|
78
|
+
struct timespec ts_start;
|
82
79
|
|
83
80
|
int fd;
|
84
81
|
int wrap_body;
|
@@ -213,11 +210,6 @@ static VALUE obj_fileno(VALUE obj)
|
|
213
210
|
return rb_funcall(obj, rb_intern("fileno"), 0);
|
214
211
|
}
|
215
212
|
|
216
|
-
static VALUE obj_enable_sync(VALUE obj)
|
217
|
-
{
|
218
|
-
return rb_funcall(obj, rb_intern("sync="), 1, Qtrue);
|
219
|
-
}
|
220
|
-
|
221
213
|
/* only for writing to regular files, not stupid crap like NFS */
|
222
214
|
static void write_full(int fd, const void *buf, size_t count)
|
223
215
|
{
|
@@ -341,34 +333,40 @@ static void append_body_bytes_sent(struct clogger *c)
|
|
341
333
|
rb_str_buf_cat(c->log_buf, buf, nr);
|
342
334
|
}
|
343
335
|
|
344
|
-
static void
|
336
|
+
static void append_ts(struct clogger *c, const VALUE *op, struct timespec *ts)
|
345
337
|
{
|
346
|
-
char buf[sizeof(".000000") + ((sizeof(
|
338
|
+
char buf[sizeof(".000000") + ((sizeof(ts->tv_sec) * 8) / 3)];
|
347
339
|
int nr;
|
348
340
|
char *fmt = RSTRING_PTR(op[1]);
|
349
341
|
int ndiv = NUM2INT(op[2]);
|
342
|
+
int usec = ts->tv_nsec / 1000;
|
350
343
|
|
351
344
|
nr = snprintf(buf, sizeof(buf), fmt,
|
352
|
-
(int)
|
345
|
+
(int)ts->tv_sec, (int)(usec / ndiv));
|
353
346
|
assert(nr > 0 && nr < (int)sizeof(buf));
|
354
347
|
rb_str_buf_cat(c->log_buf, buf, nr);
|
355
348
|
}
|
356
349
|
|
357
350
|
static void append_request_time_fmt(struct clogger *c, const VALUE *op)
|
358
351
|
{
|
359
|
-
struct
|
352
|
+
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)");
|
360
357
|
|
361
|
-
|
362
|
-
|
363
|
-
append_tv(c, op, &d);
|
358
|
+
clock_diff(&now, &c->ts_start);
|
359
|
+
append_ts(c, op, &now);
|
364
360
|
}
|
365
361
|
|
366
362
|
static void append_time_fmt(struct clogger *c, const VALUE *op)
|
367
363
|
{
|
368
|
-
struct
|
364
|
+
struct timespec now;
|
365
|
+
int r = clock_gettime(CLOCK_REALTIME, &now);
|
369
366
|
|
370
|
-
|
371
|
-
|
367
|
+
if (unlikely(r != 0))
|
368
|
+
rb_sys_fail("clock_gettime(CLOCK_REALTIME)");
|
369
|
+
append_ts(c, op, &now);
|
372
370
|
}
|
373
371
|
|
374
372
|
static void append_request_uri(struct clogger *c)
|
@@ -588,12 +586,35 @@ static VALUE cwrite(struct clogger *c)
|
|
588
586
|
return Qnil;
|
589
587
|
}
|
590
588
|
|
589
|
+
static void init_logger(struct clogger *c, VALUE path)
|
590
|
+
{
|
591
|
+
ID id;
|
592
|
+
|
593
|
+
if (!NIL_P(path) && !NIL_P(c->logger))
|
594
|
+
rb_raise(rb_eArgError, ":logger and :path are independent");
|
595
|
+
if (!NIL_P(path)) {
|
596
|
+
VALUE ab = rb_str_new2("ab");
|
597
|
+
id = rb_intern("open");
|
598
|
+
c->logger = rb_funcall(rb_cFile, id, 2, path, ab);
|
599
|
+
}
|
600
|
+
|
601
|
+
id = rb_intern("sync=");
|
602
|
+
if (rb_respond_to(c->logger, id))
|
603
|
+
rb_funcall(c->logger, id, 1, Qtrue);
|
604
|
+
|
605
|
+
id = rb_intern("fileno");
|
606
|
+
if (rb_respond_to(c->logger, id))
|
607
|
+
c->fd = raw_fd(rb_funcall(c->logger, id, 0));
|
608
|
+
}
|
609
|
+
|
591
610
|
/**
|
592
611
|
* call-seq:
|
593
612
|
* Clogger.new(app, :logger => $stderr, :format => string) => obj
|
594
613
|
*
|
595
614
|
* Creates a new Clogger object that wraps +app+. +:logger+ may
|
596
615
|
* be any object that responds to the "<<" method with a string argument.
|
616
|
+
* If +:logger:+ is a string, it will be treated as a path to a
|
617
|
+
* File that will be opened in append mode.
|
597
618
|
*/
|
598
619
|
static VALUE clogger_init(int argc, VALUE *argv, VALUE self)
|
599
620
|
{
|
@@ -609,12 +630,9 @@ static VALUE clogger_init(int argc, VALUE *argv, VALUE self)
|
|
609
630
|
if (TYPE(o) == T_HASH) {
|
610
631
|
VALUE tmp;
|
611
632
|
|
633
|
+
tmp = rb_hash_aref(o, ID2SYM(rb_intern("path")));
|
612
634
|
c->logger = rb_hash_aref(o, ID2SYM(rb_intern("logger")));
|
613
|
-
|
614
|
-
rb_rescue(obj_enable_sync, c->logger, NULL, 0);
|
615
|
-
tmp = rb_rescue(obj_fileno, c->logger, NULL, 0);
|
616
|
-
c->fd = raw_fd(tmp);
|
617
|
-
}
|
635
|
+
init_logger(c, tmp);
|
618
636
|
|
619
637
|
tmp = rb_hash_aref(o, ID2SYM(rb_intern("format")));
|
620
638
|
if (!NIL_P(tmp))
|
@@ -710,7 +728,7 @@ static VALUE ccall(struct clogger *c, VALUE env)
|
|
710
728
|
{
|
711
729
|
VALUE rv;
|
712
730
|
|
713
|
-
|
731
|
+
clock_gettime(CLOCK_MONOTONIC, &c->ts_start);
|
714
732
|
c->env = env;
|
715
733
|
c->cookies = Qfalse;
|
716
734
|
rv = rb_funcall(c->app, call_id, 1, env);
|
@@ -800,9 +818,17 @@ static VALUE clogger_init_copy(VALUE clone, VALUE orig)
|
|
800
818
|
|
801
819
|
#define CONST_GLOBAL_STR(val) CONST_GLOBAL_STR2(val, #val)
|
802
820
|
|
821
|
+
#ifdef RSTRUCT_PTR
|
822
|
+
# define ToPath_clogger(tp) RSTRUCT_PTR(tp)[0]
|
823
|
+
#else
|
824
|
+
static ID clogger_id;
|
825
|
+
# define ToPath_clogger(tp) rb_funcall(tp,clogger_id,0)
|
826
|
+
#endif
|
827
|
+
|
803
828
|
static VALUE to_path(VALUE self)
|
804
829
|
{
|
805
|
-
|
830
|
+
VALUE my_clogger = ToPath_clogger(self);
|
831
|
+
struct clogger *c = clogger_get(my_clogger);
|
806
832
|
VALUE path = rb_funcall(c->body, to_path_id, 0);
|
807
833
|
struct stat sb;
|
808
834
|
int rv;
|
@@ -879,4 +905,7 @@ void Init_clogger_ext(void)
|
|
879
905
|
cHeaderHash = rb_const_get(tmp, rb_intern("HeaderHash"));
|
880
906
|
cToPath = rb_const_get(cClogger, rb_intern("ToPath"));
|
881
907
|
rb_define_method(cToPath, "to_path", to_path, 0);
|
908
|
+
#ifndef RSTRUCT_PTR
|
909
|
+
clogger_id = rb_intern("clogger");
|
910
|
+
#endif
|
882
911
|
}
|
data/ext/clogger_ext/extconf.rb
CHANGED
@@ -13,6 +13,10 @@ begin
|
|
13
13
|
have_macro('O_NONBLOCK', %w(unistd.h fcntl.h))
|
14
14
|
end
|
15
15
|
|
16
|
+
unless have_macro('CLOCK_MONOTONIC', 'time.h', '-D_POSIX_C_SOURCE=200112L')
|
17
|
+
$CPPFLAGS += '-D_POSIX_SOURCE_200112L'
|
18
|
+
have_func('CLOCK_MONOTONIC', 'time.h')
|
19
|
+
end
|
16
20
|
have_func('localtime_r', 'time.h') or raise "localtime_r needed"
|
17
21
|
have_func('gmtime_r', 'time.h') or raise "gmtime_r needed"
|
18
22
|
have_func('rb_str_set_len', 'ruby.h')
|
@@ -11,11 +11,13 @@
|
|
11
11
|
#ifndef RARRAY_LEN
|
12
12
|
# define RARRAY_LEN(s) (RARRAY(s)->len)
|
13
13
|
#endif
|
14
|
-
#ifndef
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
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
|
19
21
|
#endif
|
20
22
|
|
21
23
|
#ifndef HAVE_RB_STR_SET_LEN
|
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.6.0
|
8
|
+
VERSION = '0.6.0'
|
9
9
|
|
10
10
|
# :stopdoc:
|
11
11
|
OP_LITERAL = 0
|
@@ -57,7 +57,7 @@ private
|
|
57
57
|
path_info query_string script_name
|
58
58
|
server_name server_port
|
59
59
|
auth_type gateway_interface server_software path_translated
|
60
|
-
).join('|') << ')\z')
|
60
|
+
).join('|') << ')\z')
|
61
61
|
|
62
62
|
SCAN = /([^$]*)(\$+(?:env\{\w+(?:\.[\w\.]+)?\}|
|
63
63
|
e\{[^\}]+\}|
|
@@ -73,28 +73,28 @@ private
|
|
73
73
|
|
74
74
|
unless tok.nil?
|
75
75
|
if tok.sub!(/\A(\$+)\$/, '$')
|
76
|
-
rv << [ OP_LITERAL, $1
|
76
|
+
rv << [ OP_LITERAL, $1 ]
|
77
77
|
end
|
78
78
|
|
79
79
|
compat = ALIASES[tok] and tok = compat
|
80
80
|
|
81
81
|
case tok
|
82
82
|
when /\A(\$*)\z/
|
83
|
-
rv << [ OP_LITERAL, $1
|
83
|
+
rv << [ OP_LITERAL, $1 ]
|
84
84
|
when /\A\$env\{(\w+(?:\.[\w\.]+))\}\z/
|
85
|
-
rv << [ OP_REQUEST, $1
|
85
|
+
rv << [ OP_REQUEST, $1 ]
|
86
86
|
when /\A\$e\{([^\}]+)\}\z/
|
87
|
-
rv << [ OP_EVAL, $1
|
87
|
+
rv << [ OP_EVAL, $1 ]
|
88
88
|
when /\A\$cookie_(\w+)\z/
|
89
|
-
rv << [ OP_COOKIE, $1
|
89
|
+
rv << [ OP_COOKIE, $1 ]
|
90
90
|
when CGI_ENV, /\A\$(http_\w+)\z/
|
91
|
-
rv << [ OP_REQUEST, $1.upcase
|
91
|
+
rv << [ OP_REQUEST, $1.upcase ]
|
92
92
|
when /\A\$sent_http_(\w+)\z/
|
93
|
-
rv << [ OP_RESPONSE, $1.downcase.tr('_','-')
|
93
|
+
rv << [ OP_RESPONSE, $1.downcase.tr('_','-') ]
|
94
94
|
when /\A\$time_local\{([^\}]+)\}\z/
|
95
|
-
rv << [ OP_TIME_LOCAL, $1
|
95
|
+
rv << [ OP_TIME_LOCAL, $1 ]
|
96
96
|
when /\A\$time_utc\{([^\}]+)\}\z/
|
97
|
-
rv << [ OP_TIME_UTC, $1
|
97
|
+
rv << [ OP_TIME_UTC, $1 ]
|
98
98
|
when /\A\$time\{(\d+)\}\z/
|
99
99
|
rv << [ OP_TIME, *usec_conv_pair(tok, $1.to_i) ]
|
100
100
|
when /\A\$request_time\{(\d+)\}\z/
|
data/lib/clogger/format.rb
CHANGED
@@ -7,19 +7,19 @@ class Clogger
|
|
7
7
|
# common log format used by Apache:
|
8
8
|
# http://httpd.apache.org/docs/2.2/logs.html
|
9
9
|
Common = "$remote_addr - $remote_user [$time_local] " \
|
10
|
-
'"$request" $status $response_length'
|
10
|
+
'"$request" $status $response_length'
|
11
11
|
|
12
12
|
# combined log format used by Apache:
|
13
13
|
# http://httpd.apache.org/docs/2.2/logs.html
|
14
|
-
Combined = %Q|#{Common} "$http_referer" "$http_user_agent"
|
14
|
+
Combined = %Q|#{Common} "$http_referer" "$http_user_agent"|
|
15
15
|
|
16
16
|
# combined log format used by nginx:
|
17
17
|
# http://wiki.nginx.org/NginxHttpLogModule
|
18
|
-
NginxCombined = Combined.gsub(/response_length/, 'body_bytes_sent')
|
18
|
+
NginxCombined = Combined.gsub(/response_length/, 'body_bytes_sent')
|
19
19
|
|
20
20
|
# log format used by Rack 1.0
|
21
21
|
Rack_1_0 = "$ip - $remote_user [$time_local{%d/%b/%Y %H:%M:%S}] " \
|
22
|
-
'"$request" $status $response_length $request_time{4}'
|
22
|
+
'"$request" $status $response_length $request_time{4}'
|
23
23
|
end
|
24
24
|
|
25
25
|
end
|
data/lib/clogger/pure.rb
CHANGED
@@ -14,7 +14,12 @@ class Clogger
|
|
14
14
|
|
15
15
|
@app = app
|
16
16
|
@logger = opts[:logger]
|
17
|
-
|
17
|
+
path = opts[:path]
|
18
|
+
path && @logger and
|
19
|
+
raise ArgumentError, ":logger and :path are independent"
|
20
|
+
path and @logger = File.open(path, "ab")
|
21
|
+
|
22
|
+
@logger.sync = true if @logger.respond_to?(:sync=)
|
18
23
|
@fmt_ops = compile_format(opts[:format] || Format::Common, opts)
|
19
24
|
@wrap_body = need_wrap_body?(@fmt_ops)
|
20
25
|
@reentrant = opts[:reentrant]
|
@@ -69,7 +74,7 @@ class Clogger
|
|
69
74
|
end
|
70
75
|
|
71
76
|
def fileno
|
72
|
-
@logger.fileno
|
77
|
+
@logger.respond_to?(:fileno) ? @logger.fileno : nil
|
73
78
|
end
|
74
79
|
|
75
80
|
private
|
@@ -138,7 +143,7 @@ private
|
|
138
143
|
time_format(t.to_i, (t - t.to_i) * 1000000, op[1], op[2])
|
139
144
|
when OP_TIME
|
140
145
|
t = Time.now
|
141
|
-
time_format(t.
|
146
|
+
time_format(t.to_i, t.usec, op[1], op[2])
|
142
147
|
when OP_COOKIE
|
143
148
|
(env['rack.request.cookie_hash'][op[1]] rescue "-") || "-"
|
144
149
|
else
|
data/test/test_clogger.rb
CHANGED
@@ -3,6 +3,7 @@ $stderr.sync = $stdout.sync = true
|
|
3
3
|
require "test/unit"
|
4
4
|
require "date"
|
5
5
|
require "stringio"
|
6
|
+
require "tempfile"
|
6
7
|
|
7
8
|
require "rack"
|
8
9
|
|
@@ -240,32 +241,52 @@ class TestClogger < Test::Unit::TestCase
|
|
240
241
|
str = StringIO.new
|
241
242
|
app = lambda { |env| [ 200, {}, [] ] }
|
242
243
|
cl = Clogger.new(app, :logger => str, :format => '$msec')
|
244
|
+
a = Time.now.to_f - 0.001
|
243
245
|
status, header, bodies = cl.call(@req)
|
244
246
|
assert_match %r(\A\d+\.\d{3}\n\z), str.string
|
247
|
+
b = Time.now.to_f + 0.001
|
248
|
+
logged = str.string.to_f
|
249
|
+
assert logged >= a, "#{logged} >= #{a}"
|
250
|
+
assert logged <= b, "#{logged} <= #{b}"
|
245
251
|
end
|
246
252
|
|
247
253
|
def test_usec
|
248
254
|
str = StringIO.new
|
249
255
|
app = lambda { |env| [ 200, {}, [] ] }
|
250
256
|
cl = Clogger.new(app, :logger => str, :format => '$usec')
|
257
|
+
a = Time.now.to_f - 0.000001
|
251
258
|
status, header, bodies = cl.call(@req)
|
252
259
|
assert_match %r(\A\d+\.\d{6}\n\z), str.string
|
260
|
+
b = Time.now.to_f + 0.000001
|
261
|
+
logged = str.string.to_f
|
262
|
+
assert logged >= a, "#{logged} >= #{a}"
|
263
|
+
assert logged <= b, "#{logged} <= #{b}"
|
253
264
|
end
|
254
265
|
|
255
266
|
def test_time_0
|
256
267
|
str = StringIO.new
|
257
268
|
app = lambda { |env| [ 200, {}, [] ] }
|
258
269
|
cl = Clogger.new(app, :logger => str, :format => '$time{0}')
|
270
|
+
a = Time.now.to_f - 1
|
259
271
|
status, header, bodies = cl.call(@req)
|
260
272
|
assert_match %r(\A\d+\n\z), str.string
|
273
|
+
b = Time.now.to_f + 1
|
274
|
+
logged = str.string.to_f
|
275
|
+
assert logged >= a, "#{logged} >= #{a}"
|
276
|
+
assert logged <= b, "#{logged} <= #{b}"
|
261
277
|
end
|
262
278
|
|
263
279
|
def test_time_1
|
264
280
|
str = StringIO.new
|
265
281
|
app = lambda { |env| [ 200, {}, [] ] }
|
266
282
|
cl = Clogger.new(app, :logger => str, :format => '$time{1}')
|
283
|
+
a = Time.now.to_f - 0.5
|
267
284
|
status, header, bodies = cl.call(@req)
|
268
285
|
assert_match %r(\A\d+\.\d\n\z), str.string
|
286
|
+
b = Time.now.to_f + 0.5
|
287
|
+
logged = str.string.to_f
|
288
|
+
assert logged >= a, "#{logged} >= #{a}"
|
289
|
+
assert logged <= b, "#{logged} <= #{b}"
|
269
290
|
end
|
270
291
|
|
271
292
|
def test_request_length
|
@@ -629,4 +650,31 @@ class TestClogger < Test::Unit::TestCase
|
|
629
650
|
end
|
630
651
|
end if RUBY_PLATFORM =~ /linux/ && File.readable?(LINUX_PROC_PID_STATUS)
|
631
652
|
|
653
|
+
def test_path_open_file
|
654
|
+
tmp = Tempfile.new('test_clogger')
|
655
|
+
app = lambda { |env| [ 200, {}, [] ] }
|
656
|
+
app = Clogger.new(app, :format => '$status', :path => tmp.path)
|
657
|
+
assert_kind_of Integer, app.fileno
|
658
|
+
assert app.fileno != tmp.fileno
|
659
|
+
status, headers, body = app.call(@req)
|
660
|
+
assert_equal "200\n", tmp.read
|
661
|
+
end
|
662
|
+
|
663
|
+
def test_path_logger_conflict
|
664
|
+
tmp = Tempfile.new('test_clogger')
|
665
|
+
app = lambda { |env| [ 200, {}, [] ] }
|
666
|
+
assert_raises(ArgumentError) {
|
667
|
+
Clogger.new(app, :logger=> $stderr, :path => tmp.path)
|
668
|
+
}
|
669
|
+
end
|
670
|
+
|
671
|
+
def test_request_time
|
672
|
+
s = []
|
673
|
+
app = lambda { |env| sleep(0.1) ; [302, [], [] ] }
|
674
|
+
cl = Clogger.new(app, :logger => s, :format => "$request_time")
|
675
|
+
status, headers, body = cl.call(@req)
|
676
|
+
assert_nothing_raised { body.each { |x| } ; body.close }
|
677
|
+
assert s[-1].to_f >= 0.100
|
678
|
+
assert s[-1].to_f <= 0.110
|
679
|
+
end
|
632
680
|
end
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clogger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 7
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 6
|
9
|
+
- 0
|
10
|
+
version: 0.6.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- cloggers
|
@@ -9,22 +15,40 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date: 2010-
|
18
|
+
date: 2010-12-25 00:00:00 +00:00
|
13
19
|
default_executable:
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
22
|
name: rack
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
20
26
|
requirements:
|
21
27
|
- - ">"
|
22
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 25
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 9
|
23
33
|
version: "0.9"
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: wrongdoc
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 15
|
45
|
+
segments:
|
46
|
+
- 1
|
47
|
+
- 0
|
48
|
+
version: "1.0"
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
51
|
+
description: == DESCRIPTION
|
28
52
|
email: clogger@librelist.com
|
29
53
|
executables: []
|
30
54
|
|
@@ -39,15 +63,18 @@ extra_rdoc_files:
|
|
39
63
|
- lib/clogger/pure.rb
|
40
64
|
- ext/clogger_ext/clogger.c
|
41
65
|
- LICENSE
|
66
|
+
- LATEST
|
42
67
|
files:
|
43
68
|
- .document
|
44
69
|
- .gitignore
|
45
70
|
- .manifest
|
71
|
+
- .wrongdoc.yml
|
46
72
|
- COPYING
|
47
73
|
- ChangeLog
|
48
74
|
- GIT-VERSION-FILE
|
49
75
|
- GIT-VERSION-GEN
|
50
76
|
- GNUmakefile
|
77
|
+
- LATEST
|
51
78
|
- LICENSE
|
52
79
|
- NEWS
|
53
80
|
- README
|
@@ -68,28 +95,35 @@ licenses: []
|
|
68
95
|
|
69
96
|
post_install_message:
|
70
97
|
rdoc_options:
|
71
|
-
- -Na
|
72
98
|
- -t
|
73
|
-
- Clogger - configurable request logging for Rack
|
99
|
+
- \Clogger - configurable request logging for Rack
|
100
|
+
- -W
|
101
|
+
- http://git.bogomips.org/cgit/clogger.git/tree/%s
|
74
102
|
require_paths:
|
75
103
|
- lib
|
76
104
|
- ext
|
77
105
|
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
78
107
|
requirements:
|
79
108
|
- - ">="
|
80
109
|
- !ruby/object:Gem::Version
|
110
|
+
hash: 3
|
111
|
+
segments:
|
112
|
+
- 0
|
81
113
|
version: "0"
|
82
|
-
version:
|
83
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
84
116
|
requirements:
|
85
117
|
- - ">="
|
86
118
|
- !ruby/object:Gem::Version
|
119
|
+
hash: 3
|
120
|
+
segments:
|
121
|
+
- 0
|
87
122
|
version: "0"
|
88
|
-
version:
|
89
123
|
requirements: []
|
90
124
|
|
91
125
|
rubyforge_project: clogger
|
92
|
-
rubygems_version: 1.3.
|
126
|
+
rubygems_version: 1.3.7
|
93
127
|
signing_key:
|
94
128
|
specification_version: 3
|
95
129
|
summary: configurable request logging for Rack
|