X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Flogs-show.c;h=d60e5e53081c3cdacf828dc6562ef8837f2a9390;hb=b5b46d599524341ddd7407e5dff1021af8ff5089;hp=540b5a2a2cb3770416afea05745df470996c3846;hpb=e02d1cf72d115d1d61defdca5b551672d876c6bd;p=elogind.git diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 540b5a2a2..d60e5e530 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -28,19 +28,10 @@ #include "logs-show.h" #include "log.h" #include "util.h" +#include "utf8.h" #define PRINT_THRESHOLD 128 -static bool contains_unprintable(const void *p, size_t l) { - const char *j; - - for (j = p; j < (const char *) p + l; j++) - if (*j < ' ' || *j >= 127) - return true; - - return false; -} - static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) { size_t fl, nl; void *buf; @@ -59,12 +50,11 @@ static int parse_field(const void *data, size_t length, const char *field, char nl = length - fl; buf = malloc(nl+1); + if (!buf) + return log_oom(); + memcpy(buf, (const char*) data + fl, nl); ((char*)buf)[nl] = 0; - if (!buf) { - log_error("Out of memory"); - return -ENOMEM; - } free(*target); *target = buf; @@ -80,24 +70,33 @@ static bool shall_print(bool show_all, char *p, size_t l) { if (l > PRINT_THRESHOLD) return false; - if (contains_unprintable(p, l)) + if (!utf8_is_printable_n(p, l)) return false; return true; } -static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool show_all, bool monotonic_mode) { +static int output_short(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, + OutputFlags flags) { int r; const void *data; size_t length; size_t n = 0; - char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = 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; + 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(j); SD_JOURNAL_FOREACH_DATA(j, data, length) { + r = parse_field(data, length, "PRIORITY=", &priority, &priority_len); + if (r < 0) + goto finish; + else if (r > 0) + continue; + r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len); if (r < 0) goto finish; @@ -150,7 +149,10 @@ static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool s goto finish; } - if (monotonic_mode) { + if (priority_len == 1 && *priority >= '0' && *priority <= '7') + p = *priority - '0'; + + if (mode == OUTPUT_SHORT_MONOTONIC) { uint64_t t; sd_id128_t boot_id; @@ -202,44 +204,59 @@ static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool s n += strlen(buf); } - if (hostname && shall_print(show_all, hostname, hostname_len)) { + if (hostname && shall_print(flags & OUTPUT_SHOW_ALL, + hostname, hostname_len)) { printf(" %.*s", (int) hostname_len, hostname); n += hostname_len + 1; } - if (identifier && shall_print(show_all, identifier, identifier_len)) { + if (identifier && shall_print(flags & OUTPUT_SHOW_ALL, + identifier, identifier_len)) { printf(" %.*s", (int) identifier_len, identifier); n += identifier_len + 1; - } else if (comm && shall_print(show_all, comm, comm_len)) { + } else if (comm && shall_print(flags & OUTPUT_SHOW_ALL, + comm, comm_len)) { printf(" %.*s", (int) comm_len, comm); n += comm_len + 1; } else putchar(' '); - if (pid && shall_print(show_all, pid, pid_len)) { + if (pid && shall_print(flags & OUTPUT_SHOW_ALL, pid, pid_len)) { printf("[%.*s]", (int) pid_len, pid); n += pid_len + 2; - } else if (fake_pid && shall_print(show_all, fake_pid, fake_pid_len)) { + } else if (fake_pid && shall_print(flags & OUTPUT_SHOW_ALL, + fake_pid, fake_pid_len)) { printf("[%.*s]", (int) fake_pid_len, fake_pid); n += fake_pid_len + 2; } - if (show_all) - printf(": %.*s\n", (int) message_len, message); - else if (contains_unprintable(message, message_len)) { + 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) + printf(": %s%.*s%s\n", color_on, (int) message_len, message, color_off); + else if (!utf8_is_printable_n(message, message_len)) { char bytes[FORMAT_BYTES_MAX]; printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len)); - } else if (message_len + n < n_columns) - printf(": %.*s\n", (int) message_len, message); - else if (n < n_columns) { + } else if ((flags & OUTPUT_FULL_WIDTH) || + (message_len + n + 1 < n_columns)) + printf(": %s%.*s%s\n", color_on, (int) message_len, message, color_off); + else if (n < n_columns && n_columns - n - 2 >= 3) { char *e; e = ellipsize_mem(message, message_len, n_columns - n - 2, 90); if (!e) - printf(": %.*s\n", (int) message_len, message); + printf(": %s%.*s%s\n", color_on, (int) message_len, message, color_off); else - printf(": %s\n", e); + printf(": %s%s%s\n", color_on, e, color_off); free(e); } else @@ -256,19 +273,13 @@ finish: free(message); free(monotonic); free(realtime); + free(priority); return r; } -static int output_short_realtime(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { - return output_short(j, line, n_columns, show_all, false); -} - -static int output_short_monotonic(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { - return output_short(j, line, n_columns, show_all, true); -} - -static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { +static int output_verbose(sd_journal *j, OutputMode mode, unsigned line, + unsigned n_columns, OutputFlags flags) { const void *data; size_t length; char *cursor; @@ -297,8 +308,8 @@ static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool free(cursor); SD_JOURNAL_FOREACH_DATA(j, data, length) { - if (!show_all && (length > PRINT_THRESHOLD || - contains_unprintable(data, length))) { + if (!(flags & OUTPUT_SHOW_ALL) && (length > PRINT_THRESHOLD || + !utf8_is_printable_n(data, length))) { const char *c; char bytes[FORMAT_BYTES_MAX]; @@ -319,7 +330,8 @@ static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool return 0; } -static int output_export(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { +static int output_export(sd_journal *j, OutputMode mode, unsigned line, + unsigned n_columns, OutputFlags flags) { sd_id128_t boot_id; char sid[33]; int r; @@ -367,7 +379,7 @@ static int output_export(sd_journal *j, unsigned line, unsigned n_columns, bool memcmp(data, "_BOOT_ID=", 9) == 0) continue; - if (contains_unprintable(data, length)) { + if (!utf8_is_printable_n(data, length)) { const char *c; uint64_t le64; @@ -394,8 +406,7 @@ static int output_export(sd_journal *j, unsigned line, unsigned n_columns, bool } static void json_escape(const char* p, size_t l) { - - if (contains_unprintable(p, l)) { + if (!utf8_is_printable_n(p, l)) { bool not_first = false; fputs("[ ", stdout); @@ -431,7 +442,8 @@ static void json_escape(const char* p, size_t l) { } } -static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { +static int output_json(sd_journal *j, OutputMode mode, unsigned line, + unsigned n_columns, OutputFlags flags) { uint64_t realtime, monotonic; char *cursor; const void *data; @@ -460,21 +472,25 @@ static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool sh return r; } - if (line == 1) - fputc('\n', stdout); + if (mode == OUTPUT_JSON_PRETTY) + printf("{\n" + "\t\"__CURSOR\" : \"%s\",\n" + "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n" + "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n" + "\t\"_BOOT_ID\" : \"%s\"", + cursor, + (unsigned long long) realtime, + (unsigned long long) monotonic, + sd_id128_to_string(boot_id, sid)); else - fputs(",\n", stdout); - - printf("{\n" - "\t\"__CURSOR\" : \"%s\",\n" - "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n" - "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n" - "\t\"_BOOT_ID\" : \"%s\"", - cursor, - (unsigned long long) realtime, - (unsigned long long) monotonic, - sd_id128_to_string(boot_id, sid)); - + printf("{ \"__CURSOR\" : \"%s\", " + "\"__REALTIME_TIMESTAMP\" : \"%llu\", " + "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", " + "\"_BOOT_ID\" : \"%s\"", + cursor, + (unsigned long long) realtime, + (unsigned long long) monotonic, + sd_id128_to_string(boot_id, sid)); free(cursor); SD_JOURNAL_FOREACH_DATA(j, data, length) { @@ -492,19 +508,26 @@ static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool sh return -EINVAL; } - fputs(",\n\t", stdout); + if (mode == OUTPUT_JSON_PRETTY) + fputs(",\n\t", stdout); + else + fputs(", ", stdout); + json_escape(data, c - (const char*) data); fputs(" : ", stdout); json_escape(c + 1, length - (c - (const char*) data) - 1); } - fputs("\n}", stdout); - fflush(stdout); + if (mode == OUTPUT_JSON_PRETTY) + fputs("\n}\n", stdout); + else + fputs(" }\n", stdout); return 0; } -static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { +static int output_cat(sd_journal *j, OutputMode mode, unsigned line, + unsigned n_columns, OutputFlags flags) { const void *data; size_t l; int r; @@ -525,23 +548,29 @@ static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool sho return 0; } -static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, unsigned n_columns, bool show_all) = { - [OUTPUT_SHORT] = output_short_realtime, - [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic, +static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, OutputMode mode, unsigned line, + unsigned n_columns, OutputFlags flags) = { + [OUTPUT_SHORT] = output_short, + [OUTPUT_SHORT_MONOTONIC] = output_short, [OUTPUT_VERBOSE] = output_verbose, [OUTPUT_EXPORT] = output_export, [OUTPUT_JSON] = output_json, + [OUTPUT_JSON_PRETTY] = output_json, [OUTPUT_CAT] = output_cat }; -int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all) { +int output_journal(sd_journal *j, OutputMode mode, unsigned line, + unsigned n_columns, OutputFlags flags) { + int ret; assert(mode >= 0); assert(mode < _OUTPUT_MODE_MAX); if (n_columns <= 0) n_columns = columns(); - return output_funcs[mode](j, line, n_columns, show_all); + ret = output_funcs[mode](j, mode, line, n_columns, flags); + fflush(stdout); + return ret; } int show_journal_by_unit( @@ -550,15 +579,14 @@ int show_journal_by_unit( unsigned n_columns, usec_t not_before, unsigned how_many, - bool show_all, - bool follow, - bool warn_cutoff) { + OutputFlags flags) { - char *m = NULL; + char *m1 = NULL, *m2 = NULL, *m3 = NULL; sd_journal *j = NULL; int r; unsigned line = 0; bool need_seek = false; + int warn_cutoff = flags & OUTPUT_WARN_CUTOFF; assert(mode >= 0); assert(mode < _OUTPUT_MODE_MAX); @@ -573,7 +601,9 @@ int show_journal_by_unit( if (how_many <= 0) return 0; - if (asprintf(&m, "_SYSTEMD_UNIT=%s", unit) < 0) { + if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 || + asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 || + asprintf(&m3, "UNIT=%s", unit) < 0) { r = -ENOMEM; goto finish; } @@ -582,10 +612,34 @@ int show_journal_by_unit( if (r < 0) goto finish; - r = sd_journal_add_match(j, m, strlen(m)); + /* Look for messages from the service itself */ + r = sd_journal_add_match(j, m1, 0); + if (r < 0) + goto finish; + + /* Look for coredumps of the service */ + r = sd_journal_add_disjunction(j); + if (r < 0) + goto finish; + r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0); + if (r < 0) + goto finish; + r = sd_journal_add_match(j, m2, 0); + if (r < 0) + goto finish; + + /* Look for messages from PID 1 about this service */ + r = sd_journal_add_disjunction(j); + if (r < 0) + goto finish; + r = sd_journal_add_match(j, "_PID=1", 0); + if (r < 0) + goto finish; + r = sd_journal_add_match(j, m3, 0); if (r < 0) goto finish; + /* Seek to end */ r = sd_journal_seek_tail(j); if (r < 0) goto finish; @@ -630,7 +684,7 @@ int show_journal_by_unit( line ++; - r = output_journal(j, mode, line, n_columns, show_all); + r = output_journal(j, mode, line, n_columns, flags); if (r < 0) goto finish; } @@ -649,13 +703,13 @@ int show_journal_by_unit( if (r < 0) goto finish; - if (not_before < cutoff) + if (r > 0 && 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) + if (!(flags & OUTPUT_FOLLOW)) break; r = sd_journal_wait(j, (usec_t) -1); @@ -668,8 +722,9 @@ int show_journal_by_unit( fputs("\n]\n", stdout); finish: - if (m) - free(m); + free(m1); + free(m2); + free(m3); if (j) sd_journal_close(j); @@ -683,6 +738,7 @@ static const char *const output_mode_table[_OUTPUT_MODE_MAX] = { [OUTPUT_VERBOSE] = "verbose", [OUTPUT_EXPORT] = "export", [OUTPUT_JSON] = "json", + [OUTPUT_JSON_PRETTY] = "json-pretty", [OUTPUT_CAT] = "cat" };