diff --git a/man/journalctl.xml b/man/journalctl.xml index ac900ff1a6..ea517f4ac4 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -362,6 +362,18 @@ + + + + + Exclude messages for the specified syslog identifier + SYSLOG_IDENTIFIER. + + This parameter can be specified multiple times. + + + + diff --git a/shell-completion/bash/journalctl b/shell-completion/bash/journalctl index 067b05396d..0b40f04eb1 100644 --- a/shell-completion/bash/journalctl +++ b/shell-completion/bash/journalctl @@ -46,9 +46,9 @@ _journalctl() { --show-cursor --dmesg -k --pager-end -e -r --reverse --utc -x --catalog --no-full --force --dump-catalog --flush --rotate --sync --no-hostname -N --fields' - [ARG]='-b --boot -D --directory --file -F --field -t --identifier --facility - -M --machine -o --output -u --unit --user-unit -p --priority - --root --case-sensitive' + [ARG]='-b --boot -D --directory --file -F --field -t --identifier + -T --exclude-identifier --facility -M --machine -o --output + -u --unit --user-unit -p --priority --root --case-sensitive' [ARGUNKNOWN]='-c --cursor --interval -n --lines -S --since -U --until --after-cursor --cursor-file --verify-key -g --grep --vacuum-size --vacuum-time --vacuum-files --output-fields' @@ -107,7 +107,7 @@ _journalctl() { --user-unit) comps=$(journalctl -F '_SYSTEMD_USER_UNIT' 2>/dev/null) ;; - --identifier|-t) + --identifier|-t|--exclude-identifier|-T) comps=$(journalctl -F 'SYSLOG_IDENTIFIER' 2>/dev/null) ;; --case-sensitive) diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index fe68ec4310..c26d7f1def 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -122,6 +122,7 @@ static bool arg_force = false; static usec_t arg_since = 0, arg_until = 0; static bool arg_since_set = false, arg_until_set = false; static char **arg_syslog_identifier = NULL; +static char **arg_exclude_identifier = NULL; static char **arg_system_units = NULL; static char **arg_user_units = NULL; static const char *arg_field = NULL; @@ -146,6 +147,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_file, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_facilities, set_freep); STATIC_DESTRUCTOR_REGISTER(arg_verify_key, freep); STATIC_DESTRUCTOR_REGISTER(arg_syslog_identifier, strv_freep); +STATIC_DESTRUCTOR_REGISTER(arg_exclude_identifier, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_system_units, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_user_units, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); @@ -380,6 +382,8 @@ static int help(void) { " -u --unit=UNIT Show logs from the specified unit\n" " --user-unit=UNIT Show logs from the specified user unit\n" " -t --identifier=STRING Show entries with the specified syslog identifier\n" + " -T --exclude-identifier=STRING\n" + " Hide entries with the specified syslog identifier\n" " -p --priority=RANGE Show entries with the specified priority\n" " --facility=FACILITY... Show entries with the specified facilities\n" " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n" @@ -519,6 +523,7 @@ static int parse_argv(int argc, char *argv[]) { { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, { "header", no_argument, NULL, ARG_HEADER }, { "identifier", required_argument, NULL, 't' }, + { "exclude-identifier", required_argument, NULL, 'T' }, { "priority", required_argument, NULL, 'p' }, { "facility", required_argument, NULL, ARG_FACILITY }, { "grep", required_argument, NULL, 'g' }, @@ -564,7 +569,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:g:c:S:U:t:u:NF:xrM:i:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:g:c:S:U:t:T:u:NF:xrM:i:", options, NULL)) >= 0) switch (c) { @@ -958,6 +963,12 @@ static int parse_argv(int argc, char *argv[]) { return log_oom(); break; + case 'T': + r = strv_extend(&arg_exclude_identifier, optarg); + if (r < 0) + return log_oom(); + break; + case 'u': r = strv_extend(&arg_system_units, optarg); if (r < 0) @@ -1572,6 +1583,19 @@ static int add_syslog_identifier(sd_journal *j) { return 0; } +static int add_exclude_identifier(sd_journal *j) { + _cleanup_set_free_ Set *excludes = NULL; + int r; + + assert(j); + + r = set_put_strdupv(&excludes, arg_exclude_identifier); + if (r < 0) + return r; + + return set_free_and_replace(j->exclude_syslog_identifiers, excludes); +} + #if HAVE_GCRYPT static int format_journal_url( const void *seed, @@ -2408,6 +2432,10 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to add filter for syslog identifiers: %m"); + r = add_exclude_identifier(j); + if (r < 0) + return log_error_errno(r, "Failed to add exclude filter for syslog identifiers: %m"); + r = add_priorities(j); if (r < 0) return r; diff --git a/src/libsystemd/sd-journal/journal-internal.h b/src/libsystemd/sd-journal/journal-internal.h index 1b86d3d3c4..e57c5208c1 100644 --- a/src/libsystemd/sd-journal/journal-internal.h +++ b/src/libsystemd/sd-journal/journal-internal.h @@ -87,6 +87,7 @@ struct sd_journal { uint64_t current_field; Match *level0, *level1, *level2; + Set *exclude_syslog_identifiers; uint64_t origin_id; diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c index 18e62e7ac0..4d7e53af08 100644 --- a/src/libsystemd/sd-journal/sd-journal.c +++ b/src/libsystemd/sd-journal/sd-journal.c @@ -2327,6 +2327,8 @@ _public_ void sd_journal_close(sd_journal *j) { hashmap_free_free(j->errors); + set_free(j->exclude_syslog_identifiers); + free(j->path); free(j->prefix); free(j->namespace); diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index a5d04003bd..858b707f6c 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -523,6 +523,9 @@ static int output_short( return 0; } + if (identifier && set_contains(j->exclude_syslog_identifiers, identifier)) + return 0; + if (!(flags & OUTPUT_SHOW_ALL)) strip_tab_ansi(&message, &message_len, highlight_shifted); diff --git a/test/testsuite-04.units/verbose-success.service b/test/testsuite-04.units/verbose-success.service new file mode 100644 index 0000000000..67c8bf1007 --- /dev/null +++ b/test/testsuite-04.units/verbose-success.service @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Unit] +Description=Verbose successful service + +[Service] +ExecStart=/bin/echo success diff --git a/test/units/testsuite-04.journal.sh b/test/units/testsuite-04.journal.sh index 4d9e48717a..88fab48b9a 100755 --- a/test/units/testsuite-04.journal.sh +++ b/test/units/testsuite-04.journal.sh @@ -107,6 +107,15 @@ systemctl start silent-success journalctl --sync [[ -z "$(journalctl -b -q -u silent-success.service)" ]] +# Test syslog identifiers exclusion +systemctl start verbose-success +journalctl --sync +[[ -n "$(journalctl -b -q -u verbose-success.service -t systemd)" ]] +[[ -n "$(journalctl -b -q -u verbose-success.service -t echo)" ]] +[[ -n "$(journalctl -b -q -u verbose-success.service -T systemd)" ]] +[[ -n "$(journalctl -b -q -u verbose-success.service -T echo)" ]] +[[ -z "$(journalctl -b -q -u verbose-success.service -T echo -T '(echo)' -T systemd -T '(systemd)' -T systemd-executor)" ]] + # Exercise the matching machinery SYSTEMD_LOG_LEVEL=debug journalctl -b -n 1 /dev/null /dev/zero /dev/null /dev/null /dev/null journalctl -b -n 1 /bin/true /bin/false