chiark / gitweb /
journal: expose and make use of cutoff times of journal
authorLennart Poettering <lennart@poettering.net>
Sat, 9 Jun 2012 08:32:38 +0000 (10:32 +0200)
committerLennart Poettering <lennart@poettering.net>
Sat, 16 Jun 2012 22:03:12 +0000 (00:03 +0200)
This helps explaining when the log output of "systemctl status" is
incomplete because the logs got rotated since the service was started.

src/journal/journal-def.h
src/journal/journal-file.c
src/journal/journal-file.h
src/journal/journalctl.c
src/journal/libsystemd-journal.sym
src/journal/sd-journal.c
src/shared/logs-show.c
src/shared/logs-show.h
src/systemctl/systemctl.c
src/systemd/sd-journal.h

index 86aef8f372a8fd538cfd74e40a845b55fe6cf62f..b30ae796836d6586222f4143d1d7660254ac0d9c 100644 (file)
@@ -160,8 +160,8 @@ _packed_ struct Header {
         uint8_t state;
         uint8_t reserved[7];
         sd_id128_t file_id;
         uint8_t state;
         uint8_t reserved[7];
         sd_id128_t file_id;
-        sd_id128_t machine_id;
-        sd_id128_t boot_id;
+        sd_id128_t machine_id; /* last writer */
+        sd_id128_t boot_id;    /* last writer */
         sd_id128_t seqnum_id;
         le64_t header_size;
         le64_t arena_size;
         sd_id128_t seqnum_id;
         le64_t header_size;
         le64_t arena_size;
index 9cec140f58032a158bffa76cb3468efd15a73e33..73420d9c1b17530cd7aecb07d04702026d3addb7 100644 (file)
@@ -183,6 +183,7 @@ static int journal_file_verify_header(JournalFile *f) {
 
                 if (state == STATE_ONLINE)
                         log_debug("Journal file %s is already online. Assuming unclean closing. Ignoring.", f->path);
 
                 if (state == STATE_ONLINE)
                         log_debug("Journal file %s is already online. Assuming unclean closing. Ignoring.", f->path);
+                        /* FIXME: immediately rotate */
                 else if (state == STATE_ARCHIVED)
                         return -ESHUTDOWN;
                 else if (state != STATE_OFFLINE)
                 else if (state == STATE_ARCHIVED)
                         return -ESHUTDOWN;
                 else if (state != STATE_OFFLINE)
@@ -2284,3 +2285,74 @@ void journal_default_metrics(JournalMetrics *m, int fd) {
                  format_bytes(c, sizeof(c), m->min_size),
                  format_bytes(d, sizeof(d), m->keep_free));
 }
                  format_bytes(c, sizeof(c), m->min_size),
                  format_bytes(d, sizeof(d), m->keep_free));
 }
+
+int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to) {
+        Object *o;
+        int r;
+
+        assert(f);
+        assert(from || to);
+
+        if (from) {
+                r = journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, &o, NULL);
+                if (r <= 0)
+                        return r;
+
+                *from = le64toh(o->entry.realtime);
+        }
+
+        if (to) {
+                r = journal_file_next_entry(f, NULL, 0, DIRECTION_UP, &o, NULL);
+                if (r <= 0)
+                        return r;
+
+                *to = le64toh(o->entry.realtime);
+        }
+
+        return 1;
+}
+
+int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot_id, usec_t *from, usec_t *to) {
+        char t[9+32+1] = "_BOOT_ID=";
+        Object *o;
+        uint64_t p;
+        int r;
+
+        assert(f);
+        assert(from || to);
+
+        sd_id128_to_string(boot_id, t + 9);
+
+        r = journal_file_find_data_object(f, t, strlen(t), &o, &p);
+        if (r <= 0)
+                return r;
+
+        if (le64toh(o->data.n_entries) <= 0)
+                return 0;
+
+        if (from) {
+                r = journal_file_move_to_object(f, OBJECT_ENTRY, le64toh(o->data.entry_offset), &o);
+                if (r < 0)
+                        return r;
+
+                *from = le64toh(o->entry.monotonic);
+        }
+
+        if (to) {
+                r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
+                if (r < 0)
+                        return r;
+
+                r = generic_array_get_plus_one(f,
+                                               le64toh(o->data.entry_offset),
+                                               le64toh(o->data.entry_array_offset),
+                                               le64toh(o->data.n_entries)-1,
+                                               &o, NULL);
+                if (r <= 0)
+                        return r;
+
+                *to = le64toh(o->entry.monotonic);
+        }
+
+        return 1;
+}
index aeb6d46c79c12b4d49fe69fd4d05da50bf25233a..a9925c07540ba4e119d2bf5eb712c813075f5947 100644 (file)
@@ -125,4 +125,7 @@ void journal_file_post_change(JournalFile *f);
 
 void journal_default_metrics(JournalMetrics *m, int fd);
 
 
 void journal_default_metrics(JournalMetrics *m, int fd);
 
