chiark / gitweb /
logs-show: limit to 3 lines and use dots if not showing full message
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 11 Aug 2013 14:56:09 +0000 (10:56 -0400)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 11 Aug 2013 22:10:34 +0000 (18:10 -0400)
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.

A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below).  The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.

Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).

Aug 11 10:46:21 fedora python[67]: test message
                                   line
                                   line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...

TODO
src/shared/logs-show.c
src/shared/util.c

diff --git a/TODO b/TODO
index 438b644..d72a65d 100644 (file)
--- a/TODO
+++ b/TODO
@@ -19,6 +19,10 @@ Bugfixes:
 
 * properly handle .mount unit state tracking when two mount points are stacked one on top of another on the exact same mount point.
 
+* ellipsize_mem must take into account multi-byte unicode characters, and
+  - make the resulting line the requested number of *characters*, not *bytes*,
+  - avoid truncuating multi-byte sequences in the middle.
+
 Fedora 20:
 
 * external: ps should gain colums for slice and machine
index 2270c3b..af738a3 100644 (file)
 #include "hashmap.h"
 #include "journal-internal.h"
 
-#define PRINT_THRESHOLD 128
+/* up to three lines (each up to 100 characters),
+   or 300 characters, whichever is less */
+#define PRINT_LINE_THRESHOLD 3
+#define PRINT_CHAR_THRESHOLD 300
+
 #define JSON_THRESHOLD 4096
 
 static int print_catalog(FILE *f, sd_journal *j) {
@@ -92,7 +96,7 @@ static bool shall_print(const char *p, size_t l, OutputFlags flags) {
         if (flags & OUTPUT_SHOW_ALL)
                 return true;
 
-        if (l >= PRINT_THRESHOLD)
+        if (l >= PRINT_CHAR_THRESHOLD)
                 return false;
 
         if (!utf8_is_printable(p, l))
@@ -104,8 +108,8 @@ static bool shall_print(const char *p, size_t l, OutputFlags flags) {
 static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputMode flags, int priority, const char* message, size_t message_len) {
         const char *color_on = "", *color_off = "";
         const char *pos, *end;
-        bool continuation = false;
         bool ellipsized = false;
+        int line = 0;
 
         if (flags & OUTPUT_COLOR) {
                 if (priority <= LOG_ERR) {
@@ -117,37 +121,61 @@ static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, Output
                 }
         }
 
-        for (pos = message; pos < message + message_len; pos = end + 1) {
+        for (pos = message;
+             pos < message + message_len;
+             pos = end + 1, line++) {
+                bool continuation = line > 0;
+                bool tail_line;
                 int len;
                 for (end = pos; end < message + message_len && *end != '\n'; end++)
                         ;
                 len = end - pos;
                 assert(len >= 0);
 
-                if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) || prefix + len + 1 < n_columns)
+                /* We need to figure out when we are showing the 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;
+
+                if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
+                    (prefix + len + 1 < n_columns && !tail_line)) {
                         fprintf(f, "%*s%s%.*s%s\n",
                                 continuation * prefix, "",
                                 color_on, len, pos, color_off);
-                else if (prefix < n_columns && n_columns - prefix >= 3) {
-                        _cleanup_free_ char *e;
+                        continue;
+                }
 
-                        ellipsized = true;
-                        e = ellipsize_mem(pos, len, n_columns - prefix, 90);
+                /* Beyond this point, ellipsization will happen. */
+                ellipsized = true;
 
-                        if (!e)
-                                fprintf(f, "%*s%s%.*s%s\n",
+                if (prefix < n_columns && n_columns - prefix >= 3) {
+                        if (n_columns - prefix > (unsigned) len + 3)
+                                fprintf(f, "%*s%s%.*s...%s\n",
                                         continuation * prefix, "",
                                         color_on, len, pos, color_off);
-                        else
-                                fprintf(f, "%*s%s%s%s\n",
-                                        continuation * prefix, "",
-                                        color_on, e, color_off);
-                } else {
-                        ellipsized = true;
+                        else {
+                                _cleanup_free_ char *e;
+
+                                e = ellipsize_mem(pos, len, n_columns - prefix,
+                                                  tail_line ? 100 : 90);
+                                if (!e)
+                                        fprintf(f, "%*s%s%.*s%s\n",
+                                                continuation * prefix, "",
+                                                color_on, len, pos, color_off);
+                                else
+                                        fprintf(f, "%*s%s%s%s\n",
+                                                continuation * prefix, "",
+                                                color_on, e, color_off);
+                        }
+                } else
                         fputs("...\n", f);
-                }
 
-                continuation = true;
+                if (tail_line)
+                        break;
         }
 
         return ellipsized;
@@ -172,7 +200,13 @@ static int output_short(
         assert(f);
         assert(j);
 
-        sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_THRESHOLD);
+        /* Set the threshold to one bigger than the actual print
+         * treshold, 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.
+         */
+        sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
 
         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
 
@@ -389,7 +423,8 @@ static int output_verbose(
                 }
 
                 if (flags & OUTPUT_SHOW_ALL ||
-                    (((length < PRINT_THRESHOLD) || flags & OUTPUT_FULL_WIDTH) && utf8_is_printable(data, length))) {
+                    (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
+                     && utf8_is_printable(data, length))) {
                         fprintf(f, "    %s%.*s=", on, fieldlen, (const char*)data);
                         print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
                         fputs(off, f);
index c8ed53c..f23dd92 100644 (file)
@@ -3332,7 +3332,7 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
 
         r = new0(char, new_length+1);
         if (!r)
-                return r;
+                return NULL;
 
         x = (new_length * percent) / 100;