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 (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
277 log_error("Failed to format time.");
285 if (hostname && shall_print(hostname, hostname_len, flags)) {
286 fprintf(f, " %.*s", (int) hostname_len, hostname);
287 n += hostname_len + 1;
290 if (identifier && shall_print(identifier, identifier_len, flags)) {
291 fprintf(f, " %.*s", (int) identifier_len, identifier);
292 n += identifier_len + 1;
293 } else if (comm && shall_print(comm, comm_len, flags)) {
294 fprintf(f, " %.*s", (int) comm_len, comm);
299 if (pid && shall_print(pid, pid_len, flags)) {
300 fprintf(f, "[%.*s]", (int) pid_len, pid);
302 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
303 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
304 n += fake_pid_len + 2;
307 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
308 char bytes[FORMAT_BYTES_MAX];
309 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
312 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
315 if (flags & OUTPUT_CATALOG)
321 static int output_verbose(
330 _cleanup_free_ char *cursor = NULL;
332 char ts[FORMAT_TIMESTAMP_MAX];
338 sd_journal_set_data_threshold(j, 0);
340 r = sd_journal_get_realtime_usec(j, &realtime);
342 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
343 "Failed to get realtime timestamp: %s", strerror(-r));
347 r = sd_journal_get_cursor(j, &cursor);
349 log_error("Failed to get cursor: %s", strerror(-r));
353 fprintf(f, "%s [%s]\n",
354 format_timestamp(ts, sizeof(ts), realtime),
357 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
360 const char *on = "", *off = "";
362 c = memchr(data, '=', length);
364 log_error("Invalid field.");
367 fieldlen = c - (const char*) data;
369 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
370 on = ANSI_HIGHLIGHT_ON;
371 off = ANSI_HIGHLIGHT_OFF;
374 if (flags & OUTPUT_SHOW_ALL ||
375 (((length < PRINT_THRESHOLD) || flags & OUTPUT_FULL_WIDTH) && utf8_is_printable(data, length))) {
376 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
377 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
380 char bytes[FORMAT_BYTES_MAX];
382 fprintf(f, " %s%.*s=[%s blob data]%s\n",
384 (int) (c - (const char*) data),
386 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
394 if (flags & OUTPUT_CATALOG)
400 static int output_export(
410 usec_t realtime, monotonic;
411 _cleanup_free_ char *cursor = NULL;
417 sd_journal_set_data_threshold(j, 0);
419 r = sd_journal_get_realtime_usec(j, &realtime);
421 log_error("Failed to get realtime timestamp: %s", strerror(-r));
425 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
427 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
431 r = sd_journal_get_cursor(j, &cursor);
433 log_error("Failed to get cursor: %s", strerror(-r));
439 "__REALTIME_TIMESTAMP=%llu\n"
440 "__MONOTONIC_TIMESTAMP=%llu\n"
443 (unsigned long long) realtime,
444 (unsigned long long) monotonic,
445 sd_id128_to_string(boot_id, sid));
447 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
449 /* We already printed the boot id, from the data in
450 * the header, hence let's suppress it here */
452 hasprefix(data, "_BOOT_ID="))
455 if (!utf8_is_printable(data, length)) {
459 c = memchr(data, '=', length);
461 log_error("Invalid field.");
465 fwrite(data, c - (const char*) data, 1, f);
467 le64 = htole64(length - (c - (const char*) data) - 1);
468 fwrite(&le64, sizeof(le64), 1, f);
469 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
471 fwrite(data, length, 1, f);
493 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
497 else if (!utf8_is_printable(p, l)) {
498 bool not_first = false;
504 fprintf(f, ", %u", (uint8_t) *p);
507 fprintf(f, "%u", (uint8_t) *p);
519 if (*p == '"' || *p == '\\') {
522 } else if (*p == '\n')
525 fprintf(f, "\\u%04x", *p);
537 static int output_json(
544 uint64_t realtime, monotonic;
545 _cleanup_free_ char *cursor = NULL;
552 bool done, separator;
556 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
558 r = sd_journal_get_realtime_usec(j, &realtime);
560 log_error("Failed to get realtime timestamp: %s", strerror(-r));
564 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
566 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
570 r = sd_journal_get_cursor(j, &cursor);
572 log_error("Failed to get cursor: %s", strerror(-r));
576 if (mode == OUTPUT_JSON_PRETTY)
579 "\t\"__CURSOR\" : \"%s\",\n"
580 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
581 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
582 "\t\"_BOOT_ID\" : \"%s\"",
584 (unsigned long long) realtime,
585 (unsigned long long) monotonic,
586 sd_id128_to_string(boot_id, sid));
588 if (mode == OUTPUT_JSON_SSE)
592 "{ \"__CURSOR\" : \"%s\", "
593 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
594 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
595 "\"_BOOT_ID\" : \"%s\"",
597 (unsigned long long) realtime,
598 (unsigned long long) monotonic,
599 sd_id128_to_string(boot_id, sid));
602 h = hashmap_new(string_hash_func, string_compare_func);
606 /* First round, iterate through the entry and count how often each field appears */
607 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
613 memcmp(data, "_BOOT_ID=", 9) == 0)
616 eq = memchr(data, '=', length);
620 n = strndup(data, eq - (const char*) data);
626 u = PTR_TO_UINT(hashmap_get(h, n));
628 r = hashmap_put(h, n, UINT_TO_PTR(1));
634 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
648 SD_JOURNAL_FOREACH_DATA(j, data, length) {
654 /* We already printed the boot id, from the data in
655 * the header, hence let's suppress it here */
657 memcmp(data, "_BOOT_ID=", 9) == 0)
660 eq = memchr(data, '=', length);
665 if (mode == OUTPUT_JSON_PRETTY)
671 m = eq - (const char*) data;
673 n = strndup(data, m);
679 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
681 /* We already printed this, let's jump to the next */
687 /* Field only appears once, output it directly */
689 json_escape(f, data, m, flags);
692 json_escape(f, eq + 1, length - m - 1, flags);
694 hashmap_remove(h, n);
703 /* Field appears multiple times, output it as array */
704 json_escape(f, data, m, flags);
706 json_escape(f, eq + 1, length - m - 1, flags);
708 /* Iterate through the end of the list */
710 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
714 if (memcmp(data, n, m) != 0)
717 if (((const char*) data)[m] != '=')
721 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
726 hashmap_remove(h, n);
730 /* Iterate data fields form the beginning */
740 if (mode == OUTPUT_JSON_PRETTY)
742 else if (mode == OUTPUT_JSON_SSE)
750 while ((k = hashmap_steal_first_key(h)))
758 static int output_cat(
772 sd_journal_set_data_threshold(j, 0);
774 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
776 /* An entry without MESSAGE=? */
780 log_error("Failed to get data: %s", strerror(-r));
786 fwrite((const char*) data + 8, 1, l - 8, f);
792 static int (*output_funcs[_OUTPUT_MODE_MAX])(
797 OutputFlags flags) = {
799 [OUTPUT_SHORT] = output_short,
800 [OUTPUT_SHORT_MONOTONIC] = output_short,
801 [OUTPUT_VERBOSE] = output_verbose,
802 [OUTPUT_EXPORT] = output_export,
803 [OUTPUT_JSON] = output_json,
804 [OUTPUT_JSON_PRETTY] = output_json,
805 [OUTPUT_JSON_SSE] = output_json,
806 [OUTPUT_CAT] = output_cat
818 assert(mode < _OUTPUT_MODE_MAX);
821 n_columns = columns();
823 ret = output_funcs[mode](f, j, mode, n_columns, flags);
828 static int show_journal(FILE *f,
838 bool need_seek = false;
839 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
843 assert(mode < _OUTPUT_MODE_MAX);
846 r = sd_journal_seek_tail(j);
850 r = sd_journal_previous_skip(j, how_many);
859 r = sd_journal_next(j);
869 if (not_before > 0) {
870 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
872 /* -ESTALE is returned if the
873 timestamp is not from this boot */
879 if (usec < not_before)
885 r = output_journal(f, j, mode, n_columns, flags);
890 if (warn_cutoff && line < how_many && not_before > 0) {
894 /* Check whether the cutoff line is too early */
896 r = sd_id128_get_boot(&boot_id);
900 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
904 if (r > 0 && not_before < cutoff)
905 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
910 if (!(flags & OUTPUT_FOLLOW))
913 r = sd_journal_wait(j, (usec_t) -1);
923 int add_matches_for_unit(sd_journal *j, const char *unit) {
925 char *m1, *m2, *m3, *m4;
930 m1 = strappenda("_SYSTEMD_UNIT=", unit);
931 m2 = strappenda("COREDUMP_UNIT=", unit);
932 m3 = strappenda("UNIT=", unit);
933 m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit);
936 /* Look for messages from the service itself */
937 (r = sd_journal_add_match(j, m1, 0)) ||
939 /* Look for coredumps of the service */
940 (r = sd_journal_add_disjunction(j)) ||
941 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
942 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
943 (r = sd_journal_add_match(j, m2, 0)) ||
945 /* Look for messages from PID 1 about this service */
946 (r = sd_journal_add_disjunction(j)) ||
947 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
948 (r = sd_journal_add_match(j, m3, 0)) ||
950 /* Look for messages from authorized daemons about this service */
951 (r = sd_journal_add_disjunction(j)) ||
952 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
953 (r = sd_journal_add_match(j, m4, 0))
959 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
961 char *m1, *m2, *m3, *m4;
962 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
967 m1 = strappenda("_SYSTEMD_USER_UNIT=", unit);
968 m2 = strappenda("USER_UNIT=", unit);
969 m3 = strappenda("COREDUMP_USER_UNIT=", unit);
970 m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit);
971 sprintf(muid, "_UID=%lu", (unsigned long) uid);
974 /* Look for messages from the user service itself */
975 (r = sd_journal_add_match(j, m1, 0)) ||
976 (r = sd_journal_add_match(j, muid, 0)) ||
978 /* Look for messages from systemd about this service */
979 (r = sd_journal_add_disjunction(j)) ||
980 (r = sd_journal_add_match(j, m2, 0)) ||
981 (r = sd_journal_add_match(j, muid, 0)) ||
983 /* Look for coredumps of the service */
984 (r = sd_journal_add_disjunction(j)) ||
985 (r = sd_journal_add_match(j, m3, 0)) ||
986 (r = sd_journal_add_match(j, muid, 0)) ||
987 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
989 /* Look for messages from authorized daemons about this service */
990 (r = sd_journal_add_disjunction(j)) ||
991 (r = sd_journal_add_match(j, m4, 0)) ||
992 (r = sd_journal_add_match(j, muid, 0)) ||
993 (r = sd_journal_add_match(j, "_UID=0", 0))
998 int add_match_this_boot(sd_journal *j) {
999 char match[9+32+1] = "_BOOT_ID=";
1005 r = sd_id128_get_boot(&boot_id);
1007 log_error("Failed to get boot id: %s", strerror(-r));
1011 sd_id128_to_string(boot_id, match + 9);
1012 r = sd_journal_add_match(j, match, strlen(match));
1014 log_error("Failed to add match: %s", strerror(-r));
1018 r = sd_journal_add_conjunction(j);
1025 int show_journal_by_unit(
1036 _cleanup_journal_close_ sd_journal*j = NULL;
1038 int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM;
1041 assert(mode < _OUTPUT_MODE_MAX);
1047 r = sd_journal_open(&j, jflags);
1051 r = add_match_this_boot(j);
1056 r = add_matches_for_unit(j, unit);
1058 r = add_matches_for_user_unit(j, unit, uid);
1062 log_debug("Journal filter: %s", journal_make_match_string(j));
1064 r = show_journal(f, j, mode, n_columns, not_before, how_many, flags);
1071 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1072 [OUTPUT_SHORT] = "short",
1073 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1074 [OUTPUT_VERBOSE] = "verbose",
1075 [OUTPUT_EXPORT] = "export",
1076 [OUTPUT_JSON] = "json",
1077 [OUTPUT_JSON_PRETTY] = "json-pretty",
1078 [OUTPUT_JSON_SSE] = "json-sse",
1079 [OUTPUT_CAT] = "cat"
1082 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);