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, OutputMode mode, 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 (mode == OUTPUT_SHORT_MONOTONIC) {
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_verbose(sd_journal *j, OutputMode mode, unsigned line,
282 unsigned n_columns, OutputFlags flags) {
287 char ts[FORMAT_TIMESTAMP_MAX];
292 r = sd_journal_get_realtime_usec(j, &realtime);
294 log_error("Failed to get realtime timestamp: %s", strerror(-r));
298 r = sd_journal_get_cursor(j, &cursor);
300 log_error("Failed to get cursor: %s", strerror(-r));
305 format_timestamp(ts, sizeof(ts), realtime),
310 SD_JOURNAL_FOREACH_DATA(j, data, length) {
311 if (!(flags & OUTPUT_SHOW_ALL) && (length > PRINT_THRESHOLD ||
312 !utf8_is_printable_n(data, length))) {
314 char bytes[FORMAT_BYTES_MAX];
316 c = memchr(data, '=', length);
318 log_error("Invalid field.");
322 printf("\t%.*s=[%s blob data]\n",
323 (int) (c - (const char*) data),
325 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
327 printf("\t%.*s\n", (int) length, (const char*) data);
333 static int output_export(sd_journal *j, OutputMode mode, unsigned line,
334 unsigned n_columns, OutputFlags flags) {
338 usec_t realtime, monotonic;
345 r = sd_journal_get_realtime_usec(j, &realtime);
347 log_error("Failed to get realtime timestamp: %s", strerror(-r));
351 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
353 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
357 r = sd_journal_get_cursor(j, &cursor);
359 log_error("Failed to get cursor: %s", strerror(-r));
363 printf("__CURSOR=%s\n"
364 "__REALTIME_TIMESTAMP=%llu\n"
365 "__MONOTONIC_TIMESTAMP=%llu\n"
368 (unsigned long long) realtime,
369 (unsigned long long) monotonic,
370 sd_id128_to_string(boot_id, sid));
374 SD_JOURNAL_FOREACH_DATA(j, data, length) {
376 /* We already printed the boot id, from the data in
377 * the header, hence let's suppress it here */
379 memcmp(data, "_BOOT_ID=", 9) == 0)
382 if (!utf8_is_printable_n(data, length)) {
386 c = memchr(data, '=', length);
388 log_error("Invalid field.");
392 fwrite(data, c - (const char*) data, 1, stdout);
394 le64 = htole64(length - (c - (const char*) data) - 1);
395 fwrite(&le64, sizeof(le64), 1, stdout);
396 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
398 fwrite(data, length, 1, stdout);
408 static void json_escape(const char* p, size_t l) {
409 if (!utf8_is_printable_n(p, l)) {
410 bool not_first = false;
416 printf(", %u", (uint8_t) *p);
419 printf("%u", (uint8_t) *p);
431 if (*p == '"' || *p == '\\') {
445 static int output_json(sd_journal *j, OutputMode mode, unsigned line,
446 unsigned n_columns, OutputFlags flags) {
447 uint64_t realtime, monotonic;
457 r = sd_journal_get_realtime_usec(j, &realtime);
459 log_error("Failed to get realtime timestamp: %s", strerror(-r));
463 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
465 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
469 r = sd_journal_get_cursor(j, &cursor);
471 log_error("Failed to get cursor: %s", strerror(-r));
475 if (mode == OUTPUT_JSON_PRETTY)
477 "\t\"__CURSOR\" : \"%s\",\n"
478 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
479 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
480 "\t\"_BOOT_ID\" : \"%s\"",
482 (unsigned long long) realtime,
483 (unsigned long long) monotonic,
484 sd_id128_to_string(boot_id, sid));
486 printf("{ \"__CURSOR\" : \"%s\", "
487 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
488 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
489 "\"_BOOT_ID\" : \"%s\"",
491 (unsigned long long) realtime,
492 (unsigned long long) monotonic,
493 sd_id128_to_string(boot_id, sid));
496 SD_JOURNAL_FOREACH_DATA(j, data, length) {
499 /* We already printed the boot id, from the data in
500 * the header, hence let's suppress it here */
502 memcmp(data, "_BOOT_ID=", 9) == 0)
505 c = memchr(data, '=', length);
507 log_error("Invalid field.");
511 if (mode == OUTPUT_JSON_PRETTY)
512 fputs(",\n\t", stdout);
516 json_escape(data, c - (const char*) data);
517 fputs(" : ", stdout);
518 json_escape(c + 1, length - (c - (const char*) data) - 1);
521 if (mode == OUTPUT_JSON_PRETTY)
522 fputs("\n}\n", stdout);
524 fputs(" }\n", stdout);
529 static int output_cat(sd_journal *j, OutputMode mode, 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, OutputMode mode, unsigned line,
552 unsigned n_columns, OutputFlags flags) = {
553 [OUTPUT_SHORT] = output_short,
554 [OUTPUT_SHORT_MONOTONIC] = output_short,
555 [OUTPUT_VERBOSE] = output_verbose,
556 [OUTPUT_EXPORT] = output_export,
557 [OUTPUT_JSON] = output_json,
558 [OUTPUT_JSON_PRETTY] = output_json,
559 [OUTPUT_CAT] = output_cat
562 int output_journal(sd_journal *j, OutputMode mode, unsigned line,
563 unsigned n_columns, OutputFlags flags) {
566 assert(mode < _OUTPUT_MODE_MAX);
569 n_columns = columns();
571 ret = output_funcs[mode](j, mode, line, n_columns, flags);
576 int show_journal_by_unit(
584 char *m1 = NULL, *m2 = NULL, *m3 = NULL;
585 sd_journal *j = NULL;
588 bool need_seek = false;
589 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
592 assert(mode < _OUTPUT_MODE_MAX);
595 if (!endswith(unit, ".service") &&
596 !endswith(unit, ".socket") &&
597 !endswith(unit, ".mount") &&
598 !endswith(unit, ".swap"))
604 if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
605 asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
606 asprintf(&m3, "UNIT=%s", unit) < 0) {
611 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
615 /* Look for messages from the service itself */
616 r = sd_journal_add_match(j, m1, 0);
620 /* Look for coredumps of the service */
621 r = sd_journal_add_disjunction(j);
624 r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0);
627 r = sd_journal_add_match(j, m2, 0);
631 /* Look for messages from PID 1 about this service */
632 r = sd_journal_add_disjunction(j);
635 r = sd_journal_add_match(j, "_PID=1", 0);
638 r = sd_journal_add_match(j, m3, 0);
643 r = sd_journal_seek_tail(j);
647 r = sd_journal_previous_skip(j, how_many);
651 if (mode == OUTPUT_JSON) {
661 r = sd_journal_next(j);
671 if (not_before > 0) {
672 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
674 /* -ESTALE is returned if the
675 timestamp is not from this boot */
681 if (usec < not_before)
687 r = output_journal(j, mode, line, n_columns, flags);
692 if (warn_cutoff && line < how_many && not_before > 0) {
696 /* Check whether the cutoff line is too early */
698 r = sd_id128_get_boot(&boot_id);
702 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
706 if (r > 0 && not_before < cutoff)
707 printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
712 if (!(flags & OUTPUT_FOLLOW))
715 r = sd_journal_wait(j, (usec_t) -1);
721 if (mode == OUTPUT_JSON)
722 fputs("\n]\n", stdout);
735 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
736 [OUTPUT_SHORT] = "short",
737 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
738 [OUTPUT_VERBOSE] = "verbose",
739 [OUTPUT_EXPORT] = "export",
740 [OUTPUT_JSON] = "json",
741 [OUTPUT_JSON_PRETTY] = "json-pretty",
745 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);