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"
34 #define PRINT_THRESHOLD 128
35 #define JSON_THRESHOLD 4096
37 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
50 if (memcmp(data, field, fl))
58 memcpy(buf, (const char*) data + fl, nl);
68 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
71 if (flags & OUTPUT_SHOW_ALL)
74 if (l > PRINT_THRESHOLD)
77 if (!utf8_is_printable_n(p, l))
83 static int output_short(
94 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
95 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;
97 const char *color_on = "", *color_off = "";
102 SD_JOURNAL_FOREACH_DATA(j, data, length) {
104 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
110 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
116 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
122 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
128 r = parse_field(data, length, "_PID=", &pid, &pid_len);
134 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
140 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
146 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
152 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
160 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
163 if (mode == OUTPUT_SHORT_MONOTONIC) {
170 r = safe_atou64(monotonic, &t);
173 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
176 log_error("Failed to get monotonic: %s", strerror(-r));
180 fprintf(f, "[%5llu.%06llu]",
181 (unsigned long long) (t / USEC_PER_SEC),
182 (unsigned long long) (t % USEC_PER_SEC));
184 n += 1 + 5 + 1 + 6 + 1;
195 r = safe_atou64(realtime, &x);
198 r = sd_journal_get_realtime_usec(j, &x);
201 log_error("Failed to get realtime: %s", strerror(-r));
205 t = (time_t) (x / USEC_PER_SEC);
206 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
207 log_error("Failed to format time.");
215 if (hostname && shall_print(hostname, hostname_len, flags)) {
216 fprintf(f, " %.*s", (int) hostname_len, hostname);
217 n += hostname_len + 1;
220 if (identifier && shall_print(identifier, identifier_len, flags)) {
221 fprintf(f, " %.*s", (int) identifier_len, identifier);
222 n += identifier_len + 1;
223 } else if (comm && shall_print(comm, comm_len, flags)) {
224 fprintf(f, " %.*s", (int) comm_len, comm);
229 if (pid && shall_print(pid, pid_len, flags)) {
230 fprintf(f, "[%.*s]", (int) pid_len, pid);
232 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
233 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
234 n += fake_pid_len + 2;
237 if (flags & OUTPUT_COLOR) {
239 color_on = ANSI_HIGHLIGHT_RED_ON;
240 color_off = ANSI_HIGHLIGHT_OFF;
241 } else if (p <= LOG_NOTICE) {
242 color_on = ANSI_HIGHLIGHT_ON;
243 color_off = ANSI_HIGHLIGHT_OFF;
247 if (flags & OUTPUT_SHOW_ALL)
248 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
249 else if (!utf8_is_printable_n(message, message_len)) {
250 char bytes[FORMAT_BYTES_MAX];
251 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
252 } else if ((flags & OUTPUT_FULL_WIDTH) || (message_len + n + 1 < n_columns))
253 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
254 else if (n < n_columns && n_columns - n - 2 >= 3) {
257 e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
260 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
262 fprintf(f, ": %s%s%s\n", color_on, e, color_off);
271 static int output_verbose(
282 char ts[FORMAT_TIMESTAMP_MAX];
288 r = sd_journal_get_realtime_usec(j, &realtime);
290 log_error("Failed to get realtime timestamp: %s", strerror(-r));
294 r = sd_journal_get_cursor(j, &cursor);
296 log_error("Failed to get cursor: %s", strerror(-r));
300 fprintf(f, "%s [%s]\n",
301 format_timestamp(ts, sizeof(ts), realtime),
306 SD_JOURNAL_FOREACH_DATA(j, data, length) {
307 if (!shall_print(data, length, flags)) {
309 char bytes[FORMAT_BYTES_MAX];
311 c = memchr(data, '=', length);
313 log_error("Invalid field.");
317 fprintf(f, "\t%.*s=[%s blob data]\n",
318 (int) (c - (const char*) data),
320 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
322 fprintf(f, "\t%.*s\n", (int) length, (const char*) data);
328 static int output_export(
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));
365 "__REALTIME_TIMESTAMP=%llu\n"
366 "__MONOTONIC_TIMESTAMP=%llu\n"
369 (unsigned long long) realtime,
370 (unsigned long long) monotonic,
371 sd_id128_to_string(boot_id, sid));
375 SD_JOURNAL_FOREACH_DATA(j, data, length) {
377 /* We already printed the boot id, from the data in
378 * the header, hence let's suppress it here */
380 memcmp(data, "_BOOT_ID=", 9) == 0)
383 if (!utf8_is_printable_n(data, length)) {
387 c = memchr(data, '=', length);
389 log_error("Invalid field.");
393 fwrite(data, c - (const char*) data, 1, f);
395 le64 = htole64(length - (c - (const char*) data) - 1);
396 fwrite(&le64, sizeof(le64), 1, f);
397 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
399 fwrite(data, length, 1, f);
418 if (!(flags & OUTPUT_SHOW_ALL) && l > JSON_THRESHOLD)
422 else if (!utf8_is_printable_n(p, l)) {
423 bool not_first = false;
429 fprintf(f, ", %u", (uint8_t) *p);
432 fprintf(f, "%u", (uint8_t) *p);
444 if (*p == '"' || *p == '\\') {
448 fprintf(f, "\\u%04x", *p);
460 static int output_json(
467 uint64_t realtime, monotonic;
475 bool done, separator;
479 r = sd_journal_get_realtime_usec(j, &realtime);
481 log_error("Failed to get realtime timestamp: %s", strerror(-r));
485 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
487 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
491 r = sd_journal_get_cursor(j, &cursor);
493 log_error("Failed to get cursor: %s", strerror(-r));
497 if (mode == OUTPUT_JSON_PRETTY)
500 "\t\"__CURSOR\" : \"%s\",\n"
501 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
502 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
503 "\t\"_BOOT_ID\" : \"%s\"",
505 (unsigned long long) realtime,
506 (unsigned long long) monotonic,
507 sd_id128_to_string(boot_id, sid));
509 if (mode == OUTPUT_JSON_SSE)
513 "{ \"__CURSOR\" : \"%s\", "
514 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
515 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
516 "\"_BOOT_ID\" : \"%s\"",
518 (unsigned long long) realtime,
519 (unsigned long long) monotonic,
520 sd_id128_to_string(boot_id, sid));
524 h = hashmap_new(string_hash_func, string_compare_func);
528 /* First round, iterate through the entry and count how often each field appears */
529 SD_JOURNAL_FOREACH_DATA(j, data, length) {
535 memcmp(data, "_BOOT_ID=", 9) == 0)
538 eq = memchr(data, '=', length);
542 n = strndup(data, eq - (const char*) data);
548 u = PTR_TO_UINT(hashmap_get(h, n));
550 r = hashmap_put(h, n, UINT_TO_PTR(1));
556 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
567 SD_JOURNAL_FOREACH_DATA(j, data, length) {
573 /* We already printed the boot id, from the data in
574 * the header, hence let's suppress it here */
576 memcmp(data, "_BOOT_ID=", 9) == 0)
579 eq = memchr(data, '=', length);
584 if (mode == OUTPUT_JSON_PRETTY)
590 m = eq - (const char*) data;
592 n = strndup(data, m);
598 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
600 /* We already printed this, let's jump to the next */
606 /* Field only appears once, output it directly */
608 json_escape(f, data, m, flags);
611 json_escape(f, eq + 1, length - m - 1, flags);
613 hashmap_remove(h, n);
622 /* Field appears multiple times, output it as array */
623 json_escape(f, data, m, flags);
625 json_escape(f, eq + 1, length - m - 1, flags);
627 /* Iterate through the end of the list */
629 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
633 if (memcmp(data, n, m) != 0)
636 if (((const char*) data)[m] != '=')
640 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
645 hashmap_remove(h, n);
649 /* Iterate data fields form the beginning */
659 if (mode == OUTPUT_JSON_PRETTY)
661 else if (mode == OUTPUT_JSON_SSE)
669 while ((k = hashmap_steal_first_key(h)))
677 static int output_cat(
691 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
693 /* An entry without MESSAGE=? */
697 log_error("Failed to get data: %s", strerror(-r));
703 fwrite((const char*) data + 8, 1, l - 8, f);
709 static int (*output_funcs[_OUTPUT_MODE_MAX])(
714 OutputFlags flags) = {
716 [OUTPUT_SHORT] = output_short,
717 [OUTPUT_SHORT_MONOTONIC] = output_short,
718 [OUTPUT_VERBOSE] = output_verbose,
719 [OUTPUT_EXPORT] = output_export,
720 [OUTPUT_JSON] = output_json,
721 [OUTPUT_JSON_PRETTY] = output_json,
722 [OUTPUT_JSON_SSE] = output_json,
723 [OUTPUT_CAT] = output_cat
735 assert(mode < _OUTPUT_MODE_MAX);
738 n_columns = columns();
740 ret = output_funcs[mode](f, j, mode, n_columns, flags);
745 int show_journal_by_unit(
754 _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL;
755 sd_journal *j = NULL;
758 bool need_seek = false;
759 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
762 assert(mode < _OUTPUT_MODE_MAX);
765 if (!endswith(unit, ".service") &&
766 !endswith(unit, ".socket") &&
767 !endswith(unit, ".mount") &&
768 !endswith(unit, ".swap"))
774 if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
775 asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
776 asprintf(&m3, "UNIT=%s", unit) < 0) {
781 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
785 /* Look for messages from the service itself */
786 r = sd_journal_add_match(j, m1, 0);
790 /* Look for coredumps of the service */
791 r = sd_journal_add_disjunction(j);
794 r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0);
797 r = sd_journal_add_match(j, m2, 0);
801 /* Look for messages from PID 1 about this service */
802 r = sd_journal_add_disjunction(j);
805 r = sd_journal_add_match(j, "_PID=1", 0);
808 r = sd_journal_add_match(j, m3, 0);
813 r = sd_journal_seek_tail(j);
817 r = sd_journal_previous_skip(j, how_many);
826 r = sd_journal_next(j);
836 if (not_before > 0) {
837 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
839 /* -ESTALE is returned if the
840 timestamp is not from this boot */
846 if (usec < not_before)
852 r = output_journal(f, j, mode, n_columns, flags);
857 if (warn_cutoff && line < how_many && not_before > 0) {
861 /* Check whether the cutoff line is too early */
863 r = sd_id128_get_boot(&boot_id);
867 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
871 if (r > 0 && not_before < cutoff)
872 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
877 if (!(flags & OUTPUT_FOLLOW))
880 r = sd_journal_wait(j, (usec_t) -1);
893 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
894 [OUTPUT_SHORT] = "short",
895 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
896 [OUTPUT_VERBOSE] = "verbose",
897 [OUTPUT_EXPORT] = "export",
898 [OUTPUT_JSON] = "json",
899 [OUTPUT_JSON_PRETTY] = "json-pretty",
900 [OUTPUT_JSON_SSE] = "json-sse",
904 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);