about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--ext/clogger_ext/clogger.c50
-rw-r--r--lib/clogger.rb4
-rw-r--r--lib/clogger/pure.rb12
-rw-r--r--test/test_clogger.rb45
4 files changed, 99 insertions, 12 deletions
diff --git a/ext/clogger_ext/clogger.c b/ext/clogger_ext/clogger.c
index 416ab30..eb1605b 100644
--- a/ext/clogger_ext/clogger.c
+++ b/ext/clogger_ext/clogger.c
@@ -92,6 +92,8 @@ enum clogger_special {
         CL_SP_pid,
         CL_SP_request_uri,
         CL_SP_time_iso8601,
+        CL_SP_time_local,
+        CL_SP_time_utc
 };
 
 struct clogger {
@@ -445,7 +447,7 @@ static void append_request_length(struct clogger *c)
         }
 }
 
-static long gmtoffset(struct tm *tm)
+static long local_gmtoffset(struct tm *tm)
 {
         time_t t = time(NULL);
 
@@ -463,7 +465,7 @@ static void append_time_iso8601(struct clogger *c)
         char buf[sizeof("1970-01-01T00:00:00+00:00")];
         struct tm tm;
         int nr;
-        long gmtoff = gmtoffset(&tm);
+        long gmtoff = local_gmtoffset(&tm);
 
         nr = snprintf(buf, sizeof(buf),
                       "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
@@ -476,6 +478,44 @@ static void append_time_iso8601(struct clogger *c)
         rb_str_buf_cat(c->log_buf, buf, sizeof(buf) - 1);
 }
 
+static const char months[] = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0"
+                             "Jul\0Aug\0Sep\0Oct\0Nov\0Dec";
+
+static void append_time_local(struct clogger *c)
+{
+        char buf[sizeof("01/Jan/1970:00:00:00 +0000")];
+        struct tm tm;
+        int nr;
+        long gmtoff = local_gmtoffset(&tm);
+
+        nr = snprintf(buf, sizeof(buf),
+                      "%02d/%s/%d:%02d:%02d:%02d %c%02d%02d",
+                      tm.tm_mday, months + (tm.tm_mon * sizeof("Jan")),
+                      tm.tm_year + 1900, tm.tm_hour,
+                      tm.tm_min, tm.tm_sec,
+                      gmtoff < 0 ? '-' : '+',
+                      abs(gmtoff / 60), abs(gmtoff % 60));
+        assert(nr == (sizeof(buf) - 1) && "snprintf fail");
+        rb_str_buf_cat(c->log_buf, buf, sizeof(buf) - 1);
+}
+
+static void append_time_utc(struct clogger *c)
+{
+        char buf[sizeof("01/Jan/1970:00:00:00 +0000")];
+        struct tm tm;
+        int nr;
+        time_t t = time(NULL);
+
+        gmtime_r(&t, &tm);
+        nr = snprintf(buf, sizeof(buf),
+                      "%02d/%s/%d:%02d:%02d:%02d +0000",
+                      tm.tm_mday, months + (tm.tm_mon * sizeof("Jan")),
+                      tm.tm_year + 1900, tm.tm_hour,
+                      tm.tm_min, tm.tm_sec);
+        assert(nr == (sizeof(buf) - 1) && "snprintf fail");
+        rb_str_buf_cat(c->log_buf, buf, sizeof(buf) - 1);
+}
+
 static void
 append_time(struct clogger *c, enum clogger_opcode op, VALUE fmt, VALUE buf)
 {
@@ -583,6 +623,12 @@ static void special_var(struct clogger *c, enum clogger_special var)
                 break;
         case CL_SP_time_iso8601:
                 append_time_iso8601(c);
+                break;
+        case CL_SP_time_local:
+                append_time_local(c);
+                break;
+        case CL_SP_time_utc:
+                append_time_utc(c);
         }
 }
 
diff --git a/lib/clogger.rb b/lib/clogger.rb
index e368115..be1bdce 100644
--- a/lib/clogger.rb
+++ b/lib/clogger.rb
@@ -19,8 +19,6 @@ class Clogger
   # support nginx variables that are less customizable than our own
   ALIASES = {
     '$request_time' => '$request_time{3}',
-    '$time_local' => '$time_local{%d/%b/%Y:%H:%M:%S %z}',
-    '$time_utc' => '$time_utc{%d/%b/%Y:%H:%M:%S %z}',
     '$msec' => '$time{3}',
     '$usec' => '$time{6}',
     '$http_content_length' => '$content_length',
@@ -37,6 +35,8 @@ class Clogger
     :pid => 6, # getpid()
     :request_uri => 7,
     :time_iso8601 => 8,
+    :time_local => 9,
+    :time_utc => 10,
   }
 
 private
diff --git a/lib/clogger/pure.rb b/lib/clogger/pure.rb
index a56b982..63907ae 100644
--- a/lib/clogger/pure.rb
+++ b/lib/clogger/pure.rb
@@ -137,6 +137,18 @@ private
       $$.to_s
     when :time_iso8601
       Time.now.iso8601
