about summary refs log tree commit homepage
path: root/ext/clogger_ext/clogger.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/clogger_ext/clogger.c')
-rw-r--r--ext/clogger_ext/clogger.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/ext/clogger_ext/clogger.c b/ext/clogger_ext/clogger.c
index fdc23e3..a1f3bc4 100644
--- a/ext/clogger_ext/clogger.c
+++ b/ext/clogger_ext/clogger.c
@@ -374,12 +374,40 @@ static void append_ts(struct clogger *c, VALUE op, struct timespec *ts)
         rb_str_buf_cat(c->log_buf, buf, nr);
 }
 
+#define NANO_PER_SEC (1000 * 1000 * 1000)
 static void append_request_time_fmt(struct clogger *c, VALUE op)
 {
         struct timespec now;
+        unsigned long ipow = NUM2ULONG(rb_ary_entry(op, 3));
 
         clock_gettime(hopefully_CLOCK_MONOTONIC, &now);
         clock_diff(&now, &c->ts_start);
+        if (ipow) {
+                struct timespec prev;
+                unsigned long adj = 1;
+                /*
+                  * n.b. timespec.tv_sec may not be time_t on some platforms,
+                  * so we use a full timespec struct instead of time_t:
+                  */
+                prev.tv_sec = now.tv_sec;
+                do { adj *= 10; } while (--ipow);
+                now.tv_sec *= adj;
+                now.tv_nsec *= adj;
+                if (now.tv_nsec >= NANO_PER_SEC) {
+                        int64_t add = now.tv_nsec / NANO_PER_SEC;
+                        now.tv_sec += add;
+                        now.tv_nsec %= NANO_PER_SEC;
+                }
+                if (now.tv_sec < prev.tv_sec) { /* overflowed */
+                        now.tv_nsec = NANO_PER_SEC - 1;
+                        /*
+                          * some platforms may use unsigned .tv_sec, but
+                          * they're not worth supporting, so keep unsigned:
+                          */
+                        now.tv_sec = (time_t)(sizeof(now.tv_sec) == 4 ?
+                                     INT_MAX : LONG_MAX);
+                }
+        }
         append_ts(c, op, &now);
 }