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 /* An entry without MESSAGE=? */
543 log_error("Failed to get data: %s", strerror(-r));
549 fwrite((const char*) data + 8, 1, l - 8, stdout);
555 static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, OutputMode mode, unsigned line,
556 unsigned n_columns, OutputFlags flags) = {
557 [OUTPUT_SHORT] = output_short,
558 [OUTPUT_SHORT_MONOTONIC] = output_short,
559 [OUTPUT_VERBOSE] = output_verbose,
560 [OUTPUT_EXPORT] = output_export,
561 [OUTPUT_JSON] = output_json,
562 [OUTPUT_JSON_PRETTY] = output_json,
563 [OUTPUT_CAT] = output_cat
566 int output_journal(sd_journal *j, OutputMode mode, unsigned line,
567 unsigned n_columns, OutputFlags flags) {
570 assert(mode < _OUTPUT_MODE_MAX);
573 n_columns = columns();
575 ret = output_funcs[mode](j, mode, line, n_columns, flags);
580 int show_journal_by_unit(
588 char *m1 = NULL, *m2 = NULL, *m3 = NULL;
589 sd_journal *j = NULL;
592 bool need_seek = false;
593 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
596 assert(mode < _OUTPUT_MODE_MAX);
599 if (!endswith(unit, ".service") &&
600 !endswith(unit, ".socket") &&
601 !endswith(unit, ".mount") &&
602 !endswith(unit, ".swap"))
608 if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
609 asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
610 asprintf(&m3, "UNIT=%s", unit) < 0) {
615 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
619 /* Look for messages from the service itself */
620 r = sd_journal_add_match(j, m1, 0);
624 /* Look for coredumps of the service */
625 r = sd_journal_add_disjunction(j);
628 r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0);
631 r = sd_journal_add_match(j, m2, 0);
635 /* Look for messages from PID 1 about this service */
636 r = sd_journal_add_disjunction(j);
639 r = sd_journal_add_match(j, "_PID=1", 0);
642 r = sd_journal_add_match(j, m3, 0);
647 r = sd_journal_seek_tail(j);
651 r = sd_journal_previous_skip(j, how_many);
655 if (mode == OUTPUT_JSON) {
665 r = sd_journal_next(j);
675 if (not_before > 0) {
676 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
678 /* -ESTALE is returned if the
679 timestamp is not from this boot */
685 if (usec < not_before)
691 r = output_journal(j, mode, line, n_columns, flags);
696 if (warn_cutoff && line < how_many && not_before > 0) {
700 /* Check whether the cutoff line is too early */
702 r = sd_id128_get_boot(&boot_id);
706 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
710 if (r > 0 && not_before < cutoff)
711 printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
716 if (!(flags & OUTPUT_FOLLOW))
719 r = sd_journal_wait(j, (usec_t) -1);
725 if (mode == OUTPUT_JSON)
726 fputs("\n]\n", stdout);
739 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
740 [OUTPUT_SHORT] = "short",
741 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
742 [OUTPUT_VERBOSE] = "verbose",
743 [OUTPUT_EXPORT] = "export",
744 [OUTPUT_JSON] = "json",
745 [OUTPUT_JSON_PRETTY] = "json-pretty",
749 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);