]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/logs-show.c
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
,
86 char *hostname
= NULL
, *identifier
= NULL
, *comm
= NULL
, *pid
= NULL
, *fake_pid
= NULL
, *message
= NULL
, *realtime
= NULL
, *monotonic
= NULL
;
87 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;
91 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
93 r
= parse_field(data
, length
, "_HOSTNAME=", &hostname
, &hostname_len
);
99 r
= parse_field(data
, length
, "SYSLOG_IDENTIFIER=", &identifier
, &identifier_len
);
105 r
= parse_field(data
, length
, "_COMM=", &comm
, &comm_len
);
111 r
= parse_field(data
, length
, "_PID=", &pid
, &pid_len
);
117 r
= parse_field(data
, length
, "SYSLOG_PID=", &fake_pid
, &fake_pid_len
);
123 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &realtime
, &realtime_len
);
129 r
= parse_field(data
, length
, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic
, &monotonic_len
);
135 r
= parse_field(data
, length
, "MESSAGE=", &message
, &message_len
);
145 if (flags
& OUTPUT_MONOTONIC_MODE
) {
152 r
= safe_atou64(monotonic
, &t
);
155 r
= sd_journal_get_monotonic_usec(j
, &t
, &boot_id
);
158 log_error("Failed to get monotonic: %s", strerror(-r
));
162 printf("[%5llu.%06llu]",
163 (unsigned long long) (t
/ USEC_PER_SEC
),
164 (unsigned long long) (t
% USEC_PER_SEC
));
166 n
+= 1 + 5 + 1 + 6 + 1;
177 r
= safe_atou64(realtime
, &x
);
180 r
= sd_journal_get_realtime_usec(j
, &x
);
183 log_error("Failed to get realtime: %s", strerror(-r
));
187 t
= (time_t) (x
/ USEC_PER_SEC
);
188 if (strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", localtime_r(&t
, &tm
)) <= 0) {
189 log_error("Failed to format time.");
197 if (hostname
&& shall_print(flags
& OUTPUT_SHOW_ALL
,
198 hostname
, hostname_len
)) {
199 printf(" %.*s", (int) hostname_len
, hostname
);
200 n
+= hostname_len
+ 1;
203 if (identifier
&& shall_print(flags
& OUTPUT_SHOW_ALL
,
204 identifier
, identifier_len
)) {
205 printf(" %.*s", (int) identifier_len
, identifier
);
206 n
+= identifier_len
+ 1;
207 } else if (comm
&& shall_print(flags
& OUTPUT_SHOW_ALL
,
209 printf(" %.*s", (int) comm_len
, comm
);
214 if (pid
&& shall_print(flags
& OUTPUT_SHOW_ALL
, pid
, pid_len
)) {
215 printf("[%.*s]", (int) pid_len
, pid
);
217 } else if (fake_pid
&& shall_print(flags
& OUTPUT_SHOW_ALL
,
218 fake_pid
, fake_pid_len
)) {
219 printf("[%.*s]", (int) fake_pid_len
, fake_pid
);
220 n
+= fake_pid_len
+ 2;
223 if (flags
& OUTPUT_SHOW_ALL
)
224 printf(": %.*s\n", (int) message_len
, message
);
225 else if (!utf8_is_printable_n(message
, message_len
)) {
226 char bytes
[FORMAT_BYTES_MAX
];
227 printf(": [%s blob data]\n", format_bytes(bytes
, sizeof(bytes
), message_len
));
228 } else if ((flags
& OUTPUT_FULL_WIDTH
) ||
229 (message_len
+ n
< n_columns
))
230 printf(": %.*s\n", (int) message_len
, message
);
231 else if (n
< n_columns
&& n_columns
- n
- 2 >= 3) {
234 e
= ellipsize_mem(message
, message_len
, n_columns
- n
- 2, 90);
237 printf(": %.*s\n", (int) message_len
, message
);
260 static int output_short_realtime(sd_journal
*j
, unsigned line
,
261 unsigned n_columns
, OutputFlags flags
) {
262 return output_short(j
, line
, n_columns
, flags
& ~OUTPUT_MONOTONIC_MODE
);
265 static int output_short_monotonic(sd_journal
*j
, unsigned line
,
266 unsigned n_columns
, OutputFlags flags
) {
267 return output_short(j
, line
, n_columns
, flags
| OUTPUT_MONOTONIC_MODE
);
270 static int output_verbose(sd_journal
*j
, unsigned line
,
271 unsigned n_columns
, OutputFlags flags
) {
276 char ts
[FORMAT_TIMESTAMP_MAX
];
281 r
= sd_journal_get_realtime_usec(j
, &realtime
);
283 log_error("Failed to get realtime timestamp: %s", strerror(-r
));
287 r
= sd_journal_get_cursor(j
, &cursor
);
289 log_error("Failed to get cursor: %s", strerror(-r
));
294 format_timestamp(ts
, sizeof(ts
), realtime
),
299 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
300 if (!(flags
& OUTPUT_SHOW_ALL
) && (length
> PRINT_THRESHOLD
||
301 !utf8_is_printable_n(data
, length
))) {
303 char bytes
[FORMAT_BYTES_MAX
];
305 c
= memchr(data
, '=', length
);
307 log_error("Invalid field.");
311 printf("\t%.*s=[%s blob data]\n",
312 (int) (c
- (const char*) data
),
314 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1));
316 printf("\t%.*s\n", (int) length
, (const char*) data
);
322 static int output_export(sd_journal
*j
, unsigned line
,
323 unsigned n_columns
, OutputFlags flags
) {
327 usec_t realtime
, monotonic
;
334 r
= sd_journal_get_realtime_usec(j
, &realtime
);
336 log_error("Failed to get realtime timestamp: %s", strerror(-r
));
340 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
342 log_error("Failed to get monotonic timestamp: %s", strerror(-r
));
346 r
= sd_journal_get_cursor(j
, &cursor
);
348 log_error("Failed to get cursor: %s", strerror(-r
));
352 printf("__CURSOR=%s\n"
353 "__REALTIME_TIMESTAMP=%llu\n"
354 "__MONOTONIC_TIMESTAMP=%llu\n"
357 (unsigned long long) realtime
,
358 (unsigned long long) monotonic
,
359 sd_id128_to_string(boot_id
, sid
));
363 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
365 /* We already printed the boot id, from the data in
366 * the header, hence let's suppress it here */
368 memcmp(data
, "_BOOT_ID=", 9) == 0)
371 if (!utf8_is_printable_n(data
, length
)) {
375 c
= memchr(data
, '=', length
);
377 log_error("Invalid field.");
381 fwrite(data
, c
- (const char*) data
, 1, stdout
);
383 le64
= htole64(length
- (c
- (const char*) data
) - 1);
384 fwrite(&le64
, sizeof(le64
), 1, stdout
);
385 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, stdout
);
387 fwrite(data
, length
, 1, stdout
);
397 static void json_escape(const char* p
, size_t l
) {
398 if (!utf8_is_printable_n(p
, l
)) {
399 bool not_first
= false;
405 printf(", %u", (uint8_t) *p
);
408 printf("%u", (uint8_t) *p
);
420 if (*p
== '"' || *p
== '\\') {
434 static int output_json(sd_journal
*j
, unsigned line
,
435 unsigned n_columns
, OutputFlags flags
) {
436 uint64_t realtime
, monotonic
;
446 r
= sd_journal_get_realtime_usec(j
, &realtime
);
448 log_error("Failed to get realtime timestamp: %s", strerror(-r
));
452 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
454 log_error("Failed to get monotonic timestamp: %s", strerror(-r
));
458 r
= sd_journal_get_cursor(j
, &cursor
);
460 log_error("Failed to get cursor: %s", strerror(-r
));
467 fputs(",\n", stdout
);
470 "\t\"__CURSOR\" : \"%s\",\n"
471 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
472 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
473 "\t\"_BOOT_ID\" : \"%s\"",
475 (unsigned long long) realtime
,
476 (unsigned long long) monotonic
,
477 sd_id128_to_string(boot_id
, sid
));
481 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
484 /* We already printed the boot id, from the data in
485 * the header, hence let's suppress it here */
487 memcmp(data
, "_BOOT_ID=", 9) == 0)
490 c
= memchr(data
, '=', length
);
492 log_error("Invalid field.");
496 fputs(",\n\t", stdout
);
497 json_escape(data
, c
- (const char*) data
);
498 fputs(" : ", stdout
);
499 json_escape(c
+ 1, length
- (c
- (const char*) data
) - 1);
502 fputs("\n}", stdout
);
508 static int output_cat(sd_journal
*j
, unsigned line
,
509 unsigned n_columns
, OutputFlags flags
) {
516 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
518 log_error("Failed to get data: %s", strerror(-r
));
524 fwrite((const char*) data
+ 8, 1, l
- 8, stdout
);
530 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(sd_journal
*j
, unsigned line
,
531 unsigned n_columns
, OutputFlags flags
) = {
532 [OUTPUT_SHORT
] = output_short_realtime
,
533 [OUTPUT_SHORT_MONOTONIC
] = output_short_monotonic
,
534 [OUTPUT_VERBOSE
] = output_verbose
,
535 [OUTPUT_EXPORT
] = output_export
,
536 [OUTPUT_JSON
] = output_json
,
537 [OUTPUT_CAT
] = output_cat
540 int output_journal(sd_journal
*j
, OutputMode mode
, unsigned line
,
541 unsigned n_columns
, OutputFlags flags
) {
543 assert(mode
< _OUTPUT_MODE_MAX
);
546 n_columns
= columns();
548 return output_funcs
[mode
](j
, line
, n_columns
, flags
);
551 int show_journal_by_unit(
560 sd_journal
*j
= NULL
;
563 bool need_seek
= false;
564 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
567 assert(mode
< _OUTPUT_MODE_MAX
);
570 if (!endswith(unit
, ".service") &&
571 !endswith(unit
, ".socket") &&
572 !endswith(unit
, ".mount") &&
573 !endswith(unit
, ".swap"))
579 if (asprintf(&m
, "_SYSTEMD_UNIT=%s", unit
) < 0) {
584 r
= sd_journal_open(&j
, SD_JOURNAL_LOCAL_ONLY
|SD_JOURNAL_SYSTEM_ONLY
);
588 r
= sd_journal_add_match(j
, m
, strlen(m
));
592 r
= sd_journal_seek_tail(j
);
596 r
= sd_journal_previous_skip(j
, how_many
);
600 if (mode
== OUTPUT_JSON
) {
610 r
= sd_journal_next(j
);
620 if (not_before
> 0) {
621 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
623 /* -ESTALE is returned if the
624 timestamp is not from this boot */
630 if (usec
< not_before
)
636 r
= output_journal(j
, mode
, line
, n_columns
, flags
);
641 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
645 /* Check whether the cutoff line is too early */
647 r
= sd_id128_get_boot(&boot_id
);
651 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
655 if (r
> 0 && not_before
< cutoff
)
656 printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
661 if (!(flags
& OUTPUT_FOLLOW
))
664 r
= sd_journal_wait(j
, (usec_t
) -1);
670 if (mode
== OUTPUT_JSON
)
671 fputs("\n]\n", stdout
);
683 static const char *const output_mode_table
[_OUTPUT_MODE_MAX
] = {
684 [OUTPUT_SHORT
] = "short",
685 [OUTPUT_SHORT_MONOTONIC
] = "short-monotonic",
686 [OUTPUT_VERBOSE
] = "verbose",
687 [OUTPUT_EXPORT
] = "export",
688 [OUTPUT_JSON
] = "json",
692 DEFINE_STRING_TABLE_LOOKUP(output_mode
, OutputMode
);