+    when :time_local
+      t = Time.now
+      off = t.utc_offset
+      sign = off < 0 ? '-' : '+'
+      sprintf("%02d/%s/%d:%02d:%02d:%02d #{sign}%02d%02d",
+              t.mday, Time::RFC2822_MONTH_NAME[t.mon - 1],
+              t.year, t.hour, t.min, t.sec, *(off.abs / 60).divmod(60))
+    when :time_utc
+      t = Time.now.utc
+      sprintf("%02d/%s/%d:%02d:%02d:%02d +0000",
+              t.mday, Time::RFC2822_MONTH_NAME[t.mon - 1],
+              t.year, t.hour, t.min, t.sec)
     else
       raise "EDOOFUS #{special_nr}"
     end
diff --git a/test/test_clogger.rb b/test/test_clogger.rb
index 1a555ba..9440d74 100644
--- a/test/test_clogger.rb
+++ b/test/test_clogger.rb
@@ -18,6 +18,8 @@ class TestClogger < Test::Unit::TestCase
   include Clogger::Format
 
   def setup
+    @tz = ENV["TZ"]
+    @nginx_fmt = "%d/%b/%Y:%H:%M:%S %z"
     @req = {
       "REQUEST_METHOD" => "GET",
       "HTTP_VERSION" => "HTTP/1.0",
@@ -30,6 +32,10 @@ class TestClogger < Test::Unit::TestCase
     }
   end
 
+  def teardown
+    ENV["TZ"] = @tz
+  end
+
   def test_init_basic
     Clogger.new(lambda { |env| [ 0, {}, [] ] })
   end
@@ -162,13 +168,12 @@ class TestClogger < Test::Unit::TestCase
         '$env{rack.url_scheme}' \
         "\n")
     }
-    longest_day = Time.at(26265600).strftime('%d/%b/%Y:%H:%M:%S %z')
     expect = [
       [ Clogger::OP_REQUEST, "REMOTE_ADDR" ],
       [ Clogger::OP_LITERAL, " - " ],
       [ Clogger::OP_REQUEST, "REMOTE_USER" ],
       [ Clogger::OP_LITERAL, " [" ],
-      [ Clogger::OP_TIME_LOCAL, '%d/%b/%Y:%H:%M:%S %z', longest_day ],
+      [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:time_local] ],
       [ Clogger::OP_LITERAL, "] \"" ],
       [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:request] ],
       [ Clogger::OP_LITERAL, "\" "],
@@ -714,7 +719,6 @@ class TestClogger < Test::Unit::TestCase
   end
 
   def test_time_iso8601_pst8pdt
-    orig = ENV["TZ"]
     ENV["TZ"] = "PST8PDT"
     s = []
     app = lambda { |env| [200, [], [] ] }
@@ -722,12 +726,9 @@ class TestClogger < Test::Unit::TestCase
     status, headers, body = cl.call(@req)
     t = Time.parse(s[0])
     assert_equal t.iso8601, s[0].strip
-    ensure
-      ENV["TZ"] = orig
   end
 
   def test_time_iso8601_utc
-    orig = ENV["TZ"]
     ENV["TZ"] = "UTC"
     s = []
     app = lambda { |env| [200, [], [] ] }
@@ -735,8 +736,36 @@ class TestClogger < Test::Unit::TestCase
     status, headers, body = cl.call(@req)
     t = Time.parse(s[0])
     assert_equal t.iso8601, s[0].strip
-    ensure
-      ENV["TZ"] = orig
+  end
+
+  def test_time_local
+    s = []
+    app = lambda { |env| [200, [], [] ] }
+    cl = Clogger.new(app, :logger => s, :format => "$time_local")
+    status, headers, body = cl.call(@req)
+    t = DateTime.strptime(s[0].strip, @nginx_fmt)
+    assert_equal t.strftime(@nginx_fmt), s[0].strip
+  end
+
+  def test_time_local_pst8pdt
+    orig = ENV["TZ"]
+    ENV["TZ"] = "PST8PDT"
+    s = []
+    app = lambda { |env| [200, [], [] ] }
+    cl = Clogger.new(app, :logger => s, :format => "$time_local")
+    status, headers, body = cl.call(@req)
+    t = DateTime.strptime(s[0].strip, @nginx_fmt)
+    assert_equal t.strftime(@nginx_fmt), s[0].strip
+  end
+
+  def test_time_local_utc
+    ENV["TZ"] = "UTC"
+    s = []
+    app = lambda { |env| [200, [], [] ] }
+    cl = Clogger.new(app, :logger => s, :format => "$time_local")
+    status, headers, body = cl.call(@req)
+    t = DateTime.strptime(s[0].strip, @nginx_fmt)
+    assert_equal t.strftime(@nginx_fmt), s[0].strip
   end
 
   def test_method_missing