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"
34 #define PRINT_THRESHOLD 128
35 #define JSON_THRESHOLD 4096
37 static int print_catalog(FILE *f, sd_journal *j) {
39 _cleanup_free_ char *t = NULL, *z = NULL;
42 r = sd_journal_get_catalog(j, &t);
46 z = strreplace(strstrip(t), "\n", "\n-- ");
57 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
70 if (memcmp(data, field, fl))
78 memcpy(buf, (const char*) data + fl, nl);
88 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
91 if (flags & OUTPUT_SHOW_ALL)
94 if (l >= PRINT_THRESHOLD)
97 if (!utf8_is_printable_n(p, l))
103 static int output_short(
114 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
115 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;
117 const char *color_on = "", *color_off = "";
122 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : PRINT_THRESHOLD);
124 SD_JOURNAL_FOREACH_DATA(j, data, length) {
126 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
132 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
138 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
144 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
150 r = parse_field(data, length, "_PID=", &pid, &pid_len);
156 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
162 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
168 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
174 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
182 if (!(flags & OUTPUT_SHOW_ALL))
183 strip_tab_ansi(&message, &message_len);
185 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
188 if (mode == OUTPUT_SHORT_MONOTONIC) {
195 r = safe_atou64(monotonic, &t);
198 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
201 log_error("Failed to get monotonic: %s", strerror(-r));
205 fprintf(f, "[%5llu.%06llu]",
206 (unsigned long long) (t / USEC_PER_SEC),
207 (unsigned long long) (t % USEC_PER_SEC));
209 n += 1 + 5 + 1 + 6 + 1;
220 r = safe_atou64(realtime, &x);
223 r = sd_journal_get_realtime_usec(j, &x);
226 log_error("Failed to get realtime: %s", strerror(-r));
230 t = (time_t) (x / USEC_PER_SEC);
231 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
232 log_error("Failed to format time.");
240 if (hostname && shall_print(hostname, hostname_len, flags)) {
241 fprintf(f, " %.*s", (int) hostname_len, hostname);
242 n += hostname_len + 1;
245 if (identifier && shall_print(identifier, identifier_len, flags)) {
246 fprintf(f, " %.*s", (int) identifier_len, identifier);
247 n += identifier_len + 1;
248 } else if (comm && shall_print(comm, comm_len, flags)) {
249 fprintf(f, " %.*s", (int) comm_len, comm);
254 if (pid && shall_print(pid, pid_len, flags)) {
255 fprintf(f, "[%.*s]", (int) pid_len, pid);
257 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
258 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
259 n += fake_pid_len + 2;
262 if (flags & OUTPUT_COLOR) {
264 color_on = ANSI_HIGHLIGHT_RED_ON;
265 color_off = ANSI_HIGHLIGHT_OFF;
266 } else if (p <= LOG_NOTICE) {
267 color_on = ANSI_HIGHLIGHT_ON;
268 color_off = ANSI_HIGHLIGHT_OFF;
272 if (flags & OUTPUT_SHOW_ALL)
273 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
274 else if (!utf8_is_printable_n(message, message_len)) {
275 char bytes[FORMAT_BYTES_MAX];
276 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
277 } else if ((flags & OUTPUT_FULL_WIDTH) || (message_len + n + 1 < n_columns))
278 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
279 else if (n < n_columns && n_columns - n - 2 >= 3) {
282 e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
285 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
287 fprintf(f, ": %s%s%s\n", color_on, e, color_off);
293 if (flags & OUTPUT_CATALOG)
299 static int output_verbose(
310 char ts[FORMAT_TIMESTAMP_MAX];
316 sd_journal_set_data_threshold(j, 0);
318 r = sd_journal_get_realtime_usec(j, &realtime);
320 log_error("Failed to get realtime timestamp: %s", strerror(-r));
324 r = sd_journal_get_cursor(j, &cursor);
326 log_error("Failed to get cursor: %s", strerror(-r));
330 fprintf(f, "%s [%s]\n",
331 format_timestamp(ts, sizeof(ts), realtime),
336 SD_JOURNAL_FOREACH_DATA(j, data, length) {
337 if (!shall_print(data, length, flags)) {
339 char bytes[FORMAT_BYTES_MAX];
341 c = memchr(data, '=', length);
343 log_error("Invalid field.");
347 fprintf(f, "\t%.*s=[%s blob data]\n",
348 (int) (c - (const char*) data),
350 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
352 fprintf(f, "\t%.*s\n", (int) length, (const char*) data);
355 if (flags & OUTPUT_CATALOG)
361 static int output_export(
371 usec_t realtime, monotonic;
378 sd_journal_set_data_threshold(j, 0);
380 r = sd_journal_get_realtime_usec(j, &realtime);
382 log_error("Failed to get realtime timestamp: %s", strerror(-r));
386 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
388 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
392 r = sd_journal_get_cursor(j, &cursor);
394 log_error("Failed to get cursor: %s", strerror(-r));
400 "__REALTIME_TIMESTAMP=%llu\n"
401 "__MONOTONIC_TIMESTAMP=%llu\n"
404 (unsigned long long) realtime,
405 (unsigned long long) monotonic,
406 sd_id128_to_string(boot_id, sid));
410 SD_JOURNAL_FOREACH_DATA(j, data, length) {
412 /* We already printed the boot id, from the data in
413 * the header, hence let's suppress it here */
415 memcmp(data, "_BOOT_ID=", 9) == 0)
418 if (!utf8_is_printable_n(data, length)) {
422 c = memchr(data, '=', length);
424 log_error("Invalid field.");
428 fwrite(data, c - (const char*) data, 1, f);
430 le64 = htole64(length - (c - (const char*) data) - 1);
431 fwrite(&le64, sizeof(le64), 1, f);
432 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
434 fwrite(data, length, 1, f);
453 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
457 else if (!utf8_is_printable_n(p, l)) {
458 bool not_first = false;
464 fprintf(f, ", %u", (uint8_t) *p);
467 fprintf(f, "%u", (uint8_t) *p);
479 if (*p == '"' || *p == '\\') {
483 fprintf(f, "\\u%04x", *p);
495 static int output_json(
502 uint64_t realtime, monotonic;
510 bool done, separator;
514 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
516 r = sd_journal_get_realtime_usec(j, &realtime);
518 log_error("Failed to get realtime timestamp: %s", strerror(-r));
522 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
524 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
528 r = sd_journal_get_cursor(j, &cursor);
530 log_error("Failed to get cursor: %s", strerror(-r));
534 if (mode == OUTPUT_JSON_PRETTY)
537 "\t\"__CURSOR\" : \"%s\",\n"
538 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
539 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
540 "\t\"_BOOT_ID\" : \"%s\"",
542 (unsigned long long) realtime,
543 (unsigned long long) monotonic,
544 sd_id128_to_string(boot_id, sid));
546 if (mode == OUTPUT_JSON_SSE)
550 "{ \"__CURSOR\" : \"%s\", "
551 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
552 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
553 "\"_BOOT_ID\" : \"%s\"",
555 (unsigned long long) realtime,
556 (unsigned long long) monotonic,
557 sd_id128_to_string(boot_id, sid));
561 h = hashmap_new(string_hash_func, string_compare_func);
565 /* First round, iterate through the entry and count how often each field appears */
566 SD_JOURNAL_FOREACH_DATA(j, data, length) {
572 memcmp(data, "_BOOT_ID=", 9) == 0)
575 eq = memchr(data, '=', length);
579 n = strndup(data, eq - (const char*) data);
585 u = PTR_TO_UINT(hashmap_get(h, n));
587 r = hashmap_put(h, n, UINT_TO_PTR(1));
593 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
604 SD_JOURNAL_FOREACH_DATA(j, data, length) {
610 /* We already printed the boot id, from the data in
611 * the header, hence let's suppress it here */
613 memcmp(data, "_BOOT_ID=", 9) == 0)
616 eq = memchr(data, '=', length);
621 if (mode == OUTPUT_JSON_PRETTY)
627 m = eq - (const char*) data;
629 n = strndup(data, m);
635 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
637 /* We already printed this, let's jump to the next */
643 /* Field only appears once, output it directly */
645 json_escape(f, data, m, flags);
648 json_escape(f, eq + 1, length - m - 1, flags);
650 hashmap_remove(h, n);
659 /* Field appears multiple times, output it as array */
660 json_escape(f, data, m, flags);
662 json_escape(f, eq + 1, length - m - 1, flags);
664 /* Iterate through the end of the list */
666 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
670 if (memcmp(data, n, m) != 0)
673 if (((const char*) data)[m] != '=')
677 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
682 hashmap_remove(h, n);
686 /* Iterate data fields form the beginning */
696 if (mode == OUTPUT_JSON_PRETTY)
698 else if (mode == OUTPUT_JSON_SSE)
706 while ((k = hashmap_steal_first_key(h)))
714 static int output_cat(
728 sd_journal_set_data_threshold(j, 0);
730 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
732 /* An entry without MESSAGE=? */
736 log_error("Failed to get data: %s", strerror(-r));
742 fwrite((const char*) data + 8, 1, l - 8, f);
748 static int (*output_funcs[_OUTPUT_MODE_MAX])(
753 OutputFlags flags) = {
755 [OUTPUT_SHORT] = output_short,
756 [OUTPUT_SHORT_MONOTONIC] = output_short,
757 [OUTPUT_VERBOSE] = output_verbose,
758 [OUTPUT_EXPORT] = output_export,
759 [OUTPUT_JSON] = output_json,
760 [OUTPUT_JSON_PRETTY] = output_json,
761 [OUTPUT_JSON_SSE] = output_json,
762 [OUTPUT_CAT] = output_cat
774 assert(mode < _OUTPUT_MODE_MAX);
777 n_columns = columns();
779 ret = output_funcs[mode](f, j, mode, n_columns, flags);
784 int show_journal_by_unit(
793 _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL;
794 sd_journal *j = NULL;
797 bool need_seek = false;
798 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
801 assert(mode < _OUTPUT_MODE_MAX);
804 if (!endswith(unit, ".service") &&
805 !endswith(unit, ".socket") &&
806 !endswith(unit, ".mount") &&
807 !endswith(unit, ".swap"))
813 if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
814 asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
815 asprintf(&m3, "UNIT=%s", unit) < 0) {
820 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
824 /* Look for messages from the service itself */
825 r = sd_journal_add_match(j, m1, 0);
829 /* Look for coredumps of the service */
830 r = sd_journal_add_disjunction(j);
833 r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0);
836 r = sd_journal_add_match(j, m2, 0);
840 /* Look for messages from PID 1 about this service */
841 r = sd_journal_add_disjunction(j);
844 r = sd_journal_add_match(j, "_PID=1", 0);
847 r = sd_journal_add_match(j, m3, 0);
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);
932 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
933 [OUTPUT_SHORT] = "short",
934 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
935 [OUTPUT_VERBOSE] = "verbose",
936 [OUTPUT_EXPORT] = "export",
937 [OUTPUT_JSON] = "json",
938 [OUTPUT_JSON_PRETTY] = "json-pretty",
939 [OUTPUT_JSON_SSE] = "json-sse",
943 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);