summaryrefslogtreecommitdiffstats
path: root/collectors/plugins.d
diff options
context:
space:
mode:
authorStelios Fragkakis <52996999+stelfrag@users.noreply.github.com>2020-05-25 20:25:08 +0300
committerGitHub <noreply@github.com>2020-05-25 20:25:08 +0300
commit570d5253f53b46ce59b3fd93a53b15f56f946038 (patch)
tree490cda44451f87f1dc46457f381cbc8296238ee4 /collectors/plugins.d
parent4fb41597da6961813679c1b795793600ddc0a402 (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.c523
-rw-r--r--collectors/plugins.d/plugins_d.h12
-rw-r--r--collectors/plugins.d/pluginsd_parser.c630
-rw-r--r--collectors/plugins.d/pluginsd_parser.h20
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];</