[syslog-ng] [PATCH 1/3] value-pairs: A framework to filter key=value pairs.

Gergely Nagy algernon at balabit.hu
Sun Apr 24 11:28:29 CEST 2011


This is the implementation of the value-pairs() framework discussed on
the list in the past.

The syntax is as follows:

destination d_driver {
  driver(
    value-pairs(
      scope($SCOPE)
      exclude("S_*") # shell-style glob to exclude keys
      pair("my-own-key" "$SOURCE/$HOST")
      key("HOST_FROM")
    )
  );
};

Of course, this is not only for destination drivers: there is support
for parsing arguments passed to template functions. The above set
would look like this in a template function:

$(function --scope $SCOPE --exclude S_* --pair my-own-key=$SOURCE/$HOST --key HOST_FROM)

The idea is that we select a scope (see later for the list of scopes
currently supported), from which we can exclude certain keys using a
shell-style glob pattern, or add custom key-value pairs of our own, or
add back pre-defined keys that we do want, but the scope doesn't have
by default.

The available scopes at the moment are:

* rfc3164: Key-value pairs based on the old syslog protocol, also
  available as "core" and "base".
* rfc5424: Key-value pairs based on the new syslog protocol, also
  available as "syslog_proto".
* all_macros: All macros known to syslog-ng (this only includes the
  pre-defined macros!)
* selected_macros: A smaller set of selected macros, which the
  developers deemed important (see the source for the list, for now).
* nv_pairs: Name-value pairs, the results of SDATA or patterndb
  parsing.
* everything: All of the above, combined into one big set.

On the driver side, supporting value-pairs is reasonably easy:

driver_option
	: value_pair_stmt			{
	  driver_dd_set_value_pairs(last_driver, last_value_pairs);
	}
	| <etc...>
	;

And in the driver itself, make a foreach callback:

static gboolean
driver_vp_foreach (const gchar *name, const gchar *value,
		   gpointer user_data)
{
  /* Do something here with the name-value pairs */

  return FALSE;
}

And whenever you want to work with the set, call
value_pairs_foreach():

value_pairs_foreach (self->value_pairs, driver_vp_foreach,
		     msg, self->seq_num, USER_DATA);

And that's about it.

Signed-off-by: Gergely Nagy <algernon at balabit.hu>
---
 lib/Makefile.am   |    3 +-
 lib/cfg-grammar.y |   68 ++++++++-
 lib/cfg-parser.c  |   17 ++
 lib/cfg-parser.h  |    1 +
 lib/syslog-ng.h   |    2 +
 lib/value-pairs.c |  458 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/value-pairs.h |   62 +++++++
 7 files changed, 608 insertions(+), 3 deletions(-)
 create mode 100644 lib/value-pairs.c
 create mode 100644 lib/value-pairs.h

diff --git a/lib/Makefile.am b/lib/Makefile.am
index 33a886e..16075b9 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -59,7 +59,8 @@ libsyslog_ng_la_SOURCES = \
 	block-ref-grammar.y block-ref-parser.c block-ref-parser.h \
 	pragma-grammar.y pragma-parser.h pragma-parser.c \
 	parser-expr-grammar.y parser-expr-parser.c parser-expr-parser.h \
-	rewrite-expr-grammar.y rewrite-expr-parser.c rewrite-expr-parser.h
+	rewrite-expr-grammar.y rewrite-expr-parser.c rewrite-expr-parser.h \
+	value-pairs.c value-pairs.h
 
 BUILT_SOURCES = cfg-lex.c cfg-lex.h cfg-grammar.c cfg-grammar.h \
 	filter-expr-grammar.y filter-expr-grammar.c filter-expr-grammar.h \
diff --git a/lib/cfg-grammar.y b/lib/cfg-grammar.y
index 0ec55ad..e1d97b6 100644
--- a/lib/cfg-grammar.y
+++ b/lib/cfg-grammar.y
@@ -28,6 +28,7 @@
 #include "cfg-lexer.h"
 #include "driver.h"
 
+#include "value-pairs.h"
 }
 
 %name-prefix "main_"
@@ -134,7 +135,6 @@
 
 %token KW_SYSLOG                      10060
 
