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))
53 memcpy(buf, (const char*) data + fl, nl);
65 static bool shall_print(bool show_all, char *p, size_t l) {
69 if (l > PRINT_THRESHOLD)
72 if (!utf8_is_printable_n(p, l))
78 static int output_short(sd_journal *j, unsigned line, unsigned n_columns,
84 char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL;
85 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;
89 SD_JOURNAL_FOREACH_DATA(j, data, length) {
91 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
97 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
103 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
109 r = parse_field(data, length, "_PID=", &pid, &pid_len);
115 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
121 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
127 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
133 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
143 if (flags & OUTPUT_MONOTONIC_MODE) {
150 r = safe_atou64(monotonic, &t);
153 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
156 log_error("Failed to get monotonic: %s", strerror(-r));
160 printf("[%5llu.%06llu]",
161 (unsigned long long) (t / USEC_PER_SEC),
162 (unsigned long long) (t % USEC_PER_SEC));
164 n += 1 + 5 + 1 + 6 + 1;
175 r = safe_atou64(realtime, &x);
178 r = sd_journal_get_realtime_usec(j, &x);
181 log_error("Failed to get realtime: %s", strerror(-r));
185 t = (time_t) (x / USEC_PER_SEC);
186 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
187 log_error("Failed to format time.");
195 if (hostname && shall_print(flags & OUTPUT_SHOW_ALL,
196 hostname, hostname_len)) {
197 printf(" %.*s", (int) hostname_len, hostname);
198 n += hostname_len + 1;
201 if (identifier && shall_print(flags & OUTPUT_SHOW_ALL,
202 identifier, identifier_len)) {
203 printf(" %.*s", (int) identifier_len, identifier);
204 n += identifier_len + 1;
205 } else if (comm && shall_print(flags & OUTPUT_SHOW_ALL,
207 printf(" %.*s", (int) comm_len, comm);
212 if (pid && shall_print(flags & OUTPUT_SHOW_ALL, pid, pid_len)) {
213 printf("[%.*s]", (int) pid_len, pid);
215 } else if (fake_pid && shall_print(flags & OUTPUT_SHOW_ALL,
216 fake_pid, fake_pid_len)) {
217 printf("[%.*s]", (int) fake_pid_len, fake_pid);
218 n += fake_pid_len + 2;
221 if (flags & OUTPUT_SHOW_ALL)
222 printf(": %.*s\n", (int) message_len, message);
223 else if (!utf8_is_printable_n(message, message_len)) {
224 char bytes[FORMAT_BYTES_MAX];
225 printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
226 } else if ((flags & OUTPUT_FULL_WIDTH) ||
227 (message_len + n < n_columns))
228 printf(": %.*s\n", (int) message_len, message);
229 else if (n < n_columns && n_columns - n - 2 >= 3) {
232 e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
235 printf(": %.*s\n", (int) message_len, message);
258 static int output_short_realtime(sd_journal *j, unsigned line,
259 unsigned n_columns, OutputFlags flags) {
260 return output_short(j, line, n_columns, flags & ~OUTPUT_MONOTONIC_MODE);
263 static int output_short_monotonic(sd_journal *j, unsigned line,
264 unsigned n_columns, OutputFlags flags) {
265 return output_short(j, line, n_columns, flags | OUTPUT_MONOTONIC_MODE);
268 static int output_verbose(sd_journal *j, unsigned line,
269 unsigned n_columns, OutputFlags flags) {
274 char ts[FORMAT_TIMESTAMP_MAX];
279 r = sd_journal_get_realtime_usec(j, &realtime);
281 log_error("Failed to get realtime timestamp: %s", strerror(-r));
285 r = sd_journal_get_cursor(j, &cursor);
287 log_error("Failed to get cursor: %s", strerror(-r));
292 format_timestamp(ts, sizeof(ts), realtime),
297 SD_JOURNAL_FOREACH_DATA(j, data, length) {
298 if (!(flags & OUTPUT_SHOW_ALL) && (length > PRINT_THRESHOLD ||
299 !utf8_is_printable_n(data, length))) {
301 char bytes[FORMAT_BYTES_MAX];
303 c = memchr(data, '=', length);
305 log_error("Invalid field.");
309 printf("\t%.*s=[%s blob data]\n",
310 (int) (c - (const char*) data),
312 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
314 printf("\t%.*s\n", (int) length, (const char*) data);
320 static int output_export(sd_journal *j, unsigned line,
321 unsigned n_columns, OutputFlags flags) {
325 usec_t realtime, monotonic;
332 r = sd_journal_get_realtime_usec(j, &realtime);
334 log_error("Failed to get realtime timestamp: %s", strerror(-r));
338 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
340 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
344 r = sd_journal_get_cursor(j, &cursor);
346 log_error("Failed to get cursor: %s", strerror(-r));
350 printf("__CURSOR=%s\n"
351 "__REALTIME_TIMESTAMP=%llu\n"
352 "__MONOTONIC_TIMESTAMP=%llu\n"
355 (unsigned long long) realtime,
356 (unsigned long long) monotonic,
357 sd_id128_to_string(boot_id, sid));
361 SD_JOURNAL_FOREACH_DATA(j, data, length) {
363 /* We already printed the boot id, from the data in
364 * the header, hence let's suppress it here */
366 memcmp(data, "_BOOT_ID=", 9) == 0)
369 if (!utf8_is_printable_n(data, length)) {
373 c = memchr(data, '=', length);
375 log_error("Invalid field.");
379 fwrite(data, c - (const char*) data, 1, stdout);
381 le64 = htole64(length - (c - (const char*) data) - 1);
382 fwrite(&le64, sizeof(le64), 1, stdout);
383 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
385 fwrite(data, length, 1, stdout);
395 static void json_escape(const char* p, size_t l) {
396 if (!utf8_is_printable_n(p, l)) {
397 bool not_first = false;
403 printf(", %u", (uint8_t) *p);
406 printf("%u", (uint8_t) *p);
418 if (*p == '"' || *p == '\\') {
432 static int output_json(sd_journal *j, unsigned line,
433 unsigned n_columns, OutputFlags flags) {
434 uint64_t realtime, monotonic;
444 r = sd_journal_get_realtime_usec(j, &realtime);
446 log_error("Failed to get realtime timestamp: %s", strerror(-r));
450 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
452 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
456 r = sd_journal_get_cursor(j, &cursor);
458 log_error("Failed to get cursor: %s", strerror(-r));
465 fputs(",\n", stdout);
468 "\t\"__CURSOR\" : \"%s\",\n"
469 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
470 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
471 "\t\"_BOOT_ID\" : \"%s\"",
473 (unsigned long long) realtime,
474 (unsigned long long) monotonic,
475 sd_id128_to_string(boot_id, sid));
479 SD_JOURNAL_FOREACH_DATA(j, data, length) {
482 /* We already printed the boot id, from the data in
483 * the header, hence let's suppress it here */
485 memcmp(data, "_BOOT_ID=", 9) == 0)
488 c = memchr(data, '=', length);
490 log_error("Invalid field.");
494 fputs(",\n\t", stdout);
495 json_escape(data, c - (const char*) data);
496 fputs(" : ", stdout);
497 json_escape(c + 1, length - (c - (const char*) data) - 1);
500 fputs("\n}", stdout);
506 static int output_cat(sd_journal *j, unsigned line,
507 unsigned n_columns, OutputFlags flags) {
514 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
516 log_error("Failed to get data: %s", strerror(-r));
522 fwrite((const char*) data + 8, 1, l - 8, stdout);
528 static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line,
529 unsigned n_columns, OutputFlags flags) = {
530 [OUTPUT_SHORT] = output_short_realtime,
531 [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic,
532 [OUTPUT_VERBOSE] = output_verbose,
533 [OUTPUT_EXPORT] = output_export,
534 [OUTPUT_JSON] = output_json,
535 [OUTPUT_CAT] = output_cat
538 int output_journal(sd_journal *j, OutputMode mode, unsigned line,
539 unsigned n_columns, OutputFlags flags) {
541 assert(mode < _OUTPUT_MODE_MAX);
544 n_columns = columns();
546 return output_funcs[mode](j, line, n_columns, flags);
549 int show_journal_by_unit(
558 sd_journal *j = NULL;
561 bool need_seek = false;
562 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
565 assert(mode < _OUTPUT_MODE_MAX);
568 if (!endswith(unit, ".service") &&
569 !endswith(unit, ".socket") &&
570 !endswith(unit, ".mount") &&
571 !endswith(unit, ".swap"))
577 if (asprintf(&m, "_SYSTEMD_UNIT=%s", unit) < 0) {
582 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
586 r = sd_journal_add_match(j, m, strlen(m));
590 r = sd_journal_seek_tail(j);
594 r = sd_journal_previous_skip(j, how_many);
598 if (mode == OUTPUT_JSON) {
608 r = sd_journal_next(j);
618 if (not_before > 0) {
619 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
621 /* -ESTALE is returned if the
622 timestamp is not from this boot */
628 if (usec < not_before)
634 r = output_journal(j, mode, line, n_columns, flags);
639 if (warn_cutoff && line < how_many && not_before > 0) {
643 /* Check whether the cutoff line is too early */
645 r = sd_id128_get_boot(&boot_id);
649 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
653 if (r > 0 && not_before < cutoff)
654 printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
659 if (!(flags & OUTPUT_FOLLOW))
662 r = sd_journal_wait(j, (usec_t) -1);
668 if (mode == OUTPUT_JSON)
669 fputs("\n]\n", stdout);
681 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
682 [OUTPUT_SHORT] = "short",
683 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
684 [OUTPUT_VERBOSE] = "verbose",
685 [OUTPUT_EXPORT] = "export",
686 [OUTPUT_JSON] = "json",
690 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);