+int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to);
+int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to);
+
 #endif
 #endif
index 9d4403267eb8aa22b6b7c113783accad468bf6fc..e9d918a733a78fdc381ff3b1f2a20f93d89d1750 100644 (file)
@@ -281,6 +281,26 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
                 goto finish;
         }
 
+        if (!arg_quiet) {
+                usec_t start, end;
+                char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
+
+                r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
+                if (r < 0) {
+                        log_error("Failed to get cutoff: %s", strerror(-r));
+                        goto finish;
+                }
+
+                if (r > 0) {
+                        if (arg_follow)
+                                printf("Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start));
+                        else
+                                printf("Logs begin at %s, end at %s.\n",
+                                       format_timestamp(start_buf, sizeof(start_buf), start),
+                                       format_timestamp(end_buf, sizeof(end_buf), end));
+                }
+        }
+
         if (arg_lines >= 0) {
                 r = sd_journal_seek_tail(j);
                 if (r < 0) {
         if (arg_lines >= 0) {
                 r = sd_journal_seek_tail(j);
                 if (r < 0) {
index 74bd298fdcba95288e40ac531ef9019f14982177..d291084262318c1bffc9c0ccf2429d1172e254dd 100644 (file)
@@ -51,3 +51,9 @@ global:
         sd_journal_send_with_location;
         sd_journal_sendv_with_location;
 } LIBSYSTEMD_JOURNAL_38;
         sd_journal_send_with_location;
         sd_journal_sendv_with_location;
 } LIBSYSTEMD_JOURNAL_38;
+
+LIBSYSTEMD_JOURNAL_184 {
+global:
+        sd_journal_get_cutoff_realtime_usec;
+        sd_journal_get_cutoff_monotonic_usec;
+} LIBSYSTEMD_JOURNAL_183;
index 9f46f5c6aa4d85e3fa3f02ec2e7cc6a0b28455cb..5ed8c3f7a5a6ae4b4f2d95fcb31fdae206b5a40b 100644 (file)
@@ -1620,6 +1620,81 @@ _public_ int sd_journal_process(sd_journal *j) {
         }
 }
 
         }
 }
 
+_public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
+        Iterator i;
+        JournalFile *f;
+        bool first = true;
+        int r;
+
+        if (!j)
+                return -EINVAL;
+        if (!from && !to)
+                return -EINVAL;
+
+        HASHMAP_FOREACH(f, j->files, i) {
+                usec_t fr, t;
+
+                r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        continue;
+
+                if (first) {
+                        if (from)
+                                *from = fr;
+                        if (to)
+                                *to = t;
+                        first = false;
+                } else {
+                        if (from)
+                                *from = MIN(fr, *from);
+                        if (to)
+                                *to = MIN(t, *to);
+                }
+        }
+
+        return first ? 0 : 1;
+}
+
+_public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
+        Iterator i;
+        JournalFile *f;
+        bool first = true;
+        int r;
+
+        if (!j)
+                return -EINVAL;
+        if (!from && !to)
+                return -EINVAL;
+
+        HASHMAP_FOREACH(f, j->files, i) {
+                usec_t fr, t;
+
+                r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        continue;
+
+                if (first) {
+                        if (from)
+                                *from = fr;
+                        if (to)
+                                *to = t;
+                        first = false;
+                } else {
+                        if (from)
+                                *from = MIN(fr, *from);
+                        if (to)
+                                *to = MIN(t, *to);
+                }
+        }
+
+        return first ? 0 : 1;
+}
+
+
 /* _public_ int sd_journal_query_unique(sd_journal *j, const char *field) { */
 /*         if (!j) */
 /*                 return -EINVAL; */
 /* _public_ int sd_journal_query_unique(sd_journal *j, const char *field) { */
 /*         if (!j) */
 /*                 return -EINVAL; */
