[systemd-commits] 3 commits - Makefile.am man/sd_journal_get_cursor.xml man/sd_journal_seek_head.xml src/journal src/systemd TODO

Lennart Poettering lennart at kemper.freedesktop.org
Wed Oct 10 13:41:16 PDT 2012


 Makefile.am                        |    4 +
 TODO                               |    2 
 man/sd_journal_get_cursor.xml      |   53 ++++++++++++++++-----
 man/sd_journal_seek_head.xml       |    7 ++
 src/journal/browse.html            |   77 +++++++++++++++++++++++++++---
 src/journal/journal-gatewayd.c     |   38 +++++++++++++++
 src/journal/libsystemd-journal.sym |    5 +
 src/journal/sd-journal.c           |   93 ++++++++++++++++++++++++++++++++++---
 src/journal/test-journal-stream.c  |   16 +++++-
 src/systemd/sd-journal.h           |    1 
 10 files changed, 267 insertions(+), 29 deletions(-)

New commits:
commit c6511e859c35b12de4e6fb5f58d7258d9de3b8f2
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 10 22:39:45 2012 +0200

    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 0b3013b..c23afdf 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 9e00ef7..354168b 100644
--- a/man/sd_journal_get_cursor.xml
+++ b/man/sd_journal_get_cursor.xml
@@ -44,7 +44,8 @@
 
         <refnamediv>
                 <refname>sd_journal_get_cursor</refname>
-                <refpurpose>Get cursor string for the current journal entry</refpurpose>
+                <refname>sd_journal_test_cursor</refname>
+                <refpurpose>Get cursor string for or test cursor string against the current journal entry</refpurpose>
         </refnamediv>
 
         <refsynopsisdiv>
@@ -57,6 +58,12 @@
                                 <paramdef>char ** <parameter>cursor</parameter></paramdef>
                         </funcprototype>
 
+                        <funcprototype>
+                                <funcdef>int <function>sd_journal_test_cursor</function></funcdef>
+                                <paramdef>sd_journal* <parameter>j</parameter></paramdef>
+                                <paramdef>const char * <parameter>cursor</parameter></paramdef>
+                        </funcprototype>
+
                 </funcsynopsis>
         </refsynopsisdiv>
 
@@ -66,7 +73,7 @@
                 <para><function>sd_journal_get_cursor()</function>
                 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 <citerefentry><refentrytitle>malloc</refentrytitle><manvolnum>3</manvolnum></citerefentry> 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
+                <citerefentry><refentrytitle>malloc</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+                and should be freed after use with
                 <citerefentry><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
 
-                <para>Note that this function will not work before
+                <para>Note that
+                <function>sd_journal_get_cursor()</function> will not
+                work before
                 <citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-                (or related call) has been called at least
-                once, in order to position the read pointer at a valid entry.</para>
+                (or related call) has been called at least once, in
+                order to position the read pointer at a valid
+                entry.</para>
+
+                <para><function>sd_journal_test_cursor()</function>
+                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
+                <citerefentry><refentrytitle>sd_journal_seek_cursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+                whether the entry being seeked to was actually found
+                in the journal or the next closest entry was used
+                instead.</para>
         </refsect1>
 
         <refsect1>
@@ -94,15 +118,20 @@
 
                 <para><function>sd_journal_get_cursor()</function>
                 returns 0 on success or a negative errno-style error
-                code.</para>
+                code. <function>sd_journal_test_cursor()</function>
+                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.</para>
         </refsect1>
 
         <refsect1>
                 <title>Notes</title>
 
                 <para>The <function>sd_journal_get_cursor()</function>
-                interface is available as shared library, which can be
-                compiled and linked to with the
+                and <function>sd_journal_test_cursor()</function>
+                interfaces are available as shared library, which can
+                be compiled and linked to with the
                 <literal>libsystemd-journal</literal>
                 <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                 file.</para>
diff --git a/man/sd_journal_seek_head.xml b/man/sd_journal_seek_head.xml
index f8a4eb1..b10f069 100644
--- a/man/sd_journal_seek_head.xml
+++ b/man/sd_journal_seek_head.xml
@@ -115,7 +115,12 @@
                 <para><function>sd_journal_seek_cursor()</function>
                 seeks to the entry located at the specified cursor
                 string. For details on cursors see
-                <citerefentry><refentrytitle>sd_journal_get_cursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+                <citerefentry><refentrytitle>sd_journal_get_cursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>. 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
+                <citerefentry><refentrytitle>sd_journal_test_cursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
 
                 <para>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 5ceca26..068b296 100644
--- a/src/journal/browse.html
+++ b/src/journal/browse.html
@@ -4,7 +4,7 @@
         <title>Journal</title>
         <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
         <style type="text/css">
