[syslog-ng] [PATCH 6/7] json: Use a hand-coded JSON formatter
Gergely Nagy
algernon at balabit.hu
Fri Sep 14 11:52:00 CEST 2012
Instead of relying on json-c to format our JSON, do it ourselves,
skipping quite a bit of object allocations that we do not need.
Signed-off-by: Gergely Nagy <algernon at balabit.hu>
---
modules/json/tfjson.c | 152 +++++++++++++++++++++++++++++++++----------------
1 file changed, 103 insertions(+), 49 deletions(-)
diff --git a/modules/json/tfjson.c b/modules/json/tfjson.c
index c8a2472..e46cbd4 100644
--- a/modules/json/tfjson.c
+++ b/modules/json/tfjson.c
@@ -25,10 +25,6 @@
#include "cfg.h"
#include "value-pairs.h"
-#include <printbuf.h>
-#include <json.h>
-#include <json_object_private.h>
-
typedef struct _TFJsonState
{
TFSimpleFuncState super;
@@ -49,33 +45,70 @@ tf_json_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent,
return TRUE;
}
-static int
-tf_json_object_to_string (struct json_object *jso,
- struct printbuf *pb)
+typedef struct
+{
+ gboolean need_comma;
+ GString *buffer;
+} json_state_t;
+
+static inline void
+g_string_append_escaped(GString *dest, const char *str)
{
- int i = 0;
- struct json_object_iter iter;
- sprintbuf (pb, "{");
+ /* Assumes ASCII! Keep in sync with the switch! */
+ static const unsigned char json_exceptions[UCHAR_MAX + 1] =
+ {
+ [0x01] = 1, [0x02] = 1, [0x03] = 1, [0x04] = 1, [0x05] = 1, [0x06] = 1,
+ [0x07] = 1, [0x08] = 1, [0x09] = 1, [0x0a] = 1, [0x0b] = 1, [0x0c] = 1,
+ [0x0d] = 1, [0x0e] = 1, [0x0f] = 1, [0x10] = 1, [0x11] = 1, [0x12] = 1,
+ [0x13] = 1, [0x14] = 1, [0x15] = 1, [0x16] = 1, [0x17] = 1, [0x18] = 1,
+ [0x19] = 1, [0x1a] = 1, [0x1b] = 1, [0x1c] = 1, [0x1d] = 1, [0x1e] = 1,
+ [0x1f] = 1, ['\\'] = 1, ['"'] = 1
+ };
+
+ const unsigned char *p;
- json_object_object_foreachC (jso, iter)
+ p = (unsigned char *)str;
+
+ while (*p)
{
- gchar *esc;
-
- if (i)
- sprintbuf (pb, ",");
- sprintbuf (pb, "\"");
- esc = g_strescape (iter.key, NULL);
- sprintbuf (pb, esc);
- g_free (esc);
- sprintbuf (pb, "\":");
- if (iter.val == NULL)
- sprintbuf (pb, "null");
+ if (json_exceptions[*p] == 0)
+ g_string_append_c(dest, *p);
else
- iter.val->_to_json_string (iter.val, pb);
- i++;
+ {
+ /* Keep in sync with json_exceptions! */
+ switch (*p)
+ {
+ case '\b':
+ g_string_append(dest, "\\b");
+ break;
+ case '\n':
+ g_string_append(dest, "\\n");
+ break;
+ case '\r':
+ g_string_append(dest, "\\r");
+ break;
+ case '\t':
+ g_string_append(dest, "\\t");
+ break;
+ case '\\':
+ g_string_append(dest, "\\\\");
+ break;
+ case '"':
+ g_string_append(dest, "\\\"");
+ break;
+ default:
+ {
+ static const char json_hex_chars[16] = "0123456789abcdef";
+
+ g_string_append(dest, "\\u00");
+ g_string_append_c(dest, json_hex_chars[(*p) >> 4]);
+ g_string_append_c(dest, json_hex_chars[(*p) & 0xf]);
+ break;
+ }
+ }
+ }
+ p++;
}
-
- return sprintbuf(pb, "}");
}
static gboolean
@@ -84,14 +117,30 @@ tf_json_obj_start(const gchar *name,
const gchar *prev, gpointer *prev_data,
gpointer user_data)
{
- struct json_object *o;
+ json_state_t *state = (json_state_t *)user_data;
+ gboolean need_comma = FALSE;
if (prefix_data)
+ need_comma = GPOINTER_TO_INT(*prefix_data);
+ else
+ need_comma = state->need_comma;
+
+ if (need_comma)
+ g_string_append_c(state->buffer, ',');
+
+ if (name)
{
- o = json_object_new_object();
- *prefix_data = o;
- o->_to_json_string = tf_json_object_to_string;
+ g_string_append_c(state->buffer, '"');
+ g_string_append_escaped(state->buffer, name);
+ g_string_append(state->buffer, "\":{");
+ state->need_comma = TRUE;
}
+ else
+ g_string_append_c(state->buffer, '{');
+
+ if (prefix_data)
+ *prefix_data=GINT_TO_POINTER(0);
+
return FALSE;
}
@@ -101,15 +150,13 @@ tf_json_obj_end(const gchar *name,
const gchar *prev, gpointer *prev_data,
gpointer user_data)
{
- struct json_object *root;
+ json_state_t *state = (json_state_t *)user_data;
if (prev_data)
- root = (struct json_object *)*prev_data;
- else
- root = (struct json_object *)user_data;
+ *prev_data = GINT_TO_POINTER(1);
+
+ g_string_append_c(state->buffer, '}');
- if (prefix_data)
- json_object_object_add (root, (gchar *) name, (struct json_object *)*prefix_data);
return FALSE;
}
@@ -117,16 +164,26 @@ static gboolean
tf_json_value(const gchar *name, const gchar *prefix, const gchar *value,
gpointer *prefix_data, gpointer user_data)
{
- struct json_object *root;
- struct json_object *this;
+ gboolean need_comma = FALSE;
+ json_state_t *state = (json_state_t *)user_data;
if (prefix_data)
- root = (struct json_object *)*prefix_data;
+ need_comma = GPOINTER_TO_INT(*prefix_data);
else
- root = (struct json_object *)user_data;
+ need_comma = state->need_comma;
+
+ if (need_comma)
+ g_string_append_c(state->buffer, ',');
+ else if (prefix_data)
+ *prefix_data = GINT_TO_POINTER(1);
- this = json_object_new_string ((gchar *) value);
- json_object_object_add (root, (gchar *) name, this);
+ g_string_append_c(state->buffer, '"');
+ g_string_append_escaped(state->buffer, name);
+ g_string_append(state->buffer, "\":\"");
+ g_string_append_escaped(state->buffer, value);
+ g_string_append_c(state->buffer, '"');
+
+ state->need_comma = TRUE;
return FALSE;
}
@@ -134,17 +191,14 @@ tf_json_value(const gchar *name, const gchar *prefix, const gchar *value,
static void
tf_json_append(GString *result, ValuePairs *vp, LogMessage *msg)
{
- struct json_object *json;
+ json_state_t state;
- json = json_object_new_object();
- json->_to_json_string = tf_json_object_to_string;
+ state.need_comma = FALSE;
+ state.buffer = result;
value_pairs_walk(vp,
tf_json_obj_start, tf_json_value, tf_json_obj_end,
- msg, 0, json);
-
- g_string_append(result, json_object_to_json_string (json));
- json_object_put(json);
+ msg, 0, &state);
}
static void
--
1.7.10.4
More information about the syslog-ng
mailing list