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
34 #define JSON_THRESHOLD 4096
36 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
49 if (memcmp(data, field, fl))
57 memcpy(buf, (const char*) data + fl, nl);
67 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
70 if (flags & OUTPUT_SHOW_ALL)
73 if (l > PRINT_THRESHOLD)
76 if (!utf8_is_printable_n(p, l))
82 static int output_short(
93 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
94 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;
96 const char *color_on = "", *color_off = "";
101 SD_JOURNAL_FOREACH_DATA(j, data, length) {
103 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
109 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
115 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
121 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
127 r = parse_field(data, length, "_PID=", &pid, &pid_len);
133 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
139 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
145 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
151 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
159 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
162 if (mode == OUTPUT_SHORT_MONOTONIC) {
169 r = safe_atou64(monotonic, &t);
172 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
175 log_error("Failed to get monotonic: %s", strerror(-r));
179 fprintf(f, "[%5llu.%06llu]",
180 (unsigned long long) (t / USEC_PER_SEC),
181 (unsigned long long) (t % USEC_PER_SEC));
183 n += 1 + 5 + 1 + 6 + 1;
194 r = safe_atou64(realtime, &x);
197 r = sd_journal_get_realtime_usec(j, &x);
200 log_error("Failed to get realtime: %s", strerror(-r));
204 t = (time_t) (x / USEC_PER_SEC);
205 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
206 log_error("Failed to format time.");
214 if (hostname && shall_print(hostname, hostname_len, flags)) {
215 fprintf(f, " %.*s", (int) hostname_len, hostname);
216 n += hostname_len + 1;
219 if (identifier && shall_print(identifier, identifier_len, flags)) {
220 fprintf(f, " %.*s", (int) identifier_len, identifier);
221 n += identifier_len + 1;
222 } else if (comm && shall_print(comm, comm_len, flags)) {
223 fprintf(f, " %.*s", (int) comm_len, comm);
228 if (pid && shall_print(pid, pid_len, flags)) {
229 fprintf(f, "[%.*s]", (int) pid_len, pid);
231 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
232 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
233 n += fake_pid_len + 2;
236 if (flags & OUTPUT_COLOR) {
238 color_on = ANSI_HIGHLIGHT_RED_ON;
239 color_off = ANSI_HIGHLIGHT_OFF;
240 } else if (p <= LOG_NOTICE) {
241 color_on = ANSI_HIGHLIGHT_ON;
242 color_off = ANSI_HIGHLIGHT_OFF;
247 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
248 else if (!utf8_is_printable_n(message, message_len)) {
249 char bytes[FORMAT_BYTES_MAX];
250 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
251 } else if ((flags & OUTPUT_FULL_WIDTH) || (message_len + n + 1 < n_columns))
252 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
253 else if (n < n_columns && n_columns - n - 2 >= 3) {
256 e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
259 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
261 fprintf(f, ": %s%s%s\n", color_on, e, color_off);
270 static int output_verbose(
281 char ts[FORMAT_TIMESTAMP_MAX];
287 r = sd_journal_get_realtime_usec(j, &realtime);
289 log_error("Failed to get realtime timestamp: %s", strerror(-r));
293 r = sd_journal_get_cursor(j, &cursor);
295 log_error("Failed to get cursor: %s", strerror(-r));
299 fprintf(f, "%s [%s]\n",
300 format_timestamp(ts, sizeof(ts), realtime),
305 SD_JOURNAL_FOREACH_DATA(j, data, length) {
306 if (!shall_print(data, length, flags)) {
308 char bytes[FORMAT_BYTES_MAX];
310 c = memchr(data, '=', length);
312 log_error("Invalid field.");
316 fprintf(f, "\t%.*s=[%s blob data]\n",
317 (int) (c - (const char*) data),
319 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
321 fprintf(f, "\t%.*s\n", (int) length, (const char*) data);
327 static int output_export(
337 usec_t realtime, monotonic;
344 r = sd_journal_get_realtime_usec(j, &realtime);
346 log_error("Failed to get realtime timestamp: %s", strerror(-r));
350 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
352 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
356 r = sd_journal_get_cursor(j, &cursor);
358 log_error("Failed to get cursor: %s", strerror(-r));
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, f);
394 le64 = htole64(length - (c - (const char*) data) - 1);
395 fwrite(&le64, sizeof(le64), 1, f);
396 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
398 fwrite(data, length, 1, f);
408 static void json_escape(
417 if (!(flags & OUTPUT_SHOW_ALL) && l > JSON_THRESHOLD)
421 else if (!utf8_is_printable_n(p, l)) {
422 bool not_first = false;
428 fprintf(f, ", %u", (uint8_t) *p);
431 fprintf(f, "%u", (uint8_t) *p);
443 if (*p == '"' || *p == '\\') {
447 fprintf(f, "\\u%04x", *p);
459 static int output_json(
466 uint64_t realtime, monotonic;
476 r = sd_journal_get_realtime_usec(j, &realtime);
478 log_error("Failed to get realtime timestamp: %s", strerror(-r));
482 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
484 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
488 r = sd_journal_get_cursor(j, &cursor);
490 log_error("Failed to get cursor: %s", strerror(-r));
494 if (mode == OUTPUT_JSON_PRETTY)
497 "\t\"__CURSOR\" : \"%s\",\n"
498 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
499 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
500 "\t\"_BOOT_ID\" : \"%s\"",
502 (unsigned long long) realtime,
503 (unsigned long long) monotonic,
504 sd_id128_to_string(boot_id, sid));
506 if (mode == OUTPUT_JSON_SSE)
510 "{ \"__CURSOR\" : \"%s\", "
511 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
512 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
513 "\"_BOOT_ID\" : \"%s\"",
515 (unsigned long long) realtime,
516 (unsigned long long) monotonic,
517 sd_id128_to_string(boot_id, sid));
521 SD_JOURNAL_FOREACH_DATA(j, data, length) {
524 /* We already printed the boot id, from the data in
525 * the header, hence let's suppress it here */
527 memcmp(data, "_BOOT_ID=", 9) == 0)
530 c = memchr(data, '=', length);
532 log_error("Invalid field.");
536 if (mode == OUTPUT_JSON_PRETTY)
541 json_escape(f, data, c - (const char*) data, flags);
543 json_escape(f, c + 1, length - (c - (const char*) data) - 1, flags);
546 if (mode == OUTPUT_JSON_PRETTY)
548 else if (mode == OUTPUT_JSON_SSE)
556 static int output_cat(
570 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
572 /* An entry without MESSAGE=? */
576 log_error("Failed to get data: %s", strerror(-r));
582 fwrite((const char*) data + 8, 1, l - 8, f);
588 static int (*output_funcs[_OUTPUT_MODE_MAX])(
593 OutputFlags flags) = {
595 [OUTPUT_SHORT] = output_short,
596 [OUTPUT_SHORT_MONOTONIC] = output_short,
597 [OUTPUT_VERBOSE] = output_verbose,
598 [OUTPUT_EXPORT] = output_export,
599 [OUTPUT_JSON] = output_json,
600 [OUTPUT_JSON_PRETTY] = output_json,
601 [OUTPUT_JSON_SSE] = output_json,
602 [OUTPUT_CAT] = output_cat
614 assert(mode < _OUTPUT_MODE_MAX);
617 n_columns = columns();
619 ret = output_funcs[mode](f, j, mode, n_columns, flags);
624 int show_journal_by_unit(
633 _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL;
634 sd_journal *j = NULL;
637 bool need_seek = false;
638 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
641 assert(mode < _OUTPUT_MODE_MAX);
644 if (!endswith(unit, ".service") &&
645 !endswith(unit, ".socket") &&
646 !endswith(unit, ".mount") &&
647 !endswith(unit, ".swap"))
653 if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
654 asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
655 asprintf(&m3, "UNIT=%s", unit) < 0) {
660 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
664 /* Look for messages from the service itself */
665 r = sd_journal_add_match(j, m1, 0);
669 /* Look for coredumps of the service */
670 r = sd_journal_add_disjunction(j);
673 r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0);
676 r = sd_journal_add_match(j, m2, 0);
680 /* Look for messages from PID 1 about this service */
681 r = sd_journal_add_disjunction(j);
684 r = sd_journal_add_match(j, "_PID=1", 0);
687 r = sd_journal_add_match(j, m3, 0);
692 r = sd_journal_seek_tail(j);
696 r = sd_journal_previous_skip(j, how_many);
705 r = sd_journal_next(j);
715 if (not_before > 0) {
716 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
718 /* -ESTALE is returned if the
719 timestamp is not from this boot */
725 if (usec < not_before)
731 r = output_journal(f, j, mode, n_columns, flags);
736 if (warn_cutoff && line < how_many && not_before > 0) {
740 /* Check whether the cutoff line is too early */
742 r = sd_id128_get_boot(&boot_id);
746 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
750 if (r > 0 && not_before < cutoff)
751 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
756 if (!(flags & OUTPUT_FOLLOW))
759 r = sd_journal_wait(j, (usec_t) -1);
772 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
773 [OUTPUT_SHORT] = "short",
774 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
775 [OUTPUT_VERBOSE] = "verbose",
776 [OUTPUT_EXPORT] = "export",
777 [OUTPUT_JSON] = "json",
778 [OUTPUT_JSON_PRETTY] = "json-pretty",
779 [OUTPUT_JSON_SSE] = "json-sse",
783 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);