[syslog-ng] [PATCH 3/3] format-json: Support type hints

Gergely Nagy algernon at balabit.hu
Thu Nov 15 18:24:18 CET 2012


Unfortunately, format-json does not use the yacc grammar to parse its
options, so we have to implement our own: this is what
value_pairs_parse_type() does, conveniently hidden, so that
value_pairs_new_from_cmdline() will do the right thing, and annotate
the constructed templates with type hints.

The assumption made here is that if a template string has '(' and a
')' after, then it is a type-hinted template. This may be refined
later to be stricter (for example, to require the closing parens to be
at the end).

And since we can construct type-hinted templates from the
command-line, we can teach $(format-json) to handle these types too!

Signed-off-by: Gergely Nagy <algernon at balabit.hu>
---
 lib/value-pairs.c              |   32 ++++++++++++++++++++++++++++++--
 modules/json/format-json.c     |   35 ++++++++++++++++++++++++++++++-----
 modules/json/tests/test_json.c |   12 ++++++++++++
 3 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/lib/value-pairs.c b/lib/value-pairs.c
index da2e391..a8511fd 100644
--- a/lib/value-pairs.c
+++ b/lib/value-pairs.c
@@ -151,6 +151,32 @@ value_pairs_add_glob_pattern(ValuePairs *vp, const gchar *pattern,
   vp->patterns[i] = p;
 }
 
+static void
+value_pairs_parse_type(gchar *spec, gchar **value, gchar **type)
+{
+  char *sp, *ep;
+
+  *type = NULL;
+
+  sp = strchr(spec, '(');
+  if (sp == NULL)
+    {
+      *value = spec;
+      return;
+    }
+  ep = strchr(sp, ')');
+  if (ep == NULL)
+    {
+      *value = spec;
+      return;
+    }
+
+  *value = sp + 1;
+  *type = spec;
+  sp[0] = '\0';
+  ep[0] = '\0';
+}
+
 gboolean
 value_pairs_add_pair_with_type(ValuePairs *vp, GlobalConfig *cfg,
                                const gchar *key, const gchar *type,
@@ -770,7 +796,7 @@ vp_cmdline_parse_pair (const gchar *option_name, const gchar *value,
   gpointer *args = (gpointer *) data;
   ValuePairs *vp = (ValuePairs *) args[1];
   GlobalConfig *cfg = (GlobalConfig *) args[0];
-  gchar **kv;
+  gchar **kv, *v, *t;
 
   vp_cmdline_parse_rekey_finish (data);
   if (!g_strstr_len (value, strlen (value), "="))
@@ -781,7 +807,9 @@ vp_cmdline_parse_pair (const gchar *option_name, const gchar *value,
     }
 
   kv = g_strsplit(value, "=", 2);
-  value_pairs_add_pair (vp, cfg, kv[0], kv[1]);
+  value_pairs_parse_type(kv[1], &v, &t);
+
+  value_pairs_add_pair_with_type(vp, cfg, kv[0], t, v, NULL);
 
   g_free (kv[0]);
   g_free (kv[1]);
diff --git a/modules/json/format-json.c b/modules/json/format-json.c
index 4b79701..cbdb513 100644
--- a/modules/json/format-json.c
+++ b/modules/json/format-json.c
@@ -172,11 +172,36 @@ tf_json_value(const gchar *name, const gchar *prefix,
   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, "\":\"");
-  g_string_append_escaped(state->buffer, value);
-  g_string_append_c(state->buffer, '"');
+  switch (type)
+    {
+    case TEMPLATE_TYPE_STRING:
+    case TEMPLATE_TYPE_DATETIME:
+    default:
+      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, '"');
+      break;
+    case TEMPLATE_TYPE_INT32:
+    case TEMPLATE_TYPE_INT64:
+      g_string_append_c(state->buffer, '"');
+      g_string_append_escaped(state->buffer, name);
+      g_string_append(state->buffer, "\":");
+      g_string_append(state->buffer, value);
+      break;
+    case TEMPLATE_TYPE_BOOLEAN:
+      {
+        g_string_append_c(state->buffer, '"');
+        g_string_append_escaped(state->buffer, name);
+        g_string_append(state->buffer, "\":");
+        if (value[0] == 't' || value[0] == 'T' || value[0] == '1')
+          g_string_append(state->buffer, "true");
+        else
+          g_string_append(state->buffer, "false");
+        break;
+      }
+    }
 
   state->need_comma = TRUE;
 
diff --git a/modules/json/tests/test_json.c b/modules/json/tests/test_json.c
index 8087c3e..ada48b6 100644
--- a/modules/json/tests/test_json.c
+++ b/modules/json/tests/test_json.c
@@ -23,6 +23,17 @@ 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}");
+}
+
 int
 main(int argc G_GNUC_UNUSED, char *argv[] G_GNUC_UNUSED)
 {
@@ -34,6 +45,7 @@ main(int argc G_GNUC_UNUSED, char *argv[] G_GNUC_UNUSED)
 
   test_format_json();
   test_format_json_rekey();
+  test_format_json_with_type_hints();
 
   deinit_template_tests();
   app_shutdown();
-- 
1.7.10.4




More information about the syslog-ng mailing list