diff options
author | Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com> | 2020-05-25 20:25:08 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-25 20:25:08 +0300 |
commit | 570d5253f53b46ce59b3fd93a53b15f56f946038 (patch) | |
tree | 490cda44451f87f1dc46457f381cbc8296238ee4 /collectors/plugins.d | |
parent | 4fb41597da6961813679c1b795793600ddc0a402 (diff) |
Implement new incremental parser (#9074)
Implemented a new parser for the pluginsd language
Diffstat (limited to 'collectors/plugins.d')
-rw-r--r-- | collectors/plugins.d/plugins_d.c | 523 | ||||
-rw-r--r-- | collectors/plugins.d/plugins_d.h | 12 | ||||
-rw-r--r-- | collectors/plugins.d/pluginsd_parser.c | 630 | ||||
-rw-r--r-- | collectors/plugins.d/pluginsd_parser.h | 20 |
4 files changed, 688 insertions, 497 deletions
diff --git a/collectors/plugins.d/plugins_d.c b/collectors/plugins.d/plugins_d.c index b5b9b1b111..e39d9b0376 100644 --- a/collectors/plugins.d/plugins_d.c +++ b/collectors/plugins.d/plugins_d.c @@ -1,22 +1,22 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "plugins_d.h" +#include "pluginsd_parser.h" char *plugin_directories[PLUGINSD_MAX_DIRECTORIES] = { NULL }; struct plugind *pluginsd_root = NULL; -static inline int pluginsd_space(char c) -{ - switch (c) { - case ' ': - case '\t': - case '\r': - case '\n': - case '=': - return 1; +inline int pluginsd_space(char c) { + switch(c) { + case ' ': + case '\t': + case '\r': + case '\n': + case '=': + return 1; - default: - return 0; + default: + return 0; } } @@ -36,10 +36,11 @@ inline int config_isspace(char c) } // split a text into words, respecting quotes -static inline int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char)) +static inline int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char), char *recover_input, char **recover_location, int max_recover) { char *s = str, quote = 0; - int i = 0, j; + int i = 0, j, rec = 0; + char *recover = recover_input; // skip all white space while (unlikely(custom_isspace(*s))) @@ -65,6 +66,10 @@ static inline int quoted_strings_splitter(char *str, char **words, int max_words // if it is quote else if (unlikely(*s == quote)) { quote = 0; + if (recover && rec < max_recover) { + recover_location[rec++] = s; + *recover++ = *s; + } *s = ' '; continue; } @@ -72,6 +77,12 @@ static inline int quoted_strings_splitter(char *str, char **words, int max_words // if it is a space else if (unlikely(quote == 0 && custom_isspace(*s))) { // terminate the word + if (recover && rec < max_recover) { + if (!rec || (rec && recover_location[rec-1] != s)) { + recover_location[rec++] = s; + *recover++ = *s; + } + } *s++ = '\0'; // skip all white space @@ -120,12 +131,12 @@ inline int pluginsd_initialize_plugin_directories() } // Parse it and store it to plugin directories - return quoted_strings_splitter(plugins_dir_list, plugin_directories, PLUGINSD_MAX_DIRECTORIES, config_isspace); + return quoted_strings_splitter(plugins_dir_list, plugin_directories, PLUGINSD_MAX_DIRECTORIES, config_isspace, NULL, NULL, 0); } -inline int pluginsd_split_words(char *str, char **words, int max_words) +inline int pluginsd_split_words(char *str, char **words, int max_words, char *recover_input, char **recover_location, int max_recover) { - return quoted_strings_splitter(str, words, max_words, pluginsd_space); + return quoted_strings_splitter(str, words, max_words, pluginsd_space, recover_input, recover_location, max_recover); } #ifdef ENABLE_HTTPS @@ -226,482 +237,6 @@ char *pluginsd_get_from_buffer(char *output, int *bytesread, char *input, SSL *s } #endif -inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations) -{ - int enabled = cd->enabled; - - if (!fp || !enabled) { - cd->enabled = 0; - return 0; - } - - size_t count = 0; - - char line[PLUGINSD_LINE_MAX + 1]; - - char *words[PLUGINSD_MAX_WORDS] = { NULL }; - uint32_t BEGIN_HASH = simple_hash(PLUGINSD_KEYWORD_BEGIN); - uint32_t END_HASH = simple_hash(PLUGINSD_KEYWORD_END); - uint32_t FLUSH_HASH = simple_hash(PLUGINSD_KEYWORD_FLUSH); - uint32_t CHART_HASH = simple_hash(PLUGINSD_KEYWORD_CHART); - uint32_t DIMENSION_HASH = simple_hash(PLUGINSD_KEYWORD_DIMENSION); - uint32_t DISABLE_HASH = simple_hash(PLUGINSD_KEYWORD_DISABLE); - uint32_t VARIABLE_HASH = simple_hash(PLUGINSD_KEYWORD_VARIABLE); - uint32_t LABEL_HASH = simple_hash(PLUGINSD_KEYWORD_LABEL); - uint32_t OVERWRITE_HASH = simple_hash(PLUGINSD_KEYWORD_OVERWRITE); - - RRDSET *st = NULL; - uint32_t hash; - struct label *new_labels = NULL; - - errno = 0; - clearerr(fp); - - if (unlikely(fileno(fp) == -1)) { - error("file descriptor given is not a valid stream"); - goto cleanup; - } - -#ifdef ENABLE_HTTPS - int bytesleft = 0; - char tmpbuffer[PLUGINSD_LINE_MAX]; - char *readfrom = NULL; -#endif - char *r = NULL; - while (!ferror(fp)) { - if (unlikely(netdata_exit)) - break; - -#ifdef ENABLE_HTTPS - int normalread = 1; - if (netdata_srv_ctx) { - if (host->stream_ssl.conn && !host->stream_ssl.flags) { - if (!bytesleft) { - r = line; - readfrom = tmpbuffer; - bytesleft = pluginsd_update_buffer(readfrom, host->stream_ssl.conn); - if (bytesleft <= 0) { - break; - } - } - - readfrom = pluginsd_get_from_buffer(line, &bytesleft, readfrom, host->stream_ssl.conn, tmpbuffer); - if (!readfrom) { - r = NULL; - } - - normalread = 0; - } - } - - if (normalread) { - r = fgets(line, PLUGINSD_LINE_MAX, fp); - } -#else - r = fgets(line, PLUGINSD_LINE_MAX, fp); -#endif - - if (unlikely(!r)) { - if (feof(fp)) - error("read failed: end of file"); - else if (ferror(fp)) - error("read failed: input error"); - else - error("read failed: unknown error"); - break; - } - - if (unlikely(netdata_exit)) - break; - - line[PLUGINSD_LINE_MAX] = '\0'; - - int w = pluginsd_split_words(line, words, PLUGINSD_MAX_WORDS); - char *s = words[0]; - if (unlikely(!s || !*s || !w)) { - continue; - } - - // debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]); - - if (likely(!simple_hash_strcmp(s, "SET", &hash))) { - char *dimension = words[1]; - char *value = words[2]; - - if (unlikely(!dimension || !*dimension)) { - error( - "requested a SET on chart '%s' of host '%s', without a dimension. Disabling it.", st->id, - host->hostname); - enabled = 0; - break; - } - - if (unlikely(!value || !*value)) - value = NULL; - - if (unlikely(!st)) { - error( - "requested a SET on dimension %s with value %s on host '%s', without a BEGIN. Disabling it.", - dimension, value ? value : "<nothing>", host->hostname); - enabled = 0; - break; - } - - if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) - debug(D_PLUGINSD, "is setting dimension %s/%s to %s", st->id, dimension, value ? value : "<nothing>"); - - if (value) { - RRDDIM *rd = rrddim_find(st, dimension); - if (unlikely(!rd)) { - error( - "requested a SET to dimension with id '%s' on stats '%s' (%s) on host '%s', which does not exist. Disabling it.", - dimension, st->name, st->id, st->rrdhost->hostname); - enabled = 0; - break; - } else - rrddim_set_by_pointer(st, rd, strtoll(value, NULL, 0)); - } - } else if (likely(hash == BEGIN_HASH && !strcmp(s, PLUGINSD_KEYWORD_BEGIN))) { - char *id = words[1]; - char *microseconds_txt = words[2]; - - if (unlikely(!id)) { - error("requested a BEGIN without a chart id for host '%s'. Disabling it.", host->hostname); - enabled = 0; - break; - } - - st = rrdset_find(host, id); - if (unlikely(!st)) { - error( - "requested a BEGIN on chart '%s', which does not exist on host '%s'. Disabling it.", id, - host->hostname); - enabled = 0; - break; - } - - if (likely(st->counter_done)) { - usec_t microseconds = 0; - if (microseconds_txt && *microseconds_txt) - microseconds = str2ull(microseconds_txt); - - if (likely(microseconds)) { - if (trust_durations) - rrdset_next_usec_unfiltered(st, microseconds); - else - rrdset_next_usec(st, microseconds); - } else - rrdset_next(st); - } - } else if (likely(hash == END_HASH && !strcmp(s, PLUGINSD_KEYWORD_END))) { - if (unlikely(!st)) { - error("requested an END, without a BEGIN on host '%s'. Disabling it.", host->hostname); - enabled = 0; - break; - } - - if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) - debug(D_PLUGINSD, "requested an END on chart %s", st->id); - - rrdset_done(st); - st = NULL; - - count++; - } else if (likely(hash == CHART_HASH && !strcmp(s, PLUGINSD_KEYWORD_CHART))) { - st = NULL; - - char *type = words[1]; - char *name = words[2]; - char *title = words[3]; - char *units = words[4]; - char *family = words[5]; - char *context = words[6]; - char *chart = words[7]; - char *priority_s = words[8]; - char *update_every_s = words[9]; - char *options = words[10]; - char *plugin = words[11]; - char *module = words[12]; - - // parse the id from type - char *id = NULL; - if (likely(type && (id = strchr(type, '.')))) { - *id = '\0'; - id++; - } - - // make sure we have the required variables - if (unlikely(!type || !*type || !id || !*id)) { - error("requested a CHART, without a type.id, on host '%s'. Disabling it.", host->hostname); - enabled = 0; - break; - } - - // parse the name, and make sure it does not include 'type.' - if (unlikely(name && *name)) { - // when data are coming from slaves - // name will be type.name - // so we have to remove 'type.' from name too - size_t len = strlen(type); - if (strncmp(type, name, len) == 0 && name[len] == '.') - name = &name[len + 1]; - - // if the name is the same with the id, - // or is just 'NULL', clear it. - if (unlikely(strcmp(name, id) == 0 || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0)) - name = NULL; - } - - int priority = 1000; - if (likely(priority_s && *priority_s)) - priority = str2i(priority_s); - - int update_every = cd->update_every; - if (likely(update_every_s && *update_every_s)) - update_every = str2i(update_every_s); - if (unlikely(!update_every)) - update_every = cd->update_every; - - RRDSET_TYPE chart_type = RRDSET_TYPE_LINE; - if (unlikely(chart)) - chart_type = rrdset_type_id(chart); - - if (unlikely(name && !*name)) - name = NULL; - if (unlikely(family && !*family)) - family = NULL; - if (unlikely(context && !*context)) - context = NULL; - if (unlikely(!title)) - title = ""; - if (unlikely(!units)) - units = "unknown"; - - debug( - D_PLUGINSD, - "creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d", - type, id, name ? name : "", family ? family : "", context ? context : "", rrdset_type_name(chart_type), - priority, update_every); - - st = rrdset_create( - host, type, id, name, family, context, title, units, (plugin && *plugin) ? plugin : cd->filename, - module, priority, update_every, chart_type); - - if (options && *options) { - if (strstr(options, "obsolete")) - rrdset_is_obsolete(st); - else - rrdset_isnot_obsolete(st); - - if (strstr(options, "detail")) - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - else - rrdset_flag_clear(st, RRDSET_FLAG_DETAIL); - - if (strstr(options, "hidden")) - rrdset_flag_set(st, RRDSET_FLAG_HIDDEN); - else - rrdset_flag_clear(st, RRDSET_FLAG_HIDDEN); - - if (strstr(options, "store_first")) - rrdset_flag_set(st, RRDSET_FLAG_STORE_FIRST); - else - rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST); - } else { - rrdset_isnot_obsolete(st); - rrdset_flag_clear(st, RRDSET_FLAG_DETAIL); - rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST); - } - } else if (likely(hash == DIMENSION_HASH && !strcmp(s, PLUGINSD_KEYWORD_DIMENSION))) { - char *id = words[1]; - char *name = words[2]; - char *algorithm = words[3]; - char *multiplier_s = words[4]; - char *divisor_s = words[5]; - char *options = words[6]; - - if (unlikely(!id || !*id)) { - error( - "requested a DIMENSION, without an id, host '%s' and chart '%s'. Disabling it.", host->hostname, - st ? st->id : "UNSET"); - enabled = 0; - break; - } - - if (unlikely(!st)) { - error("requested a DIMENSION, without a CHART, on host '%s'. Disabling it.", host->hostname); - enabled = 0; - break; - } - - long multiplier = 1; - if (multiplier_s && *multiplier_s) - multiplier = strtol(multiplier_s, NULL, 0); - if (unlikely(!multiplier)) - multiplier = 1; - - long divisor = 1; - if (likely(divisor_s && *divisor_s)) - divisor = strtol(divisor_s, NULL, 0); - if (unlikely(!divisor)) - divisor = 1; - - if (unlikely(!algorithm || !*algorithm)) - algorithm = "absolute"; - - if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) - debug( - D_PLUGINSD, - "creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'", - st->id, id, name ? name : "", rrd_algorithm_name(rrd_algorithm_id(algorithm)), multiplier, divisor, - options ? options : ""); - - RRDDIM *rd = rrddim_add(st, id, name, multiplier, divisor, rrd_algorithm_id(algorithm)); - rrddim_flag_clear(rd, RRDDIM_FLAG_HIDDEN); - rrddim_flag_clear(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS); - if (options && *options) { - if (strstr(options, "obsolete") != NULL) - rrddim_is_obsolete(st, rd); - else - rrddim_isnot_obsolete(st, rd); - if (strstr(options, "hidden") != NULL) - rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN); - if (strstr(options, "noreset") != NULL) - rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS); - if (strstr(options, "nooverflow") != NULL) - rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS); - } else { - rrddim_isnot_obsolete(st, rd); - } - } else if (likely(hash == VARIABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_VARIABLE))) { - char *name = words[1]; - char *value = words[2]; - int global = (st) ? 0 : 1; - - if (name && *name) { - if ((strcmp(name, "GLOBAL") == 0 || strcmp(name, "HOST") == 0)) { - global = 1; - name = words[2]; - value = words[3]; - } else if ((strcmp(name, "LOCAL") == 0 || strcmp(name, "CHART") == 0)) { - global = 0; - name = words[2]; - value = words[3]; - } - } - - if (unlikely(!name || !*name)) { - error("requested a VARIABLE on host '%s', without a variable name. Disabling it.", host->hostname); - enabled = 0; - break; - } - - if (unlikely(!value || !*value)) - value = NULL; - - if (value) { - char *endptr = NULL; - calculated_number v = (calculated_number)str2ld(value, &endptr); - - if (unlikely(endptr && *endptr)) { - if (endptr == value) - error( - "the value '%s' of VARIABLE '%s' on host '%s' cannot be parsed as a number", value, name, - host->hostname); - else - error( - "the value '%s' of VARIABLE '%s' on host '%s' has leftovers: '%s'", value, name, - host->hostname, endptr); - } - - if (global) { - RRDVAR *rv = rrdvar_custom_host_variable_create(host, name); - if (rv) - rrdvar_custom_host_variable_set(host, rv, v); - else - error("cannot find/create HOST VARIABLE '%s' on host '%s'", name, host->hostname); - } else if (st) { - RRDSETVAR *rs = rrdsetvar_custom_chart_variable_create(st, name); - if (rs) - rrdsetvar_custom_chart_variable_set(rs, v); - else - error( - "cannot find/create CHART VARIABLE '%s' on host '%s', chart '%s'", name, host->hostname, - st->id); - } else - error("cannot find/create CHART VARIABLE '%s' on host '%s' without a chart", name, host->hostname); - } else - error( - "cannot set %s VARIABLE '%s' on host '%s' to an empty value", (global) ? "HOST" : "CHART", name, - host->hostname); - } else if (likely(hash == FLUSH_HASH && !strcmp(s, PLUGINSD_KEYWORD_FLUSH))) { - debug(D_PLUGINSD, "requested a FLUSH"); - st = NULL; - } else if (unlikely(hash == DISABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_DISABLE))) { - info("called DISABLE. Disabling it."); - enabled = 0; - break; - } else if (likely(hash == LABEL_HASH && !strcmp(s, PLUGINSD_KEYWORD_LABEL))) { - debug(D_PLUGINSD, "requested a LABEL CHANGE"); - char *store; - if (!words[4]) - store = words[3]; - else { - store = callocz(PLUGINSD_LINE_MAX + 1, sizeof(char)); - size_t remaining = PLUGINSD_LINE_MAX; - char *move = store; - int i = 3; - while (i < w) { - size_t length = strlen(words[i]); - if ((length + 1) >= remaining) - break; - - remaining -= (length + 1); - memcpy(move, words[i], length); - move += length; - *move++ = ' '; - - i++; - if (!words[i]) - break; - } - } - - new_labels = add_label_to_list(new_labels, words[1], store, strtol(words[2], NULL, 10)); - if (store != words[3]) - freez(store); - } else if (likely(hash == OVERWRITE_HASH && !strcmp(s, PLUGINSD_KEYWORD_OVERWRITE))) { - debug(D_PLUGINSD, "requested a OVERWITE a variable"); - if (!host->labels) { - host->labels = new_labels; - } else { - rrdhost_rdlock(host); - replace_label_list(host, new_labels); - rrdhost_unlock(host); - } - - new_labels = NULL; - } else { - error("sent command '%s' which is not known by netdata, for host '%s'. Disabling it.", s, host->hostname); - enabled = 0; - break; - } - } - -cleanup: - cd->enabled = enabled; - - if (new_labels) - free_host_labels(new_labels); - - if (likely(count)) { - cd->successful_collections += count; - cd->serial_failures = 0; - } else - cd->serial_failures++; - - return count; -} static void pluginsd_worker_thread_cleanup(void *arg) { @@ -809,9 +344,7 @@ void *pluginsd_worker_thread(void *arg) info("connected to '%s' running on pid %d", cd->fullfilename, cd->pid); count = pluginsd_process(localhost, cd, fp, 0); - error( - "'%s' (pid %d) disconnected after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid, - count); + error("'%s' (pid %d) disconnected after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid, count); killpid(cd->pid); int worker_ret_code = mypclose(fp, cd->pid); diff --git a/collectors/plugins.d/plugins_d.h b/collectors/plugins.d/plugins_d.h index 8134b99650..e3589c6717 100644 --- a/collectors/plugins.d/plugins_d.h +++ b/collectors/plugins.d/plugins_d.h @@ -31,6 +31,11 @@ #define PLUGINSD_KEYWORD_VARIABLE "VARIABLE" #define PLUGINSD_KEYWORD_LABEL "LABEL" #define PLUGINSD_KEYWORD_OVERWRITE "OVERWRITE" +#define PLUGINSD_KEYWORD_CONTEXT "CONTEXT" +#define PLUGINSD_KEYWORD_GUID "GUID" +#define PLUGINSD_KEYWORD_HOST "HOST" +#define PLUGINSD_KEYWORD_TOMBSTONE "TOMBSTONE" + #define PLUGINSD_LINE_MAX 1024 #define PLUGINSD_LINE_MAX_SSL_READ 512 @@ -60,7 +65,7 @@ struct plugind { volatile sig_atomic_t enabled; // if this is enabled or not time_t started_t; - + uint32_t version; struct plugind *next; }; @@ -69,10 +74,13 @@ extern struct plugind *pluginsd_root; extern void *pluginsd_main(void *ptr); extern size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations); -extern int pluginsd_split_words(char *str, char **words, int max_words); +extern int pluginsd_split_words(char *str, char **words, int max_words, char *recover_string, char **recover_location, int max_recover); extern int pluginsd_initialize_plugin_directories(); extern int config_isspace(char c); +extern int pluginsd_space(char c); +extern int pluginsd_update_buffer(char *output, SSL *ssl); +extern char * pluginsd_get_from_buffer(char *output, int *bytesread, char *input, SSL *ssl, char *src); #endif /* NETDATA_PLUGINS_D_H */ diff --git a/collectors/plugins.d/pluginsd_parser.c b/collectors/plugins.d/pluginsd_parser.c new file mode 100644 index 0000000000..aaf95dc789 --- /dev/null +++ b/collectors/plugins.d/pluginsd_parser.c @@ -0,0 +1,630 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "pluginsd_parser.h" + +/* + * This is the action defined for the FLUSH command + */ +PARSER_RC pluginsd_set_action(void *user, RRDSET *st, RRDDIM *rd, long long int value) +{ + UNUSED(user); + + rrddim_set_by_pointer(st, rd, value); + return PARSER_RC_OK; +} + +PARSER_RC pluginsd_flush_action(void *user, RRDSET *st) +{ + UNUSED(user); + UNUSED(st); + return PARSER_RC_OK; +} + +PARSER_RC pluginsd_begin_action(void *user, RRDSET *st, usec_t microseconds, int trust_durations) +{ + UNUSED(user); + if (likely(st->counter_done)) { + if (likely(microseconds)) { + if (trust_durations) + rrdset_next_usec_unfiltered(st, microseconds); + else + rrdset_next_usec(st, microseconds); + } else + rrdset_next(st); + } + return PARSER_RC_OK; +} + + +PARSER_RC pluginsd_end_action(void *user, RRDSET *st) +{ + UNUSED(user); + + rrdset_done(st); + return PARSER_RC_OK; +} + +PARSER_RC pluginsd_chart_action(void *user, char *type, char *id, char *name, char *family, char *context, char *title, char *units, char *plugin, + char *module, int priority, int update_every, RRDSET_TYPE chart_type, char *options) +{ + RRDSET *st = NULL; + RRDHOST *host = ((PARSER_USER_OBJECT *) user)->host; + + st = rrdset_create( + host, type, id, name, family, context, title, units, + plugin, module, priority, update_every, + chart_type); + + if (options && *options) { + if (strstr(options, "obsolete")) + rrdset_is_obsolete(st); + else + rrdset_isnot_obsolete(st); + + if (strstr(options, "detail")) + rrdset_flag_set(st, RRDSET_FLAG_DETAIL); + else + rrdset_flag_clear(st, RRDSET_FLAG_DETAIL); + + if (strstr(options, "hidden")) + rrdset_flag_set(st, RRDSET_FLAG_HIDDEN); + else + rrdset_flag_clear(st, RRDSET_FLAG_HIDDEN); + + if (strstr(options, "store_first")) + rrdset_flag_set(st, RRDSET_FLAG_STORE_FIRST); + else + rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST); + } else { + rrdset_isnot_obsolete(st); + rrdset_flag_clear(st, RRDSET_FLAG_DETAIL); + rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST); + } + ((PARSER_USER_OBJECT *)user)->st = st; + + return PARSER_RC_OK; +} + + +PARSER_RC pluginsd_disable_action(void *user) +{ + UNUSED(user); + + info("called DISABLE. Disabling it."); + ((PARSER_USER_OBJECT *) user)->enabled = 0; + return PARSER_RC_ERROR; +} + + +PARSER_RC pluginsd_variable_action(void *user, RRDHOST *host, RRDSET *st, char *name, int global, calculated_number value) +{ + UNUSED(user); + + if (global) { + RRDVAR *rv = rrdvar_custom_host_variable_create(host, name); + if (rv) + rrdvar_custom_host_variable_set(host, rv, value); + else + error("cannot find/create HOST VARIABLE '%s' on host '%s'", name, host->hostname); + } else { + RRDSETVAR *rs = rrdsetvar_custom_chart_variable_create(st, name); + if (rs) + rrdsetvar_custom_chart_variable_set(rs, value); + else + error("cannot find/create CHART VARIABLE '%s' on host '%s', chart '%s'", name, host->hostname, st->id); + } + return PARSER_RC_OK; +} + + + +PARSER_RC pluginsd_dimension_action(void *user, RRDSET *st, char *id, char *name, char *algorithm, long multiplier, long divisor, char *options, + RRD_ALGORITHM algorithm_type) +{ + UNUSED(user); + UNUSED(algorithm); + + RRDDIM *rd = rrddim_add(st, id, name, multiplier, divisor, algorithm_type); + rrddim_flag_clear(rd, RRDDIM_FLAG_HIDDEN); + rrddim_flag_clear(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS); + if (options && *options) { + if (strstr(options, "obsolete") != NULL) + rrddim_is_obsolete(st, rd); + else + rrddim_isnot_obsolete(st, rd); + if (strstr(options, "hidden") != NULL) + rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN); + if (strstr(options, "noreset") != NULL) + rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS); + if (strstr(options, "nooverflow") != NULL) + rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS); + } else { + rrddim_isnot_obsolete(st, rd); + } + return PARSER_RC_OK; +} + +PARSER_RC pluginsd_label_action(void *user, char *key, char *value, LABEL_SOURCE source) +{ + + ((PARSER_USER_OBJECT *) user)->new_labels = add_label_to_list(((PARSER_USER_OBJECT *) user)->new_labels, key, value, source); + + return PARSER_RC_OK; +} + + +PARSER_RC pluginsd_overwrite_action(void *user, RRDHOST *host, struct label *new_labels) +{ + UNUSED(user); + + if (!host->labels) { + host->labels = new_labels; + } else { + rrdhost_rdlock(host); + replace_label_list(host, new_labels); + rrdhost_unlock(host); + } + return PARSER_RC_OK; +} + +PARSER_RC pluginsd_set(char **words, void *user, PLUGINSD_ACTION *plugins_action) +{ + char *dimension = words[1]; + char *value = words[2]; + + RRDSET *st = ((PARSER_USER_OBJECT *) user)->st; + RRDHOST *host = ((PARSER_USER_OBJECT *) user)->host; + + if (unlikely(!dimension || !*dimension)) { + error("requested a SET on chart '%s' of host '%s', without a dimension. Disabling it.", st->id, host->hostname); + goto disable; + } + + if (unlikely(!value || !*value)) + value = NULL; + + if (unlikely(!st)) { + error( + "requested a SET on dimension %s with value %s on host '%s', without a BEGIN. Disabling it.", dimension, + value ? value : "<nothing>", host->hostname); + goto disable; + } + + if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) + debug(D_PLUGINSD, "is setting dimension %s/%s to %s", st->id, dimension, value ? value : "<nothing>"); + + if (value) { + RRDDIM *rd = rrddim_find(st, dimension); + if (unlikely(!rd)) { + error( + "requested a SET to dimension with id '%s' on stats '%s' (%s) on host '%s', which does not exist. Disabling it.", + dimension, st->name, st->id, st->rrdhost->hostname); + goto disable; + } else { + if (plugins_action->set_action) { + return plugins_action->set_action( + user, st, rd, strtoll(value, NULL, 0)); + } + } + } + return PARSER_RC_OK; + +disable: + ((PARSER_USER_OBJECT *) user)->enabled = 0; + return PARSER_RC_ERROR; +} + +PARSER_RC pluginsd_begin(char **words, void *user, PLUGINSD_ACTION *plugins_action) +{ + char *id = words[1]; + char *microseconds_txt = words[2]; + + RRDSET *st = NULL; + RRDHOST *host = ((PARSER_USER_OBJECT *)user)->host; + + if (unlikely(!id)) { + error("requested a BEGIN without a chart id for host '%s'. Disabling it.", host->hostname); + goto disable; + } + + st = rrdset_find(host, id); + if (unlikely(!st)) { + error("requested a BEGIN on chart '%s', which does not exist on host '%s'. Disabling it.", id, host->hostname); + goto disable; + } + ((PARSER_USER_OBJECT *)user)->st = st; + + usec_t microseconds = 0; + if (microseconds_txt && *microseconds_txt) + microseconds = str2ull(microseconds_txt); + + if (plugins_action->begin_action) { + return plugins_action->begin_action(user, st, microseconds, ((PARSER_USER_OBJECT *)user)->trust_durations); + } + return PARSER_RC_OK; +disable: + ((PARSER_USER_OBJECT *)user)->enabled = 0; + return PARSER_RC_ERROR; +} + +PARSER_RC pluginsd_end(char **words, void *user, PLUGINSD_ACTION *plugins_action) +{ + UNUSED(words); + RRDSET *st = ((PARSER_USER_OBJECT *) user)->st; + RRDHOST *host = ((PARSER_USER_OBJECT *) user)->host; + + if (unlikely(!st)) { + error("requested an END, without a BEGIN on host '%s'. Disabling it.", host->hostname); + ((PARSER_USER_OBJECT *) user)->enabled = 0; + return PARSER_RC_ERROR; + } + + if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) + debug(D_PLUGINSD, "requested an END on chart %s", st->id); + + ((PARSER_USER_OBJECT *) user)->st = NULL; + ((PARSER_USER_OBJECT *) user)->count++; + if (plugins_action->end_action) { + return plugins_action->end_action(user, st); + } + return PARSER_RC_OK; +} + +PARSER_RC pluginsd_chart(char **words, void *user, PLUGINSD_ACTION *plugins_action) +{ + RRDHOST *host = ((PARSER_USER_OBJECT *) user)->host; + + char *type = words[1]; + char *name = words[2]; + char *title = words[3]; + char *units = words[4]; + char *family = words[5]; + char *context = words[6]; + char *chart = words[7]; + char *priority_s = words[8]; + char *update_every_s = words[9]; + char *options = words[10]; + char *plugin = words[11]; + char *module = words[12]; |