journalctl: augment short mode with a cursor at the end

Two options are added: --show-cursor to print the cursor at the end,
and --after-cursor to resume logs on the next line after the previous one.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2013-07-16 10:21:18 -04:00
parent dd94c17e7d
commit 248fc619b5
3 changed files with 129 additions and 90 deletions

2
TODO
View file

@ -64,8 +64,6 @@ Features:
* when parsing calendar timestamps support the UTC timezone (even if we won't support arbitrary timezone specs, support UTC itself certainly makes sense), also support syntaxes such as +0200
* journalctl: add an output mode that looks like classic /var/log/messages, but also outputs the cursor of the last entry so that people can write scripts that can run iteratively and always process data that has been added since the last time.
* when a kernel driver logs in a tight loop we should ratelimit that too.
* man: document in the journalctl man page what the colors mean

View file

@ -522,6 +522,16 @@
cursor.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--after-cursor=</option></term>
<listitem><para>Start showing entries from the
location in the journal
<emphasis>after</emphasis> the location
specified by the this cursor.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--since=</option></term>
<term><option>--until=</option></term>

View file

@ -74,6 +74,8 @@ static bool arg_boot_id = false;
static char *arg_boot_id_descriptor = NULL;
static bool arg_dmesg = false;
static const char *arg_cursor = NULL;
static const char *arg_after_cursor = NULL;
static bool arg_show_cursor = false;
static const char *arg_directory = NULL;
static char **arg_file = NULL;
static int arg_priorities = 0xFF;
@ -119,6 +121,8 @@ static int help(void) {
" --since=DATE Start showing entries newer or of the specified date\n"
" --until=DATE Stop showing entries older or of the specified date\n"
" -c --cursor=CURSOR Start showing entries from specified cursor\n"
" --after-cursor=CURSOR Start showing entries from specified cursor\n"
" --show-cursor Print the cursor after all the entries\n"
" -b --boot[=ID] Show data only from ID or current boot if unspecified\n"
" -k --dmesg Show kernel message log from current boot\n"
" -u --unit=UNIT Show data only from the specified unit\n"
@ -143,6 +147,7 @@ static int help(void) {
#ifdef HAVE_GCRYPT
" --interval=TIME Time interval for changing the FSS sealing key\n"
" --verify-key=KEY Specify FSS verification key\n"
" --force Force overriding new FSS key pair with --setup-keys\n"
#endif
"\nCommands:\n"
" -h --help Show this help\n"
@ -156,7 +161,6 @@ static int help(void) {
" --update-catalog Update the message catalog database\n"
#ifdef HAVE_GCRYPT
" --setup-keys Generate new FSS key pair\n"
" --force Force overriding new FSS key pair with --setup-keys\n"
" --verify Verify journal file consistency\n"
#endif
, program_invocation_short_name);
@ -183,6 +187,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_DISK_USAGE,
ARG_SINCE,
ARG_UNTIL,
ARG_AFTER_CURSOR,
ARG_SHOW_CURSOR,
ARG_USER_UNIT,
ARG_LIST_CATALOG,
ARG_DUMP_CATALOG,
@ -221,6 +227,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
{ "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
{ "cursor", required_argument, NULL, 'c' },
{ "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
{ "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
{ "since", required_argument, NULL, ARG_SINCE },
{ "until", required_argument, NULL, ARG_UNTIL },
{ "unit", required_argument, NULL, 'u' },
@ -379,6 +387,14 @@ static int parse_argv(int argc, char *argv[]) {
arg_cursor = optarg;
break;
case ARG_AFTER_CURSOR:
arg_after_cursor = optarg;
break;
case ARG_SHOW_CURSOR:
arg_show_cursor = true;
break;
case ARG_HEADER:
arg_action = ACTION_PRINT_HEADER;
break;
@ -549,8 +565,8 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
if (arg_cursor && arg_since_set) {
log_error("Please specify either --since= or --cursor=, not both.");
if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) {
log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
return -EINVAL;
}
@ -1435,16 +1451,20 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
if (arg_cursor) {
r = sd_journal_seek_cursor(j, arg_cursor);
if (arg_cursor || arg_after_cursor) {
r = sd_journal_seek_cursor(j, arg_cursor ? arg_cursor : arg_after_cursor);
if (r < 0) {
log_error("Failed to seek to cursor: %s", strerror(-r));
return EXIT_FAILURE;
}
if (!arg_reverse)
r = sd_journal_next(j);
r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
else
r = sd_journal_previous(j);
r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
if (arg_after_cursor && r < 2 && !arg_follow)
/* We couldn't find the next entry after the cursor. */
arg_lines = 0;
} else if (arg_since_set && !arg_reverse) {
r = sd_journal_seek_realtime_usec(j, arg_since);
@ -1592,8 +1612,19 @@ int main(int argc, char *argv[]) {
n_shown++;
}
if (!arg_follow)
if (!arg_follow) {
if (arg_show_cursor) {
_cleanup_free_ char *cursor = NULL;
r = sd_journal_get_cursor(j, &cursor);
if (r < 0 && r != -EADDRNOTAVAIL)
log_error("Failed to get cursor: %s", strerror(-r));
else if (r >= 0)
printf("-- cursor: %s\n", cursor);
}
break;
}
r = sd_journal_wait(j, (uint64_t) -1);
if (r < 0) {