[systemd-commits] 2 commits - TODO man/journalctl.xml src/journal src/shared

Lennart Poettering lennart at kemper.freedesktop.org
Wed Oct 24 18:00:39 PDT 2012


 TODO                            |    5 -
 man/journalctl.xml              |    5 +
 src/journal/test-journal-send.c |   10 ++
 src/shared/hashmap.c            |   40 +++++++++-
 src/shared/hashmap.h            |    2 
 src/shared/logs-show.c          |  155 +++++++++++++++++++++++++++++++++++-----
 6 files changed, 194 insertions(+), 23 deletions(-)

New commits:
commit a73d88fa024b5668ed7dde681e99547d41e6a864
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 25 01:20:18 2012 +0200

    update TODO

diff --git a/TODO b/TODO
index 4f32c52..d12308e 100644
--- a/TODO
+++ b/TODO
@@ -19,6 +19,8 @@ F18:
 
 Features:
 
+* link up selected blog stories from man pages?
+
 * journactl: support negative filtering, i.e. FOOBAR!="waldo"
 
 * drop header/footer from systemctl --failed output if there are no entries shown, print nice message instead, and hook that into ExecStartPre of rescue.service/emergency.service
@@ -475,13 +477,12 @@ Features:
   - remote access
   - how to pass throw-away units to systemd, or dynamically change properties of existing units
   - how to integrate cgconfig and suchlike with systemd
-  - resource control in systemd
   - testing with Harald's awesome test kit
   - auto-restart
-  - journalctl advanced usage
   - how to make use of the journal submission APIs
   - same for journal browsing
   - the journal HTTP iface
+  - non-cgroup resource management
 
 * allow port=0 in .socket units
 

commit d99ae53a7327e1520ea4b9a3408c2d7f938c4b37
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 25 01:19:24 2012 +0200

    journal: properly serialize fields with multiple values into JSON
    
    This now matches the JSON serialization spec from:
    
    http://www.freedesktop.org/wiki/Software/systemd/json

diff --git a/man/journalctl.xml b/man/journalctl.xml
index 9bc0153..026bb22 100644
--- a/man/journalctl.xml
+++ b/man/journalctl.xml
@@ -212,7 +212,10 @@
                                 information). <literal>json</literal>
                                 formats entries as JSON data
                                 structures, one per
-                                line. <literal>json-pretty</literal>
+                                line (see <ulink
+                                url="http://www.freedesktop.org/wiki/Software/systemd/json">Journal
+                                JSON Format</ulink> for more
+                                information). <literal>json-pretty</literal>
                                 also formats entries as JSON data
                                 structures, but formats them in
                                 multiple lines in order to make them
diff --git a/src/journal/test-journal-send.c b/src/journal/test-journal-send.c
index 168c843..9bf42f9 100644
--- a/src/journal/test-journal-send.c
+++ b/src/journal/test-journal-send.c
@@ -47,5 +47,15 @@ int main(int argc, char *argv[]) {
                         huge,
                         NULL);
 
+        sd_journal_send("MESSAGE=uiui",
+                        "VALUE=A",
+                        "VALUE=B",
+                        "VALUE=C",
+                        "SINGLETON=1",
+                        "OTHERVALUE=X",
+                        "OTHERVALUE=Y",
+                        "WITH_BINARY=this is a binary value \a",
+                        NULL);
+
         return 0;
 }
diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c
index 26a4eff..ef78070 100644
--- a/src/shared/hashmap.c
+++ b/src/shared/hashmap.c
@@ -328,7 +328,8 @@ int hashmap_put(Hashmap *h, const void *key, void *value) {
 
         hash = h->hash_func(key) % NBUCKETS;
 
-        if ((e = hash_scan(h, hash, key))) {
+        e = hash_scan(h, hash, key);
+        if (e) {
 
                 if (e->value == value)
                         return 0;
@@ -359,8 +360,8 @@ int hashmap_replace(Hashmap *h, const void *key, void *value) {
         assert(h);
 
         hash = h->hash_func(key) % NBUCKETS;
-
-        if ((e = hash_scan(h, hash, key))) {
+        e = hash_scan(h, hash, key);
+        if (e) {
                 e->key = key;
                 e->value = value;
                 return 0;
@@ -369,6 +370,21 @@ int hashmap_replace(Hashmap *h, const void *key, void *value) {
         return hashmap_put(h, key, value);
 }
 
+int hashmap_update(Hashmap *h, const void *key, void *value) {
+        struct hashmap_entry *e;
+        unsigned hash;
+
+        assert(h);
+
+        hash = h->hash_func(key) % NBUCKETS;
+        e = hash_scan(h, hash, key);
+        if (!e)
+                return -ENOENT;
+
+        e->value = value;
+        return 0;
+}
+
 void* hashmap_get(Hashmap *h, const void *key) {
         unsigned hash;
         struct hashmap_entry *e;
@@ -384,6 +400,24 @@ void* hashmap_get(Hashmap *h, const void *key) {
         return e->value;
 }
 
+void* hashmap_get2(Hashmap *h, const void *key, void **key2) {
+        unsigned hash;
+        struct hashmap_entry *e;
+
+        if (!h)
+                return NULL;
+
+        hash = h->hash_func(key) % NBUCKETS;
+        e = hash_scan(h, hash, key);
+        if (!e)
+                return NULL;
+
+        if (key2)
+                *key2 = (void*) e->key;
+
+        return e->value;
+}
+
 bool hashmap_contains(Hashmap *h, const void *key) {
         unsigned hash;
 
diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h
index ed41817..55dea0a 100644
--- a/src/shared/hashmap.h
+++ b/src/shared/hashmap.h
@@ -51,8 +51,10 @@ Hashmap *hashmap_copy(Hashmap *h);
 int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func);
 
 int hashmap_put(Hashmap *h, const void *key, void *value);
+int hashmap_update(Hashmap *h, const void *key, void *value);
 int hashmap_replace(Hashmap *h, const void *key, void *value);
 void* hashmap_get(Hashmap *h, const void *key);
+void* hashmap_get2(Hashmap *h, const void *key, void **rkey);
 bool hashmap_contains(Hashmap *h, const void *key);
 void* hashmap_remove(Hashmap *h, const void *key);
 void* hashmap_remove_value(Hashmap *h, const void *key, void *value);
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index 63a48e4..36cce73 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -29,6 +29,7 @@
 #include "log.h"
 #include "util.h"
 #include "utf8.h"
+#include "hashmap.h"
 
 #define PRINT_THRESHOLD 128
 #define JSON_THRESHOLD 4096
@@ -464,12 +465,14 @@ static int output_json(
                 OutputFlags flags) {
 
         uint64_t realtime, monotonic;
-        char *cursor;
+        char *cursor, *k;
         const void *data;
         size_t length;
         sd_id128_t boot_id;
         char sid[33];
         int r;
+        Hashmap *h = NULL;
+        bool done, separator;
 
         assert(j);
 
@@ -518,31 +521,141 @@ static int output_json(
         }
         free(cursor);
 
+        h = hashmap_new(string_hash_func, string_compare_func);
+        if (!h)
+                return -ENOMEM;
+
+        /* First round, iterate through the entry and count how often each field appears */
         SD_JOURNAL_FOREACH_DATA(j, data, length) {
-                const char *c;
+                const char *eq;
+                char *n;
+                unsigned u;
 
-                /* We already printed the boot id, from the data in
-                 * the header, hence let's suppress it here */
                 if (length >= 9 &&
                     memcmp(data, "_BOOT_ID=", 9) == 0)
                         continue;
 
-                c = memchr(data, '=', length);
-                if (!c) {
-                        log_error("Invalid field.");
-                        return -EINVAL;
-                }
+                eq = memchr(data, '=', length);
+                if (!eq)
+                        continue;
 
-                if (mode == OUTPUT_JSON_PRETTY)
-                        fputs(",\n\t", f);
-                else
-                        fputs(", ", f);
+                n = strndup(data, eq - (const char*) data);
+                if (!n) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
 
-                json_escape(f, data, c - (const char*) data, flags);
-                fputs(" : ", f);
-                json_escape(f, c + 1, length - (c - (const char*) data) - 1, flags);
+                u = PTR_TO_UINT(hashmap_get(h, n));
+                if (u == 0) {
+                        r = hashmap_put(h, n, UINT_TO_PTR(1));
+                        if (r < 0) {
+                                free(n);
+                                goto finish;
+                        }
+                } else {
+                        r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
+                        free(n);
+                        if (r < 0)
+                                goto finish;
+                }
         }
 
+        separator = true;
+        do {
+                done = true;
+
+                SD_JOURNAL_FOREACH_DATA(j, data, length) {
+                        const char *eq;
+                        char *kk, *n;
+                        size_t m;
+                        unsigned u;
+
+                        /* We already printed the boot id, from the data in
+                         * the header, hence let's suppress it here */
+                        if (length >= 9 &&
+                            memcmp(data, "_BOOT_ID=", 9) == 0)
+                                continue;
+
+                        eq = memchr(data, '=', length);
+                        if (!eq)
+                                continue;
+
+                        if (separator) {
+                                if (mode == OUTPUT_JSON_PRETTY)
+                                        fputs(",\n\t", f);
+                                else
+                                        fputs(", ", f);
+                        }
+
+                        m = eq - (const char*) data;
+
+                        n = strndup(data, m);
+                        if (!n) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
+                        if (u == 0) {
+                                /* We already printed this, let's jump to the next */
+                                free(n);
+                                separator = false;
+
+                                continue;
+                        } else if (u == 1) {
+                                /* Field only appears once, output it directly */
+
+                                json_escape(f, data, m, flags);
+                                fputs(" : ", f);
+
+                                json_escape(f, eq + 1, length - m - 1, flags);
+
+                                hashmap_remove(h, n);
+                                free(kk);
+                                free(n);
+
+                                separator = true;
+
+                                continue;
+
+                        } else {
+                                /* Field appears multiple times, output it as array */
+                                json_escape(f, data, m, flags);
+                                fputs(" : [ ", f);
+                                json_escape(f, eq + 1, length - m - 1, flags);
+
+                                /* Iterate through the end of the list */
+
+                                while (sd_journal_enumerate_data(j, &data, &length) > 0) {
+                                        if (length < m + 1)
+                                                continue;
+
+                                        if (memcmp(data, n, m) != 0)
+                                                continue;
+
+                                        if (((const char*) data)[m] != '=')
+                                                continue;
+
+                                        fputs(", ", f);
+                                        json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
+                                }
+
+                                fputs(" ]", f);
+
+                                hashmap_remove(h, n);
+                                free(kk);
+                                free(n);
+
+                                /* Iterate data fields form the beginning */
+                                done = false;
+                                separator = true;
+
+                                break;
+                        }
+                }
+
+        } while (!done);
+
         if (mode == OUTPUT_JSON_PRETTY)
                 fputs("\n}\n", f);
         else if (mode == OUTPUT_JSON_SSE)
@@ -550,7 +663,15 @@ static int output_json(
         else
                 fputs(" }\n", f);
 
-        return 0;
+        r = 0;
+
+finish:
+        while ((k = hashmap_steal_first_key(h)))
+                free(k);
+
+        hashmap_free(h);
+
+        return r;
 }
 
 static int output_cat(



More information about the systemd-commits mailing list