chiark / gitweb /
logs-show.c: show all messages for a slice
[elogind.git] / src / shared / logs-show.c
index af738a313e01613802fca058ee761b1386c12c46..7bb19b4006bce9524e066ddf840123ad1b4be1b5 100644 (file)
@@ -105,7 +105,7 @@ static bool shall_print(const char *p, size_t l, OutputFlags flags) {
         return true;
 }
 
-static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputMode flags, int priority, const char* message, size_t message_len) {
+static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) {
         const char *color_on = "", *color_off = "";
         const char *pos, *end;
         bool ellipsized = false;
@@ -132,14 +132,14 @@ static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, Output
                 len = end - pos;
                 assert(len >= 0);
 
-                /* We need to figure out when we are showing the last line, and
+                /* We need to figure out when we are showing not-last line, *and*
                  * will skip subsequent lines. In that case, we will put the dots
                  * at the end of the line, instead of putting dots in the middle
                  * or not at all.
                  */
                 tail_line =
                         line + 1 == PRINT_LINE_THRESHOLD ||
-                        end + 1 >= message + message_len;
+                        end + 1 >= message + PRINT_CHAR_THRESHOLD;
 
                 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
                     (prefix + len + 1 < n_columns && !tail_line)) {
@@ -201,7 +201,7 @@ static int output_short(
         assert(j);
 
         /* Set the threshold to one bigger than the actual print
-         * treshold, so that if the line is actually longer than what
+         * threshold, so that if the line is actually longer than what
          * we're willing to print, ellipsization will occur. This way
          * we won't output a misleading line without any indication of
          * truncation.
@@ -318,10 +318,21 @@ static int output_short(
                 }
 
                 t = (time_t) (x / USEC_PER_SEC);
-                if (mode == OUTPUT_SHORT_ISO)
+
+                switch(mode) {
+                case OUTPUT_SHORT_ISO:
                         r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&t, &tm));
-                else
+                        break;
+                case OUTPUT_SHORT_PRECISE:
+                        r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm));
+                        if (r > 0) {
+                                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                                         ".%06llu", x % USEC_PER_SEC);
+                        }
+                        break;
+                default:
                         r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm));
+                }
 
                 if (r <= 0) {
                         log_error("Failed to format time.");
@@ -380,7 +391,7 @@ static int output_verbose(
         size_t length;
         _cleanup_free_ char *cursor = NULL;
         uint64_t realtime;
-        char ts[FORMAT_TIMESTAMP_MAX];
+        char ts[FORMAT_TIMESTAMP_MAX + 7];
         int r;
 
         assert(f);
@@ -388,11 +399,35 @@ static int output_verbose(
 
         sd_journal_set_data_threshold(j, 0);
 
-        r = sd_journal_get_realtime_usec(j, &realtime);
-        if (r < 0) {
+        r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
+        if (r == -ENOENT)
+                log_debug("Source realtime timestamp not found");
+        else if (r < 0) {
                 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
-                         "Failed to get realtime timestamp: %s", strerror(-r));
+                         "Failed to get source realtime timestamp: %s", strerror(-r));
                 return r;
+        } else {
+                _cleanup_free_ char *value = NULL;
+                size_t size;
+
+                r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
+                if (r < 0)
+                        log_debug("_SOURCE_REALTIME_TIMESTAMP invalid: %s", strerror(-r));
+                else {
+                        r = safe_atou64(value, &realtime);
+                        if (r < 0)
+                                log_debug("Failed to parse realtime timestamp: %s",
+                                          strerror(-r));
+                }
+        }
+
+        if (r < 0) {
+                r = sd_journal_get_realtime_usec(j, &realtime);
+                if (r < 0) {
+                        log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
+                                 "Failed to get realtime timestamp: %s", strerror(-r));
+                        return r;
+                }
         }
 
         r = sd_journal_get_cursor(j, &cursor);
@@ -402,7 +437,7 @@ static int output_verbose(
         }
 
         fprintf(f, "%s [%s]\n",
-                format_timestamp(ts, sizeof(ts), realtime),
+                format_timestamp_us(ts, sizeof(ts), realtime),
                 cursor);
 
         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
@@ -501,7 +536,7 @@ static int output_export(
                 /* We already printed the boot id, from the data in
                  * the header, hence let's suppress it here */
                 if (length >= 9 &&
-                    hasprefix(data, "_BOOT_ID="))
+                    startswith(data, "_BOOT_ID="))
                         continue;
 
                 if (!utf8_is_printable(data, length)) {
@@ -849,8 +884,9 @@ static int (*output_funcs[_OUTPUT_MODE_MAX])(
                 OutputFlags flags) = {
 
         [OUTPUT_SHORT] = output_short,
-        [OUTPUT_SHORT_MONOTONIC] = output_short,
         [OUTPUT_SHORT_ISO] = output_short,
+        [OUTPUT_SHORT_PRECISE] = output_short,
+        [OUTPUT_SHORT_MONOTONIC] = output_short,
         [OUTPUT_VERBOSE] = output_verbose,
         [OUTPUT_EXPORT] = output_export,
         [OUTPUT_JSON] = output_json,
@@ -1012,6 +1048,16 @@ int add_matches_for_unit(sd_journal *j, const char *unit) {
             (r = sd_journal_add_match(j, m4, 0))
         );
 
+        if (r == 0 && endswith(unit, ".slice")) {
+                char *m5 = strappend("_SYSTEMD_SLICE=", unit);
+
+                /* Show all messages belonging to a slice */
+                (void)(
+                        (r = sd_journal_add_disjunction(j)) ||
+                        (r = sd_journal_add_match(j, m5, 0))
+                        );
+        }
+
         return r;
 }
 
@@ -1051,6 +1097,18 @@ int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
                 (r = sd_journal_add_match(j, muid, 0)) ||
                 (r = sd_journal_add_match(j, "_UID=0", 0))
         );
+
+        if (r == 0 && endswith(unit, ".slice")) {
+                char *m5 = strappend("_SYSTEMD_SLICE=", unit);
+
+                /* Show all messages belonging to a slice */
+                (void)(
+                        (r = sd_journal_add_disjunction(j)) ||
+                        (r = sd_journal_add_match(j, m5, 0)) ||
+                        (r = sd_journal_add_match(j, muid, 0))
+                        );
+        }
+
         return r;
 }
 
@@ -1131,8 +1189,9 @@ int show_journal_by_unit(
 
 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
         [OUTPUT_SHORT] = "short",
-        [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
         [OUTPUT_SHORT_ISO] = "short-iso",
+        [OUTPUT_SHORT_PRECISE] = "short-precise",
+        [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
         [OUTPUT_VERBOSE] = "verbose",
         [OUTPUT_EXPORT] = "export",
         [OUTPUT_JSON] = "json",