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 #define PRINT_THRESHOLD 128
35 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
48 if (memcmp(data, field, fl))
53 memcpy(buf, (const char*) data + fl, nl);
56 log_error("Out of memory");
67 static bool shall_print(bool show_all, char *p, size_t l) {
71 if (l > PRINT_THRESHOLD)
74 if (!utf8_is_printable_n(p, l))
80 static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool show_all, bool monotonic_mode) {
85 char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL;
86 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;
90 SD_JOURNAL_FOREACH_DATA(j, data, length) {
92 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
98 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
104 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
110 r = parse_field(data, length, "_PID=", &pid, &pid_len);
116 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
122 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
128 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
134 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
144 if (monotonic_mode) {
151 r = safe_atou64(monotonic, &t);
154 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
157 log_error("Failed to get monotonic: %s", strerror(-r));
161 printf("[%5llu.%06llu]",
162 (unsigned long long) (t / USEC_PER_SEC),
163 (unsigned long long) (t % USEC_PER_SEC));
165 n += 1 + 5 + 1 + 6 + 1;
176 r = safe_atou64(realtime, &x);
179 r = sd_journal_get_realtime_usec(j, &x);
182 log_error("Failed to get realtime: %s", strerror(-r));
186 t = (time_t) (x / USEC_PER_SEC);
187 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
188 log_error("Failed to format time.");
196 if (hostname && shall_print(show_all, hostname, hostname_len)) {
197 printf(" %.*s", (int) hostname_len, hostname);
198 n += hostname_len + 1;
201 if (identifier && shall_print(show_all, identifier, identifier_len)) {
202 printf(" %.*s", (int) identifier_len, identifier);
203 n += identifier_len + 1;
204 } else if (comm && shall_print(show_all, comm, comm_len)) {
205 printf(" %.*s", (int) comm_len, comm);
210 if (pid && shall_print(show_all, pid, pid_len)) {
211 printf("[%.*s]", (int) pid_len, pid);
213 } else if (fake_pid && shall_print(show_all, fake_pid, fake_pid_len)) {
214 printf("[%.*s]", (int) fake_pid_len, fake_pid);
215 n += fake_pid_len + 2;
219 printf(": %.*s\n", (int) message_len, message);
220 else if (!utf8_is_printable_n(message, message_len)) {
221 char bytes[FORMAT_BYTES_MAX];
222 printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
223 } else if (message_len + n < n_columns)
224 printf(": %.*s\n", (int) message_len, message);
225 else if (n < n_columns) {
228 e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
231 printf(": %.*s\n", (int) message_len, message);
254 static int output_short_realtime(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
255 return output_short(j, line, n_columns, show_all, false);
258 static int output_short_monotonic(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
259 return output_short(j, line, n_columns, show_all, true);
262 static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
267 char ts[FORMAT_TIMESTAMP_MAX];
272 r = sd_journal_get_realtime_usec(j, &realtime);
274 log_error("Failed to get realtime timestamp: %s", strerror(-r));
278 r = sd_journal_get_cursor(j, &cursor);
280 log_error("Failed to get cursor: %s", strerror(-r));
285 format_timestamp(ts, sizeof(ts), realtime),
290 SD_JOURNAL_FOREACH_DATA(j, data, length) {
291 if (!show_all && (length > PRINT_THRESHOLD ||
292 !utf8_is_printable_n(data, length))) {
294 char bytes[FORMAT_BYTES_MAX];
296 c = memchr(data, '=', length);
298 log_error("Invalid field.");
302 printf("\t%.*s=[%s blob data]\n",
303 (int) (c - (const char*) data),
305 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
307 printf("\t%.*s\n", (int) length, (const char*) data);
313 static int output_export(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
317 usec_t realtime, monotonic;
324 r = sd_journal_get_realtime_usec(j, &realtime);
326 log_error("Failed to get realtime timestamp: %s", strerror(-r));
330 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
332 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
336 r = sd_journal_get_cursor(j, &cursor);
338 log_error("Failed to get cursor: %s", strerror(-r));
342 printf("__CURSOR=%s\n"
343 "__REALTIME_TIMESTAMP=%llu\n"
344 "__MONOTONIC_TIMESTAMP=%llu\n"
347 (unsigned long long) realtime,
348 (unsigned long long) monotonic,
349 sd_id128_to_string(boot_id, sid));
353 SD_JOURNAL_FOREACH_DATA(j, data, length) {
355 /* We already printed the boot id, from the data in
356 * the header, hence let's suppress it here */
358 memcmp(data, "_BOOT_ID=", 9) == 0)
361 if (!utf8_is_printable_n(data, length)) {
365 c = memchr(data, '=', length);
367 log_error("Invalid field.");
371 fwrite(data, c - (const char*) data, 1, stdout);
373 le64 = htole64(length - (c - (const char*) data) - 1);
374 fwrite(&le64, sizeof(le64), 1, stdout);
375 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
377 fwrite(data, length, 1, stdout);
387 static void json_escape(const char* p, size_t l) {
388 if (!utf8_is_printable_n(p, l)) {
389 bool not_first = false;
395 printf(", %u", (uint8_t) *p);
398 printf("%u", (uint8_t) *p);
410 if (*p == '"' || *p == '\\') {
424 static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
425 uint64_t realtime, monotonic;
435 r = sd_journal_get_realtime_usec(j, &realtime);
437 log_error("Failed to get realtime timestamp: %s", strerror(-r));
441 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
443 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
447 r = sd_journal_get_cursor(j, &cursor);
449 log_error("Failed to get cursor: %s", strerror(-r));
456 fputs(",\n", stdout);
459 "\t\"__CURSOR\" : \"%s\",\n"
460 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
461 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
462 "\t\"_BOOT_ID\" : \"%s\"",
464 (unsigned long long) realtime,
465 (unsigned long long) monotonic,
466 sd_id128_to_string(boot_id, sid));
470 SD_JOURNAL_FOREACH_DATA(j, data, length) {
473 /* We already printed the boot id, from the data in
474 * the header, hence let's suppress it here */
476 memcmp(data, "_BOOT_ID=", 9) == 0)
479 c = memchr(data, '=', length);
481 log_error("Invalid field.");
485 fputs(",\n\t", stdout);
486 json_escape(data, c - (const char*) data);
487 fputs(" : ", stdout);
488 json_escape(c + 1, length - (c - (const char*) data) - 1);
491 fputs("\n}", stdout);
497 static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
504 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
506 log_error("Failed to get data: %s", strerror(-r));
512 fwrite((const char*) data + 8, 1, l - 8, stdout);
518 static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, unsigned n_columns, bool show_all) = {
519 [OUTPUT_SHORT] = output_short_realtime,
520 [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic,
521 [OUTPUT_VERBOSE] = output_verbose,
522 [OUTPUT_EXPORT] = output_export,
523 [OUTPUT_JSON] = output_json,
524 [OUTPUT_CAT] = output_cat
527 int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all) {
529 assert(mode < _OUTPUT_MODE_MAX);
532 n_columns = columns();
534 return output_funcs[mode](j, line, n_columns, show_all);
537 int show_journal_by_unit(
548 sd_journal *j = NULL;
551 bool need_seek = false;
554 assert(mode < _OUTPUT_MODE_MAX);
557 if (!endswith(unit, ".service") &&
558 !endswith(unit, ".socket") &&
559 !endswith(unit, ".mount") &&
560 !endswith(unit, ".swap"))
566 if (asprintf(&m, "_SYSTEMD_UNIT=%s", unit) < 0) {
571 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
575 r = sd_journal_add_match(j, m, strlen(m));
579 r = sd_journal_seek_tail(j);
583 r = sd_journal_previous_skip(j, how_many);
587 if (mode == OUTPUT_JSON) {
597 r = sd_journal_next(j);
607 if (not_before > 0) {
608 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
610 /* -ESTALE is returned if the
611 timestamp is not from this boot */
617 if (usec < not_before)
623 r = output_journal(j, mode, line, n_columns, show_all);
628 if (warn_cutoff && line < how_many && not_before > 0) {
632 /* Check whether the cutoff line is too early */
634 r = sd_id128_get_boot(&boot_id);
638 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
642 if (r > 0 && not_before < cutoff)
643 printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
651 r = sd_journal_wait(j, (usec_t) -1);
657 if (mode == OUTPUT_JSON)
658 fputs("\n]\n", stdout);
670 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
671 [OUTPUT_SHORT] = "short",
672 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
673 [OUTPUT_VERBOSE] = "verbose",
674 [OUTPUT_EXPORT] = "export",
675 [OUTPUT_JSON] = "json",
679 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);