chiark / gitweb /
journalctl: always show monotonic timestamp even if it's from an old boot
[elogind.git] / src / logs-show.c
index d067ab818e32f4b1808378e451b73356b4c6ec62..cb18da2aa5ae21ee61cf29cb491fa928706e7c31 100644 (file)
@@ -58,12 +58,15 @@ static int parse_field(const void *data, size_t length, const char *field, char
                 return 0;
 
         nl = length - fl;
-        buf = memdup((const char*) data + fl, nl);
+        buf = malloc(nl+1);
+        memcpy(buf, (const char*) data + fl, nl);
+        ((char*)buf)[nl] = 0;
         if (!buf) {
                 log_error("Out of memory");
                 return -ENOMEM;
         }
 
+        free(*target);
         *target = buf;
         *target_size = nl;
 
@@ -83,17 +86,13 @@ static bool shall_print(bool show_all, char *p, size_t l) {
         return true;
 }
 
-static int output_short(sd_journal *j, unsigned line, bool show_all) {
+static int output_short(sd_journal *j, unsigned line, bool show_all, bool monotonic_mode) {
         int r;
-        uint64_t realtime;
-        time_t t;
-        struct tm tm;
-        char buf[64];
         const void *data;
         size_t length;
         size_t n = 0;
-        char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *message = NULL;
-        size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, message_len = 0;
+        char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL;
+        size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0, realtime_len = 0, monotonic_len = 0;
 
         assert(j);
 
@@ -123,6 +122,24 @@ static int output_short(sd_journal *j, unsigned line, bool show_all) {
                 else if (r > 0)
                         continue;
 
+                r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
+                if (r < 0)
+                        goto finish;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
+                if (r < 0)
+                        goto finish;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
+                if (r < 0)
+                        goto finish;
+                else if (r > 0)
+                        continue;
+
                 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
                 if (r < 0)
                         goto finish;
@@ -133,20 +150,56 @@ static int output_short(sd_journal *j, unsigned line, bool show_all) {
                 goto finish;
         }
 
-        r = sd_journal_get_realtime_usec(j, &realtime);
-        if (r < 0) {
-                log_error("Failed to get realtime: %s", strerror(-r));
-                goto finish;
-        }
+        if (monotonic_mode) {
+                uint64_t t;
+                sd_id128_t boot_id;
 
-        t = (time_t) (realtime / USEC_PER_SEC);
-        if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
-                log_error("Failed to format time.");
-                goto finish;
-        }
+                r = -ENOENT;
+
+                if (monotonic)
+                        r = safe_atou64(monotonic, &t);
 
-        fputs(buf, stdout);
-        n += strlen(buf);
+                if (r < 0)
+                        r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
+
+                if (r < 0) {
+                        log_error("Failed to get monotonic: %s", strerror(-r));
+                        goto finish;
+                }
+
+                printf("[%5llu.%06llu]",
+                       (unsigned long long) (t / USEC_PER_SEC),
+                       (unsigned long long) (t % USEC_PER_SEC));
+
+                n += 1 + 5 + 1 + 6 + 1;
+
+        } else {
+                char buf[64];
+                uint64_t x;
+                time_t t;
+                struct tm tm;
+                r = -ENOENT;
+
+                if (realtime)
+                        r = safe_atou64(realtime, &x);
+
+                if (r < 0)
+                        r = sd_journal_get_realtime_usec(j, &x);
+
+                if (r < 0) {
+                        log_error("Failed to get realtime: %s", strerror(-r));
+                        goto finish;
+                }
+
+                t = (time_t) (x / USEC_PER_SEC);
+                if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
+                        log_error("Failed to format time.");
+                        goto finish;
+                }
+
+                fputs(buf, stdout);
+                n += strlen(buf);
+        }
 
         if (hostname && shall_print(show_all, hostname, hostname_len)) {
                 printf(" %.*s", (int) hostname_len, hostname);
@@ -164,6 +217,9 @@ static int output_short(sd_journal *j, unsigned line, bool show_all) {
         if (pid && shall_print(show_all, pid, pid_len)) {
                 printf("[%.*s]", (int) pid_len, pid);
                 n += pid_len + 2;
+        } else if (fake_pid && shall_print(show_all, fake_pid, fake_pid_len)) {
+                printf("[%.*s]", (int) fake_pid_len, fake_pid);
+                n += fake_pid_len + 2;
         }
 
         if (show_all)
@@ -193,11 +249,22 @@ finish:
         free(identifier);
         free(comm);
         free(pid);
+        free(fake_pid);
         free(message);
+        free(monotonic);
+        free(realtime);
 
         return r;
 }
 
+static int output_short_realtime(sd_journal *j, unsigned line, bool show_all) {
+        return output_short(j, line, show_all, false);
+}
+
+static int output_short_monotonic(sd_journal *j, unsigned line, bool show_all) {
+        return output_short(j, line, show_all, true);
+}
+
 static int output_verbose(sd_journal *j, unsigned line, bool show_all) {
         const void *data;
         size_t length;
@@ -421,7 +488,8 @@ static int output_json(sd_journal *j, unsigned line, bool show_all) {
 }
 
 static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, bool show_all) = {
-        [OUTPUT_SHORT] = output_short,
+        [OUTPUT_SHORT] = output_short_realtime,
+        [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic,
         [OUTPUT_VERBOSE] = output_verbose,
         [OUTPUT_EXPORT] = output_export,
         [OUTPUT_JSON] = output_json
@@ -564,6 +632,7 @@ finish:
 
 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
         [OUTPUT_SHORT] = "short",
+        [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
         [OUTPUT_VERBOSE] = "verbose",
         [OUTPUT_EXPORT] = "export",
         [OUTPUT_JSON] = "json"