-
 /* option items */
 %token KW_MARK_FREQ                   10071
 %token KW_STATS_FREQ                  10072
@@ -263,6 +263,20 @@
 %token LL_EOL                         10428
 %token LL_ERROR                       10429
 
+/* value pairs */
+%token KW_VALUE_PAIRS                 10500
+%token KW_SELECT                      10501
+%token KW_EXCLUDE                     10502
+%token KW_PAIR                        10503
+%token KW_KEY                         10504
+%token KW_SCOPE                       10505
+%token KW_SCOPE_NV_PAIRS              10506
+%token KW_SCOPE_RFC3164               10507
+%token KW_SCOPE_RFC5424               10508
+%token KW_SCOPE_ALL_MACROS            10509
+%token KW_SCOPE_SELECTED_MACROS       10510
+%token KW_SCOPE_EVERYTHING            10511
+
 /* END_DECLS */
 
 %code {
@@ -277,6 +291,7 @@
 #include "logreader.h"
 #include "logparser.h"
 #include "logrewrite.h"
+#include "value-pairs.h"
 #include "filter-expr-parser.h"
 #include "rewrite-expr-parser.h"
 #include "block-ref-parser.h"
@@ -306,7 +321,7 @@ GList *last_rewrite_expr;
 GList *last_parser_expr;
 FilterExprNode *last_filter_expr;
 CfgArgs *last_block_args;
-
+ValuePairs *last_value_pairs;
 }
 
 
@@ -318,6 +333,7 @@ CfgArgs *last_block_args;
 %type	<ptr> log_stmt
 %type	<ptr> options_stmt
 %type	<ptr> template_stmt
+%type   <ptr> value_pair_stmt
 
 %type	<ptr> source_items
 %type	<ptr> source_item
@@ -803,6 +819,54 @@ dest_writer_options_flags
 	|					{ $$ = 0; }
 	;
 
+value_pair_stmt
+	: KW_VALUE_PAIRS value_pairs_def	{ }
+	;
+
+value_pairs_def
+	: { last_value_pairs = value_pairs_new(configuration); }
+	  '(' value_pair_options ')'
+	  { }
+	;
+
+value_pair_options
+	: value_pair_option value_pair_options
+	|
+	;
+
+value_pair_option
+	: KW_PAIR '(' string ':' string ')' { value_pairs_add_pair(last_value_pairs, $3, $5); free($3); free($5); }
+	| KW_PAIR '(' string string ')' { value_pairs_add_pair(last_value_pairs, $3, $4); free($3); free($4); }
+	| KW_KEY '(' string ')'		    {
+	  	gchar *k = g_strconcat("$", $3, NULL);
+		value_pairs_add_pair(last_value_pairs, $3, k);
+		g_free(k);
+		free($3);
+	  }
+	| KW_EXCLUDE '(' string ')'	{ value_pairs_exclude_glob_pattern(last_value_pairs, $3); free($3); }
+	| KW_SCOPE '(' vp_scope_list ')'	{ }
+	;
+
+vp_scope_list
+	: vp_scope vp_scope_list
+	|
+	;
+
+vp_scope
+	: KW_SCOPE_NV_PAIRS
+	{ value_pairs_add_scope(last_value_pairs, VALUE_PAIR_SCOPE_NV_PAIRS); }
+	| KW_SCOPE_RFC3164
+	{ value_pairs_add_scope(last_value_pairs, VALUE_PAIR_SCOPE_RFC3164); }
+	| KW_SCOPE_RFC5424
+	{ value_pairs_add_scope(last_value_pairs, VALUE_PAIR_SCOPE_RFC5424); }
+	| KW_SCOPE_ALL_MACROS
+	{ value_pairs_add_scope(last_value_pairs, VALUE_PAIR_SCOPE_ALL_MACROS); }
+	| KW_SCOPE_SELECTED_MACROS
+	{ value_pairs_add_scope(last_value_pairs, VALUE_PAIR_SCOPE_SELECTED_MACROS); }
+	| KW_SCOPE_EVERYTHING
+	{ value_pairs_add_scope(last_value_pairs, VALUE_PAIR_SCOPE_EVERYTHING); }
+	;
+
 /* END_RULES */
 
 
