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 (priority_len == 1 && *priority >= '0' && *priority <= '7')
185 if (mode == OUTPUT_SHORT_MONOTONIC) {
192 r = safe_atou64(monotonic, &t);
195 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
198 log_error("Failed to get monotonic: %s", strerror(-r));
202 fprintf(f, "[%5llu.%06llu]",
203 (unsigned long long) (t / USEC_PER_SEC),
204 (unsigned long long) (t % USEC_PER_SEC));
206 n += 1 + 5 + 1 + 6 + 1;
217 r = safe_atou64(realtime, &x);
220 r = sd_journal_get_realtime_usec(j, &x);
223 log_error("Failed to get realtime: %s", strerror(-r));
227 t = (time_t) (x / USEC_PER_SEC);
228 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
229 log_error("Failed to format time.");
237 if (hostname && shall_print(hostname, hostname_len, flags)) {
238 fprintf(f, " %.*s", (int) hostname_len, hostname);
239 n += hostname_len + 1;
242 if (identifier && shall_print(identifier, identifier_len, flags)) {
243 fprintf(f, " %.*s", (int) identifier_len, identifier);
244 n += identifier_len + 1;
245 } else if (comm && shall_print(comm, comm_len, flags)) {
246 fprintf(f, " %.*s", (int) comm_len, comm);
251 if (pid && shall_print(pid, pid_len, flags)) {
252 fprintf(f, "[%.*s]", (int) pid_len, pid);
254 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
255 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
256 n += fake_pid_len + 2;
259 if (flags & OUTPUT_COLOR) {
261 color_on = ANSI_HIGHLIGHT_RED_ON;
262 color_off = ANSI_HIGHLIGHT_OFF;
263 } else if (p <= LOG_NOTICE) {
264 color_on = ANSI_HIGHLIGHT_ON;
265 color_off = ANSI_HIGHLIGHT_OFF;
269 if (flags & OUTPUT_SHOW_ALL)
270 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
271 else if (!utf8_is_printable_n(message, message_len)) {
272 char bytes[FORMAT_BYTES_MAX];
273 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
274 } else if ((flags & OUTPUT_FULL_WIDTH) || (message_len + n + 1 < n_columns))
275 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
276 else if (n < n_columns && n_columns - n - 2 >= 3) {
279 e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
282 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
284 fprintf(f, ": %s%s%s\n", color_on, e, color_off);
290 if (flags & OUTPUT_CATALOG)
296 static int output_verbose(
307 char ts[FORMAT_TIMESTAMP_MAX];
313 sd_journal_set_data_threshold(j, 0);
315 r = sd_journal_get_realtime_usec(j, &realtime);
317 log_error("Failed to get realtime timestamp: %s", strerror(-r));
321 r = sd_journal_get_cursor(j, &cursor);
323 log_error("Failed to get cursor: %s", strerror(-r));
327 fprintf(f, "%s [%s]\n",
328 format_timestamp(ts, sizeof(ts), realtime),
333 SD_JOURNAL_FOREACH_DATA(j, data, length) {
334 if (!shall_print(data, length, flags)) {
336 char bytes[FORMAT_BYTES_MAX];
338 c = memchr(data, '=', length);
340 log_error("Invalid field.");
344 fprintf(f, "\t%.*s=[%s blob data]\n",
345 (int) (c - (const char*) data),
347 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
349 fprintf(f, "\t%.*s\n", (int) length, (const char*) data);
352 if (flags & OUTPUT_CATALOG)
358 static int output_export(
368 usec_t realtime, monotonic;
375 sd_journal_set_data_threshold(j, 0);
377 r = sd_journal_get_realtime_usec(j, &realtime);
379 log_error("Failed to get realtime timestamp: %s", strerror(-r));
383 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
385 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
389 r = sd_journal_get_cursor(j, &cursor);
391 log_error("Failed to get cursor: %s", strerror(-r));
397 "__REALTIME_TIMESTAMP=%llu\n"
398 "__MONOTONIC_TIMESTAMP=%llu\n"
401 (unsigned long long) realtime,
402 (unsigned long long) monotonic,
403 sd_id128_to_string(boot_id, sid));
407 SD_JOURNAL_FOREACH_DATA(j, data, length) {
409 /* We already printed the boot id, from the data in
410 * the header, hence let's suppress it here */
412 memcmp(data, "_BOOT_ID=", 9) == 0)
415 if (!utf8_is_printable_n(data, length)) {
419 c = memchr(data, '=', length);
421 log_error("Invalid field.");
425 fwrite(data, c - (const char*) data, 1, f);
427 le64 = htole64(length - (c - (const char*) data) - 1);
428 fwrite(&le64, sizeof(le64), 1, f);
429 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
431 fwrite(data, length, 1, f);
450 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
454 else if (!utf8_is_printable_n(p, l)) {
455 bool not_first = false;
461 fprintf(f, ", %u", (uint8_t) *p);
464 fprintf(f, "%u", (uint8_t) *p);
476 if (*p == '"' || *p == '\\') {
480 fprintf(f, "\\u%04x", *p);
492 static int output_json(
499 uint64_t realtime, monotonic;
507 bool done, separator;
511 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
513 r = sd_journal_get_realtime_usec(j, &realtime);
515 log_error("Failed to get realtime timestamp: %s", strerror(-r));
519 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
521 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
525 r = sd_journal_get_cursor(j, &cursor);
527 log_error("Failed to get cursor: %s", strerror(-r));
531 if (mode == OUTPUT_JSON_PRETTY)
534 "\t\"__CURSOR\" : \"%s\",\n"
535 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
536 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
537 "\t\"_BOOT_ID\" : \"%s\"",
539 (unsigned long long) realtime,
540 (unsigned long long) monotonic,
541 sd_id128_to_string(boot_id, sid));
543 if (mode == OUTPUT_JSON_SSE)
547 "{ \"__CURSOR\" : \"%s\", "
548 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
549 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
550 "\"_BOOT_ID\" : \"%s\"",
552 (unsigned long long) realtime,
553 (unsigned long long) monotonic,
554 sd_id128_to_string(boot_id, sid));
558 h = hashmap_new(string_hash_func, string_compare_func);
562 /* First round, iterate through the entry and count how often each field appears */
563 SD_JOURNAL_FOREACH_DATA(j, data, length) {
569 memcmp(data, "_BOOT_ID=", 9) == 0)
572 eq = memchr(data, '=', length);
576 n = strndup(data, eq - (const char*) data);
582 u = PTR_TO_UINT(hashmap_get(h, n));
584 r = hashmap_put(h, n, UINT_TO_PTR(1));
590 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
601 SD_JOURNAL_FOREACH_DATA(j, data, length) {
607 /* We already printed the boot id, from the data in
608 * the header, hence let's suppress it here */
610 memcmp(data, "_BOOT_ID=", 9) == 0)
613 eq = memchr(data, '=', length);
618 if (mode == OUTPUT_JSON_PRETTY)
624 m = eq - (const char*) data;
626 n = strndup(data, m);
632 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
634 /* We already printed this, let's jump to the next */
640 /* Field only appears once, output it directly */
642 json_escape(f, data, m, flags);
645 json_escape(f, eq + 1, length - m - 1, flags);
647 hashmap_remove(h, n);
656 /* Field appears multiple times, output it as array */
657 json_escape(f, data, m, flags);
659 json_escape(f, eq + 1, length - m - 1, flags);
661 /* Iterate through the end of the list */
663 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
667 if (memcmp(data, n, m) != 0)
670 if (((const char*) data)[m] != '=')
674 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
679 hashmap_remove(h, n);
683 /* Iterate data fields form the beginning */
693 if (mode == OUTPUT_JSON_PRETTY)
695 else if (mode == OUTPUT_JSON_SSE)
703 while ((k = hashmap_steal_first_key(h)))
711 static int output_cat(
725 sd_journal_set_data_threshold(j, 0);
727 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
729 /* An entry without MESSAGE=? */
733 log_error("Failed to get data: %s", strerror(-r));
739 fwrite((const char*) data + 8, 1, l - 8, f);
745 static int (*output_funcs[_OUTPUT_MODE_MAX])(
750 OutputFlags flags) = {
752 [OUTPUT_SHORT] = output_short,
753 [OUTPUT_SHORT_MONOTONIC] = output_short,
754 [OUTPUT_VERBOSE] = output_verbose,
755 [OUTPUT_EXPORT] = output_export,
756 [OUTPUT_JSON] = output_json,
757 [OUTPUT_JSON_PRETTY] = output_json,
758 [OUTPUT_JSON_SSE] = output_json,
759 [OUTPUT_CAT] = output_cat
771 assert(mode < _OUTPUT_MODE_MAX);
774 n_columns = columns();
776 ret = output_funcs[mode](f, j, mode, n_columns, flags);
781 int show_journal_by_unit(
790 _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL;
791 sd_journal *j = NULL;
794 bool need_seek = false;
795 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
798 assert(mode < _OUTPUT_MODE_MAX);
801 if (!endswith(unit, ".service") &&
802 !endswith(unit, ".socket") &&
803 !endswith(unit, ".mount") &&
804 !endswith(unit, ".swap"))
810 if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
811 asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
812 asprintf(&m3, "UNIT=%s", unit) < 0) {
817 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
821 /* Look for messages from the service itself */
822 r = sd_journal_add_match(j, m1, 0);
826 /* Look for coredumps of the service */
827 r = sd_journal_add_disjunction(j);
830 r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0);
833 r = sd_journal_add_match(j, m2, 0);
837 /* Look for messages from PID 1 about this service */
838 r = sd_journal_add_disjunction(j);
841 r = sd_journal_add_match(j, "_PID=1", 0);
844 r = sd_journal_add_match(j, m3, 0);
849 r = sd_journal_seek_tail(j);
853 r = sd_journal_previous_skip(j, how_many);
862 r = sd_journal_next(j);
872 if (not_before > 0) {
873 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
875 /* -ESTALE is returned if the
876 timestamp is not from this boot */
882 if (usec < not_before)
888 r = output_journal(f, j, mode, n_columns, flags);
893 if (warn_cutoff && line < how_many && not_before > 0) {
897 /* Check whether the cutoff line is too early */
899 r = sd_id128_get_boot(&boot_id);
903 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
907 if (r > 0 && not_before < cutoff)
908 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
913 if (!(flags & OUTPUT_FOLLOW))
916 r = sd_journal_wait(j, (usec_t) -1);
929 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
930 [OUTPUT_SHORT] = "short",
931 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
932 [OUTPUT_VERBOSE] = "verbose",
933 [OUTPUT_EXPORT] = "export",
934 [OUTPUT_JSON] = "json",
935 [OUTPUT_JSON_PRETTY] = "json-pretty",
936 [OUTPUT_JSON_SSE] = "json-sse",
940 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);