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, int 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) || (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 SD_JOURNAL_FOREACH_DATA(j, data, length) {
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);
224 if (!(flags & OUTPUT_SHOW_ALL))
225 strip_tab_ansi(&message, &message_len);
227 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
230 if (mode == OUTPUT_SHORT_MONOTONIC) {
237 r = safe_atou64(monotonic, &t);
240 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
243 log_error("Failed to get monotonic: %s", strerror(-r));
247 fprintf(f, "[%5llu.%06llu]",
248 (unsigned long long) (t / USEC_PER_SEC),
249 (unsigned long long) (t % USEC_PER_SEC));
251 n += 1 + 5 + 1 + 6 + 1;
262 r = safe_atou64(realtime, &x);
265 r = sd_journal_get_realtime_usec(j, &x);
268 log_error("Failed to get realtime: %s", strerror(-r));
272 t = (time_t) (x / USEC_PER_SEC);
273 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
274 log_error("Failed to format time.");
282 if (hostname && shall_print(hostname, hostname_len, flags)) {
283 fprintf(f, " %.*s", (int) hostname_len, hostname);
284 n += hostname_len + 1;
287 if (identifier && shall_print(identifier, identifier_len, flags)) {
288 fprintf(f, " %.*s", (int) identifier_len, identifier);
289 n += identifier_len + 1;
290 } else if (comm && shall_print(comm, comm_len, flags)) {
291 fprintf(f, " %.*s", (int) comm_len, comm);
296 if (pid && shall_print(pid, pid_len, flags)) {
297 fprintf(f, "[%.*s]", (int) pid_len, pid);
299 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
300 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
301 n += fake_pid_len + 2;
304 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
305 char bytes[FORMAT_BYTES_MAX];
306 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
309 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
312 if (flags & OUTPUT_CATALOG)
318 static int output_verbose(
327 _cleanup_free_ char *cursor = NULL;
329 char ts[FORMAT_TIMESTAMP_MAX];
335 sd_journal_set_data_threshold(j, 0);
337 r = sd_journal_get_realtime_usec(j, &realtime);
339 log_error("Failed to get realtime timestamp: %s", strerror(-r));
343 r = sd_journal_get_cursor(j, &cursor);
345 log_error("Failed to get cursor: %s", strerror(-r));
349 fprintf(f, "%s [%s]\n",
350 format_timestamp(ts, sizeof(ts), realtime),
353 SD_JOURNAL_FOREACH_DATA(j, data, length) {
356 c = memchr(data, '=', length);
358 log_error("Invalid field.");
361 fieldlen = c - (const char*) data;
363 if ((flags & OUTPUT_SHOW_ALL) || (length < PRINT_THRESHOLD && utf8_is_printable(data, length))) {
364 fprintf(f, " %.*s=", fieldlen, (const char*)data);
365 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
367 char bytes[FORMAT_BYTES_MAX];
369 fprintf(f, " %.*s=[%s blob data]\n",
370 (int) (c - (const char*) data),
372 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
376 if (flags & OUTPUT_CATALOG)
382 static int output_export(
392 usec_t realtime, monotonic;
393 _cleanup_free_ char *cursor = NULL;
399 sd_journal_set_data_threshold(j, 0);
401 r = sd_journal_get_realtime_usec(j, &realtime);
403 log_error("Failed to get realtime timestamp: %s", strerror(-r));
407 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
409 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
413 r = sd_journal_get_cursor(j, &cursor);
415 log_error("Failed to get cursor: %s", strerror(-r));
421 "__REALTIME_TIMESTAMP=%llu\n"
422 "__MONOTONIC_TIMESTAMP=%llu\n"
425 (unsigned long long) realtime,
426 (unsigned long long) monotonic,
427 sd_id128_to_string(boot_id, sid));
429 SD_JOURNAL_FOREACH_DATA(j, data, length) {
431 /* We already printed the boot id, from the data in
432 * the header, hence let's suppress it here */
434 memcmp(data, "_BOOT_ID=", 9) == 0)
437 if (!utf8_is_printable(data, length)) {
441 c = memchr(data, '=', length);
443 log_error("Invalid field.");
447 fwrite(data, c - (const char*) data, 1, f);
449 le64 = htole64(length - (c - (const char*) data) - 1);
450 fwrite(&le64, sizeof(le64), 1, f);
451 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
453 fwrite(data, length, 1, f);
472 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
476 else if (!utf8_is_printable(p, l)) {
477 bool not_first = false;
483 fprintf(f, ", %u", (uint8_t) *p);
486 fprintf(f, "%u", (uint8_t) *p);
498 if (*p == '"' || *p == '\\') {
501 } else if (*p == '\n')
504 fprintf(f, "\\u%04x", *p);
516 static int output_json(
523 uint64_t realtime, monotonic;
524 _cleanup_free_ char *cursor = NULL;
531 bool done, separator;
535 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
537 r = sd_journal_get_realtime_usec(j, &realtime);
539 log_error("Failed to get realtime timestamp: %s", strerror(-r));
543 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
545 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
549 r = sd_journal_get_cursor(j, &cursor);
551 log_error("Failed to get cursor: %s", strerror(-r));
555 if (mode == OUTPUT_JSON_PRETTY)
558 "\t\"__CURSOR\" : \"%s\",\n"
559 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
560 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
561 "\t\"_BOOT_ID\" : \"%s\"",
563 (unsigned long long) realtime,
564 (unsigned long long) monotonic,
565 sd_id128_to_string(boot_id, sid));
567 if (mode == OUTPUT_JSON_SSE)
571 "{ \"__CURSOR\" : \"%s\", "
572 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
573 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
574 "\"_BOOT_ID\" : \"%s\"",
576 (unsigned long long) realtime,
577 (unsigned long long) monotonic,
578 sd_id128_to_string(boot_id, sid));
581 h = hashmap_new(string_hash_func, string_compare_func);
585 /* First round, iterate through the entry and count how often each field appears */
586 SD_JOURNAL_FOREACH_DATA(j, data, length) {
592 memcmp(data, "_BOOT_ID=", 9) == 0)
595 eq = memchr(data, '=', length);
599 n = strndup(data, eq - (const char*) data);
605 u = PTR_TO_UINT(hashmap_get(h, n));
607 r = hashmap_put(h, n, UINT_TO_PTR(1));
613 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
624 SD_JOURNAL_FOREACH_DATA(j, data, length) {
630 /* We already printed the boot id, from the data in
631 * the header, hence let's suppress it here */
633 memcmp(data, "_BOOT_ID=", 9) == 0)
636 eq = memchr(data, '=', length);
641 if (mode == OUTPUT_JSON_PRETTY)
647 m = eq - (const char*) data;
649 n = strndup(data, m);
655 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
657 /* We already printed this, let's jump to the next */
663 /* Field only appears once, output it directly */
665 json_escape(f, data, m, flags);
668 json_escape(f, eq + 1, length - m - 1, flags);
670 hashmap_remove(h, n);
679 /* Field appears multiple times, output it as array */
680 json_escape(f, data, m, flags);
682 json_escape(f, eq + 1, length - m - 1, flags);
684 /* Iterate through the end of the list */
686 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
690 if (memcmp(data, n, m) != 0)
693 if (((const char*) data)[m] != '=')
697 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
702 hashmap_remove(h, n);
706 /* Iterate data fields form the beginning */
716 if (mode == OUTPUT_JSON_PRETTY)
718 else if (mode == OUTPUT_JSON_SSE)
726 while ((k = hashmap_steal_first_key(h)))
734 static int output_cat(
748 sd_journal_set_data_threshold(j, 0);
750 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
752 /* An entry without MESSAGE=? */
756 log_error("Failed to get data: %s", strerror(-r));
762 fwrite((const char*) data + 8, 1, l - 8, f);
768 static int (*output_funcs[_OUTPUT_MODE_MAX])(
773 OutputFlags flags) = {
775 [OUTPUT_SHORT] = output_short,
776 [OUTPUT_SHORT_MONOTONIC] = output_short,
777 [OUTPUT_VERBOSE] = output_verbose,
778 [OUTPUT_EXPORT] = output_export,
779 [OUTPUT_JSON] = output_json,
780 [OUTPUT_JSON_PRETTY] = output_json,
781 [OUTPUT_JSON_SSE] = output_json,
782 [OUTPUT_CAT] = output_cat
794 assert(mode < _OUTPUT_MODE_MAX);
797 n_columns = columns();
799 ret = output_funcs[mode](f, j, mode, n_columns, flags);
804 static int show_journal(FILE *f,
814 bool need_seek = false;
815 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
819 assert(mode < _OUTPUT_MODE_MAX);
822 r = sd_journal_seek_tail(j);
826 r = sd_journal_previous_skip(j, how_many);
835 r = sd_journal_next(j);
845 if (not_before > 0) {
846 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
848 /* -ESTALE is returned if the
849 timestamp is not from this boot */
855 if (usec < not_before)
861 r = output_journal(f, j, mode, n_columns, flags);
866 if (warn_cutoff && line < how_many && not_before > 0) {
870 /* Check whether the cutoff line is too early */
872 r = sd_id128_get_boot(&boot_id);
876 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
880 if (r > 0 && not_before < cutoff)
881 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
886 if (!(flags & OUTPUT_FOLLOW))
889 r = sd_journal_wait(j, (usec_t) -1);
899 int add_matches_for_unit(sd_journal *j, const char *unit) {
901 _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL;
906 if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
907 asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
908 asprintf(&m3, "UNIT=%s", unit) < 0)
912 /* Look for messages from the service itself */
913 (r = sd_journal_add_match(j, m1, 0)) ||
915 /* Look for coredumps of the service */
916 (r = sd_journal_add_disjunction(j)) ||
917 (r = sd_journal_add_match(j,
918 "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
919 (r = sd_journal_add_match(j, m2, 0)) ||
921 /* Look for messages from PID 1 about this service */
922 (r = sd_journal_add_disjunction(j)) ||
923 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
924 (r = sd_journal_add_match(j, m3, 0))
929 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
931 _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL, *m4 = NULL;
936 if (asprintf(&m1, "_SYSTEMD_USER_UNIT=%s", unit) < 0 ||
937 asprintf(&m2, "USER_UNIT=%s", unit) < 0 ||
938 asprintf(&m3, "COREDUMP_USER_UNIT=%s", unit) < 0 ||
939 asprintf(&m4, "_UID=%d", uid) < 0)
943 /* Look for messages from the user service itself */
944 (r = sd_journal_add_match(j, m1, 0)) ||
945 (r = sd_journal_add_match(j, m4, 0)) ||
947 /* Look for messages from systemd about this service */
948 (r = sd_journal_add_disjunction(j)) ||
949 (r = sd_journal_add_match(j, m2, 0)) ||
950 (r = sd_journal_add_match(j, m4, 0)) ||
952 /* Look for coredumps of the service */
953 (r = sd_journal_add_disjunction(j)) ||
954 (r = sd_journal_add_match(j, m3, 0)) ||
955 (r = sd_journal_add_match(j, m4, 0))
960 int add_match_this_boot(sd_journal *j) {
961 char match[9+32+1] = "_BOOT_ID=";
967 r = sd_id128_get_boot(&boot_id);
969 log_error("Failed to get boot id: %s", strerror(-r));
973 sd_id128_to_string(boot_id, match + 9);
974 r = sd_journal_add_match(j, match, strlen(match));
976 log_error("Failed to add match: %s", strerror(-r));
980 r = sd_journal_add_conjunction(j);
987 int show_journal_by_unit(
998 _cleanup_journal_close_ sd_journal*j = NULL;
1000 int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM_ONLY;
1003 assert(mode < _OUTPUT_MODE_MAX);
1009 r = sd_journal_open(&j, jflags);
1013 r = add_match_this_boot(j);
1018 r = add_matches_for_unit(j, unit);
1020 r = add_matches_for_user_unit(j, unit, uid);
1024 log_debug("Journal filter: %s", journal_make_match_string(j));
1026 r = show_journal(f, j, mode, n_columns, not_before, how_many, flags);
1033 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1034 [OUTPUT_SHORT] = "short",
1035 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1036 [OUTPUT_VERBOSE] = "verbose",
1037 [OUTPUT_EXPORT] = "export",
1038 [OUTPUT_JSON] = "json",
1039 [OUTPUT_JSON_PRETTY] = "json-pretty",
1040 [OUTPUT_JSON_SSE] = "json-sse",
1041 [OUTPUT_CAT] = "cat"
1044 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);