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 CHANGED
@@ -4,3 +4,4 @@ ChangeLog
4
4
  lib
5
5
  ext/clogger_ext/clogger.c
6
6
  LICENSE
7
+ LATEST
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ Makefile
15
15
  /ChangeLog
16
16
  /NEWS
17
17
  /GIT-VERSION-FILE
18
+ /LATEST
data/.wrongdoc.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ rdoc_url: http://clogger.rubyforge.org/
3
+ cgit_url: http://git.bogomips.org/cgit/clogger.git
4
+ git_url: git://git.bogomips.org/clogger.git
5
+ changelog_since: 0.4.0
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.5.0.GIT
4
+ DEF_VER=v0.6.0.GIT
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  all:: test
2
2
  RUBY = ruby
3
3
  RAKE = rake
4
- GIT_URL = git://git.bogomips.org/clogger.git
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): export RUBYLIB := ext/clogger_ext:lib
29
+ $(test_unit): mylib := ext/clogger_ext:lib
30
30
  $(test_unit): ext/clogger_ext/clogger.$(DLEXT)
31
31
  else
32
- $(test_unit): export RUBYLIB := lib
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=0 $(MAKE) test-unit
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
- NEWS: GIT-VERSION-FILE .manifest
59
- $(RAKE) -s news_rdoc > $@+
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
- news_atom := http://clogger.rubyforge.org/NEWS.atom.xml
71
- cgit_atom := http://git.bogomips.org/cgit/clogger.git/atom/?h=master
72
- atom = <link rel="alternate" title="Atom feed" href="$(1)" \
73
- type="application/atom+xml"/>
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) doc/
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
- rsync -av doc/ rubyforge.org:/var/www/gforge-projects/clogger/
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
- $(RAKE) -s release_changes > $@+
90
+ wrongdoc release_changes > $@+
110
91
  $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
111
92
  $(release_notes):
112
- GIT_URL=$(GIT_URL) $(RAKE) -s release_notes > $@+
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 c `cat .manifest` | (cd $(distdir) && tar x)
144
- cd pkg && tar c $(basename $(@F)) | gzip -9 > $(@F)+
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
- :logger => ::File.open("/path/to/log", "ab"),
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
- :logger => ::File.open("/path/to/log", "ab"),
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 = ENV['GIT_URL'] || 'git://git.bogomips.org/clogger.git'
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 = %q{
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 = [ "-Na",
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 = %q{configurable request logging for Rack}
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
@@ -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
- /* in case _BSD_SOURCE doesn't give us this macro */
21
- #ifndef timersub
22
- # define timersub(a, b, result) \
23
- do { \
24
- (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
25
- (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
26
- if ((result)->tv_usec < 0) { \
27
- --(result)->tv_sec; \
28
- (result)->tv_usec += 1000000; \
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 timeval tv_start;
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 append_tv(struct clogger *c, const VALUE *op, struct timeval *tv)
336
+ static void append_ts(struct clogger *c, const VALUE *op, struct timespec *ts)
345
337
  {
346
- char buf[sizeof(".000000") + ((sizeof(tv->tv_sec) * 8) / 3)];
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)tv->tv_sec, (int)(tv->tv_usec / ndiv));
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 timeval now, d;
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
- gettimeofday(&now, NULL);
362
- timersub(&now, &c->tv_start, &d);
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 timeval now;
364
+ struct timespec now;
365
+ int r = clock_gettime(CLOCK_REALTIME, &now);
369
366
 
370
- gettimeofday(&now, NULL);
371
- append_tv(c, op, &now);
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
- if (!NIL_P(c->logger)) {
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
- gettimeofday(&c->tv_start, NULL);
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
- struct clogger *c = clogger_get(RSTRUCT_PTR(self)[0]);
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
  }
@@ -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 RSTRUCT_PTR
15
- # define RSTRUCT_PTR(s) (RSTRUCT(s)->ptr)
16
- #endif
17
- #ifndef RSTRUCT_LEN
18
- # define RSTRUCT_LEN(s) (RSTRUCT(s)->len)
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.5.0
8
- VERSION = '0.5.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').freeze
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.dup ]
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.dup ]
83
+ rv << [ OP_LITERAL, $1 ]
84
84
  when /\A\$env\{(\w+(?:\.[\w\.]+))\}\z/
85
- rv << [ OP_REQUEST, $1.freeze ]
85
+ rv << [ OP_REQUEST, $1 ]
86
86
  when /\A\$e\{([^\}]+)\}\z/
87
- rv << [ OP_EVAL, $1.dup ]
87
+ rv << [ OP_EVAL, $1 ]
88
88
  when /\A\$cookie_(\w+)\z/
89
- rv << [ OP_COOKIE, $1.dup.freeze ]
89
+ rv << [ OP_COOKIE, $1 ]
90
90
  when CGI_ENV, /\A\$(http_\w+)\z/
91
- rv << [ OP_REQUEST, $1.upcase.freeze ]
91
+ rv << [ OP_REQUEST, $1.upcase ]
92
92
  when /\A\$sent_http_(\w+)\z/
93
- rv << [ OP_RESPONSE, $1.downcase.tr('_','-').freeze ]
93
+ rv << [ OP_RESPONSE, $1.downcase.tr('_','-') ]
94
94
  when /\A\$time_local\{([^\}]+)\}\z/
95
- rv << [ OP_TIME_LOCAL, $1.dup ]
95
+ rv << [ OP_TIME_LOCAL, $1 ]
96
96
  when /\A\$time_utc\{([^\}]+)\}\z/
97
- rv << [ OP_TIME_UTC, $1.dup ]
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/
@@ -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'.freeze
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"|.freeze
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').freeze
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}'.freeze
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
- (@logger.sync = true) rescue nil
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 rescue nil
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.sec, t.usec, op[1], op[2])
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
- version: 0.5.0
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-06-06 00:00:00 +00:00
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
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
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
- 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.
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.5
126
+ rubygems_version: 1.3.7
93
127
  signing_key:
94
128
  specification_version: 3
95
129
  summary: configurable request logging for Rack