From: Lennart Poettering Date: Wed, 10 Oct 2012 20:39:45 +0000 (+0200) Subject: journal: when browsing the journal via browse.html allow clicking on entries to show... X-Git-Tag: v195~137 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=c6511e859c35b12de4e6fb5f58d7258d9de3b8f2 journal: when browsing the journal via browse.html allow clicking on entries to show their details --- diff --git a/Makefile.am b/Makefile.am index 0b3013b44..c23afdf17 100644 --- a/Makefile.am +++ b/Makefile.am @@ -580,7 +580,8 @@ MANPAGES_ALIAS = \ man/sd_journal_seek_tail.3 \ man/sd_journal_seek_monotonic_usec.3 \ man/sd_journal_seek_realtime_usec.3 \ - man/sd_journal_seek_cursor.3 + man/sd_journal_seek_cursor.3 \ + man/sd_journal_test_cursor.3 man/reboot.8: man/halt.8 man/poweroff.8: man/halt.8 @@ -649,6 +650,7 @@ man/sd_journal_seek_tail.3: man/sd_journal_seek_head.3 man/sd_journal_seek_monotonic_usec.3: man/sd_journal_seek_head.3 man/sd_journal_seek_realtime_usec.3: man/sd_journal_seek_head.3 man/sd_journal_seek_cursor.3: man/sd_journal_seek_head.3 +man/sd_journal_test_cursor.3: man/sd_journal_get_cursor.3 XML_FILES = \ ${patsubst %.1,%.xml,${patsubst %.3,%.xml,${patsubst %.5,%.xml,${patsubst %.7,%.xml,${patsubst %.8,%.xml,$(MANPAGES)}}}}} diff --git a/man/sd_journal_get_cursor.xml b/man/sd_journal_get_cursor.xml index 9e00ef7c8..354168bee 100644 --- a/man/sd_journal_get_cursor.xml +++ b/man/sd_journal_get_cursor.xml @@ -44,7 +44,8 @@ sd_journal_get_cursor - Get cursor string for the current journal entry + sd_journal_test_cursor + Get cursor string for or test cursor string against the current journal entry @@ -57,6 +58,12 @@ char ** cursor + + int sd_journal_test_cursor + sd_journal* j + const char * cursor + + @@ -66,7 +73,7 @@ sd_journal_get_cursor() returns a cursor string for the current journal entry. A cursor is a serialization of the current - journal position in text form. The string only + journal position formatted as text. The string only contains printable characters and can be passed around in text form. The cursor identifies a journal entry globally and in a stable way and may be used to later @@ -77,16 +84,33 @@ without the specific entry being available locally will seek to the next closest (in terms of time) available entry. The call takes two arguments: a - journal context object and a pointer to a - string pointer where the cursor string will be - placed. The string is allocated via libc malloc3 and should - be freed after use with + journal context object and a pointer to a string + pointer where the cursor string will be placed. The + string is allocated via libc + malloc3 + and should be freed after use with free3. - Note that this function will not work before + Note that + sd_journal_get_cursor() will not + work before sd_journal_next3 - (or related call) has been called at least - once, in order to position the read pointer at a valid entry. + (or related call) has been called at least once, in + order to position the read pointer at a valid + entry. + + sd_journal_test_cursor() + may be used to check whether the current position in + the journal matches the specified cursor. This is + useful since cursor strings do not uniquely identify + an entry: the same entry might be referred to by + multiple different cursor strings, and hence string + comparing cursors is not possible. Use this call to + verify after an invocation of + sd_journal_seek_cursor3 + whether the entry being seeked to was actually found + in the journal or the next closest entry was used + instead. @@ -94,15 +118,20 @@ sd_journal_get_cursor() returns 0 on success or a negative errno-style error - code. + code. sd_journal_test_cursor() + returns positive if the current entry matches the + specified cursor, 0 if it doesn't match the specified + cursor or a negative errno-style error code on + failure. Notes The sd_journal_get_cursor() - interface is available as shared library, which can be - compiled and linked to with the + and sd_journal_test_cursor() + interfaces are available as shared library, which can + be compiled and linked to with the libsystemd-journal pkg-config1 file. diff --git a/man/sd_journal_seek_head.xml b/man/sd_journal_seek_head.xml index f8a4eb1d2..b10f069e8 100644 --- a/man/sd_journal_seek_head.xml +++ b/man/sd_journal_seek_head.xml @@ -115,7 +115,12 @@ sd_journal_seek_cursor() seeks to the entry located at the specified cursor string. For details on cursors see - sd_journal_get_cursor3. + sd_journal_get_cursor3. If + no entry matching the specified cursor is found the + call will seek to the next closest entry (in terms of + time) instead. To verify whether the newly selected + entry actually matches the cursor use + sd_journal_test_cursor3. Note that these calls do not actually make any entry the new current entry, this needs to be done in diff --git a/src/journal/browse.html b/src/journal/browse.html index 5ceca26a5..068b296da 100644 --- a/src/journal/browse.html +++ b/src/journal/browse.html @@ -4,7 +4,7 @@ Journal @@ -65,6 +95,8 @@
+ +
@@ -271,7 +303,7 @@ else if (d.SYSLOG_PID != undefined) buf += "[" + d.SYSLOG_PID + "]"; - buf += ''; + buf += ''; if (d.MESSAGE == null) buf += "[blob data]"; @@ -280,10 +312,10 @@ else buf += d.MESSAGE; - buf += ''; + buf += ''; } - logs.innerHTML = buf + ''; + logs.innerHTML = '' + buf + ''; if (fc != null) first_cursor = fc; @@ -293,12 +325,41 @@ function entriesMore() { setNEntries(getNEntries() + 10); - entriesLoad(""); + entriesLoad(first_cursor); } function entriesLess() { setNEntries(getNEntries() - 10); - entriesLoad(""); + entriesLoad(first_cursor); + } + + function onResultMessageClick(event) { + if ((event.currentTarget.readyState != 4) || + (event.currentTarget.status != 200 && event.currentTarget.status != 0)) + return; + + var d = JSON.parse(event.currentTarget.responseText); + + document.getElementById("diventry").style.display = "block"; + + entry = document.getElementById("tableentry"); + + var buf = ""; + + for (var key in d){ + buf += '' + key + '' + d[key] + ''; + } + + entry.innerHTML = '' + buf + ''; + } + + function onMessageClick(t) { + var request = new XMLHttpRequest(); + request.open("GET", "/entries?discrete"); + request.onreadystatechange = onResultMessageClick; + request.setRequestHeader("Accept", "application/json"); + request.setRequestHeader("Range", "entries=" + t + ":0:1"); + request.send(null); } machineLoad(); diff --git a/src/journal/journal-gatewayd.c b/src/journal/journal-gatewayd.c index 274ef5ffe..33dda266b 100644 --- a/src/journal/journal-gatewayd.c +++ b/src/journal/journal-gatewayd.c @@ -49,6 +49,7 @@ typedef struct RequestMeta { int argument_parse_error; bool follow; + bool discrete; } RequestMeta; static const char* const mime_types[_OUTPUT_MODE_MAX] = { @@ -205,6 +206,19 @@ static ssize_t request_reader_entries( return MHD_CONTENT_READER_END_OF_STREAM; } + if (m->discrete) { + assert(m->cursor); + + r = sd_journal_test_cursor(m->journal, m->cursor); + if (r < 0) { + log_error("Failed to test cursor: %s", strerror(-r)); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + + if (r == 0) + return MHD_CONTENT_READER_END_OF_STREAM; + } + pos -= m->size; m->delta += m->size; @@ -380,6 +394,22 @@ static int request_parse_arguments_iterator( return MHD_YES; } + if (streq(key, "discrete")) { + if (isempty(value)) { + m->discrete = true; + return MHD_YES; + } + + r = parse_boolean(value); + if (r < 0) { + m->argument_parse_error = r; + return MHD_NO; + } + + m->discrete = r; + return MHD_YES; + } + p = strjoin(key, "=", strempty(value), NULL); if (!p) { m->argument_parse_error = log_oom(); @@ -436,6 +466,14 @@ static int request_handler_entries( if (request_parse_arguments(m, connection) < 0) return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Failed to parse URL arguments.\n"); + if (m->discrete) { + if (!m->cursor) + return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Discrete seeks require a cursor specification.\n"); + + m->n_entries = 1; + m->n_entries_set = true; + } + if (m->cursor) r = sd_journal_seek_cursor(m->journal, m->cursor); else if (m->n_skip >= 0) diff --git a/src/journal/libsystemd-journal.sym b/src/journal/libsystemd-journal.sym index 7dfae2625..77de862dc 100644 --- a/src/journal/libsystemd-journal.sym +++ b/src/journal/libsystemd-journal.sym @@ -75,3 +75,8 @@ LIBSYSTEMD_JOURNAL_190 { global: sd_journal_get_usage; } LIBSYSTEMD_JOURNAL_188; + +LIBSYSTEMD_JOURNAL_195 { +global: + sd_journal_test_cursor; +} LIBSYSTEMD_JOURNAL_190; diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 9e594a2cf..88b382f4c 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -951,9 +951,8 @@ _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) { } _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) { - char *w; + char *w, *state; size_t l; - char *state; unsigned long long seqnum, monotonic, realtime, xor_hash; bool seqnum_id_set = false, @@ -966,7 +965,7 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) { if (!j) return -EINVAL; - if (!cursor) + if (isempty(cursor)) return -EINVAL; FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) { @@ -1057,6 +1056,89 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) { return 0; } +_public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { + int r; + char *w, *state; + size_t l; + Object *o; + + if (!j) + return -EINVAL; + if (isempty(cursor)) + return -EINVAL; + + if (!j->current_file || j->current_file->current_offset <= 0) + return -EADDRNOTAVAIL; + + r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o); + if (r < 0) + return r; + + FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) { + _cleanup_free_ char *item = NULL; + sd_id128_t id; + unsigned long long ll; + int k = 0; + + if (l < 2 || w[1] != '=') + return -EINVAL; + + item = strndup(w, l); + if (!item) + return -ENOMEM; + + switch (w[0]) { + + case 's': + k = sd_id128_from_string(item+2, &id); + if (k < 0) + return k; + if (!sd_id128_equal(id, j->current_file->header->seqnum_id)) + return 0; + break; + + case 'i': + if (sscanf(item+2, "%llx", &ll) != 1) + return -EINVAL; + if (ll != le64toh(o->entry.seqnum)) + return 0; + break; + + case 'b': + k = sd_id128_from_string(item+2, &id); + if (k < 0) + return k; + if (!sd_id128_equal(id, o->entry.boot_id)) + return 0; + break; + + case 'm': + if (sscanf(item+2, "%llx", &ll) != 1) + return -EINVAL; + if (ll != le64toh(o->entry.monotonic)) + return 0; + break; + + case 't': + if (sscanf(item+2, "%llx", &ll) != 1) + return -EINVAL; + if (ll != le64toh(o->entry.realtime)) + return 0; + break; + + case 'x': + if (sscanf(item+2, "%llx", &ll) != 1) + return -EINVAL; + if (ll != le64toh(o->entry.xor_hash)) + return 0; + break; + } + } + + return 1; +} + + _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) { if (!j) return -EINVAL; diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c index 707dcc178..caea2b2c6 100644 --- a/src/journal/test-journal-stream.c +++ b/src/journal/test-journal-stream.c @@ -39,7 +39,7 @@ static void verify_contents(sd_journal *j, unsigned skip) { i = 0; SD_JOURNAL_FOREACH(j) { const void *d; - char *k; + char *k, *c; size_t l; unsigned u; @@ -61,6 +61,10 @@ static void verify_contents(sd_journal *j, unsigned skip) { } free(k); + + assert_se(sd_journal_get_cursor(j, &c) >= 0); + assert_se(sd_journal_test_cursor(j, c) > 0); + free(c); } if (skip > 0) @@ -122,17 +126,27 @@ int main(int argc, char *argv[]) { SD_JOURNAL_FOREACH_BACKWARDS(j) { const void *d; size_t l; + char *c; assert_se(sd_journal_get_data(j, "NUMBER", &d, &l) >= 0); printf("\t%.*s\n", (int) l, (const char*) d); + + assert_se(sd_journal_get_cursor(j, &c) >= 0); + assert_se(sd_journal_test_cursor(j, c) > 0); + free(c); } SD_JOURNAL_FOREACH(j) { const void *d; size_t l; + char *c; assert_se(sd_journal_get_data(j, "NUMBER", &d, &l) >= 0); printf("\t%.*s\n", (int) l, (const char*) d); + + assert_se(sd_journal_get_cursor(j, &c) >= 0); + assert_se(sd_journal_test_cursor(j, c) > 0); + free(c); } sd_journal_flush_matches(j); diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h index 6c18c8942..9a2aab923 100644 --- a/src/systemd/sd-journal.h +++ b/src/systemd/sd-journal.h @@ -104,6 +104,7 @@ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec); int sd_journal_seek_cursor(sd_journal *j, const char *cursor); int sd_journal_get_cursor(sd_journal *j, char **cursor); +int sd_journal_test_cursor(sd_journal *j, const char *cursor); int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to); int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, const sd_id128_t boot_id, uint64_t *from, uint64_t *to);