X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Ftarget_replace.c;h=dba3a8cf83b7ad6d18003c6efa982cad5da85dab;hb=41288c6a9ed050b41ad47184aa1b53668c3588cc;hp=545fa3530f960a61c26be2012cbebd8fcc0d4290;hpb=21ab7512825cf8177d5eee5101344b45d0854610;p=collectd.git diff --git a/src/target_replace.c b/src/target_replace.c index 545fa353..dba3a8cf 100644 --- a/src/target_replace.c +++ b/src/target_replace.c @@ -25,6 +25,7 @@ **/ #include "collectd.h" + #include "common.h" #include "filter_chain.h" #include "utils_subst.h" @@ -37,11 +38,22 @@ struct tr_action_s { regex_t re; char *replacement; - int may_be_empty; + _Bool may_be_empty; tr_action_t *next; }; +struct tr_meta_data_action_s; +typedef struct tr_meta_data_action_s tr_meta_data_action_t; +struct tr_meta_data_action_s +{ + char *key; + regex_t re; + char *replacement; + + tr_meta_data_action_t *next; +}; + struct tr_data_s { tr_action_t *host; @@ -49,6 +61,7 @@ struct tr_data_s tr_action_t *plugin_instance; /* tr_action_t *type; */ tr_action_t *type_instance; + tr_meta_data_action_t *meta; }; typedef struct tr_data_s tr_data_t; @@ -84,8 +97,23 @@ static void tr_action_destroy (tr_action_t *act) /* {{{ */ sfree (act); } /* }}} void tr_action_destroy */ +static void tr_meta_data_action_destroy (tr_meta_data_action_t *act) /* {{{ */ +{ + if (act == NULL) + return; + + sfree (act->key); + regfree (&act->re); + sfree (act->replacement); + + if (act->next != NULL) + tr_meta_data_action_destroy (act->next); + + sfree (act); +} /* }}} void tr_meta_data_action_destroy */ + static int tr_config_add_action (tr_action_t **dest, /* {{{ */ - const oconfig_item_t *ci, int may_be_empty) + const oconfig_item_t *ci, _Bool may_be_empty) { tr_action_t *act; int status; @@ -130,8 +158,7 @@ static int tr_config_add_action (tr_action_t **dest, /* {{{ */ if (act->replacement == NULL) { ERROR ("tr_config_add_action: tr_strdup failed."); - regfree (&act->re); - sfree (act); + tr_action_destroy (act); return (-ENOMEM); } @@ -152,23 +179,121 @@ static int tr_config_add_action (tr_action_t **dest, /* {{{ */ return (0); } /* }}} int tr_config_add_action */ +static int tr_config_add_meta_action (tr_meta_data_action_t **dest, /* {{{ */ + const oconfig_item_t *ci, _Bool should_delete) +{ + tr_meta_data_action_t *act; + int status; + + if (dest == NULL) + return (-EINVAL); + + if (should_delete) + { + if ((ci->values_num != 2) + || (ci->values[0].type != OCONFIG_TYPE_STRING) + || (ci->values[1].type != OCONFIG_TYPE_STRING)) + { + ERROR ("Target `replace': The `%s' option requires exactly two string " + "arguments.", ci->key); + return (-1); + } + } + else + { + if ((ci->values_num != 3) + || (ci->values[0].type != OCONFIG_TYPE_STRING) + || (ci->values[1].type != OCONFIG_TYPE_STRING) + || (ci->values[2].type != OCONFIG_TYPE_STRING)) + { + ERROR ("Target `replace': The `%s' option requires exactly three string " + "arguments.", ci->key); + return (-1); + } + } + + if (strlen (ci->values[0].value.string) == 0) + { + ERROR ("Target `replace': The `%s' option does not accept empty string as " + "first argument.", ci->key); + return (-1); + } + + act = calloc (1, sizeof (*act)); + if (act == NULL) + { + ERROR ("tr_config_add_meta_action: calloc failed."); + return (-ENOMEM); + } + + act->key = NULL; + act->replacement = NULL; + + status = regcomp (&act->re, ci->values[1].value.string, REG_EXTENDED); + if (status != 0) + { + char errbuf[1024] = ""; + + /* regerror assures null termination. */ + regerror (status, &act->re, errbuf, sizeof (errbuf)); + ERROR ("Target `replace': Compiling the regular expression `%s' " + "failed: %s.", + ci->values[1].value.string, errbuf); + sfree (act->key); + sfree (act); + return (-EINVAL); + } + + act->key = tr_strdup (ci->values[0].value.string); + if (act->key == NULL) + { + ERROR ("tr_config_add_meta_action: tr_strdup failed."); + tr_meta_data_action_destroy (act); + return (-ENOMEM); + } + + if (!should_delete) { + act->replacement = tr_strdup (ci->values[2].value.string); + if (act->replacement == NULL) + { + ERROR ("tr_config_add_meta_action: tr_strdup failed."); + tr_meta_data_action_destroy (act); + return (-ENOMEM); + } + } + + /* Insert action at end of list. */ + if (*dest == NULL) + *dest = act; + else + { + tr_meta_data_action_t *prev; + + prev = *dest; + while (prev->next != NULL) + prev = prev->next; + + prev->next = act; + } + + return (0); +} /* }}} int tr_config_add_meta_action */ + static int tr_action_invoke (tr_action_t *act_head, /* {{{ */ - char *buffer_in, size_t buffer_in_size, int may_be_empty) + char *buffer_in, size_t buffer_in_size, _Bool may_be_empty) { - tr_action_t *act; int status; char buffer[DATA_MAX_NAME_LEN]; - regmatch_t matches[8]; + regmatch_t matches[8] = { [0] = { 0 } }; if (act_head == NULL) return (-EINVAL); sstrncpy (buffer, buffer_in, sizeof (buffer)); - memset (matches, 0, sizeof (matches)); DEBUG ("target_replace plugin: tr_action_invoke: <- buffer = %s;", buffer); - for (act = act_head; act != NULL; act = act->next) + for (tr_action_t *act = act_head; act != NULL; act = act->next) { char temp[DATA_MAX_NAME_LEN]; char *subst_status; @@ -216,6 +341,119 @@ static int tr_action_invoke (tr_action_t *act_head, /* {{{ */ return (0); } /* }}} int tr_action_invoke */ +static int tr_meta_data_action_invoke ( /* {{{ */ + tr_meta_data_action_t *act_head, meta_data_t **dest) +{ + int status; + regmatch_t matches[8] = { [0] = { 0 } }; + + if (act_head == NULL) + return (-EINVAL); + + if ((*dest) == NULL) /* nothing to do */ + return (0); + + for (tr_meta_data_action_t *act = act_head; act != NULL; act = act->next) + { + char temp[DATA_MAX_NAME_LEN]; + char *subst_status; + int value_type; + int meta_data_status; + char *value; + meta_data_t *result; + + value_type = meta_data_type (*dest, act->key); + if (value_type == 0) /* not found */ + continue; + if (value_type != MD_TYPE_STRING) + { + WARNING ("Target `replace': Attempting replace on metadata key `%s', " + "which isn't a string.", + act->key); + continue; + } + + meta_data_status = meta_data_get_string (*dest, act->key, &value); + if (meta_data_status != 0) + { + ERROR ("Target `replace': Unable to retrieve metadata value for `%s'.", + act->key); + return (meta_data_status); + } + + DEBUG ("target_replace plugin: tr_meta_data_action_invoke: `%s' " + "old value = `%s'", act->key, value); + + status = regexec (&act->re, value, + STATIC_ARRAY_SIZE (matches), matches, + /* flags = */ 0); + if (status == REG_NOMATCH) + { + sfree (value); + continue; + } + else if (status != 0) + { + char errbuf[1024] = ""; + + regerror (status, &act->re, errbuf, sizeof (errbuf)); + ERROR ("Target `replace': Executing a regular expression failed: %s.", + errbuf); + sfree (value); + continue; + } + + if (act->replacement == NULL) + { + /* no replacement; delete the key */ + DEBUG ("target_replace plugin: tr_meta_data_action_invoke: " + "deleting `%s'", act->key); + meta_data_delete (*dest, act->key); + sfree (value); + continue; + } + + subst_status = subst (temp, sizeof (temp), value, + (size_t) matches[0].rm_so, (size_t) matches[0].rm_eo, act->replacement); + if (subst_status == NULL) + { + ERROR ("Target `replace': subst (value = %s, start = %zu, end = %zu, " + "replacement = %s) failed.", + value, (size_t) matches[0].rm_so, (size_t) matches[0].rm_eo, + act->replacement); + sfree (value); + continue; + } + + DEBUG ("target_replace plugin: tr_meta_data_action_invoke: `%s' " + "value `%s' -> `%s'", act->key, value, temp); + + if ((result = meta_data_create()) == NULL) + { + ERROR ("Target `replace': failed to create metadata for `%s'.", + act->key); + sfree (value); + return (-ENOMEM); + } + + meta_data_status = meta_data_add_string (result, act->key, temp); + if (meta_data_status != 0) + { + ERROR ("Target `replace': Unable to set metadata value for `%s'.", + act->key); + meta_data_destroy (result); + sfree (value); + return (meta_data_status); + } + + meta_data_clone_merge (dest, result); + meta_data_destroy (result); + sfree (value); + } /* for (act = act_head; act != NULL; act = act->next) */ + + return (0); +} /* }}} int tr_meta_data_action_invoke */ + static int tr_destroy (void **user_data) /* {{{ */ { tr_data_t *data; @@ -232,6 +470,7 @@ static int tr_destroy (void **user_data) /* {{{ */ tr_action_destroy (data->plugin_instance); /* tr_action_destroy (data->type); */ tr_action_destroy (data->type_instance); + tr_meta_data_action_destroy (data->meta); sfree (data); return (0); @@ -241,7 +480,6 @@ static int tr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */ { tr_data_t *data; int status; - int i; data = calloc (1, sizeof (*data)); if (data == NULL) @@ -255,9 +493,10 @@ static int tr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */ data->plugin_instance = NULL; /* data->type = NULL; */ data->type_instance = NULL; + data->meta = NULL; status = 0; - for (i = 0; i < ci->children_num; i++) + for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; @@ -279,6 +518,12 @@ static int tr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */ else if (strcasecmp ("TypeInstance", child->key) == 0) status = tr_config_add_action (&data->type_instance, child, /* may be empty = */ 1); + else if (strcasecmp ("MetaData", child->key) == 0) + status = tr_config_add_meta_action (&data->meta, child, + /* should delete = */ 0); + else if (strcasecmp ("DeleteMetaData", child->key) == 0) + status = tr_config_add_meta_action (&data->meta, child, + /* should delete = */ 1); else { ERROR ("Target `replace': The `%s' configuration option is not understood " @@ -297,7 +542,8 @@ static int tr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */ && (data->plugin == NULL) && (data->plugin_instance == NULL) /* && (data->type == NULL) */ - && (data->type_instance == NULL)) + && (data->type_instance == NULL) + && (data->meta == NULL)) { ERROR ("Target `replace': You need to set at least one of `Host', " "`Plugin', `PluginInstance' or `TypeInstance'."); @@ -332,13 +578,18 @@ static int tr_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */ return (-EINVAL); } + if (data->meta != NULL) + { + tr_meta_data_action_invoke (data->meta, &(vl->meta)); + } + #define HANDLE_FIELD(f,e) \ if (data->f != NULL) \ tr_action_invoke (data->f, vl->f, sizeof (vl->f), e) HANDLE_FIELD (host, 0); HANDLE_FIELD (plugin, 0); HANDLE_FIELD (plugin_instance, 1); - /* HANDLE_FIELD (type); */ + /* HANDLE_FIELD (type, 0); */ HANDLE_FIELD (type_instance, 1); return (FC_TARGET_CONTINUE); @@ -346,9 +597,8 @@ static int tr_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */ void module_register (void) { - target_proc_t tproc; + target_proc_t tproc = { 0 }; - memset (&tproc, 0, sizeof (tproc)); tproc.create = tr_create; tproc.destroy = tr_destroy; tproc.invoke = tr_invoke;