Allow Match:Regex to match metadata.
authorIgor Peshansky <igorpeshansky@github.com>
Mon, 12 Sep 2016 21:56:47 +0000 (17:56 -0400)
committerIgor Peshansky <igorpeshansky@github.com>
Tue, 13 Sep 2016 01:16:36 +0000 (21:16 -0400)
src/match_regex.c

index cd63016..f51ca33 100644 (file)
@@ -34,6 +34,8 @@
 #include "collectd.h"
 
 #include "filter_chain.h"
+#include "meta_data.h"
+#include "utils_llist.h"
 
 #include <sys/types.h>
 #include <regex.h>
@@ -64,6 +66,7 @@ struct mr_match_s
        mr_regex_t *plugin_instance;
        mr_regex_t *type;
        mr_regex_t *type_instance;
+       llist_t *meta;  /* Maps each meta key into mr_regex_t* */
        _Bool invert;
 };
 
@@ -93,6 +96,12 @@ static void mr_free_match (mr_match_t *m) /* {{{ */
        mr_free_regex (m->plugin_instance);
        mr_free_regex (m->type);
        mr_free_regex (m->type_instance);
+       for (llentry_t *e = llist_head(m->meta); e != NULL; e = e->next)
+       {
+               free (e->key);
+               mr_free_regex ((mr_regex_t *) e->value);
+       }
+       llist_destroy (m->meta);
 
        free (m);
 } /* }}} void mr_free_match */
@@ -127,31 +136,25 @@ static int mr_match_regexen (mr_regex_t *re_head, /* {{{ */
        return (FC_MATCH_MATCHES);
 } /* }}} int mr_match_regexen */
 
-static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
-               oconfig_item_t *ci)
+static int mr_add_regex (mr_regex_t **re_head, const char *re_str, /* {{{ */
+               const char *option)
 {
        mr_regex_t *re;
        int status;
 
-       if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
-       {
-               log_warn ("`%s' needs exactly one string argument.", ci->key);
-               return (-1);
-       }
-
        re = calloc (1, sizeof (*re));
        if (re == NULL)
        {
-               log_err ("mr_config_add_regex: calloc failed.");
+               log_err ("mr_add_regex: calloc failed.");
                return (-1);
        }
        re->next = NULL;
 
-       re->re_str = strdup (ci->values[0].value.string);
+       re->re_str = strdup (re_str);
        if (re->re_str == NULL)
        {
                free (re);
-               log_err ("mr_config_add_regex: strdup failed.");
+               log_err ("mr_add_regex: strdup failed.");
                return (-1);
        }
 
@@ -162,7 +165,7 @@ static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
                regerror (status, &re->re, errmsg, sizeof (errmsg));
                errmsg[sizeof (errmsg) - 1] = 0;
                log_err ("Compiling regex `%s' for `%s' failed: %s.",
-                               re->re_str, ci->key, errmsg);
+                               re->re_str, option, errmsg);
                free (re->re_str);
                free (re);
                return (-1);
@@ -184,8 +187,78 @@ static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
        }
 
        return (0);
+} /* }}} int mr_add_regex */
+
+static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
+               oconfig_item_t *ci)
+{
+       if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+       {
+               log_warn ("`%s' needs exactly one string argument.", ci->key);
+               return (-1);
+       }
+
+       return mr_add_regex (re_head, ci->values[0].value.string, ci->key);
 } /* }}} int mr_config_add_regex */
 
+static int mr_config_add_meta_regex (llist_t **meta, /* {{{ */
+               oconfig_item_t *ci)
+{
+       char *key;
+       llentry_t *entry;
+       mr_regex_t *re_head;
+       int status;
+       char buffer[1024];
+
+       if ((ci->values_num != 2)
+               || (ci->values[0].type != OCONFIG_TYPE_STRING)
+               || (ci->values[1].type != OCONFIG_TYPE_STRING))
+       {
+               log_warn ("`%s' needs exactly two string arguments.", ci->key);
+               return (-1);
+       }
+
+       if (*meta == NULL)
+       {
+               *meta = llist_create();
+               if (*meta == NULL)
+               {
+                       log_err ("mr_config_add_meta_regex: llist_create failed.");
+                       return (-1);
+               }
+       }
+
+       key = ci->values[0].value.string;
+       entry = llist_search (*meta, key);
+       if (entry == NULL)
+       {
+               key = strdup (key);
+               if (key == NULL)
+               {
+                       log_err ("mr_config_add_meta_regex: strdup failed.");
+                       return (-1);
+               }
+               entry = llentry_create (key, NULL);
+               if (entry == NULL)
+               {
+                       log_err ("mr_config_add_meta_regex: llentry_create failed.");
+                       free (key);
+                       return (-1);
+               }
+               /* key and entry will now be freed by mr_free_match(). */
+               llist_append (*meta, entry);
+       }
+
+       snprintf (buffer, sizeof (buffer), "%s `%s'", ci->key, key);
+       /* Can't pass &entry->value into mr_add_regex, so copy in/out. */
+       re_head = entry->value;
+       status = mr_add_regex (&re_head, ci->values[1].value.string, buffer);
+       if (status == 0) {
+               entry->value = re_head;
+       }
+       return status;
+} /* }}} int mr_config_add_meta_regex */
+
 static int mr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
 {
        mr_match_t *m;
@@ -216,6 +289,8 @@ static int mr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
                        status = mr_config_add_regex (&m->type, child);
                else if (strcasecmp ("TypeInstance", child->key) == 0)
                        status = mr_config_add_regex (&m->type_instance, child);
+               else if (strcasecmp ("MetaData", child->key) == 0)
+                       status = mr_config_add_meta_regex (&m->meta, child);
                else if (strcasecmp ("Invert", child->key) == 0)
                        status = cf_util_get_boolean(child, &m->invert);
                else
@@ -236,7 +311,8 @@ static int mr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
                                && (m->plugin == NULL)
                                && (m->plugin_instance == NULL)
                                && (m->type == NULL)
-                               && (m->type_instance == NULL))
+                               && (m->type_instance == NULL)
+                               && (m->meta == NULL))
                {
                        log_err ("No (valid) regular expressions have been configured. "
                                        "This match will be ignored.");
@@ -295,6 +371,24 @@ static int mr_match (const data_set_t __attribute__((unused)) *ds, /* {{{ */
        if (mr_match_regexen (m->type_instance,
                                vl->type_instance) == FC_MATCH_NO_MATCH)
                return (nomatch_value);
+       if (vl->meta != NULL)
+       {
+               for (llentry_t *e = llist_head(m->meta); e != NULL; e = e->next)
+               {
+                       mr_regex_t *meta_re = (mr_regex_t *) e->value;
+                       char *value;
+                       int status = meta_data_get_string (vl->meta, e->key, &value);
+                       if (status == 0)  /* key is present */
+                       {
+                               if (mr_match_regexen (meta_re, value) == FC_MATCH_NO_MATCH)
+                               {
+                                       free (value);
+                                       return (nomatch_value);
+                               }
+                               free (value);
+                       }
+               }
+       }
 
        return (match_value);
 } /* }}} int mr_match */