index 4c59ca34cd55d8b132682b52ba8fe9024e130007..697b5cf4b734c58e848114e0b2ca45beec2670e5 100644 (file)
@@ -551,7 +551,8 @@ int show_journal_by_unit(
                 usec_t not_before,
                 unsigned how_many,
                 bool show_all,
                 usec_t not_before,
                 unsigned how_many,
                 bool show_all,
-                bool follow) {
+                bool follow,
+                bool warn_cutoff) {
 
         char *m = NULL;
         sd_journal *j = NULL;
 
         char *m = NULL;
         sd_journal *j = NULL;
@@ -639,6 +640,26 @@ int show_journal_by_unit(
                                 goto finish;
                 }
 
                                 goto finish;
                 }
 
+                if (warn_cutoff && line < how_many && not_before > 0) {
+                        sd_id128_t boot_id;
+                        usec_t cutoff;
+
+                        /* Check whether the cutoff line is too early */
+
+                        r = sd_id128_get_boot(&boot_id);
+                        if (r < 0)
+                                goto finish;
+
+                        r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
+                        if (r < 0)
+                                goto finish;
+
+                        if (not_before < cutoff)
+                                printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
+
+                        warn_cutoff = false;
+                }
+
                 if (!follow)
                         break;
 
                 if (!follow)
                         break;
 
index 94caed55790faee178ade1e3ebda23e0b5b9aef8..f8a9d406bde3b65dc5df080454c8d5360557913e 100644 (file)
@@ -48,7 +48,8 @@ int show_journal_by_unit(
                 usec_t not_before,
                 unsigned how_many,
                 bool show_all,
                 usec_t not_before,
                 unsigned how_many,
                 bool show_all,
-                bool follow);
+                bool follow,
+                bool warn_cutoff);
 
 const char* output_mode_to_string(OutputMode m);
 OutputMode output_mode_from_string(const char *s);
 
 const char* output_mode_to_string(OutputMode m);
 OutputMode output_mode_from_string(const char *s);
index 133a27c67e35adb2503ce0aee5d4b2bf46f23459..ad0cd17e14b8e1a871d5aa13ff4063faab609236 100644 (file)
@@ -2554,7 +2554,7 @@ static void print_status_info(UnitStatusInfo *i) {
 
         if (i->id && arg_transport != TRANSPORT_SSH) {
                 printf("\n");
 
         if (i->id && arg_transport != TRANSPORT_SSH) {
                 printf("\n");
-                show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow);
+                show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow, !arg_quiet);
         }
 
         if (i->need_daemon_reload)
         }
 
         if (i->need_daemon_reload)
index 72c23ba522840966d6ef1fd041ff35964da35190..85f86049911c985f51420c90e23e754c79eaaec1 100644 (file)
@@ -97,6 +97,9 @@ int sd_journal_seek_cursor(sd_journal *j, const char *cursor);
 
 int sd_journal_get_cursor(sd_journal *j, char **cursor);
 
 
 int sd_journal_get_cursor(sd_journal *j, char **cursor);
 
+int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to);
+int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, const sd_id128_t boot_id, uint64_t *from, uint64_t *to);
+
 /* int sd_journal_query_unique(sd_journal *j, const char *field);      /\* missing *\/ */
 /* int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l); /\* missing *\/ */
 /* void sd_journal_restart_unique(sd_journal *j);                      /\* missing *\/ */
 /* int sd_journal_query_unique(sd_journal *j, const char *field);      /\* missing *\/ */
 /* int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l); /\* missing *\/ */
 /* void sd_journal_restart_unique(sd_journal *j);                      /\* missing *\/ */