[syslog-ng] [PATCH 4/4] format-json: Support acting on type hints
Gergely Nagy
algernon at balabit.hu
Fri Feb 15 16:26:05 CET 2013
With this patch, $(format-json) becomes able to act on type hints, and
store ints as ints and so on and so forth. Forthermore, the on-error()
setting is implemented for format-json aswell.
Together with the afmongodb patch, this fixes #6.
Signed-off-by: Gergely Nagy <algernon at balabit.hu>
---
modules/json/format-json.c | 101 ++++++++++++++++++++++++++++++++++------
modules/json/tests/test_json.c | 47 +++++++++++++++++++
2 files changed, 133 insertions(+), 15 deletions(-)
diff --git a/modules/json/format-json.c b/modules/json/format-json.c
index edb1608..06673f1 100644
--- a/modules/json/format-json.c
+++ b/modules/json/format-json.c
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2011-2012 BalaBit IT Ltd, Budapest, Hungary
+ * Copyright (c) 2011-2013 BalaBit IT Ltd, Budapest, Hungary
* Copyright (c) 2011 Balint Kovacs <blint at balabit.hu>
- * Copyright (c) 2011-2012 Gergely Nagy <algernon at balabit.hu>
+ * Copyright (c) 2011-2013 Gergely Nagy <algernon at balabit.hu>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
@@ -29,11 +29,13 @@
#include "cfg.h"
#include "value-pairs.h"
#include "vptransform.h"
+#include "syslog-ng.h"
typedef struct _TFJsonState
{
TFSimpleFuncState super;
ValuePairs *vp;
+ gint tc_strictness;
} TFJsonState;
static gboolean
@@ -48,6 +50,8 @@ tf_json_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent,
if (!state->vp)
return FALSE;
+ state->tc_strictness = parent->cfg->type_cast_strictness;
+
/* Always replace a leading dot with an underscore. */
vpts = value_pairs_transform_set_new(".*");
value_pairs_transform_set_add_func(vpts, value_pairs_new_transform_replace(".", "_"));
@@ -60,6 +64,7 @@ typedef struct
{
gboolean need_comma;
GString *buffer;
+ gint tc_strictness;
} json_state_t;
static inline void
@@ -163,37 +168,97 @@ tf_json_obj_end(const gchar *name,
}
static gboolean
-tf_json_value(const gchar *name, const gchar *prefix,
- TypeHint type, const gchar *value,
- gpointer *prefix_data, gpointer user_data)
+tf_json_append_value(const gchar *name, const gchar *value,
+ json_state_t *state, gboolean quoted)
{
- json_state_t *state = (json_state_t *)user_data;
-
if (state->need_comma)
g_string_append_c(state->buffer, ',');
g_string_append_c(state->buffer, '"');
g_string_append_escaped(state->buffer, name);
- g_string_append(state->buffer, "\":\"");
+
+ if (quoted)
+ g_string_append(state->buffer, "\":\"");
+ else
+ g_string_append(state->buffer, "\":");
+
g_string_append_escaped(state->buffer, value);
- g_string_append_c(state->buffer, '"');
+
+ if (quoted)
+ g_string_append_c(state->buffer, '"');
+
+ return TRUE;
+}
+
+static gboolean
+tf_json_value(const gchar *name, const gchar *prefix,
+ TypeHint type, const gchar *value,
+ gpointer *prefix_data, gpointer user_data)
+{
+ json_state_t *state = (json_state_t *)user_data;
+ gint tc_strictness = state->tc_strictness;
+
+ switch (type)
+ {
+ case TYPE_HINT_STRING:
+ case TYPE_HINT_DATETIME:
+ default:
+ tf_json_append_value(name, value, state, TRUE);
+ break;
+ case TYPE_HINT_LITERAL:
+ tf_json_append_value(name, value, state, FALSE);
+ break;
+ case TYPE_HINT_INT32:
+ case TYPE_HINT_INT64:
+ case TYPE_HINT_BOOLEAN:
+ {
+ gint32 i32;
+ gint64 i64;
+ gboolean b;
+ gboolean r = FALSE, fail = FALSE;
+ const gchar *v = value;
+
+ if (type == TYPE_HINT_INT32 &&
+ (fail = !type_cast_to_int32(value, &i32 , NULL)) == TRUE)
+ r = type_cast_drop_helper(tc_strictness, value, "int32");
+ else if (type == TYPE_HINT_INT64 &&
+ (fail = !type_cast_to_int64(value, &i64 , NULL)) == TRUE)
+ r = type_cast_drop_helper(tc_strictness, value, "int64");
+ else if (type == TYPE_HINT_BOOLEAN)
+ {
+ if ((fail = !type_cast_to_boolean(value, &b , NULL)) == TRUE)
+ r = type_cast_drop_helper(tc_strictness, value, "boolean");
+ else
+ v = b ? "true" : "false";
+ }
+
+ if (fail &&
+ !(tc_strictness & TYPE_CAST_FALLBACK_TO_STRING))
+ return r;
+
+ tf_json_append_value(name, v, state, fail);
+ break;
+ }
+ }
state->need_comma = TRUE;
return FALSE;
}
-static void
-tf_json_append(GString *result, ValuePairs *vp, LogMessage *msg)
+static gboolean
+tf_json_append(GString *result, ValuePairs *vp,
+ gint strictness, LogMessage *msg)
{
json_state_t state;
state.need_comma = FALSE;
state.buffer = result;
+ state.tc_strictness = strictness;
- value_pairs_walk(vp,
- tf_json_obj_start, tf_json_value, tf_json_obj_end,
- msg, 0, &state);
+ return value_pairs_walk(vp,
+ tf_json_obj_start, tf_json_value, tf_json_obj_end,
+ msg, 0, &state);
}
static void
@@ -202,9 +267,15 @@ tf_json_call(LogTemplateFunction *self, gpointer s,
{
TFJsonState *state = (TFJsonState *)s;
gint i;
+ gboolean r = TRUE;
+ gsize orig_size = result->len;
for (i = 0; i < args->num_messages; i++)
- tf_json_append(result, state->vp, args->messages[i]);
+ r &= tf_json_append(result, state->vp,
+ state->tc_strictness, args->messages[i]);
+
+ if (!r && state->tc_strictness & TYPE_CAST_DROP_MESSAGE)
+ g_string_set_size(result, orig_size);
}
static void
diff --git a/modules/json/tests/test_json.c b/modules/json/tests/test_json.c
index 8087c3e..4061c4c 100644
--- a/modules/json/tests/test_json.c
+++ b/modules/json/tests/test_json.c
@@ -23,6 +23,51 @@ test_format_json_rekey(void)
"{\"_msg\":{\"text\":\"dotted\"}}");
}
+void
+test_format_json_with_type_hints(void)
+{
+ assert_template_format("$(format-json i32=int32(1234))",
+ "{\"i32\":1234}");
+ assert_template_format("$(format-json \"i=ifoo(\")",
+ "{\"i\":\"ifoo(\"}");
+ assert_template_format("$(format-json b=boolean(TRUE))",
+ "{\"b\":true}");
+}
+
+void
+test_format_json_strictness(void)
+{
+ configuration->type_cast_strictness = TYPE_CAST_DROP_MESSAGE;
+ assert_template_format("$(format-json x=y bad=boolean(blah) foo=bar)",
+ "");
+ assert_template_format("$(format-json x=y bad=int32(blah) foo=bar)",
+ "");
+ assert_template_format("$(format-json x=y bad=int64(blah) foo=bar)",
+ "");
+
+ configuration->type_cast_strictness = TYPE_CAST_DROP_PROPERTY;
+ assert_template_format("$(format-json x=y bad=boolean(blah) foo=bar)",
+ "{\"x\":\"y\",\"foo\":\"bar\"}");
+ assert_template_format("$(format-json x=y bad=boolean(blah))",
+ "{\"x\":\"y\"}");
+ assert_template_format("$(format-json x=y bad=int32(blah))",
+ "{\"x\":\"y\"}");
+ assert_template_format("$(format-json x=y bad=int64(blah))",
+ "{\"x\":\"y\"}");
+
+ configuration->type_cast_strictness = TYPE_CAST_FALLBACK_TO_STRING;
+
+ assert_template_format("$(format-json x=y bad=boolean(blah) foo=bar)",
+ "{\"x\":\"y\",\"foo\":\"bar\",\"bad\":\"blah\"}");
+ assert_template_format("$(format-json x=y bad=boolean(blah))",
+ "{\"x\":\"y\",\"bad\":\"blah\"}");
+ assert_template_format("$(format-json x=y bad=int32(blah))",
+ "{\"x\":\"y\",\"bad\":\"blah\"}");
+ assert_template_format("$(format-json x=y bad=int64(blah))",
+ "{\"x\":\"y\",\"bad\":\"blah\"}");
+
+}
+
int
main(int argc G_GNUC_UNUSED, char *argv[] G_GNUC_UNUSED)
{
@@ -34,6 +79,8 @@ main(int argc G_GNUC_UNUSED, char *argv[] G_GNUC_UNUSED)
test_format_json();
test_format_json_rekey();
+ test_format_json_with_type_hints();
+ test_format_json_strictness();
deinit_template_tests();
app_shutdown();
--
1.7.10.4
More information about the syslog-ng
mailing list