From: Zbigniew Jędrzejewski-Szmek Date: Sun, 11 Aug 2013 14:56:09 +0000 (-0400) Subject: logs-show: limit to 3 lines and use dots if not showing full message X-Git-Tag: v207~155 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=a6f0104a16350a4c2660837da6e0e5c2e50e2389 logs-show: limit to 3 lines and use dots if not showing full message 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ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�... --- diff --git a/TODO b/TODO index 438b64403..d72a65dcf 100644 --- 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 diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 2270c3b03..af738a313 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -32,7 +32,11 @@ #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); diff --git a/src/shared/util.c b/src/shared/util.c index c8ed53c8b..f23dd92a6 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -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;