-                div#divlogs {
+                div#divlogs, div#diventry {
                         font-family: monospace;
                         font-size: 8pt;
                         background-color: #ffffff;
@@ -15,6 +15,12 @@
                         white-space: nowrap;
                         overflow-x: scroll;
                 }
+                div#diventry {
+                        display: none;
+                }
+                div#divlogs {
+                        display: block;
+                }
                 body {
                         background-color: #ededed;
                         color: #313739;
@@ -34,17 +40,41 @@
                 td.message {
                         padding-left: 5px;
                 }
+                td.message > a:link, td.message > a:visited {
+                        text-decoration: none;
+                        color: #313739;
+                }
                 td.message-error {
                         padding-left: 5px;
                         color: red;
                         font-weight: bold;
                 }
+                td.message-error > a:link, td.message-error > a:visited {
+                        text-decoration: none;
+                        color: red;
+                }
                 td.message-highlight {
                         padding-left: 5px;
                         font-weight: bold;
                 }
-                table#tablelogs {
-                        border-collapse:collapse;
+                td.message-highlight > a:link, td.message-highlight > a:visited {
+                        text-decoration: none;
+                        color: #313739;
+                }
+                td > a:hover, td > a:active {
+                        text-decoration: underline;
+                        color: #c13739;
+                }
+                table#tablelogs, table#tableentry {
+                        border-collapse: collapse;
+                }
+                td.field {
+                        text-align: right;
+                        border-right: 1px dotted lightgrey;
+                        padding-right: 5px;
+                }
+                td.data {
+                        padding-left: 5px;
                 }
         </style>
 </head>
@@ -65,6 +95,8 @@
         <div id="showing"></div>
 
         <div id="divlogs"><table id="tablelogs"></table></div>
+        <a name="entry"></a>
+        <div id="diventry"><table id="tableentry"></table></div>
 
         <form>
                 <input id="head" type="button" value="|<" onclick="entriesLoadHead();"/>
@@ -271,7 +303,7 @@
                                 else if (d.SYSLOG_PID != undefined)
                                         buf += "[" + d.SYSLOG_PID + "]";
 
-                                buf += '</td><td class="' + clazz + '">';
+                                buf += '</td><td class="' + clazz + '"><a href="#entry" onclick="onMessageClick(\'' + lc + '\');">';
 
                                 if (d.MESSAGE == null)
                                         buf += "[blob data]";
@@ -280,10 +312,10 @@
                                 else
                                         buf += d.MESSAGE;
 
-                                buf += '</td></tr>';
+                                buf += '</a></td></tr>';
                         }
 
-                        logs.innerHTML = buf + '</tbody>';
+                        logs.innerHTML = '<tbody>' + buf + '</tbody>';
 
                         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 += '<tr><td class="field">' + key + '</td><td class="data">' + d[key] + '</td></tr>';
+                        }
+
+                        entry.innerHTML = '<tbody>' + buf + '</tbody>';
+                }
+
+                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 274ef5f..33dda26 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 7dfae26..77de862 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 9e594a2..88b382f 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 707dcc1..caea2b2 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 6c18c89..9a2aab9 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);

commit 934a316cbf68c46f05b7ce0b35fc312eca786747
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 10 22:24:28 2012 +0200

    journal: drop path name from cursor strings
    
    we had this mostly for debugging purposes and it was ignored when
    parsing anyway, so let's get rid of it

diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 6764f2e..9e594a2 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -940,12 +940,11 @@ _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
         sd_id128_to_string(o->entry.boot_id, bid);
 
         if (asprintf(cursor,
-                     "s=%s;i=%llx;b=%s;m=%llx;t=%llx;x=%llx;p=%s",
+                     "s=%s;i=%llx;b=%s;m=%llx;t=%llx;x=%llx",
                      sid, (unsigned long long) le64toh(o->entry.seqnum),
                      bid, (unsigned long long) le64toh(o->entry.monotonic),
                      (unsigned long long) le64toh(o->entry.realtime),
-                     (unsigned long long) le64toh(o->entry.xor_hash),
-                     path_get_file_name(j->current_file->path)) < 0)
+                     (unsigned long long) le64toh(o->entry.xor_hash)) < 0)
                 return -ENOMEM;
 
         return 1;

commit 9a526a06bd22ccaf6641d11323fb04a0512a0e49
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 10 22:23:06 2012 +0200

    update TODO

diff --git a/TODO b/TODO
index 894b94f..5943c9a 100644
--- a/TODO
+++ b/TODO
@@ -19,6 +19,8 @@ F18:
 
 Features:
 
+* document unit_name_mangle()
+
 * add new command to systemctl: "systemctl system-reexec" which reexecs as many daemons as virtually possible
 
 * introduce generic AUGMENT_PID=, AUGMENT_DEVICE= fields



More information about the systemd-commits mailing list