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 #include "journal-internal.h"
35 #define PRINT_THRESHOLD 128
36 #define JSON_THRESHOLD 4096
38 static int print_catalog(FILE *f, sd_journal *j) {
40 _cleanup_free_ char *t = NULL, *z = NULL;
43 r = sd_journal_get_catalog(j, &t);
47 z = strreplace(strstrip(t), "\n", "\n-- ");
58 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
71 if (memcmp(data, field, fl))
79 memcpy(buf, (const char*) data + fl, nl);
89 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
92 if (flags & OUTPUT_SHOW_ALL)
95 if (l >= PRINT_THRESHOLD)
98 if (!utf8_is_printable(p, l))
104 static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputMode flags, int priority, const char* message, size_t message_len) {
105 const char *color_on = "", *color_off = "";
106 const char *pos, *end;
107 bool continuation = false;
108 bool ellipsized = false;
110 if (flags & OUTPUT_COLOR) {
111 if (priority <= LOG_ERR) {
112 color_on = ANSI_HIGHLIGHT_RED_ON;
113 color_off = ANSI_HIGHLIGHT_OFF;
114 } else if (priority <= LOG_NOTICE) {
115 color_on = ANSI_HIGHLIGHT_ON;
116 color_off = ANSI_HIGHLIGHT_OFF;
120 for (pos = message; pos < message + message_len; pos = end + 1) {
122 for (end = pos; end < message + message_len && *end != '\n'; end++)
127 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) || prefix + len + 1 < n_columns)
128 fprintf(f, "%*s%s%.*s%s\n",
129 continuation * prefix, "",
130 color_on, len, pos, color_off);
131 else if (prefix < n_columns && n_columns - prefix >= 3) {
132 _cleanup_free_ char *e;
135 e = ellipsize_mem(pos, len, n_columns - prefix, 90);
138 fprintf(f, "%s%.*s%s\n", color_on, len, pos, color_off);
140 fprintf(f, "%s%s%s\n", color_on, e, color_off);
152 static int output_short(
163 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
164 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;
166 bool ellipsized = false;
171 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : PRINT_THRESHOLD);
173 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
175 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
181 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
187 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
193 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
199 r = parse_field(data, length, "_PID=", &pid, &pid_len);
205 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
211 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
217 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
223 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
234 if (!(flags & OUTPUT_SHOW_ALL))
235 strip_tab_ansi(&message, &message_len);
237 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
240 if (mode == OUTPUT_SHORT_MONOTONIC) {
247 r = safe_atou64(monotonic, &t);
250 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
253 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
257 fprintf(f, "[%5llu.%06llu]",
258 (unsigned long long) (t / USEC_PER_SEC),
259 (unsigned long long) (t % USEC_PER_SEC));
261 n += 1 + 5 + 1 + 6 + 1;
272 r = safe_atou64(realtime, &x);
275 r = sd_journal_get_realtime_usec(j, &x);
278 log_error("Failed to get realtime timestamp: %s", strerror(-r));
282 t = (time_t) (x / USEC_PER_SEC);
283 if (mode == OUTPUT_SHORT_ISO)
284 r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&t, &tm));
286 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm));
289 log_error("Failed to format time.");
297 if (hostname && shall_print(hostname, hostname_len, flags)) {
298 fprintf(f, " %.*s", (int) hostname_len, hostname);
299 n += hostname_len + 1;
302 if (identifier && shall_print(identifier, identifier_len, flags)) {
303 fprintf(f, " %.*s", (int) identifier_len, identifier);
304 n += identifier_len + 1;
305 } else if (comm && shall_print(comm, comm_len, flags)) {
306 fprintf(f, " %.*s", (int) comm_len, comm);
311 if (pid && shall_print(pid, pid_len, flags)) {
312 fprintf(f, "[%.*s]", (int) pid_len, pid);
314 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
315 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
316 n += fake_pid_len + 2;
319 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
320 char bytes[FORMAT_BYTES_MAX];
321 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
325 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
328 if (flags & OUTPUT_CATALOG)
334 static int output_verbose(
343 _cleanup_free_ char *cursor = NULL;
345 char ts[FORMAT_TIMESTAMP_MAX];
351 sd_journal_set_data_threshold(j, 0);
353 r = sd_journal_get_realtime_usec(j, &realtime);
355 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
356 "Failed to get realtime timestamp: %s", strerror(-r));
360 r = sd_journal_get_cursor(j, &cursor);
362 log_error("Failed to get cursor: %s", strerror(-r));
366 fprintf(f, "%s [%s]\n",
367 format_timestamp(ts, sizeof(ts), realtime),
370 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
373 const char *on = "", *off = "";
375 c = memchr(data, '=', length);
377 log_error("Invalid field.");
380 fieldlen = c - (const char*) data;
382 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
383 on = ANSI_HIGHLIGHT_ON;
384 off = ANSI_HIGHLIGHT_OFF;
387 if (flags & OUTPUT_SHOW_ALL ||
388 (((length < PRINT_THRESHOLD) || flags & OUTPUT_FULL_WIDTH) && utf8_is_printable(data, length))) {
389 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
390 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
393 char bytes[FORMAT_BYTES_MAX];
395 fprintf(f, " %s%.*s=[%s blob data]%s\n",
397 (int) (c - (const char*) data),
399 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
407 if (flags & OUTPUT_CATALOG)
413 static int output_export(
423 usec_t realtime, monotonic;
424 _cleanup_free_ char *cursor = NULL;
430 sd_journal_set_data_threshold(j, 0);
432 r = sd_journal_get_realtime_usec(j, &realtime);
434 log_error("Failed to get realtime timestamp: %s", strerror(-r));
438 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
440 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
444 r = sd_journal_get_cursor(j, &cursor);
446 log_error("Failed to get cursor: %s", strerror(-r));
452 "__REALTIME_TIMESTAMP=%llu\n"
453 "__MONOTONIC_TIMESTAMP=%llu\n"
456 (unsigned long long) realtime,
457 (unsigned long long) monotonic,
458 sd_id128_to_string(boot_id, sid));
460 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
462 /* We already printed the boot id, from the data in
463 * the header, hence let's suppress it here */
465 hasprefix(data, "_BOOT_ID="))
468 if (!utf8_is_printable(data, length)) {
472 c = memchr(data, '=', length);
474 log_error("Invalid field.");
478 fwrite(data, c - (const char*) data, 1, f);
480 le64 = htole64(length - (c - (const char*) data) - 1);
481 fwrite(&le64, sizeof(le64), 1, f);
482 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
484 fwrite(data, length, 1, f);
506 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
510 else if (!utf8_is_printable(p, l)) {
511 bool not_first = false;
517 fprintf(f, ", %u", (uint8_t) *p);
520 fprintf(f, "%u", (uint8_t) *p);
532 if (*p == '"' || *p == '\\') {
535 } else if (*p == '\n')
538 fprintf(f, "\\u%04x", *p);
550 static int output_json(
557 uint64_t realtime, monotonic;
558 _cleanup_free_ char *cursor = NULL;
565 bool done, separator;
569 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
571 r = sd_journal_get_realtime_usec(j, &realtime);
573 log_error("Failed to get realtime timestamp: %s", strerror(-r));
577 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
579 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
583 r = sd_journal_get_cursor(j, &cursor);
585 log_error("Failed to get cursor: %s", strerror(-r));
589 if (mode == OUTPUT_JSON_PRETTY)
592 "\t\"__CURSOR\" : \"%s\",\n"
593 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
594 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
595 "\t\"_BOOT_ID\" : \"%s\"",
597 (unsigned long long) realtime,
598 (unsigned long long) monotonic,
599 sd_id128_to_string(boot_id, sid));
601 if (mode == OUTPUT_JSON_SSE)
605 "{ \"__CURSOR\" : \"%s\", "
606 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
607 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
608 "\"_BOOT_ID\" : \"%s\"",
610 (unsigned long long) realtime,
611 (unsigned long long) monotonic,
612 sd_id128_to_string(boot_id, sid));
615 h = hashmap_new(string_hash_func, string_compare_func);
619 /* First round, iterate through the entry and count how often each field appears */
620 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
626 memcmp(data, "_BOOT_ID=", 9) == 0)
629 eq = memchr(data, '=', length);
633 n = strndup(data, eq - (const char*) data);
639 u = PTR_TO_UINT(hashmap_get(h, n));
641 r = hashmap_put(h, n, UINT_TO_PTR(1));
647 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
661 SD_JOURNAL_FOREACH_DATA(j, data, length) {
667 /* We already printed the boot id, from the data in
668 * the header, hence let's suppress it here */
670 memcmp(data, "_BOOT_ID=", 9) == 0)
673 eq = memchr(data, '=', length);
678 if (mode == OUTPUT_JSON_PRETTY)
684 m = eq - (const char*) data;
686 n = strndup(data, m);
692 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
694 /* We already printed this, let's jump to the next */
700 /* Field only appears once, output it directly */
702 json_escape(f, data, m, flags);
705 json_escape(f, eq + 1, length - m - 1, flags);
707 hashmap_remove(h, n);
716 /* Field appears multiple times, output it as array */
717 json_escape(f, data, m, flags);
719 json_escape(f, eq + 1, length - m - 1, flags);
721 /* Iterate through the end of the list */
723 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
727 if (memcmp(data, n, m) != 0)
730 if (((const char*) data)[m] != '=')
734 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
739 hashmap_remove(h, n);
743 /* Iterate data fields form the beginning */
753 if (mode == OUTPUT_JSON_PRETTY)
755 else if (mode == OUTPUT_JSON_SSE)
763 while ((k = hashmap_steal_first_key(h)))
771 static int output_cat(
785 sd_journal_set_data_threshold(j, 0);
787 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
789 /* An entry without MESSAGE=? */
793 log_error("Failed to get data: %s", strerror(-r));
799 fwrite((const char*) data + 8, 1, l - 8, f);
805 static int (*output_funcs[_OUTPUT_MODE_MAX])(
810 OutputFlags flags) = {
812 [OUTPUT_SHORT] = output_short,
813 [OUTPUT_SHORT_MONOTONIC] = output_short,
814 [OUTPUT_SHORT_ISO] = output_short,
815 [OUTPUT_VERBOSE] = output_verbose,
816 [OUTPUT_EXPORT] = output_export,
817 [OUTPUT_JSON] = output_json,
818 [OUTPUT_JSON_PRETTY] = output_json,
819 [OUTPUT_JSON_SSE] = output_json,
820 [OUTPUT_CAT] = output_cat
833 assert(mode < _OUTPUT_MODE_MAX);
836 n_columns = columns();
838 ret = output_funcs[mode](f, j, mode, n_columns, flags);
841 if (ellipsized && ret > 0)
847 static int show_journal(FILE *f,
858 bool need_seek = false;
859 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
863 assert(mode < _OUTPUT_MODE_MAX);
866 r = sd_journal_seek_tail(j);
870 r = sd_journal_previous_skip(j, how_many);
879 r = sd_journal_next(j);
889 if (not_before > 0) {
890 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
892 /* -ESTALE is returned if the
893 timestamp is not from this boot */
899 if (usec < not_before)
905 r = output_journal(f, j, mode, n_columns, flags, ellipsized);
910 if (warn_cutoff && line < how_many && not_before > 0) {
914 /* Check whether the cutoff line is too early */
916 r = sd_id128_get_boot(&boot_id);
920 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
924 if (r > 0 && not_before < cutoff)
925 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
930 if (!(flags & OUTPUT_FOLLOW))
933 r = sd_journal_wait(j, (usec_t) -1);
943 int add_matches_for_unit(sd_journal *j, const char *unit) {
945 char *m1, *m2, *m3, *m4;
950 m1 = strappenda("_SYSTEMD_UNIT=", unit);
951 m2 = strappenda("COREDUMP_UNIT=", unit);
952 m3 = strappenda("UNIT=", unit);
953 m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit);
956 /* Look for messages from the service itself */
957 (r = sd_journal_add_match(j, m1, 0)) ||
959 /* Look for coredumps of the service */
960 (r = sd_journal_add_disjunction(j)) ||
961 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
962 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
963 (r = sd_journal_add_match(j, m2, 0)) ||
965 /* Look for messages from PID 1 about this service */
966 (r = sd_journal_add_disjunction(j)) ||
967 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
968 (r = sd_journal_add_match(j, m3, 0)) ||
970 /* Look for messages from authorized daemons about this service */
971 (r = sd_journal_add_disjunction(j)) ||
972 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
973 (r = sd_journal_add_match(j, m4, 0))
979 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
981 char *m1, *m2, *m3, *m4;
982 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
987 m1 = strappenda("_SYSTEMD_USER_UNIT=", unit);
988 m2 = strappenda("USER_UNIT=", unit);
989 m3 = strappenda("COREDUMP_USER_UNIT=", unit);
990 m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit);
991 sprintf(muid, "_UID=%lu", (unsigned long) uid);
994 /* Look for messages from the user service itself */
995 (r = sd_journal_add_match(j, m1, 0)) ||
996 (r = sd_journal_add_match(j, muid, 0)) ||
998 /* Look for messages from systemd about this service */
999 (r = sd_journal_add_disjunction(j)) ||
1000 (r = sd_journal_add_match(j, m2, 0)) ||
1001 (r = sd_journal_add_match(j, muid, 0)) ||
1003 /* Look for coredumps of the service */
1004 (r = sd_journal_add_disjunction(j)) ||
1005 (r = sd_journal_add_match(j, m3, 0)) ||
1006 (r = sd_journal_add_match(j, muid, 0)) ||
1007 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1009 /* Look for messages from authorized daemons about this service */
1010 (r = sd_journal_add_disjunction(j)) ||
1011 (r = sd_journal_add_match(j, m4, 0)) ||
1012 (r = sd_journal_add_match(j, muid, 0)) ||
1013 (r = sd_journal_add_match(j, "_UID=0", 0))
1018 int add_match_this_boot(sd_journal *j) {
1019 char match[9+32+1] = "_BOOT_ID=";
1025 r = sd_id128_get_boot(&boot_id);
1027 log_error("Failed to get boot id: %s", strerror(-r));
1031 sd_id128_to_string(boot_id, match + 9);
1032 r = sd_journal_add_match(j, match, strlen(match));
1034 log_error("Failed to add match: %s", strerror(-r));
1038 r = sd_journal_add_conjunction(j);
1045 int show_journal_by_unit(
1057 _cleanup_journal_close_ sd_journal*j = NULL;
1059 int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM;
1062 assert(mode < _OUTPUT_MODE_MAX);
1068 r = sd_journal_open(&j, jflags);
1072 r = add_match_this_boot(j);
1077 r = add_matches_for_unit(j, unit);
1079 r = add_matches_for_user_unit(j, unit, uid);
1083 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1084 _cleanup_free_ char *filter;
1086 filter = journal_make_match_string(j);
1087 log_debug("Journal filter: %s", filter);
1090 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
1093 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1094 [OUTPUT_SHORT] = "short",
1095 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1096 [OUTPUT_SHORT_ISO] = "short-iso",
1097 [OUTPUT_VERBOSE] = "verbose",
1098 [OUTPUT_EXPORT] = "export",
1099 [OUTPUT_JSON] = "json",
1100 [OUTPUT_JSON_PRETTY] = "json-pretty",
1101 [OUTPUT_JSON_SSE] = "json-sse",
1102 [OUTPUT_CAT] = "cat"
1105 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);