From: Zbigniew Jędrzejewski-Szmek Date: Wed, 24 Apr 2013 02:40:26 +0000 (-0400) Subject: logs-show: print multiline messages X-Git-Tag: v205~157 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=31f7bf1994523f5b8fd014c69b97e09d7043d9ff logs-show: print multiline messages [ 0.019862] fedora kernel: CPU0: Thermal monitoring enabled (TM1) [ 0.019900] fedora kernel: Last level iTLB entries: 4KB 512, 2MB 0, 4MB 0 Last level dTLB entries: 4KB 512, 2MB 32, 4MB 32 tlb_flushall_shift: 5 [ 0.020118] fedora kernel: Freeing SMP alternatives: 24k freed --- diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 79a977c15..b88547eb8 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -95,12 +95,54 @@ static bool shall_print(const char *p, size_t l, OutputFlags flags) { if (l >= PRINT_THRESHOLD) return false; - if (!utf8_is_printable_n(p, l)) + if (!utf8_is_printable(p, l)) return false; return true; } +static void print_multiline(FILE *f, unsigned prefix, unsigned n_columns, int flags, int priority, const char* message, size_t message_len) { + const char *color_on = "", *color_off = ""; + const char *pos, *end; + bool continuation = false; + + if (flags & OUTPUT_COLOR) { + if (priority <= LOG_ERR) { + color_on = ANSI_HIGHLIGHT_RED_ON; + color_off = ANSI_HIGHLIGHT_OFF; + } else if (priority <= LOG_NOTICE) { + color_on = ANSI_HIGHLIGHT_ON; + color_off = ANSI_HIGHLIGHT_OFF; + } + } + + for (pos = message; pos < message + message_len; pos = end + 1) { + int len; + for (end = pos; end < message + message_len && *end != '\n'; end++) + ; + len = end - pos; + assert(len >= 0); + + if ((flags & OUTPUT_FULL_WIDTH) || (prefix + len + 1 < n_columns)) + 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; + + e = ellipsize_mem(pos, len, n_columns - prefix, 90); + + if (!e) + fprintf(f, "%s%.*s%s\n", color_on, len, pos, color_off); + else + fprintf(f, "%s%s%s\n", color_on, e, color_off); + } else + fputs("...\n", f); + + continuation = true; + } +} + static int output_short( FILE *f, sd_journal *j, @@ -115,7 +157,6 @@ static int output_short( _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = 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, priority_len = 0; int p = LOG_INFO; - const char *color_on = "", *color_off = ""; assert(f); assert(j); @@ -260,34 +301,13 @@ static int output_short( n += fake_pid_len + 2; } - if (flags & OUTPUT_COLOR) { - if (p <= LOG_ERR) { - color_on = ANSI_HIGHLIGHT_RED_ON; - color_off = ANSI_HIGHLIGHT_OFF; - } else if (p <= LOG_NOTICE) { - color_on = ANSI_HIGHLIGHT_ON; - color_off = ANSI_HIGHLIGHT_OFF; - } - } - - if (flags & OUTPUT_SHOW_ALL) - fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off); - else if (!utf8_is_printable_n(message, message_len)) { + if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) { char bytes[FORMAT_BYTES_MAX]; fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len)); - } else if ((flags & OUTPUT_FULL_WIDTH) || (message_len + n + 1 < n_columns)) - fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off); - else if (n < n_columns && n_columns - n - 2 >= 3) { - _cleanup_free_ char *e; - - e = ellipsize_mem(message, message_len, n_columns - n - 2, 90); - - if (!e) - fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off); - else - fprintf(f, ": %s%s%s\n", color_on, e, color_off); - } else - fputs("\n", f); + } else { + fputs(": ", f); + print_multiline(f, n + 2, n_columns, flags, p, message, message_len); + } if (flags & OUTPUT_CATALOG) print_catalog(f, j); @@ -331,22 +351,26 @@ static int output_verbose( cursor); SD_JOURNAL_FOREACH_DATA(j, data, length) { - if (!shall_print(data, length, flags)) { - const char *c; - char bytes[FORMAT_BYTES_MAX]; + const char *c; + int fieldlen; + c = memchr(data, '=', length); + if (!c) { + log_error("Invalid field."); + return -EINVAL; + } + fieldlen = c - (const char*) data; - c = memchr(data, '=', length); - if (!c) { - log_error("Invalid field."); - return -EINVAL; - } + if ((flags & OUTPUT_SHOW_ALL) || (length < PRINT_THRESHOLD && utf8_is_printable(data, length))) { + fprintf(f, " %.*s=", fieldlen, (const char*)data); + print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1); + } else { + char bytes[FORMAT_BYTES_MAX]; - fprintf(f, "\t%.*s=[%s blob data]\n", - (int) (c - (const char*) data), - (const char*) data, - format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1)); - } else - fprintf(f, "\t%.*s\n", (int) length, (const char*) data); + fprintf(f, " %.*s=[%s blob data]\n", + (int) (c - (const char*) data), + (const char*) data, + format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1)); + } } if (flags & OUTPUT_CATALOG) @@ -410,7 +434,7 @@ static int output_export( memcmp(data, "_BOOT_ID=", 9) == 0) continue; - if (!utf8_is_printable_n(data, length)) { + if (!utf8_is_printable(data, length)) { const char *c; uint64_t le64; @@ -449,7 +473,7 @@ void json_escape( fputs("null", f); - else if (!utf8_is_printable_n(p, l)) { + else if (!utf8_is_printable(p, l)) { bool not_first = false; fputs("[ ", f); @@ -474,7 +498,9 @@ void json_escape( if (*p == '"' || *p == '\\') { fputc('\\', f); fputc(*p, f); - } else if (*p < ' ') + } else if (*p == '\n') + fputs("\\n", f); + else if (*p < ' ') fprintf(f, "\\u%04x", *p); else fputc(*p, f); diff --git a/src/shared/utf8.c b/src/shared/utf8.c index 3964e8b1c..655cc771d 100644 --- a/src/shared/utf8.c +++ b/src/shared/utf8.c @@ -86,11 +86,11 @@ static bool is_unicode_control(uint32_t ch) { '\t' is in C0 range, but more or less harmless and commonly used. */ - return (ch < ' ' && ch != '\t') || + return (ch < ' ' && ch != '\t' && ch != '\n') || (0x7F <= ch && ch <= 0x9F); } -char* utf8_is_printable_n(const char* str, size_t length) { +bool utf8_is_printable(const char* str, size_t length) { uint32_t val = 0; uint32_t min = 0; const uint8_t *p; @@ -113,40 +113,37 @@ char* utf8_is_printable_n(const char* str, size_t length) { min = (1 << 16); val = (uint32_t) (*p & 0x07); } else - goto error; + return false; p++; length--; if (!length || !is_continuation_char(*p)) - goto error; + return false; merge_continuation_char(&val, *p); TWO_REMAINING: p++; length--; if (!is_continuation_char(*p)) - goto error; + return false; merge_continuation_char(&val, *p); ONE_REMAINING: p++; length--; if (!is_continuation_char(*p)) - goto error; + return false; merge_continuation_char(&val, *p); if (val < min) - goto error; + return false; } if (is_unicode_control(val)) - goto error; + return false; } - return (char*) str; - -error: - return NULL; + return true; } static char* utf8_validate(const char *str, char *output) { diff --git a/src/shared/utf8.h b/src/shared/utf8.h index 794ae15ab..f805ea6b5 100644 --- a/src/shared/utf8.h +++ b/src/shared/utf8.h @@ -21,12 +21,14 @@ along with systemd; If not, see . ***/ +#include + #include "macro.h" char *utf8_is_valid(const char *s) _pure_; char *ascii_is_valid(const char *s) _pure_; -char *utf8_is_printable_n(const char* str, size_t length) _pure_; +bool utf8_is_printable(const char* str, size_t length) _pure_; char *utf8_filter(const char *s); char *ascii_filter(const char *s);