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 < 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);
280 static int output_short_realtime(sd_journal *j, unsigned line,
281 unsigned n_columns, OutputFlags flags) {
282 return output_short(j, line, n_columns, flags & ~OUTPUT_MONOTONIC_MODE);
285 static int output_short_monotonic(sd_journal *j, unsigned line,
286 unsigned n_columns, OutputFlags flags) {
287 return output_short(j, line, n_columns, flags | OUTPUT_MONOTONIC_MODE);
290 static int output_verbose(sd_journal *j, unsigned line,
291 unsigned n_columns, OutputFlags flags) {
296 char ts[FORMAT_TIMESTAMP_MAX];
301 r = sd_journal_get_realtime_usec(j, &realtime);
303 log_error("Failed to get realtime timestamp: %s", strerror(-r));
307 r = sd_journal_get_cursor(j, &cursor);
309 log_error("Failed to get cursor: %s", strerror(-r));
314 format_timestamp(ts, sizeof(ts), realtime),
319 SD_JOURNAL_FOREACH_DATA(j, data, length) {
320 if (!(flags & OUTPUT_SHOW_ALL) && (length > PRINT_THRESHOLD ||
321 !utf8_is_printable_n(data, length))) {
323 char bytes[FORMAT_BYTES_MAX];
325 c = memchr(data, '=', length);
327 log_error("Invalid field.");
331 printf("\t%.*s=[%s blob data]\n",
332 (int) (c - (const char*) data),
334 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
336 printf("\t%.*s\n", (int) length, (const char*) data);
342 static int output_export(sd_journal *j, unsigned line,
343 unsigned n_columns, OutputFlags flags) {
347 usec_t realtime, monotonic;
354 r = sd_journal_get_realtime_usec(j, &realtime);
356 log_error("Failed to get realtime timestamp: %s", strerror(-r));
360 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
362 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
366 r = sd_journal_get_cursor(j, &cursor);
368 log_error("Failed to get cursor: %s", strerror(-r));
372 printf("__CURSOR=%s\n"
373 "__REALTIME_TIMESTAMP=%llu\n"
374 "__MONOTONIC_TIMESTAMP=%llu\n"
377 (unsigned long long) realtime,
378 (unsigned long long) monotonic,
379 sd_id128_to_string(boot_id, sid));
383 SD_JOURNAL_FOREACH_DATA(j, data, length) {
385 /* We already printed the boot id, from the data in
386 * the header, hence let's suppress it here */
388 memcmp(data, "_BOOT_ID=", 9) == 0)
391 if (!utf8_is_printable_n(data, length)) {
395 c = memchr(data, '=', length);
397 log_error("Invalid field.");
401 fwrite(data, c - (const char*) data, 1, stdout);
403 le64 = htole64(length - (c - (const char*) data) - 1);
404 fwrite(&le64, sizeof(le64), 1, stdout);
405 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
407 fwrite(data, length, 1, stdout);
417 static void json_escape(const char* p, size_t l) {
418 if (!utf8_is_printable_n(p, l)) {
419 bool not_first = false;
425 printf(", %u", (uint8_t) *p);
428 printf("%u", (uint8_t) *p);
440 if (*p == '"' || *p == '\\') {
454 static int output_json(sd_journal *j, unsigned line,
455 unsigned n_columns, OutputFlags flags) {
456 uint64_t realtime, monotonic;
466 r = sd_journal_get_realtime_usec(j, &realtime);
468 log_error("Failed to get realtime timestamp: %s", strerror(-r));
472 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
474 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
478 r = sd_journal_get_cursor(j, &cursor);
480 log_error("Failed to get cursor: %s", strerror(-r));
487 fputs(",\n", stdout);
490 "\t\"__CURSOR\" : \"%s\",\n"
491 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
492 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
493 "\t\"_BOOT_ID\" : \"%s\"",
495 (unsigned long long) realtime,
496 (unsigned long long) monotonic,
497 sd_id128_to_string(boot_id, sid));
501 SD_JOURNAL_FOREACH_DATA(j, data, length) {
504 /* We already printed the boot id, from the data in
505 * the header, hence let's suppress it here */
507 memcmp(data, "_BOOT_ID=", 9) == 0)
510 c = memchr(data, '=', length);
512 log_error("Invalid field.");
516 fputs(",\n\t", stdout);
517 json_escape(data, c - (const char*) data);
518 fputs(" : ", stdout);
519 json_escape(c + 1, length - (c - (const char*) data) - 1);
522 fputs("\n}", stdout);
528 static int output_cat(sd_journal *j, unsigned line,
529 unsigned n_columns, OutputFlags flags) {
536 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
538 log_error("Failed to get data: %s", strerror(-r));
544 fwrite((const char*) data + 8, 1, l - 8, stdout);
550 static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line,
551 unsigned n_columns, OutputFlags flags) = {
552 [OUTPUT_SHORT] = output_short_realtime,
553 [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic,
554 [OUTPUT_VERBOSE] = output_verbose,
555 [OUTPUT_EXPORT] = output_export,
556 [OUTPUT_JSON] = output_json,
557 [OUTPUT_CAT] = output_cat
560 int output_journal(sd_journal *j, OutputMode mode, unsigned line,
561 unsigned n_columns, OutputFlags flags) {
563 assert(mode < _OUTPUT_MODE_MAX);
566 n_columns = columns();
568 return output_funcs[mode](j, line, n_columns, flags);
571 int show_journal_by_unit(
580 sd_journal *j = NULL;
583 bool need_seek = false;
584 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
587 assert(mode < _OUTPUT_MODE_MAX);
590 if (!endswith(unit, ".service") &&
591 !endswith(unit, ".socket") &&
592 !endswith(unit, ".mount") &&
593 !endswith(unit, ".swap"))
599 if (asprintf(&m, "_SYSTEMD_UNIT=%s", unit) < 0) {
604 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
608 r = sd_journal_add_match(j, m, strlen(m));
612 r = sd_journal_seek_tail(j);
616 r = sd_journal_previous_skip(j, how_many);
620 if (mode == OUTPUT_JSON) {
630 r = sd_journal_next(j);
640 if (not_before > 0) {
641 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
643 /* -ESTALE is returned if the
644 timestamp is not from this boot */
650 if (usec < not_before)
656 r = output_journal(j, mode, line, n_columns, flags);
661 if (warn_cutoff && line < how_many && not_before > 0) {
665 /* Check whether the cutoff line is too early */
667 r = sd_id128_get_boot(&boot_id);
671 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
675 if (r > 0 && not_before < cutoff)
676 printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
681 if (!(flags & OUTPUT_FOLLOW))
684 r = sd_journal_wait(j, (usec_t) -1);
690 if (mode == OUTPUT_JSON)
691 fputs("\n]\n", stdout);
703 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
704 [OUTPUT_SHORT] = "short",
705 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
706 [OUTPUT_VERBOSE] = "verbose",
707 [OUTPUT_EXPORT] = "export",
708 [OUTPUT_JSON] = "json",
712 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);