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_FOREACH_DATA(j, data, length) {
124 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
130 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
136 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
142 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
148 r = parse_field(data, length, "_PID=", &pid, &pid_len);
154 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
160 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
166 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
172 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
180 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
183 if (mode == OUTPUT_SHORT_MONOTONIC) {
190 r = safe_atou64(monotonic, &t);
193 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
196 log_error("Failed to get monotonic: %s", strerror(-r));
200 fprintf(f, "[%5llu.%06llu]",
201 (unsigned long long) (t / USEC_PER_SEC),
202 (unsigned long long) (t % USEC_PER_SEC));
204 n += 1 + 5 + 1 + 6 + 1;
215 r = safe_atou64(realtime, &x);
218 r = sd_journal_get_realtime_usec(j, &x);
221 log_error("Failed to get realtime: %s", strerror(-r));
225 t = (time_t) (x / USEC_PER_SEC);
226 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
227 log_error("Failed to format time.");
235 if (hostname && shall_print(hostname, hostname_len, flags)) {
236 fprintf(f, " %.*s", (int) hostname_len, hostname);
237 n += hostname_len + 1;
240 if (identifier && shall_print(identifier, identifier_len, flags)) {
241 fprintf(f, " %.*s", (int) identifier_len, identifier);
242 n += identifier_len + 1;
243 } else if (comm && shall_print(comm, comm_len, flags)) {
244 fprintf(f, " %.*s", (int) comm_len, comm);
249 if (pid && shall_print(pid, pid_len, flags)) {
250 fprintf(f, "[%.*s]", (int) pid_len, pid);
252 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
253 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
254 n += fake_pid_len + 2;
257 if (flags & OUTPUT_COLOR) {
259 color_on = ANSI_HIGHLIGHT_RED_ON;
260 color_off = ANSI_HIGHLIGHT_OFF;
261 } else if (p <= LOG_NOTICE) {
262 color_on = ANSI_HIGHLIGHT_ON;
263 color_off = ANSI_HIGHLIGHT_OFF;
267 if (flags & OUTPUT_SHOW_ALL)
268 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
269 else if (!utf8_is_printable_n(message, message_len)) {
270 char bytes[FORMAT_BYTES_MAX];
271 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
272 } else if ((flags & OUTPUT_FULL_WIDTH) || (message_len + n + 1 < n_columns))
273 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
274 else if (n < n_columns && n_columns - n - 2 >= 3) {
277 e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
280 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
282 fprintf(f, ": %s%s%s\n", color_on, e, color_off);
288 if (flags & OUTPUT_CATALOG)
294 static int output_verbose(
305 char ts[FORMAT_TIMESTAMP_MAX];
311 r = sd_journal_get_realtime_usec(j, &realtime);
313 log_error("Failed to get realtime timestamp: %s", strerror(-r));
317 r = sd_journal_get_cursor(j, &cursor);
319 log_error("Failed to get cursor: %s", strerror(-r));
323 fprintf(f, "%s [%s]\n",
324 format_timestamp(ts, sizeof(ts), realtime),
329 SD_JOURNAL_FOREACH_DATA(j, data, length) {
330 if (!shall_print(data, length, flags)) {
332 char bytes[FORMAT_BYTES_MAX];
334 c = memchr(data, '=', length);
336 log_error("Invalid field.");
340 fprintf(f, "\t%.*s=[%s blob data]\n",
341 (int) (c - (const char*) data),
343 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
345 fprintf(f, "\t%.*s\n", (int) length, (const char*) data);
348 if (flags & OUTPUT_CATALOG)
354 static int output_export(
364 usec_t realtime, monotonic;
371 r = sd_journal_get_realtime_usec(j, &realtime);
373 log_error("Failed to get realtime timestamp: %s", strerror(-r));
377 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
379 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
383 r = sd_journal_get_cursor(j, &cursor);
385 log_error("Failed to get cursor: %s", strerror(-r));
391 "__REALTIME_TIMESTAMP=%llu\n"
392 "__MONOTONIC_TIMESTAMP=%llu\n"
395 (unsigned long long) realtime,
396 (unsigned long long) monotonic,
397 sd_id128_to_string(boot_id, sid));
401 SD_JOURNAL_FOREACH_DATA(j, data, length) {
403 /* We already printed the boot id, from the data in
404 * the header, hence let's suppress it here */
406 memcmp(data, "_BOOT_ID=", 9) == 0)
409 if (!utf8_is_printable_n(data, length)) {
413 c = memchr(data, '=', length);
415 log_error("Invalid field.");
419 fwrite(data, c - (const char*) data, 1, f);
421 le64 = htole64(length - (c - (const char*) data) - 1);
422 fwrite(&le64, sizeof(le64), 1, f);
423 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
425 fwrite(data, length, 1, f);
444 if (!(flags & OUTPUT_SHOW_ALL) && l > JSON_THRESHOLD)
448 else if (!utf8_is_printable_n(p, l)) {
449 bool not_first = false;
455 fprintf(f, ", %u", (uint8_t) *p);
458 fprintf(f, "%u", (uint8_t) *p);
470 if (*p == '"' || *p == '\\') {
474 fprintf(f, "\\u%04x", *p);
486 static int output_json(
493 uint64_t realtime, monotonic;
501 bool done, separator;
505 r = sd_journal_get_realtime_usec(j, &realtime);
507 log_error("Failed to get realtime timestamp: %s", strerror(-r));
511 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
513 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
517 r = sd_journal_get_cursor(j, &cursor);
519 log_error("Failed to get cursor: %s", strerror(-r));
523 if (mode == OUTPUT_JSON_PRETTY)
526 "\t\"__CURSOR\" : \"%s\",\n"
527 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
528 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
529 "\t\"_BOOT_ID\" : \"%s\"",
531 (unsigned long long) realtime,
532 (unsigned long long) monotonic,
533 sd_id128_to_string(boot_id, sid));
535 if (mode == OUTPUT_JSON_SSE)
539 "{ \"__CURSOR\" : \"%s\", "
540 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
541 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
542 "\"_BOOT_ID\" : \"%s\"",
544 (unsigned long long) realtime,
545 (unsigned long long) monotonic,
546 sd_id128_to_string(boot_id, sid));
550 h = hashmap_new(string_hash_func, string_compare_func);
554 /* First round, iterate through the entry and count how often each field appears */
555 SD_JOURNAL_FOREACH_DATA(j, data, length) {
561 memcmp(data, "_BOOT_ID=", 9) == 0)
564 eq = memchr(data, '=', length);
568 n = strndup(data, eq - (const char*) data);
574 u = PTR_TO_UINT(hashmap_get(h, n));
576 r = hashmap_put(h, n, UINT_TO_PTR(1));
582 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
593 SD_JOURNAL_FOREACH_DATA(j, data, length) {
599 /* We already printed the boot id, from the data in
600 * the header, hence let's suppress it here */
602 memcmp(data, "_BOOT_ID=", 9) == 0)
605 eq = memchr(data, '=', length);
610 if (mode == OUTPUT_JSON_PRETTY)
616 m = eq - (const char*) data;
618 n = strndup(data, m);
624 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
626 /* We already printed this, let's jump to the next */
632 /* Field only appears once, output it directly */
634 json_escape(f, data, m, flags);
637 json_escape(f, eq + 1, length - m - 1, flags);
639 hashmap_remove(h, n);
648 /* Field appears multiple times, output it as array */
649 json_escape(f, data, m, flags);
651 json_escape(f, eq + 1, length - m - 1, flags);
653 /* Iterate through the end of the list */
655 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
659 if (memcmp(data, n, m) != 0)
662 if (((const char*) data)[m] != '=')
666 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
671 hashmap_remove(h, n);
675 /* Iterate data fields form the beginning */
685 if (mode == OUTPUT_JSON_PRETTY)
687 else if (mode == OUTPUT_JSON_SSE)
695 while ((k = hashmap_steal_first_key(h)))
703 static int output_cat(
717 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
719 /* An entry without MESSAGE=? */
723 log_error("Failed to get data: %s", strerror(-r));
729 fwrite((const char*) data + 8, 1, l - 8, f);
735 static int (*output_funcs[_OUTPUT_MODE_MAX])(
740 OutputFlags flags) = {
742 [OUTPUT_SHORT] = output_short,
743 [OUTPUT_SHORT_MONOTONIC] = output_short,
744 [OUTPUT_VERBOSE] = output_verbose,
745 [OUTPUT_EXPORT] = output_export,
746 [OUTPUT_JSON] = output_json,
747 [OUTPUT_JSON_PRETTY] = output_json,
748 [OUTPUT_JSON_SSE] = output_json,
749 [OUTPUT_CAT] = output_cat
761 assert(mode < _OUTPUT_MODE_MAX);
764 n_columns = columns();
766 ret = output_funcs[mode](f, j, mode, n_columns, flags);
771 int show_journal_by_unit(
780 _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL;
781 sd_journal *j = NULL;
784 bool need_seek = false;
785 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
788 assert(mode < _OUTPUT_MODE_MAX);
791 if (!endswith(unit, ".service") &&
792 !endswith(unit, ".socket") &&
793 !endswith(unit, ".mount") &&
794 !endswith(unit, ".swap"))
800 if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
801 asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
802 asprintf(&m3, "UNIT=%s", unit) < 0) {
807 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
811 /* Look for messages from the service itself */
812 r = sd_journal_add_match(j, m1, 0);
816 /* Look for coredumps of the service */
817 r = sd_journal_add_disjunction(j);
820 r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0);
823 r = sd_journal_add_match(j, m2, 0);
827 /* Look for messages from PID 1 about this service */
828 r = sd_journal_add_disjunction(j);
831 r = sd_journal_add_match(j, "_PID=1", 0);
834 r = sd_journal_add_match(j, m3, 0);
839 r = sd_journal_seek_tail(j);
843 r = sd_journal_previous_skip(j, how_many);
852 r = sd_journal_next(j);
862 if (not_before > 0) {
863 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
865 /* -ESTALE is returned if the
866 timestamp is not from this boot */
872 if (usec < not_before)
878 r = output_journal(f, j, mode, n_columns, flags);
883 if (warn_cutoff && line < how_many && not_before > 0) {
887 /* Check whether the cutoff line is too early */
889 r = sd_id128_get_boot(&boot_id);
893 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
897 if (r > 0 && not_before < cutoff)
898 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
903 if (!(flags & OUTPUT_FOLLOW))
906 r = sd_journal_wait(j, (usec_t) -1);
919 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
920 [OUTPUT_SHORT] = "short",
921 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
922 [OUTPUT_VERBOSE] = "verbose",
923 [OUTPUT_EXPORT] = "export",
924 [OUTPUT_JSON] = "json",
925 [OUTPUT_JSON_PRETTY] = "json-pretty",
926 [OUTPUT_JSON_SSE] = "json-sse",
930 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);