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 #include "journal-internal.h"
35 #define PRINT_THRESHOLD 128
36 #define JSON_THRESHOLD 4096
38 static int print_catalog(FILE *f
, sd_journal
*j
) {
40 _cleanup_free_
char *t
= NULL
, *z
= NULL
;
43 r
= sd_journal_get_catalog(j
, &t
);
47 z
= strreplace(strstrip(t
), "\n", "\n-- ");
58 static int parse_field(const void *data
, size_t length
, const char *field
, char **target
, size_t *target_size
) {
71 if (memcmp(data
, field
, fl
))
79 memcpy(buf
, (const char*) data
+ fl
, nl
);
89 static bool shall_print(const char *p
, size_t l
, OutputFlags flags
) {
92 if (flags
& OUTPUT_SHOW_ALL
)
95 if (l
>= PRINT_THRESHOLD
)
98 if (!utf8_is_printable(p
, l
))
104 static void print_multiline(FILE *f
, unsigned prefix
, unsigned n_columns
, OutputMode flags
, int priority
, const char* message
, size_t message_len
) {
105 const char *color_on
= "", *color_off
= "";
106 const char *pos
, *end
;
107 bool continuation
= false;
109 if (flags
& OUTPUT_COLOR
) {
110 if (priority
<= LOG_ERR
) {
111 color_on
= ANSI_HIGHLIGHT_RED_ON
;
112 color_off
= ANSI_HIGHLIGHT_OFF
;
113 } else if (priority
<= LOG_NOTICE
) {
114 color_on
= ANSI_HIGHLIGHT_ON
;
115 color_off
= ANSI_HIGHLIGHT_OFF
;
119 for (pos
= message
; pos
< message
+ message_len
; pos
= end
+ 1) {
121 for (end
= pos
; end
< message
+ message_len
&& *end
!= '\n'; end
++)
126 if (flags
& (OUTPUT_FULL_WIDTH
| OUTPUT_SHOW_ALL
) || prefix
+ len
+ 1 < n_columns
)
127 fprintf(f
, "%*s%s%.*s%s\n",
128 continuation
* prefix
, "",
129 color_on
, len
, pos
, color_off
);
130 else if (prefix
< n_columns
&& n_columns
- prefix
>= 3) {
131 _cleanup_free_
char *e
;
133 e
= ellipsize_mem(pos
, len
, n_columns
- prefix
, 90);
136 fprintf(f
, "%s%.*s%s\n", color_on
, len
, pos
, color_off
);
138 fprintf(f
, "%s%s%s\n", color_on
, e
, color_off
);
146 static int output_short(
157 _cleanup_free_
char *hostname
= NULL
, *identifier
= NULL
, *comm
= NULL
, *pid
= NULL
, *fake_pid
= NULL
, *message
= NULL
, *realtime
= NULL
, *monotonic
= NULL
, *priority
= NULL
;
158 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;
164 sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : PRINT_THRESHOLD
);
166 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
168 r
= parse_field(data
, length
, "PRIORITY=", &priority
, &priority_len
);
174 r
= parse_field(data
, length
, "_HOSTNAME=", &hostname
, &hostname_len
);
180 r
= parse_field(data
, length
, "SYSLOG_IDENTIFIER=", &identifier
, &identifier_len
);
186 r
= parse_field(data
, length
, "_COMM=", &comm
, &comm_len
);
192 r
= parse_field(data
, length
, "_PID=", &pid
, &pid_len
);
198 r
= parse_field(data
, length
, "SYSLOG_PID=", &fake_pid
, &fake_pid_len
);
204 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &realtime
, &realtime_len
);
210 r
= parse_field(data
, length
, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic
, &monotonic_len
);
216 r
= parse_field(data
, length
, "MESSAGE=", &message
, &message_len
);
227 if (!(flags
& OUTPUT_SHOW_ALL
))
228 strip_tab_ansi(&message
, &message_len
);
230 if (priority_len
== 1 && *priority
>= '0' && *priority
<= '7')
233 if (mode
== OUTPUT_SHORT_MONOTONIC
) {
240 r
= safe_atou64(monotonic
, &t
);
243 r
= sd_journal_get_monotonic_usec(j
, &t
, &boot_id
);
246 log_error("Failed to get monotonic timestamp: %s", strerror(-r
));
250 fprintf(f
, "[%5llu.%06llu]",
251 (unsigned long long) (t
/ USEC_PER_SEC
),
252 (unsigned long long) (t
% USEC_PER_SEC
));
254 n
+= 1 + 5 + 1 + 6 + 1;
265 r
= safe_atou64(realtime
, &x
);
268 r
= sd_journal_get_realtime_usec(j
, &x
);
271 log_error("Failed to get realtime timestamp: %s", strerror(-r
));
275 t
= (time_t) (x
/ USEC_PER_SEC
);
276 if (strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", localtime_r(&t
, &tm
)) <= 0) {
277 log_error("Failed to format time.");
285 if (hostname
&& shall_print(hostname
, hostname_len
, flags
)) {
286 fprintf(f
, " %.*s", (int) hostname_len
, hostname
);
287 n
+= hostname_len
+ 1;
290 if (identifier
&& shall_print(identifier
, identifier_len
, flags
)) {
291 fprintf(f
, " %.*s", (int) identifier_len
, identifier
);
292 n
+= identifier_len
+ 1;
293 } else if (comm
&& shall_print(comm
, comm_len
, flags
)) {
294 fprintf(f
, " %.*s", (int) comm_len
, comm
);
299 if (pid
&& shall_print(pid
, pid_len
, flags
)) {
300 fprintf(f
, "[%.*s]", (int) pid_len
, pid
);
302 } else if (fake_pid
&& shall_print(fake_pid
, fake_pid_len
, flags
)) {
303 fprintf(f
, "[%.*s]", (int) fake_pid_len
, fake_pid
);
304 n
+= fake_pid_len
+ 2;
307 if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(message
, message_len
)) {
308 char bytes
[FORMAT_BYTES_MAX
];
309 fprintf(f
, ": [%s blob data]\n", format_bytes(bytes
, sizeof(bytes
), message_len
));
312 print_multiline(f
, n
+ 2, n_columns
, flags
, p
, message
, message_len
);
315 if (flags
& OUTPUT_CATALOG
)
321 static int output_verbose(
330 _cleanup_free_
char *cursor
= NULL
;
332 char ts
[FORMAT_TIMESTAMP_MAX
];
338 sd_journal_set_data_threshold(j
, 0);
340 r
= sd_journal_get_realtime_usec(j
, &realtime
);
342 log_full(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
,
343 "Failed to get realtime timestamp: %s", strerror(-r
));
347 r
= sd_journal_get_cursor(j
, &cursor
);
349 log_error("Failed to get cursor: %s", strerror(-r
));
353 fprintf(f
, "%s [%s]\n",
354 format_timestamp(ts
, sizeof(ts
), realtime
),
357 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
360 c
= memchr(data
, '=', length
);
362 log_error("Invalid field.");
365 fieldlen
= c
- (const char*) data
;
367 if ((flags
& OUTPUT_SHOW_ALL
) || (length
< PRINT_THRESHOLD
&& utf8_is_printable(data
, length
))) {
368 fprintf(f
, " %.*s=", fieldlen
, (const char*)data
);
369 print_multiline(f
, 4 + fieldlen
+ 1, 0, OUTPUT_FULL_WIDTH
, 0, c
+ 1, length
- fieldlen
- 1);
371 char bytes
[FORMAT_BYTES_MAX
];
373 fprintf(f
, " %.*s=[%s blob data]\n",
374 (int) (c
- (const char*) data
),
376 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1));
383 if (flags
& OUTPUT_CATALOG
)
389 static int output_export(
399 usec_t realtime
, monotonic
;
400 _cleanup_free_
char *cursor
= NULL
;
406 sd_journal_set_data_threshold(j
, 0);
408 r
= sd_journal_get_realtime_usec(j
, &realtime
);
410 log_error("Failed to get realtime timestamp: %s", strerror(-r
));
414 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
416 log_error("Failed to get monotonic timestamp: %s", strerror(-r
));
420 r
= sd_journal_get_cursor(j
, &cursor
);
422 log_error("Failed to get cursor: %s", strerror(-r
));
428 "__REALTIME_TIMESTAMP=%llu\n"
429 "__MONOTONIC_TIMESTAMP=%llu\n"
432 (unsigned long long) realtime
,
433 (unsigned long long) monotonic
,
434 sd_id128_to_string(boot_id
, sid
));
436 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
438 /* We already printed the boot id, from the data in
439 * the header, hence let's suppress it here */
441 hasprefix(data
, "_BOOT_ID="))
444 if (!utf8_is_printable(data
, length
)) {
448 c
= memchr(data
, '=', length
);
450 log_error("Invalid field.");
454 fwrite(data
, c
- (const char*) data
, 1, f
);
456 le64
= htole64(length
- (c
- (const char*) data
) - 1);
457 fwrite(&le64
, sizeof(le64
), 1, f
);
458 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, f
);
460 fwrite(data
, length
, 1, f
);
482 if (!(flags
& OUTPUT_SHOW_ALL
) && l
>= JSON_THRESHOLD
)
486 else if (!utf8_is_printable(p
, l
)) {
487 bool not_first
= false;
493 fprintf(f
, ", %u", (uint8_t) *p
);
496 fprintf(f
, "%u", (uint8_t) *p
);
508 if (*p
== '"' || *p
== '\\') {
511 } else if (*p
== '\n')
514 fprintf(f
, "\\u%04x", *p
);
526 static int output_json(
533 uint64_t realtime
, monotonic
;
534 _cleanup_free_
char *cursor
= NULL
;
541 bool done
, separator
;
545 sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : JSON_THRESHOLD
);
547 r
= sd_journal_get_realtime_usec(j
, &realtime
);
549 log_error("Failed to get realtime timestamp: %s", strerror(-r
));
553 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
555 log_error("Failed to get monotonic timestamp: %s", strerror(-r
));
559 r
= sd_journal_get_cursor(j
, &cursor
);
561 log_error("Failed to get cursor: %s", strerror(-r
));
565 if (mode
== OUTPUT_JSON_PRETTY
)
568 "\t\"__CURSOR\" : \"%s\",\n"
569 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
570 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
571 "\t\"_BOOT_ID\" : \"%s\"",
573 (unsigned long long) realtime
,
574 (unsigned long long) monotonic
,
575 sd_id128_to_string(boot_id
, sid
));
577 if (mode
== OUTPUT_JSON_SSE
)
581 "{ \"__CURSOR\" : \"%s\", "
582 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
583 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
584 "\"_BOOT_ID\" : \"%s\"",
586 (unsigned long long) realtime
,
587 (unsigned long long) monotonic
,
588 sd_id128_to_string(boot_id
, sid
));
591 h
= hashmap_new(string_hash_func
, string_compare_func
);
595 /* First round, iterate through the entry and count how often each field appears */
596 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
602 memcmp(data
, "_BOOT_ID=", 9) == 0)
605 eq
= memchr(data
, '=', length
);
609 n
= strndup(data
, eq
- (const char*) data
);
615 u
= PTR_TO_UINT(hashmap_get(h
, n
));
617 r
= hashmap_put(h
, n
, UINT_TO_PTR(1));
623 r
= hashmap_update(h
, n
, UINT_TO_PTR(u
+ 1));
637 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
643 /* We already printed the boot id, from the data in
644 * the header, hence let's suppress it here */
646 memcmp(data
, "_BOOT_ID=", 9) == 0)
649 eq
= memchr(data
, '=', length
);
654 if (mode
== OUTPUT_JSON_PRETTY
)
660 m
= eq
- (const char*) data
;
662 n
= strndup(data
, m
);
668 u
= PTR_TO_UINT(hashmap_get2(h
, n
, (void**) &kk
));
670 /* We already printed this, let's jump to the next */
676 /* Field only appears once, output it directly */
678 json_escape(f
, data
, m
, flags
);
681 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
683 hashmap_remove(h
, n
);
692 /* Field appears multiple times, output it as array */
693 json_escape(f
, data
, m
, flags
);
695 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
697 /* Iterate through the end of the list */
699 while (sd_journal_enumerate_data(j
, &data
, &length
) > 0) {
703 if (memcmp(data
, n
, m
) != 0)
706 if (((const char*) data
)[m
] != '=')
710 json_escape(f
, (const char*) data
+ m
+ 1, length
- m
- 1, flags
);
715 hashmap_remove(h
, n
);
719 /* Iterate data fields form the beginning */
729 if (mode
== OUTPUT_JSON_PRETTY
)
731 else if (mode
== OUTPUT_JSON_SSE
)
739 while ((k
= hashmap_steal_first_key(h
)))
747 static int output_cat(
761 sd_journal_set_data_threshold(j
, 0);
763 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
765 /* An entry without MESSAGE=? */
769 log_error("Failed to get data: %s", strerror(-r
));
775 fwrite((const char*) data
+ 8, 1, l
- 8, f
);
781 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(
786 OutputFlags flags
) = {
788 [OUTPUT_SHORT
] = output_short
,
789 [OUTPUT_SHORT_MONOTONIC
] = output_short
,
790 [OUTPUT_VERBOSE
] = output_verbose
,
791 [OUTPUT_EXPORT
] = output_export
,
792 [OUTPUT_JSON
] = output_json
,
793 [OUTPUT_JSON_PRETTY
] = output_json
,
794 [OUTPUT_JSON_SSE
] = output_json
,
795 [OUTPUT_CAT
] = output_cat
807 assert(mode
< _OUTPUT_MODE_MAX
);
810 n_columns
= columns();
812 ret
= output_funcs
[mode
](f
, j
, mode
, n_columns
, flags
);
817 static int show_journal(FILE *f
,
827 bool need_seek
= false;
828 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
832 assert(mode
< _OUTPUT_MODE_MAX
);
835 r
= sd_journal_seek_tail(j
);
839 r
= sd_journal_previous_skip(j
, how_many
);
848 r
= sd_journal_next(j
);
858 if (not_before
> 0) {
859 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
861 /* -ESTALE is returned if the
862 timestamp is not from this boot */
868 if (usec
< not_before
)
874 r
= output_journal(f
, j
, mode
, n_columns
, flags
);
879 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
883 /* Check whether the cutoff line is too early */
885 r
= sd_id128_get_boot(&boot_id
);
889 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
893 if (r
> 0 && not_before
< cutoff
)
894 fprintf(f
, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
899 if (!(flags
& OUTPUT_FOLLOW
))
902 r
= sd_journal_wait(j
, (usec_t
) -1);
912 int add_matches_for_unit(sd_journal
*j
, const char *unit
) {
914 _cleanup_free_
char *m1
= NULL
, *m2
= NULL
, *m3
= NULL
;
919 if (asprintf(&m1
, "_SYSTEMD_UNIT=%s", unit
) < 0 ||
920 asprintf(&m2
, "COREDUMP_UNIT=%s", unit
) < 0 ||
921 asprintf(&m3
, "UNIT=%s", unit
) < 0)
925 /* Look for messages from the service itself */
926 (r
= sd_journal_add_match(j
, m1
, 0)) ||
928 /* Look for coredumps of the service */
929 (r
= sd_journal_add_disjunction(j
)) ||
930 (r
= sd_journal_add_match(j
,
931 "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
932 (r
= sd_journal_add_match(j
, m2
, 0)) ||
934 /* Look for messages from PID 1 about this service */
935 (r
= sd_journal_add_disjunction(j
)) ||
936 (r
= sd_journal_add_match(j
, "_PID=1", 0)) ||
937 (r
= sd_journal_add_match(j
, m3
, 0))
942 int add_matches_for_user_unit(sd_journal
*j
, const char *unit
, uid_t uid
) {
944 _cleanup_free_
char *m1
= NULL
, *m2
= NULL
, *m3
= NULL
, *m4
= NULL
;
949 if (asprintf(&m1
, "_SYSTEMD_USER_UNIT=%s", unit
) < 0 ||
950 asprintf(&m2
, "USER_UNIT=%s", unit
) < 0 ||
951 asprintf(&m3
, "COREDUMP_USER_UNIT=%s", unit
) < 0 ||
952 asprintf(&m4
, "_UID=%d", uid
) < 0)
956 /* Look for messages from the user service itself */
957 (r
= sd_journal_add_match(j
, m1
, 0)) ||
958 (r
= sd_journal_add_match(j
, m4
, 0)) ||
960 /* Look for messages from systemd about this service */
961 (r
= sd_journal_add_disjunction(j
)) ||
962 (r
= sd_journal_add_match(j
, m2
, 0)) ||
963 (r
= sd_journal_add_match(j
, m4
, 0)) ||
965 /* Look for coredumps of the service */
966 (r
= sd_journal_add_disjunction(j
)) ||
967 (r
= sd_journal_add_match(j
, m3
, 0)) ||
968 (r
= sd_journal_add_match(j
, m4
, 0))
973 int add_match_this_boot(sd_journal
*j
) {
974 char match
[9+32+1] = "_BOOT_ID=";
980 r
= sd_id128_get_boot(&boot_id
);
982 log_error("Failed to get boot id: %s", strerror(-r
));
986 sd_id128_to_string(boot_id
, match
+ 9);
987 r
= sd_journal_add_match(j
, match
, strlen(match
));
989 log_error("Failed to add match: %s", strerror(-r
));
993 r
= sd_journal_add_conjunction(j
);
1000 int show_journal_by_unit(
1011 _cleanup_journal_close_ sd_journal
*j
= NULL
;
1013 int jflags
= SD_JOURNAL_LOCAL_ONLY
| system
* SD_JOURNAL_SYSTEM
;
1016 assert(mode
< _OUTPUT_MODE_MAX
);
1022 r
= sd_journal_open(&j
, jflags
);
1026 r
= add_match_this_boot(j
);
1031 r
= add_matches_for_unit(j
, unit
);
1033 r
= add_matches_for_user_unit(j
, unit
, uid
);
1037 log_debug("Journal filter: %s", journal_make_match_string(j
));
1039 r
= show_journal(f
, j
, mode
, n_columns
, not_before
, how_many
, flags
);
1046 static const char *const output_mode_table
[_OUTPUT_MODE_MAX
] = {
1047 [OUTPUT_SHORT
] = "short",
1048 [OUTPUT_SHORT_MONOTONIC
] = "short-monotonic",
1049 [OUTPUT_VERBOSE
] = "verbose",
1050 [OUTPUT_EXPORT
] = "export",
1051 [OUTPUT_JSON
] = "json",
1052 [OUTPUT_JSON_PRETTY
] = "json-pretty",
1053 [OUTPUT_JSON_SSE
] = "json-sse",
1054 [OUTPUT_CAT
] = "cat"
1057 DEFINE_STRING_TABLE_LOOKUP(output_mode
, OutputMode
);