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%s\n",
139 continuation * prefix, "",
140 color_on, len, pos, color_off);
142 fprintf(f, "%*s%s%s%s\n",
143 continuation * prefix, "",
144 color_on, e, color_off);
156 static int output_short(
167 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
168 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;
170 bool ellipsized = false;
175 sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_THRESHOLD);
177 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
179 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
185 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
191 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
197 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
203 r = parse_field(data, length, "_PID=", &pid, &pid_len);
209 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
215 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
221 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
227 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
238 if (!(flags & OUTPUT_SHOW_ALL))
239 strip_tab_ansi(&message, &message_len);
241 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
244 if (mode == OUTPUT_SHORT_MONOTONIC) {
251 r = safe_atou64(monotonic, &t);
254 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
257 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
261 fprintf(f, "[%5llu.%06llu]",
262 (unsigned long long) (t / USEC_PER_SEC),
263 (unsigned long long) (t % USEC_PER_SEC));
265 n += 1 + 5 + 1 + 6 + 1;
276 r = safe_atou64(realtime, &x);
279 r = sd_journal_get_realtime_usec(j, &x);
282 log_error("Failed to get realtime timestamp: %s", strerror(-r));
286 t = (time_t) (x / USEC_PER_SEC);
287 if (mode == OUTPUT_SHORT_ISO)
288 r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&t, &tm));
290 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm));
293 log_error("Failed to format time.");
301 if (hostname && shall_print(hostname, hostname_len, flags)) {
302 fprintf(f, " %.*s", (int) hostname_len, hostname);
303 n += hostname_len + 1;
306 if (identifier && shall_print(identifier, identifier_len, flags)) {
307 fprintf(f, " %.*s", (int) identifier_len, identifier);
308 n += identifier_len + 1;
309 } else if (comm && shall_print(comm, comm_len, flags)) {
310 fprintf(f, " %.*s", (int) comm_len, comm);
315 if (pid && shall_print(pid, pid_len, flags)) {
316 fprintf(f, "[%.*s]", (int) pid_len, pid);
318 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
319 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
320 n += fake_pid_len + 2;
323 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
324 char bytes[FORMAT_BYTES_MAX];
325 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
329 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
332 if (flags & OUTPUT_CATALOG)
338 static int output_verbose(
347 _cleanup_free_ char *cursor = NULL;
349 char ts[FORMAT_TIMESTAMP_MAX];
355 sd_journal_set_data_threshold(j, 0);
357 r = sd_journal_get_realtime_usec(j, &realtime);
359 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
360 "Failed to get realtime timestamp: %s", strerror(-r));
364 r = sd_journal_get_cursor(j, &cursor);
366 log_error("Failed to get cursor: %s", strerror(-r));
370 fprintf(f, "%s [%s]\n",
371 format_timestamp(ts, sizeof(ts), realtime),
374 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
377 const char *on = "", *off = "";
379 c = memchr(data, '=', length);
381 log_error("Invalid field.");
384 fieldlen = c - (const char*) data;
386 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
387 on = ANSI_HIGHLIGHT_ON;
388 off = ANSI_HIGHLIGHT_OFF;
391 if (flags & OUTPUT_SHOW_ALL ||
392 (((length < PRINT_THRESHOLD) || flags & OUTPUT_FULL_WIDTH) && utf8_is_printable(data, length))) {
393 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
394 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
397 char bytes[FORMAT_BYTES_MAX];
399 fprintf(f, " %s%.*s=[%s blob data]%s\n",
401 (int) (c - (const char*) data),
403 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
411 if (flags & OUTPUT_CATALOG)
417 static int output_export(
427 usec_t realtime, monotonic;
428 _cleanup_free_ char *cursor = NULL;
434 sd_journal_set_data_threshold(j, 0);
436 r = sd_journal_get_realtime_usec(j, &realtime);
438 log_error("Failed to get realtime timestamp: %s", strerror(-r));
442 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
444 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
448 r = sd_journal_get_cursor(j, &cursor);
450 log_error("Failed to get cursor: %s", strerror(-r));
456 "__REALTIME_TIMESTAMP=%llu\n"
457 "__MONOTONIC_TIMESTAMP=%llu\n"
460 (unsigned long long) realtime,
461 (unsigned long long) monotonic,
462 sd_id128_to_string(boot_id, sid));
464 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
466 /* We already printed the boot id, from the data in
467 * the header, hence let's suppress it here */
469 hasprefix(data, "_BOOT_ID="))
472 if (!utf8_is_printable(data, length)) {
476 c = memchr(data, '=', length);
478 log_error("Invalid field.");
482 fwrite(data, c - (const char*) data, 1, f);
484 le64 = htole64(length - (c - (const char*) data) - 1);
485 fwrite(&le64, sizeof(le64), 1, f);
486 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
488 fwrite(data, length, 1, f);
510 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
514 else if (!utf8_is_printable(p, l)) {
515 bool not_first = false;
521 fprintf(f, ", %u", (uint8_t) *p);
524 fprintf(f, "%u", (uint8_t) *p);
536 if (*p == '"' || *p == '\\') {
539 } else if (*p == '\n')
542 fprintf(f, "\\u%04x", *p);
554 static int output_json(
561 uint64_t realtime, monotonic;
562 _cleanup_free_ char *cursor = NULL;
569 bool done, separator;
573 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
575 r = sd_journal_get_realtime_usec(j, &realtime);
577 log_error("Failed to get realtime timestamp: %s", strerror(-r));
581 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
583 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
587 r = sd_journal_get_cursor(j, &cursor);
589 log_error("Failed to get cursor: %s", strerror(-r));
593 if (mode == OUTPUT_JSON_PRETTY)
596 "\t\"__CURSOR\" : \"%s\",\n"
597 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
598 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
599 "\t\"_BOOT_ID\" : \"%s\"",
601 (unsigned long long) realtime,
602 (unsigned long long) monotonic,
603 sd_id128_to_string(boot_id, sid));
605 if (mode == OUTPUT_JSON_SSE)
609 "{ \"__CURSOR\" : \"%s\", "
610 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
611 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
612 "\"_BOOT_ID\" : \"%s\"",
614 (unsigned long long) realtime,
615 (unsigned long long) monotonic,
616 sd_id128_to_string(boot_id, sid));
619 h = hashmap_new(string_hash_func, string_compare_func);
623 /* First round, iterate through the entry and count how often each field appears */
624 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
630 memcmp(data, "_BOOT_ID=", 9) == 0)
633 eq = memchr(data, '=', length);
637 n = strndup(data, eq - (const char*) data);
643 u = PTR_TO_UINT(hashmap_get(h, n));
645 r = hashmap_put(h, n, UINT_TO_PTR(1));
651 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
665 SD_JOURNAL_FOREACH_DATA(j, data, length) {
671 /* We already printed the boot id, from the data in
672 * the header, hence let's suppress it here */
674 memcmp(data, "_BOOT_ID=", 9) == 0)
677 eq = memchr(data, '=', length);
682 if (mode == OUTPUT_JSON_PRETTY)
688 m = eq - (const char*) data;
690 n = strndup(data, m);
696 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
698 /* We already printed this, let's jump to the next */
704 /* Field only appears once, output it directly */
706 json_escape(f, data, m, flags);
709 json_escape(f, eq + 1, length - m - 1, flags);
711 hashmap_remove(h, n);
720 /* Field appears multiple times, output it as array */
721 json_escape(f, data, m, flags);
723 json_escape(f, eq + 1, length - m - 1, flags);
725 /* Iterate through the end of the list */
727 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
731 if (memcmp(data, n, m) != 0)
734 if (((const char*) data)[m] != '=')
738 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
743 hashmap_remove(h, n);
747 /* Iterate data fields form the beginning */
757 if (mode == OUTPUT_JSON_PRETTY)
759 else if (mode == OUTPUT_JSON_SSE)
767 while ((k = hashmap_steal_first_key(h)))
775 static int output_cat(
789 sd_journal_set_data_threshold(j, 0);
791 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
793 /* An entry without MESSAGE=? */
797 log_error("Failed to get data: %s", strerror(-r));
803 fwrite((const char*) data + 8, 1, l - 8, f);
809 static int (*output_funcs[_OUTPUT_MODE_MAX])(
814 OutputFlags flags) = {
816 [OUTPUT_SHORT] = output_short,
817 [OUTPUT_SHORT_MONOTONIC] = output_short,
818 [OUTPUT_SHORT_ISO] = output_short,
819 [OUTPUT_VERBOSE] = output_verbose,
820 [OUTPUT_EXPORT] = output_export,
821 [OUTPUT_JSON] = output_json,
822 [OUTPUT_JSON_PRETTY] = output_json,
823 [OUTPUT_JSON_SSE] = output_json,
824 [OUTPUT_CAT] = output_cat
837 assert(mode < _OUTPUT_MODE_MAX);
840 n_columns = columns();
842 ret = output_funcs[mode](f, j, mode, n_columns, flags);
845 if (ellipsized && ret > 0)
851 static int show_journal(FILE *f,
862 bool need_seek = false;
863 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
867 assert(mode < _OUTPUT_MODE_MAX);
870 r = sd_journal_seek_tail(j);
874 r = sd_journal_previous_skip(j, how_many);
883 r = sd_journal_next(j);
893 if (not_before > 0) {
894 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
896 /* -ESTALE is returned if the
897 timestamp is not from this boot */
903 if (usec < not_before)
909 r = output_journal(f, j, mode, n_columns, flags, ellipsized);
914 if (warn_cutoff && line < how_many && not_before > 0) {
918 /* Check whether the cutoff line is too early */
920 r = sd_id128_get_boot(&boot_id);
924 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
928 if (r > 0 && not_before < cutoff)
929 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
934 if (!(flags & OUTPUT_FOLLOW))
937 r = sd_journal_wait(j, (usec_t) -1);
947 int add_matches_for_unit(sd_journal *j, const char *unit) {
949 char *m1, *m2, *m3, *m4;
954 m1 = strappenda("_SYSTEMD_UNIT=", unit);
955 m2 = strappenda("COREDUMP_UNIT=", unit);
956 m3 = strappenda("UNIT=", unit);
957 m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit);
960 /* Look for messages from the service itself */
961 (r = sd_journal_add_match(j, m1, 0)) ||
963 /* Look for coredumps of the service */
964 (r = sd_journal_add_disjunction(j)) ||
965 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
966 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
967 (r = sd_journal_add_match(j, m2, 0)) ||
969 /* Look for messages from PID 1 about this service */
970 (r = sd_journal_add_disjunction(j)) ||
971 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
972 (r = sd_journal_add_match(j, m3, 0)) ||
974 /* Look for messages from authorized daemons about this service */
975 (r = sd_journal_add_disjunction(j)) ||
976 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
977 (r = sd_journal_add_match(j, m4, 0))
983 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
985 char *m1, *m2, *m3, *m4;
986 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
991 m1 = strappenda("_SYSTEMD_USER_UNIT=", unit);
992 m2 = strappenda("USER_UNIT=", unit);
993 m3 = strappenda("COREDUMP_USER_UNIT=", unit);
994 m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit);
995 sprintf(muid, "_UID=%lu", (unsigned long) uid);
998 /* Look for messages from the user service itself */
999 (r = sd_journal_add_match(j, m1, 0)) ||
1000 (r = sd_journal_add_match(j, muid, 0)) ||
1002 /* Look for messages from systemd about this service */
1003 (r = sd_journal_add_disjunction(j)) ||
1004 (r = sd_journal_add_match(j, m2, 0)) ||
1005 (r = sd_journal_add_match(j, muid, 0)) ||
1007 /* Look for coredumps of the service */
1008 (r = sd_journal_add_disjunction(j)) ||
1009 (r = sd_journal_add_match(j, m3, 0)) ||
1010 (r = sd_journal_add_match(j, muid, 0)) ||
1011 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1013 /* Look for messages from authorized daemons about this service */
1014 (r = sd_journal_add_disjunction(j)) ||
1015 (r = sd_journal_add_match(j, m4, 0)) ||
1016 (r = sd_journal_add_match(j, muid, 0)) ||
1017 (r = sd_journal_add_match(j, "_UID=0", 0))
1022 int add_match_this_boot(sd_journal *j) {
1023 char match[9+32+1] = "_BOOT_ID=";
1029 r = sd_id128_get_boot(&boot_id);
1031 log_error("Failed to get boot id: %s", strerror(-r));
1035 sd_id128_to_string(boot_id, match + 9);
1036 r = sd_journal_add_match(j, match, strlen(match));
1038 log_error("Failed to add match: %s", strerror(-r));
1042 r = sd_journal_add_conjunction(j);
1049 int show_journal_by_unit(
1061 _cleanup_journal_close_ sd_journal*j = NULL;
1063 int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM;
1066 assert(mode < _OUTPUT_MODE_MAX);
1072 r = sd_journal_open(&j, jflags);
1076 r = add_match_this_boot(j);
1081 r = add_matches_for_unit(j, unit);
1083 r = add_matches_for_user_unit(j, unit, uid);
1087 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1088 _cleanup_free_ char *filter;
1090 filter = journal_make_match_string(j);
1091 log_debug("Journal filter: %s", filter);
1094 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
1097 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1098 [OUTPUT_SHORT] = "short",
1099 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1100 [OUTPUT_SHORT_ISO] = "short-iso",
1101 [OUTPUT_VERBOSE] = "verbose",
1102 [OUTPUT_EXPORT] = "export",
1103 [OUTPUT_JSON] = "json",
1104 [OUTPUT_JSON_PRETTY] = "json-pretty",
1105 [OUTPUT_JSON_SSE] = "json-sse",
1106 [OUTPUT_CAT] = "cat"
1109 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);