diff --git a/lib/cfg-parser.c b/lib/cfg-parser.c
index e53c58d..1123d87 100644
--- a/lib/cfg-parser.c
+++ b/lib/cfg-parser.c
@@ -53,6 +53,23 @@ static CfgLexerKeyword main_keywords[] = {
   { "quote_pairs",        KW_QUOTE_PAIRS, 0x0300},
   { "null",               KW_NULL, 0x0300 },
 
+  /* value pairs */
+  { "value_pairs",        KW_VALUE_PAIRS },
+  { "select",             KW_SELECT },
+  { "exclude",            KW_EXCLUDE },
+  { "pair",               KW_PAIR },
+  { "key",                KW_KEY },
+  { "scope",              KW_SCOPE },
+  { "nv_pairs",           KW_SCOPE_NV_PAIRS },
+  { "rfc3164",            KW_SCOPE_RFC3164 },
+  { "core",               KW_SCOPE_RFC3164 },
+  { "base",               KW_SCOPE_RFC3164 },
+  { "rfc5424",            KW_SCOPE_RFC5424 },
+  { "syslog_proto",       KW_SCOPE_RFC5424 },
+  { "all_macros",         KW_SCOPE_ALL_MACROS },
+  { "selected_macros",    KW_SCOPE_SELECTED_MACROS },
+  { "everything",         KW_SCOPE_EVERYTHING },
+
   /* option items */
   { "flags",              KW_FLAGS },
   { "pad_size",           KW_PAD_SIZE },
diff --git a/lib/cfg-parser.h b/lib/cfg-parser.h
index 3527621..b874cd9 100644
--- a/lib/cfg-parser.h
+++ b/lib/cfg-parser.h
@@ -27,6 +27,7 @@
 
 #include "syslog-ng.h"
 #include "cfg-lexer.h"
+#include "value-pairs.h"
 
 /* high level interface to a configuration file parser, it encapsulates the
  * grammar/lexer pair. */
diff --git a/lib/syslog-ng.h b/lib/syslog-ng.h
index ce4c017..83a9651 100644
--- a/lib/syslog-ng.h
+++ b/lib/syslog-ng.h
@@ -61,10 +61,12 @@
 
 typedef struct _LogMessage LogMessage;
 typedef struct _GlobalConfig GlobalConfig;
+typedef struct _ValuePairs TValuePairs;
 
 extern GlobalConfig *configuration;
 extern gboolean seed_rng;
 extern gchar *module_path;
 extern gchar *default_modules;
+extern TValuePairs *last_value_pairs;
 
 #endif
diff --git a/lib/value-pairs.c b/lib/value-pairs.c
new file mode 100644
index 0000000..5dfbb6f
--- /dev/null
+++ b/lib/value-pairs.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2002-2011 BalaBit IT Ltd, Budapest, Hungary
+ * Copyright (c) 2011 Gergely Nagy <algernon at balabit.hu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As an additional exemption you are allowed to compile & link against the
+ * OpenSSL libraries as published by the OpenSSL project. See the file
+ * COPYING for details.
+ *
+ */
+
+#include "logmsg.h"
+#include "templates.h"
+
+#include "value-pairs.h"
+
+#include <string.h>
+
+typedef struct
+{
+  gchar *name;
+  LogTemplate *template;
+} vp_template_set;
+
+struct _ValuePairs
+{
+  GlobalConfig *cfg;
+
+  guint8 scopes;
+
+  GPatternSpec **excludes;
+  gsize exclude_size;
+  GHashTable *vpairs;
+
+  struct
+  {
+    vp_template_set *rfc3164;
+    vp_template_set *rfc5424;
+    vp_template_set *selected_macros;
+    vp_template_set *all_macros;
+  } templates;
+
+  /* Temporary */
+  GString *res;
+};
+
+static inline void
+vp_add_scope_template (GlobalConfig *cfg, vp_template_set *target,
+		       gint index, const gchar *name, const gchar *macro)
+{
+  LogTemplate *t = NULL;
+  gchar *m;
+
+  if (macro)
+    m = g_strdup (macro);
+  else
+    m = g_strconcat ("$", name, NULL);
+
+  t = log_template_new(cfg, NULL, m);
+  target[index].name = g_strdup(name);
+  target[index].template = t;
+  g_free (m);
+}
+
+ValuePairs *
+value_pairs_new (GlobalConfig *cfg)
+{
+  ValuePairs *vp;
+  gint i = 0;
+
+  vp = g_try_new0(ValuePairs, 1);
+  if (!vp)
+    return NULL;
+  vp->res = g_string_sized_new(256);
+  if (!vp->res)
+    {
+      g_free(vp);
+      return NULL;
+    }
+  vp->vpairs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+				     (GDestroyNotify) log_template_unref);
+  if (!vp->vpairs)
+    {
+      g_string_free(vp->res, TRUE);
+      g_free(vp);
+      return NULL;
+    }
+
+  vp->cfg = cfg;
+
+  vp->templates.rfc3164 = g_try_new0 (vp_template_set, 8);
+  vp->templates.rfc5424 = g_try_new0 (vp_template_set, 3);
+  vp->templates.selected_macros = g_try_new0 (vp_template_set, 5);
+
+  while (macros[i].name)
+    i++;
+
+  vp->templates.all_macros = g_try_new0 (vp_template_set, i + 1);
+  i = 0;
+
+  vp_add_scope_template (vp->cfg, vp->templates.rfc3164, 0, "FACILITY", NULL);
+  vp_add_scope_template (vp->cfg, vp->templates.rfc3164, 1, "PRIORITY", NULL);
+  vp_add_scope_template (vp->cfg, vp->templates.rfc3164, 2, "DATE", "$S_DATE");
+  vp_add_scope_template (vp->cfg, vp->templates.rfc3164, 3, "HOST", NULL);
+  vp_add_scope_template (vp->cfg, vp->templates.rfc3164, 4, "PROGRAM", NULL);
+  vp_add_scope_template (vp->cfg, vp->templates.rfc3164, 5, "PID", NULL);
+  vp_add_scope_template (vp->cfg, vp->templates.rfc3164, 6, "MSG", NULL);
+
+  vp_add_scope_template (vp->cfg, vp->templates.rfc5424, 0, "MSGID", NULL);
+  vp_add_scope_template (vp->cfg, vp->templates.rfc5424, 1, "SDATA", NULL);
+
+  vp_add_scope_template (vp->cfg, vp->templates.selected_macros, 0, "TAGS", NULL);
+  vp_add_scope_template (vp->cfg, vp->templates.selected_macros, 1, "SDATA", NULL);
+  vp_add_scope_template (vp->cfg, vp->templates.selected_macros, 2, "SOURCEIP", NULL);
+  vp_add_scope_template (vp->cfg, vp->templates.selected_macros, 3, "SEQNUM", NULL);
+
+  while (macros[i].name)
+    {
+      vp_add_scope_template (vp->cfg, vp->templates.all_macros, i, macros[i].name, NULL);
+      i++;
+    }
+
+  return vp;
+}
+
+static gboolean
+vp_cmdline_parse_scope (const gchar *option_name, const gchar *value,
+			gpointer data, GError **error)
+{
+  ValuePairs *vp = (ValuePairs *)data;
+
+  if (g_ascii_strcasecmp (value, "nv_pairs") == 0)
+    value_pairs_add_scope (vp, VALUE_PAIR_SCOPE_NV_PAIRS);
+  else if (g_ascii_strcasecmp (value, "rfc3164") == 0 ||
+	   g_ascii_strcasecmp (value, "core") == 0 ||
+	   g_ascii_strcasecmp (value, "base"))
+    value_pairs_add_scope (vp, VALUE_PAIR_SCOPE_RFC3164);
+  else if (g_ascii_strcasecmp (value, "rfc5424") == 0 ||
+	   g_ascii_strcasecmp (value, "syslog_proto") == 0)
+    value_pairs_add_scope (vp, VALUE_PAIR_SCOPE_RFC5424);
+  else if (g_ascii_strcasecmp (value, "selected_macros") == 0)
+    value_pairs_add_scope (vp, VALUE_PAIR_SCOPE_SELECTED_MACROS);
+  else if (g_ascii_strcasecmp (value, "all_macros") == 0)
+    value_pairs_add_scope (vp, VALUE_PAIR_SCOPE_ALL_MACROS);
+  else if (g_ascii_strcasecmp (value, "everything") == 0)
+    value_pairs_add_scope (vp, VALUE_PAIR_SCOPE_EVERYTHING);
+  else
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Error parsing value-pairs' scope()");
+      return FALSE;
+    }
+  return TRUE;
+}
+
+static gboolean
+vp_cmdline_parse_exclude (const gchar *option_name, const gchar *value,
+			  gpointer data, GError **error)
+{
+  ValuePairs *vp = (ValuePairs *)data;
+
+  value_pairs_exclude_glob_pattern (vp, value);
+  return TRUE;
+}
+
+static gboolean
+vp_cmdline_parse_key (const gchar *option_name, const gchar *value,
+		      gpointer data, GError **error)
+{
+  ValuePairs *vp = (ValuePairs *)data;
+  gchar *k = g_strconcat ("$", value, NULL);
+
+  value_pairs_add_pair (vp, value, k);
+  g_free (k);
+
+  return TRUE;
+}
+
+static gboolean
+vp_cmdline_parse_pair (const gchar *option_name, const gchar *value,
+		       gpointer data, GError **error)
+{
+  ValuePairs *vp = (ValuePairs *)data;
+  gchar **kv;
+
+  if (!g_strstr_len (value, strlen (value), "="))
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Error parsing value-pairs' key=value pair");
+      return FALSE;
+    }
+
+  kv = g_strsplit(value, "=", 2);
+  value_pairs_add_pair (vp, kv[0], kv[1]);
+
+  g_free (kv[0]);
+  g_free (kv[1]);
+  g_free (kv);
+
+  return TRUE;
+}
+
+ValuePairs *
+value_pairs_new_from_cmdline (GlobalConfig *cfg,
+			      gint cargc, gchar **cargv,
+			      GError **error)
+{
+  ValuePairs *vp;
+  GOptionContext *ctx;
+  GOptionEntry vp_options[] = {
+    { "scope", 's', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_scope,
+      NULL, NULL },
+    { "exclude", 'x', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_exclude,
+      NULL, NULL },
+    { "key", 'k', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_key,
+      NULL, NULL },
+    { "pair", 'p', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_pair,
+      NULL, NULL },
+    { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_pair,
+      NULL, NULL },
+    { NULL }
+  };
+  gchar **argv;
+  gint argc = cargc + 1;
+  gint i;
+  GOptionGroup *og;
+
+  argv = g_new (gchar *, argc + 1);
+  for (i = 0; i < argc; i++)
+    argv[i + 1] = cargv[i];
+  argv[0] = "value-pairs";
+  argv[argc] = NULL;
+
+  vp = value_pairs_new (cfg);
+
+  ctx = g_option_context_new ("value-pairs");
+  og = g_option_group_new (NULL, NULL, NULL, vp, NULL);
+  g_option_group_add_entries (og, vp_options);
+  g_option_context_set_main_group (ctx, og);
+
+  if (!g_option_context_parse (ctx, &argc, &argv, error))
+    {
+      value_pairs_free (vp);
+      g_option_context_free (ctx);
+      g_free (argv);
+      return NULL;
+    }
+  g_option_context_free (ctx);
+
+  if (vp->scopes == 0)
+    value_pairs_add_scope (vp, VALUE_PAIR_SCOPE_RFC3164);
+
+  return vp;
+}
+
+void
+value_pairs_free (ValuePairs *vp)
+{
+  gint i;
+
+  if (!vp)
+    return;
+
+  g_hash_table_destroy(vp->vpairs);
+
+  for (i = 0; vp->templates.rfc3164[i].name; i++)
+    {
+      g_free (vp->templates.rfc3164[i].name);
+      log_template_unref (vp->templates.rfc3164[i].template);
+    }
+  g_free (vp->templates.rfc3164);
+
+  for (i = 0; vp->templates.rfc5424[i].name; i++)
+    {
+      g_free (vp->templates.rfc5424[i].name);
+      log_template_unref (vp->templates.rfc5424[i].template);
+    }
+  g_free (vp->templates.rfc5424);
+
+  for (i = 0; vp->templates.selected_macros[i].name; i++)
+    {
+      g_free (vp->templates.selected_macros[i].name);
+      log_template_unref (vp->templates.selected_macros[i].template);
+    }
+  g_free (vp->templates.selected_macros);
+
+  for (i = 0; vp->templates.all_macros[i].name; i++)
+    {
+      g_free (vp->templates.all_macros[i].name);
+      log_template_unref (vp->templates.all_macros[i].template);
+    }
+  g_free (vp->templates.all_macros);
+
+  for (i = 0; i < vp->exclude_size; i++)
+    g_pattern_spec_free(vp->excludes[i]);
+  g_free(vp->excludes);
+  g_string_free(vp->res, TRUE);
+  g_free(vp);
+}
+
+void
+value_pairs_add_scope (ValuePairs *vp, value_pair_scope_t scope)
+{
+  if (!vp)
+    return;
+
+  vp->scopes |= scope;
+}
+
+void
+value_pairs_exclude_glob_pattern (ValuePairs *vp, const gchar *pattern)
+{
+  gint i;
+
+  if (!vp || !pattern)
+    return;
+
+  i = vp->exclude_size++;
+  vp->excludes = g_renew(GPatternSpec *, vp->excludes, vp->exclude_size);
+  vp->excludes[i] = g_pattern_spec_new(pattern);
+}
+
+void
+value_pairs_add_pair (ValuePairs *vp, const gchar *key,
+		      const gchar *value)
+{
+  LogTemplate *t = NULL;
+
+  if (!vp || !key || !value)
+    return;
+
+  t = log_template_new(vp->cfg, NULL, value);
+  g_hash_table_insert(vp->vpairs, g_strdup(key), t);
+}
+
+static void
+vp_foreach_merge_vp(gpointer key, gpointer value, gpointer user_data)
+{
+  ValuePairs *vp = ((gpointer *)user_data)[0];
+  LogMessage *msg = ((gpointer *)user_data)[2];
+  gint32 seq_num = GPOINTER_TO_INT (((gpointer *)user_data)[3]);
+  GHashTable *scope_set = ((gpointer *)user_data)[5];
+
+  g_string_truncate(vp->res, 0);
+  log_template_format((LogTemplate *)value, msg, NULL, LTZ_LOCAL,
+		      seq_num, NULL, vp->res);
+
+  if (!vp->res->str || !vp->res->str[0])
+    return;
+
+  g_hash_table_insert(scope_set, key, g_strdup (vp->res->str));
+}
+
+static gboolean
+vp_foreach_nv_add(NVHandle handle, gchar *name,
+		  const gchar *value, gssize value_len,
+		  gpointer user_data)
+{
+  ValuePairs *vp = ((gpointer *)user_data)[0];
+  GHashTable *scope_set = ((gpointer *)user_data)[5];
+  gint j;
+
+  for (j = 0; j < vp->exclude_size; j++)
+    if (g_pattern_match_string(vp->excludes[j], name))
+      return FALSE;
+
+  g_hash_table_insert (scope_set, name, (gpointer)g_strndup (value, value_len));
+  return FALSE;
+}
+
+static void
+vp_foreach_merge_template (ValuePairs *vp, LogMessage *msg, gint32 seq_num,
+			   vp_template_set *set, GHashTable *dest)
+{
+  gint i;
+
+  for (i = 0; set[i].name; i++)
+    {
+      gint j;
+      gboolean exclude = FALSE;
+
+      for (j = 0; j < vp->exclude_size; j++)
+	if (g_pattern_match_string(vp->excludes[j], set[i].name))
+	  exclude = TRUE;
+      if (exclude)
+	continue;
+
+      g_string_truncate(vp->res, 0);
+      log_template_format(set[i].template, msg, NULL, LTZ_LOCAL, seq_num, NULL,
+			  vp->res);
+
+      if (!vp->res->str || !vp->res->str[0])
+	continue;
+
+      g_hash_table_insert (dest, set[i].name, g_strdup (vp->res->str));
+    }
+}
+
+void
+value_pairs_foreach (ValuePairs *vp, VPForeachFunc func,
+		     LogMessage *msg, gint32 seq_num, gpointer user_data)
+{
+  gpointer args[] = { vp, func, msg, GINT_TO_POINTER (seq_num), user_data, NULL };
+  GHashTable *scope_set;
+
+  scope_set = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+				    (GDestroyNotify) g_free);
+
+  args[5] = scope_set;
+
+  /*
+   * Build up the base set
+   */
+  if (vp->scopes & VALUE_PAIR_SCOPE_NV_PAIRS)
+    {
+      nv_table_foreach(msg->payload, logmsg_registry,
+		       (NVTableForeachFunc)vp_foreach_nv_add, args);
+    }
+
+  if (vp->scopes & VALUE_PAIR_SCOPE_RFC3164 ||
+      vp->scopes & VALUE_PAIR_SCOPE_RFC5424 ||
+      vp->scopes & VALUE_PAIR_SCOPE_SELECTED_MACROS)
+    vp_foreach_merge_template (vp, msg, seq_num, vp->templates.rfc3164,
+			       scope_set);
+
+  if (vp->scopes & VALUE_PAIR_SCOPE_RFC5424)
+    vp_foreach_merge_template (vp, msg, seq_num, vp->templates.rfc5424,
+			       scope_set);
+
+  if (vp->scopes & VALUE_PAIR_SCOPE_SELECTED_MACROS)
+    vp_foreach_merge_template (vp, msg, seq_num, vp->templates.selected_macros,
+			       scope_set);
+
+  if (vp->scopes & VALUE_PAIR_SCOPE_ALL_MACROS)
+    vp_foreach_merge_template (vp, msg, seq_num, vp->templates.all_macros,
+			       scope_set);
+
+  /* Merge the explicit key-value pairs too */
+  g_hash_table_foreach (vp->vpairs, (GHFunc)vp_foreach_merge_vp, args);
+
+  /* Aaand we run it through the callback! */
+  g_hash_table_foreach (scope_set, (GHFunc)func, user_data);
+
+  g_hash_table_destroy (scope_set);
+}
diff --git a/lib/value-pairs.h b/lib/value-pairs.h
new file mode 100644
index 0000000..5642f28
--- /dev/null
+++ b/lib/value-pairs.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2002-2011 BalaBit IT Ltd, Budapest, Hungary
+ * Copyright (c) 2011 Gergely Nagy <algernon at balabit.hu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As an additional exemption you are allowed to compile & link against the
+ * OpenSSL libraries as published by the OpenSSL project. See the file
+ * COPYING for details.
+ *
+ */
+
+#ifndef VALUE_PAIRS_H_INCLUDED
+#define VALUE_PAIRS_H_INCLUDED 1
+
+#include "syslog-ng.h"
+#include "nvtable.h"
+
+#include <glib.h>
+
+typedef enum
+  {
+    VALUE_PAIR_SCOPE_NV_PAIRS        = 0x01,
+    VALUE_PAIR_SCOPE_RFC3164         = 0x02,
+    VALUE_PAIR_SCOPE_RFC5424         = 0x04,
+    VALUE_PAIR_SCOPE_ALL_MACROS      = 0x08,
+    VALUE_PAIR_SCOPE_SELECTED_MACROS = 0x10,
+    VALUE_PAIR_SCOPE_EVERYTHING      = 0xff,
+  } value_pair_scope_t;
+
+typedef struct _ValuePairs ValuePairs;
+typedef gboolean (*VPForeachFunc) (const gchar *name, const gchar *value,
+				   gpointer user_data);
+
+ValuePairs *value_pairs_new (GlobalConfig *cfg);
+void value_pairs_free (ValuePairs *vp);
+
+void value_pairs_add_scope (ValuePairs *vp, value_pair_scope_t scope);
+void value_pairs_exclude_glob_pattern (ValuePairs *vp, const gchar *pattern);
+void value_pairs_add_pair (ValuePairs *vp, const gchar *key, const gchar *value);
+
+void value_pairs_foreach (ValuePairs *vp, VPForeachFunc func,
+			  LogMessage *msg, gint32 seq_num,
+			  gpointer user_data);
+
+ValuePairs *value_pairs_new_from_cmdline (GlobalConfig *cfg,
+					  gint argc, gchar **argv,
+					  GError **error);
+
+#endif
-- 
1.7.2.5




More information about the syslog-ng mailing list