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 void 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;
109 if (flags & OUTPUT_COLOR) {
110 if (priority <= LOG_ERR) {
111 color_on = ANSI_HIGHLIGHT_RED_ON;
112 color_off = ANSI_HIGHLIGHT_OFF;
113 } else if (priority <= LOG_NOTICE) {
114 color_on = ANSI_HIGHLIGHT_ON;
115 color_off = ANSI_HIGHLIGHT_OFF;
119 for (pos = message; pos < message + message_len; pos = end + 1) {
121 for (end = pos; end < message + message_len && *end != '\n'; end++)
126 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) || prefix + len + 1 < n_columns)
127 fprintf(f, "%*s%s%.*s%s\n",
128 continuation * prefix, "",
129 color_on, len, pos, color_off);
130 else if (prefix < n_columns && n_columns - prefix >= 3) {
131 _cleanup_free_ char *e;
133 e = ellipsize_mem(pos, len, n_columns - prefix, 90);
136 fprintf(f, "%s%.*s%s\n", color_on, len, pos, color_off);
138 fprintf(f, "%s%s%s\n", color_on, e, color_off);
146 static int output_short(
157 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
158 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;
164 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : PRINT_THRESHOLD);
166 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
168 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
174 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
180 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
186 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
192 r = parse_field(data, length, "_PID=", &pid, &pid_len);
198 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
204 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
210 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
216 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
227 if (!(flags & OUTPUT_SHOW_ALL))
228 strip_tab_ansi(&message, &message_len);
230 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
233 if (mode == OUTPUT_SHORT_MONOTONIC) {
240 r = safe_atou64(monotonic, &t);
243 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
246 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
250 fprintf(f, "[%5llu.%06llu]",
251 (unsigned long long) (t / USEC_PER_SEC),
252 (unsigned long long) (t % USEC_PER_SEC));
254 n += 1 + 5 + 1 + 6 + 1;
265 r = safe_atou64(realtime, &x);
268 r = sd_journal_get_realtime_usec(j, &x);
271 log_error("Failed to get realtime timestamp: %s", strerror(-r));
275 t = (time_t) (x / USEC_PER_SEC);
276 if (mode == OUTPUT_SHORT_ISO)
277 r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&t, &tm));
279 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm));
282 log_error("Failed to format time.");
290 if (hostname && shall_print(hostname, hostname_len, flags)) {
291 fprintf(f, " %.*s", (int) hostname_len, hostname);
292 n += hostname_len + 1;
295 if (identifier && shall_print(identifier, identifier_len, flags)) {
296 fprintf(f, " %.*s", (int) identifier_len, identifier);
297 n += identifier_len + 1;
298 } else if (comm && shall_print(comm, comm_len, flags)) {
299 fprintf(f, " %.*s", (int) comm_len, comm);
304 if (pid && shall_print(pid, pid_len, flags)) {
305 fprintf(f, "[%.*s]", (int) pid_len, pid);
307 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
308 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
309 n += fake_pid_len + 2;
312 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
313 char bytes[FORMAT_BYTES_MAX];
314 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
317 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
320 if (flags & OUTPUT_CATALOG)
326 static int output_verbose(
335 _cleanup_free_ char *cursor = NULL;
337 char ts[FORMAT_TIMESTAMP_MAX];
343 sd_journal_set_data_threshold(j, 0);
345 r = sd_journal_get_realtime_usec(j, &realtime);
347 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
348 "Failed to get realtime timestamp: %s", strerror(-r));
352 r = sd_journal_get_cursor(j, &cursor);
354 log_error("Failed to get cursor: %s", strerror(-r));
358 fprintf(f, "%s [%s]\n",
359 format_timestamp(ts, sizeof(ts), realtime),
362 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
365 const char *on = "", *off = "";
367 c = memchr(data, '=', length);
369 log_error("Invalid field.");
372 fieldlen = c - (const char*) data;
374 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
375 on = ANSI_HIGHLIGHT_ON;
376 off = ANSI_HIGHLIGHT_OFF;
379 if (flags & OUTPUT_SHOW_ALL ||
380 (((length < PRINT_THRESHOLD) || flags & OUTPUT_FULL_WIDTH) && utf8_is_printable(data, length))) {
381 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
382 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
385 char bytes[FORMAT_BYTES_MAX];
387 fprintf(f, " %s%.*s=[%s blob data]%s\n",
389 (int) (c - (const char*) data),
391 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
399 if (flags & OUTPUT_CATALOG)
405 static int output_export(
415 usec_t realtime, monotonic;
416 _cleanup_free_ char *cursor = NULL;
422 sd_journal_set_data_threshold(j, 0);
424 r = sd_journal_get_realtime_usec(j, &realtime);
426 log_error("Failed to get realtime timestamp: %s", strerror(-r));
430 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
432 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
436 r = sd_journal_get_cursor(j, &cursor);
438 log_error("Failed to get cursor: %s", strerror(-r));
444 "__REALTIME_TIMESTAMP=%llu\n"
445 "__MONOTONIC_TIMESTAMP=%llu\n"
448 (unsigned long long) realtime,
449 (unsigned long long) monotonic,
450 sd_id128_to_string(boot_id, sid));
452 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
454 /* We already printed the boot id, from the data in
455 * the header, hence let's suppress it here */
457 hasprefix(data, "_BOOT_ID="))
460 if (!utf8_is_printable(data, length)) {
464 c = memchr(data, '=', length);
466 log_error("Invalid field.");
470 fwrite(data, c - (const char*) data, 1, f);
472 le64 = htole64(length - (c - (const char*) data) - 1);
473 fwrite(&le64, sizeof(le64), 1, f);
474 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
476 fwrite(data, length, 1, f);
498 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
502 else if (!utf8_is_printable(p, l)) {
503 bool not_first = false;
509 fprintf(f, ", %u", (uint8_t) *p);
512 fprintf(f, "%u", (uint8_t) *p);
524 if (*p == '"' || *p == '\\') {
527 } else if (*p == '\n')
530 fprintf(f, "\\u%04x", *p);
542 static int output_json(
549 uint64_t realtime, monotonic;
550 _cleanup_free_ char *cursor = NULL;
557 bool done, separator;
561 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
563 r = sd_journal_get_realtime_usec(j, &realtime);
565 log_error("Failed to get realtime timestamp: %s", strerror(-r));
569 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
571 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
575 r = sd_journal_get_cursor(j, &cursor);
577 log_error("Failed to get cursor: %s", strerror(-r));
581 if (mode == OUTPUT_JSON_PRETTY)
584 "\t\"__CURSOR\" : \"%s\",\n"
585 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
586 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
587 "\t\"_BOOT_ID\" : \"%s\"",
589 (unsigned long long) realtime,
590 (unsigned long long) monotonic,
591 sd_id128_to_string(boot_id, sid));
593 if (mode == OUTPUT_JSON_SSE)
597 "{ \"__CURSOR\" : \"%s\", "
598 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
599 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
600 "\"_BOOT_ID\" : \"%s\"",
602 (unsigned long long) realtime,
603 (unsigned long long) monotonic,
604 sd_id128_to_string(boot_id, sid));
607 h = hashmap_new(string_hash_func, string_compare_func);
611 /* First round, iterate through the entry and count how often each field appears */
612 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
618 memcmp(data, "_BOOT_ID=", 9) == 0)
621 eq = memchr(data, '=', length);
625 n = strndup(data, eq - (const char*) data);
631 u = PTR_TO_UINT(hashmap_get(h, n));
633 r = hashmap_put(h, n, UINT_TO_PTR(1));
639 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
653 SD_JOURNAL_FOREACH_DATA(j, data, length) {
659 /* We already printed the boot id, from the data in
660 * the header, hence let's suppress it here */
662 memcmp(data, "_BOOT_ID=", 9) == 0)
665 eq = memchr(data, '=', length);
670 if (mode == OUTPUT_JSON_PRETTY)
676 m = eq - (const char*) data;
678 n = strndup(data, m);
684 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
686 /* We already printed this, let's jump to the next */
692 /* Field only appears once, output it directly */
694 json_escape(f, data, m, flags);
697 json_escape(f, eq + 1, length - m - 1, flags);
699 hashmap_remove(h, n);
708 /* Field appears multiple times, output it as array */
709 json_escape(f, data, m, flags);
711 json_escape(f, eq + 1, length - m - 1, flags);
713 /* Iterate through the end of the list */
715 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
719 if (memcmp(data, n, m) != 0)
722 if (((const char*) data)[m] != '=')
726 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
731 hashmap_remove(h, n);
735 /* Iterate data fields form the beginning */
745 if (mode == OUTPUT_JSON_PRETTY)
747 else if (mode == OUTPUT_JSON_SSE)
755 while ((k = hashmap_steal_first_key(h)))
763 static int output_cat(
777 sd_journal_set_data_threshold(j, 0);
779 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
781 /* An entry without MESSAGE=? */
785 log_error("Failed to get data: %s", strerror(-r));
791 fwrite((const char*) data + 8, 1, l - 8, f);
797 static int (*output_funcs[_OUTPUT_MODE_MAX])(
802 OutputFlags flags) = {
804 [OUTPUT_SHORT] = output_short,
805 [OUTPUT_SHORT_MONOTONIC] = output_short,
806 [OUTPUT_SHORT_ISO] = output_short,
807 [OUTPUT_VERBOSE] = output_verbose,
808 [OUTPUT_EXPORT] = output_export,
809 [OUTPUT_JSON] = output_json,
810 [OUTPUT_JSON_PRETTY] = output_json,
811 [OUTPUT_JSON_SSE] = output_json,
812 [OUTPUT_CAT] = output_cat
824 assert(mode < _OUTPUT_MODE_MAX);
827 n_columns = columns();
829 ret = output_funcs[mode](f, j, mode, n_columns, flags);
834 static int show_journal(FILE *f,
844 bool need_seek = false;
845 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
849 assert(mode < _OUTPUT_MODE_MAX);
852 r = sd_journal_seek_tail(j);
856 r = sd_journal_previous_skip(j, how_many);
865 r = sd_journal_next(j);
875 if (not_before > 0) {
876 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
878 /* -ESTALE is returned if the
879 timestamp is not from this boot */
885 if (usec < not_before)
891 r = output_journal(f, j, mode, n_columns, flags);
896 if (warn_cutoff && line < how_many && not_before > 0) {
900 /* Check whether the cutoff line is too early */
902 r = sd_id128_get_boot(&boot_id);
906 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
910 if (r > 0 && not_before < cutoff)
911 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
916 if (!(flags & OUTPUT_FOLLOW))
919 r = sd_journal_wait(j, (usec_t) -1);
929 int add_matches_for_unit(sd_journal *j, const char *unit) {
931 char *m1, *m2, *m3, *m4;
936 m1 = strappenda("_SYSTEMD_UNIT=", unit);
937 m2 = strappenda("COREDUMP_UNIT=", unit);
938 m3 = strappenda("UNIT=", unit);
939 m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit);
942 /* Look for messages from the service itself */
943 (r = sd_journal_add_match(j, m1, 0)) ||
945 /* Look for coredumps of the service */
946 (r = sd_journal_add_disjunction(j)) ||
947 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
948 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
949 (r = sd_journal_add_match(j, m2, 0)) ||
951 /* Look for messages from PID 1 about this service */
952 (r = sd_journal_add_disjunction(j)) ||
953 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
954 (r = sd_journal_add_match(j, m3, 0)) ||
956 /* Look for messages from authorized daemons about this service */
957 (r = sd_journal_add_disjunction(j)) ||
958 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
959 (r = sd_journal_add_match(j, m4, 0))
965 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
967 char *m1, *m2, *m3, *m4;
968 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
973 m1 = strappenda("_SYSTEMD_USER_UNIT=", unit);
974 m2 = strappenda("USER_UNIT=", unit);
975 m3 = strappenda("COREDUMP_USER_UNIT=", unit);
976 m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit);
977 sprintf(muid, "_UID=%lu", (unsigned long) uid);
980 /* Look for messages from the user service itself */
981 (r = sd_journal_add_match(j, m1, 0)) ||
982 (r = sd_journal_add_match(j, muid, 0)) ||
984 /* Look for messages from systemd about this service */
985 (r = sd_journal_add_disjunction(j)) ||
986 (r = sd_journal_add_match(j, m2, 0)) ||
987 (r = sd_journal_add_match(j, muid, 0)) ||
989 /* Look for coredumps of the service */
990 (r = sd_journal_add_disjunction(j)) ||
991 (r = sd_journal_add_match(j, m3, 0)) ||
992 (r = sd_journal_add_match(j, muid, 0)) ||
993 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
995 /* Look for messages from authorized daemons about this service */
996 (r = sd_journal_add_disjunction(j)) ||
997 (r = sd_journal_add_match(j, m4, 0)) ||
998 (r = sd_journal_add_match(j, muid, 0)) ||
999 (r = sd_journal_add_match(j, "_UID=0", 0))
1004 int add_match_this_boot(sd_journal *j) {
1005 char match[9+32+1] = "_BOOT_ID=";
1011 r = sd_id128_get_boot(&boot_id);
1013 log_error("Failed to get boot id: %s", strerror(-r));
1017 sd_id128_to_string(boot_id, match + 9);
1018 r = sd_journal_add_match(j, match, strlen(match));
1020 log_error("Failed to add match: %s", strerror(-r));
1024 r = sd_journal_add_conjunction(j);
1031 int show_journal_by_unit(
1042 _cleanup_journal_close_ sd_journal*j = NULL;
1044 int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM;
1047 assert(mode < _OUTPUT_MODE_MAX);
1053 r = sd_journal_open(&j, jflags);
1057 r = add_match_this_boot(j);
1062 r = add_matches_for_unit(j, unit);
1064 r = add_matches_for_user_unit(j, unit, uid);
1068 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1069 _cleanup_free_ char *filter;
1071 filter = journal_make_match_string(j);
1072 log_debug("Journal filter: %s", filter);
1075 r = show_journal(f, j, mode, n_columns, not_before, how_many, flags);
1082 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1083 [OUTPUT_SHORT] = "short",
1084 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1085 [OUTPUT_SHORT_ISO] = "short-iso",
1086 [OUTPUT_VERBOSE] = "verbose",
1087 [OUTPUT_EXPORT] = "export",
1088 [OUTPUT_JSON] = "json",
1089 [OUTPUT_JSON_PRETTY] = "json-pretty",
1090 [OUTPUT_JSON_SSE] = "json-sse",
1091 [OUTPUT_CAT] = "cat"
1094 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);