1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "logs-show.h"
33 #define PRINT_THRESHOLD 128
35 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
48 if (memcmp(data, field, fl))
56 memcpy(buf, (const char*) data + fl, nl);
66 static bool shall_print(bool show_all, char *p, size_t l) {
70 if (l > PRINT_THRESHOLD)
73 if (!utf8_is_printable_n(p, l))
79 static int output_short(sd_journal *j, unsigned line, unsigned n_columns,
85 char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
86 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;
88 const char *color_on = "", *color_off = "";
92 SD_JOURNAL_FOREACH_DATA(j, data, length) {
94 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
100 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
106 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
112 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
118 r = parse_field(data, length, "_PID=", &pid, &pid_len);
124 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
130 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
136 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
142 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
152 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
155 if (flags & OUTPUT_MONOTONIC_MODE) {
162 r = safe_atou64(monotonic, &t);
165 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
168 log_error("Failed to get monotonic: %s", strerror(-r));
172 printf("[%5llu.%06llu]",
173 (unsigned long long) (t / USEC_PER_SEC),
174 (unsigned long long) (t % USEC_PER_SEC));
176 n += 1 + 5 + 1 + 6 + 1;
187 r = safe_atou64(realtime, &x);
190 r = sd_journal_get_realtime_usec(j, &x);
193 log_error("Failed to get realtime: %s", strerror(-r));
197 t = (time_t) (x / USEC_PER_SEC);
198 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
199 log_error("Failed to format time.");
207 if (hostname && shall_print(flags & OUTPUT_SHOW_ALL,
208 hostname, hostname_len)) {
209 printf(" %.*s", (int) hostname_len, hostname);
210 n += hostname_len + 1;
213 if (identifier && shall_print(flags & OUTPUT_SHOW_ALL,
214 identifier, identifier_len)) {
215 printf(" %.*s", (int) identifier_len, identifier);
216 n += identifier_len + 1;
217 } else if (comm && shall_print(flags & OUTPUT_SHOW_ALL,
219 printf(" %.*s", (int) comm_len, comm);
224 if (pid && shall_print(flags & OUTPUT_SHOW_ALL, pid, pid_len)) {
225 printf("[%.*s]", (int) pid_len, pid);
227 } else if (fake_pid && shall_print(flags & OUTPUT_SHOW_ALL,
228 fake_pid, fake_pid_len)) {
229 printf("[%.*s]", (int) fake_pid_len, fake_pid);
230 n += fake_pid_len + 2;
233 if (flags & OUTPUT_COLOR) {
235 color_on = ANSI_HIGHLIGHT_RED_ON;
236 color_off = ANSI_HIGHLIGHT_OFF;
237 } else if (p <= LOG_NOTICE) {
238 color_on = ANSI_HIGHLIGHT_ON;
239 color_off = ANSI_HIGHLIGHT_OFF;
243 if (flags & OUTPUT_SHOW_ALL)
244 printf(": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
245 else if (!utf8_is_printable_n(message, message_len)) {
246 char bytes[FORMAT_BYTES_MAX];
247 printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
248 } else if ((flags & OUTPUT_FULL_WIDTH) ||
249 (message_len + n + 1 < n_columns))
250 printf(": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
251 else if (n < n_columns && n_columns - n - 2 >= 3) {
254 e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
257 printf(": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
259 printf(": %s%s%s\n", color_on, e, color_off);
281 static int output_short_realtime(sd_journal *j, unsigned line,
282 unsigned n_columns, OutputFlags flags) {
283 return output_short(j, line, n_columns, flags & ~OUTPUT_MONOTONIC_MODE);
286 static int output_short_monotonic(sd_journal *j, unsigned line,
287 unsigned n_columns, OutputFlags flags) {
288 return output_short(j, line, n_columns, flags | OUTPUT_MONOTONIC_MODE);
291 static int output_verbose(sd_journal *j, unsigned line,
292 unsigned n_columns, OutputFlags flags) {
297 char ts[FORMAT_TIMESTAMP_MAX];
302 r = sd_journal_get_realtime_usec(j, &realtime);
304 log_error("Failed to get realtime timestamp: %s", strerror(-r));
308 r = sd_journal_get_cursor(j, &cursor);
310 log_error("Failed to get cursor: %s", strerror(-r));
315 format_timestamp(ts, sizeof(ts), realtime),
320 SD_JOURNAL_FOREACH_DATA(j, data, length) {
321 if (!(flags & OUTPUT_SHOW_ALL) && (length > PRINT_THRESHOLD ||
322 !utf8_is_printable_n(data, length))) {
324 char bytes[FORMAT_BYTES_MAX];
326 c = memchr(data, '=', length);
328 log_error("Invalid field.");
332 printf("\t%.*s=[%s blob data]\n",
333 (int) (c - (const char*) data),
335 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
337 printf("\t%.*s\n", (int) length, (const char*) data);
343 static int output_export(sd_journal *j, unsigned line,
344 unsigned n_columns, OutputFlags flags) {
348 usec_t realtime, monotonic;
355 r = sd_journal_get_realtime_usec(j, &realtime);
357 log_error("Failed to get realtime timestamp: %s", strerror(-r));
361 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
363 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
367 r = sd_journal_get_cursor(j, &cursor);
369 log_error("Failed to get cursor: %s", strerror(-r));
373 printf("__CURSOR=%s\n"
374 "__REALTIME_TIMESTAMP=%llu\n"
375 "__MONOTONIC_TIMESTAMP=%llu\n"
378 (unsigned long long) realtime,
379 (unsigned long long) monotonic,
380 sd_id128_to_string(boot_id, sid));
384 SD_JOURNAL_FOREACH_DATA(j, data, length) {
386 /* We already printed the boot id, from the data in
387 * the header, hence let's suppress it here */
389 memcmp(data, "_BOOT_ID=", 9) == 0)
392 if (!utf8_is_printable_n(data, length)) {
396 c = memchr(data, '=', length);
398 log_error("Invalid field.");
402 fwrite(data, c - (const char*) data, 1, stdout);
404 le64 = htole64(length - (c - (const char*) data) - 1);
405 fwrite(&le64, sizeof(le64), 1, stdout);
406 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
408 fwrite(data, length, 1, stdout);
418 static void json_escape(const char* p, size_t l) {
419 if (!utf8_is_printable_n(p, l)) {
420 bool not_first = false;
426 printf(", %u", (uint8_t) *p);
429 printf("%u", (uint8_t) *p);
441 if (*p == '"' || *p == '\\') {
455 static int output_json(sd_journal *j, unsigned line,
456 unsigned n_columns, OutputFlags flags) {
457 uint64_t realtime, monotonic;
467 r = sd_journal_get_realtime_usec(j, &realtime);
469 log_error("Failed to get realtime timestamp: %s", strerror(-r));
473 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
475 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
479 r = sd_journal_get_cursor(j, &cursor);
481 log_error("Failed to get cursor: %s", strerror(-r));
488 fputs(",\n", stdout);
491 "\t\"__CURSOR\" : \"%s\",\n"
492 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
493 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
494 "\t\"_BOOT_ID\" : \"%s\"",
496 (unsigned long long) realtime,
497 (unsigned long long) monotonic,
498 sd_id128_to_string(boot_id, sid));
502 SD_JOURNAL_FOREACH_DATA(j, data, length) {
505 /* We already printed the boot id, from the data in
506 * the header, hence let's suppress it here */
508 memcmp(data, "_BOOT_ID=", 9) == 0)
511 c = memchr(data, '=', length);
513 log_error("Invalid field.");
517 fputs(",\n\t", stdout);
518 json_escape(data, c - (const char*) data);
519 fputs(" : ", stdout);
520 json_escape(c + 1, length - (c - (const char*) data) - 1);
523 fputs("\n}", stdout);
529 static int output_cat(sd_journal *j, unsigned line,
530 unsigned n_columns, OutputFlags flags) {
537 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
539 log_error("Failed to get data: %s", strerror(-r));
545 fwrite((const char*) data + 8, 1, l - 8, stdout);
551 static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line,
552 unsigned n_columns, OutputFlags flags) = {
553 [OUTPUT_SHORT] = output_short_realtime,
554 [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic,
555 [OUTPUT_VERBOSE] = output_verbose,
556 [OUTPUT_EXPORT] = output_export,
557 [OUTPUT_JSON] = output_json,
558 [OUTPUT_CAT] = output_cat
561 int output_journal(sd_journal *j, OutputMode mode, unsigned line,
562 unsigned n_columns, OutputFlags flags) {
564 assert(mode < _OUTPUT_MODE_MAX);
567 n_columns = columns();
569 return output_funcs[mode](j, line, n_columns, flags);
572 int show_journal_by_unit(
581 sd_journal *j = NULL;
584 bool need_seek = false;
585 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
588 assert(mode < _OUTPUT_MODE_MAX);
591 if (!endswith(unit, ".service") &&
592 !endswith(unit, ".socket") &&
593 !endswith(unit, ".mount") &&
594 !endswith(unit, ".swap"))
600 if (asprintf(&m, "_SYSTEMD_UNIT=%s", unit) < 0) {
605 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
609 r = sd_journal_add_match(j, m, strlen(m));
613 r = sd_journal_seek_tail(j);
617 r = sd_journal_previous_skip(j, how_many);
621 if (mode == OUTPUT_JSON) {
631 r = sd_journal_next(j);
641 if (not_before > 0) {
642 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
644 /* -ESTALE is returned if the
645 timestamp is not from this boot */
651 if (usec < not_before)
657 r = output_journal(j, mode, line, n_columns, flags);
662 if (warn_cutoff && line < how_many && not_before > 0) {
666 /* Check whether the cutoff line is too early */
668 r = sd_id128_get_boot(&boot_id);
672 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
676 if (r > 0 && not_before < cutoff)
677 printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
682 if (!(flags & OUTPUT_FOLLOW))
685 r = sd_journal_wait(j, (usec_t) -1);
691 if (mode == OUTPUT_JSON)
692 fputs("\n]\n", stdout);
704 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
705 [OUTPUT_SHORT] = "short",
706 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
707 [OUTPUT_VERBOSE] = "verbose",
708 [OUTPUT_EXPORT] = "export",
709 [OUTPUT_JSON] = "json",
713 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);