mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
journalctl: New option --cursor-file
The option cursor-file takes a filename as argument. If the file exists and contains a valid cursor, this is used to start the output after this position. At the end, the last cursor gets written to the file. This allows for an easy implementation of a timer that regularly looks in the journal for some messages. journalctl --cursor-file err-cursor -b -p err journalctl --cursor-file audit-cursor -t audit --grep DENIED Or you might want to walk the journal in steps of 10 messages: journalctl --cursor-file ./curs -n10 --since=today -t systemd
This commit is contained in:
parent
200fb167a2
commit
d9e15cbd18
@ -618,6 +618,17 @@
|
||||
journal specified by the passed cursor.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--cursor-file=<replaceable>FILE</replaceable></option></term>
|
||||
|
||||
<listitem><para>If <replaceable>FILE</replaceable> exists and contains a
|
||||
cursor, start showing entries <emphasis>after</emphasis> this location.
|
||||
Otherwise the show entries according the other given options. At the end,
|
||||
write the cursor of the last entry to <replaceable>FILE</replaceable>. Use
|
||||
this option to continually read the journal by sequentially calling
|
||||
<command>journalctl</command>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--after-cursor=</option></term>
|
||||
|
||||
|
@ -48,7 +48,7 @@ _journalctl() {
|
||||
-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 --verify-key -g --grep
|
||||
--after-cursor --cursor-file --verify-key -g --grep
|
||||
--vacuum-size --vacuum-time --vacuum-files --output-fields'
|
||||
)
|
||||
|
||||
|
@ -104,6 +104,7 @@ _arguments -s \
|
||||
{-p+,--priority=}'[Show only messages within the specified priority range]:priority:_journalctl_field_values PRIORITY' \
|
||||
{-t+,--identifier=}'[Show only messages with the specified syslog identifier]:identifier:_journalctl_field_values SYSLOG_IDENTIFIER' \
|
||||
{-c+,--cursor=}'[Start showing entries from the specified cursor]:cursors:_journalctl_field_values __CURSORS' \
|
||||
'--cursor-file=[Show entries using cursor store in file]:file:_files' \
|
||||
'--after-cursor=[Start showing entries from after the specified cursor]:cursors:_journalctl_field_values __CURSORS' \
|
||||
'--since=[Start showing entries on or newer than the specified date]:YYYY-MM-DD HH\:MM\:SS' \
|
||||
'--until=[Stop showing entries on or older than the specified date]:YYYY-MM-DD HH\:MM\:SS' \
|
||||
|
@ -119,6 +119,7 @@ static int arg_boot_offset = 0;
|
||||
static bool arg_dmesg = false;
|
||||
static bool arg_no_hostname = false;
|
||||
static const char *arg_cursor = NULL;
|
||||
static const char *arg_cursor_file = NULL;
|
||||
static const char *arg_after_cursor = NULL;
|
||||
static bool arg_show_cursor = false;
|
||||
static const char *arg_directory = NULL;
|
||||
@ -315,6 +316,7 @@ static int help(void) {
|
||||
" -c --cursor=CURSOR Show entries starting at the specified cursor\n"
|
||||
" --after-cursor=CURSOR Show entries after the specified cursor\n"
|
||||
" --show-cursor Print the cursor after all the entries\n"
|
||||
" --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
|
||||
" -b --boot[=ID] Show current boot or the specified boot\n"
|
||||
" --list-boots Show terse information about recorded boots\n"
|
||||
" -k --dmesg Show kernel message log from the current boot\n"
|
||||
@ -396,6 +398,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_VERIFY_KEY,
|
||||
ARG_DISK_USAGE,
|
||||
ARG_AFTER_CURSOR,
|
||||
ARG_CURSOR_FILE,
|
||||
ARG_SHOW_CURSOR,
|
||||
ARG_USER_UNIT,
|
||||
ARG_LIST_CATALOG,
|
||||
@ -450,6 +453,7 @@ 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' },
|
||||
{ "cursor-file", required_argument, NULL, ARG_CURSOR_FILE },
|
||||
{ "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
|
||||
{ "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
|
||||
{ "since", required_argument, NULL, 'S' },
|
||||
@ -661,6 +665,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_cursor = optarg;
|
||||
break;
|
||||
|
||||
case ARG_CURSOR_FILE:
|
||||
arg_cursor_file = optarg;
|
||||
break;
|
||||
|
||||
case ARG_AFTER_CURSOR:
|
||||
arg_after_cursor = optarg;
|
||||
break;
|
||||
@ -2077,6 +2085,7 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bool previous_boot_id_valid = false, first_line = true, ellipsized = false, need_seek = false;
|
||||
bool use_cursor = false, after_cursor = false;
|
||||
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
||||
sd_id128_t previous_boot_id;
|
||||
int n_shown = 0, r, poll_fd = -1;
|
||||
@ -2420,19 +2429,41 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_cursor || arg_after_cursor) {
|
||||
r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to seek to cursor: %m");
|
||||
goto finish;
|
||||
if (arg_cursor || arg_after_cursor || arg_cursor_file) {
|
||||
_cleanup_free_ char *cursor_from_file = NULL;
|
||||
const char *cursor = arg_cursor ?: arg_after_cursor;
|
||||
|
||||
if (arg_cursor_file) {
|
||||
r = read_one_line_file(arg_cursor_file, &cursor_from_file);
|
||||
if (r < 0 && r != -ENOENT) {
|
||||
log_error_errno(r, "Failed to read cursor file %s: %m", arg_cursor_file);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (r > 0) {
|
||||
cursor = cursor_from_file;
|
||||
after_cursor = true;
|
||||
}
|
||||
} else
|
||||
after_cursor = !!arg_after_cursor;
|
||||
|
||||
if (cursor) {
|
||||
r = sd_journal_seek_cursor(j, cursor);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to seek to cursor: %m");
|
||||
goto finish;
|
||||
}
|
||||
use_cursor = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_cursor) {
|
||||
if (!arg_reverse)
|
||||
r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
|
||||
r = sd_journal_next_skip(j, 1 + after_cursor);
|
||||
else
|
||||
r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
|
||||
r = sd_journal_previous_skip(j, 1 + after_cursor);
|
||||
|
||||
if (arg_after_cursor && r < 2) {
|
||||
if (after_cursor && r < 2) {
|
||||
/* We couldn't find the next entry after the cursor. */
|
||||
if (arg_follow)
|
||||
need_seek = true;
|
||||
@ -2661,14 +2692,26 @@ int main(int argc, char *argv[]) {
|
||||
if (n_shown == 0 && !arg_quiet)
|
||||
printf("-- No entries --\n");
|
||||
|
||||
if (arg_show_cursor) {
|
||||
if (arg_show_cursor || arg_cursor_file) {
|
||||
_cleanup_free_ char *cursor = NULL;
|
||||
|
||||
r = sd_journal_get_cursor(j, &cursor);
|
||||
if (r < 0 && r != -EADDRNOTAVAIL)
|
||||
log_error_errno(r, "Failed to get cursor: %m");
|
||||
else if (r >= 0)
|
||||
printf("-- cursor: %s\n", cursor);
|
||||
else if (r >= 0) {
|
||||
if (arg_show_cursor)
|
||||
printf("-- cursor: %s\n", cursor);
|
||||
|
||||
if (arg_cursor_file) {
|
||||
r = write_string_file(arg_cursor_file, cursor,
|
||||
WRITE_STRING_FILE_CREATE |
|
||||
WRITE_STRING_FILE_ATOMIC);
|
||||
if (r < 0)
|
||||
log_error_errno(r,
|
||||
"Failed to write new cursor to %s: %m",
|
||||
arg_cursor_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user