// ---------------------------
// traversing
-void avl_walker(avl *node, void (*callback)(void *)) {
+void avl_walker(avl *node, void (*callback)(void *entry, void *data), void *data) {
if(node->avl_link[0])
- avl_walker(node->avl_link[0], callback);
+ avl_walker(node->avl_link[0], callback, data);
- callback(node);
+ callback(node, data);
if(node->avl_link[1])
- avl_walker(node->avl_link[1], callback);
+ avl_walker(node->avl_link[1], callback, data);
}
-void avl_traverse(avl_tree *t, void (*callback)(void *)) {
- avl_walker(t->root, callback);
+void avl_traverse(avl_tree *t, void (*callback)(void *entry, void *data), void *data) {
+ avl_walker(t->root, callback, data);
}
// ---------------------------
return ret;
}
-void avl_traverse_lock(avl_tree_lock *t, void (*callback)(void *)) {
+void avl_traverse_lock(avl_tree_lock *t, void (*callback)(void *entry, void *data), void *data) {
avl_read_lock(t);
- avl_traverse(&t->avl_tree, callback);
+ avl_traverse(&t->avl_tree, callback, data);
avl_unlock(t);
}
void avl_init(avl_tree *t, int (*compar)(void *a, void *b));
-void avl_traverse_lock(avl_tree_lock *t, void (*callback)(void *));
-void avl_traverse(avl_tree *t, void (*callback)(void *));
+void avl_traverse_lock(avl_tree_lock *t, void (*callback)(void *entry, void *data), void *data);
+void avl_traverse(avl_tree *t, void (*callback)(void *entry, void *data), void *data);
#endif /* avl.h */
// ----------------------------------------------------------------------------
// RRDVAR lookup
-calculated_number rrdvar2number(RRDVAR *rv) {
+static calculated_number rrdvar2number(RRDVAR *rv) {
switch(rv->type) {
case RRDVAR_TYPE_CALCULATED: {
calculated_number *n = (calculated_number *)rv->value;
}
}
-void dump_variable(void *data) {
- RRDVAR *rv = (RRDVAR *)data;
- debug(D_HEALTH, "%50s : %20.5Lf", rv->name, rrdvar2number(rv));
-}
-
int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, calculated_number *result) {
RRDSET *st = rc->rrdset;
RRDVAR *rv;
return 1;
}
- debug(D_HEALTH, "Available local chart '%s' variables:", st->id);
- avl_traverse_lock(&st->variables_root_index, dump_variable);
+ return 0;
+}
- debug(D_HEALTH, "Available family '%s' variables:", st->rrdfamily->family);
- avl_traverse_lock(&st->rrdfamily->variables_root_index, dump_variable);
+// ----------------------------------------------------------------------------
+// RRDVAR to JSON
- debug(D_HEALTH, "Available host '%s' variables:", st->rrdhost->hostname);
- avl_traverse_lock(&st->rrdhost->variables_root_index, dump_variable);
+struct variable2json_helper {
+ BUFFER *buf;
+ size_t counter;
+};
- return 0;
+static void single_variable2json(void *entry, void *data) {
+ struct variable2json_helper *helper = (struct variable2json_helper *)data;
+ RRDVAR *rv = (RRDVAR *)entry;
+ calculated_number value = rrdvar2number(rv);
+
+ if(unlikely(isnan(value) || isinf(value)))
+ buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": null", helper->counter?",":"", rv->name);
+ else
+ buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": %0.5Lf", helper->counter?",":"", rv->name, (long double)value);
+
+ helper->counter++;
}
+void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) {
+ struct variable2json_helper helper = {
+ .buf = buf,
+ .counter = 0
+ };
+
+ buffer_sprintf(buf, "{\n\t\"chart\": \"%s.%s\",\n\t\"chart_name\": \"%s.%s\",\n\t\"chart_variables\": {", st->type, st->id, st->type, st->name);
+ avl_traverse_lock(&st->variables_root_index, single_variable2json, (void *)&helper);
+ buffer_sprintf(buf, "\n\t},\n\t\"family\": \"%s\",\n\t\"family_variables\": {", st->family);
+ helper.counter = 0;
+ avl_traverse_lock(&st->rrdfamily->variables_root_index, single_variable2json, (void *)&helper);
+ buffer_sprintf(buf, "\n\t},\n\t\"host\": \"%s\",\n\t\"host_variables\": {", st->rrdhost->hostname);
+ helper.counter = 0;
+ avl_traverse_lock(&st->rrdhost->variables_root_index, single_variable2json, (void *)&helper);
+ buffer_strcat(buf, "\n\t}\n}\n");
+}
+
+
// ----------------------------------------------------------------------------
// RRDDIMVAR management
// DIMENSION VARIABLES
extern void health_alarms2json(RRDHOST *host, BUFFER *wb, int all);
extern void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after);
+void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf);
+
#endif //NETDATA_HEALTH_H
void rrdset_set_name(RRDSET *st, const char *name)
{
+ if(unlikely(st->name && !strcmp(st->name, name)))
+ return;
+
debug(D_RRD_CALLS, "rrdset_set_name() old: %s, new: %s", st->name, name);
char b[CONFIG_MAX_VALUE + 1];
void rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name)
{
- debug(D_RRD_CALLS, "rrddim_set_name() %s.%s", st->name, rd->name);
+ if(unlikely(rd->name && !strcmp(rd->name, name)))
+ return;
+
+ debug(D_RRD_CALLS, "rrddim_set_name() from %s.%s to %s.%s", st->name, rd->name, st->name, name);
char varname[CONFIG_MAX_NAME + 1];
snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
return errors;
}
-void test_variable_renames(void) {
+static int test_variable_renames(void) {
fprintf(stderr, "Creating chart\n");
- RRDSET *st = rrdset_create("netdata", "CHARTID1", NULL, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
+ RRDSET *st = rrdset_create("chart", "ID", NULL, "family", "context", "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
fprintf(stderr, "Created chart with id '%s', name '%s'\n", st->id, st->name);
fprintf(stderr, "Creating dimension DIM1\n");
fprintf(stderr, "Renaming dimension DIM2 to DIM2NAME2\n");
rrddim_set_name(st, rd2, "DIM2NAME2");
fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd2->id, rd2->name);
+
+ BUFFER *buf = buffer_create(1);
+ health_api_v1_chart_variables2json(st, buf);
+ fprintf(stderr, "%s", buffer_tostring(buf));
+ buffer_free(buf);
+ return 1;
}
int run_all_mockup_tests(void)
{
- test_variable_renames();
- exit(1);
+ if(!test_variable_renames())
+ return 1;
if(run_test(&test1))
return 1;
return 200;
}
-int web_client_api_request_v1_charts(struct web_client *w, char *url)
-{
- (void)url;
-
- buffer_flush(w->response.data);
- w->response.data->contenttype = CT_APPLICATION_JSON;
- rrd_stats_api_v1_charts(w->response.data);
- return 200;
-}
-
-int web_client_api_request_v1_chart(struct web_client *w, char *url)
+int web_client_api_request_single_chart(struct web_client *w, char *url, void callback(RRDSET *st, BUFFER *buf))
{
int ret = 400;
char *chart = NULL;
}
w->response.data->contenttype = CT_APPLICATION_JSON;
- rrd_stats_api_v1_chart(st, w->response.data);
+ callback(st, w->response.data);
return 200;
-cleanup:
+ cleanup:
return ret;
}
+int web_client_api_request_v1_alarm_variables(struct web_client *w, char *url)
+{
+ return web_client_api_request_single_chart(w, url, health_api_v1_chart_variables2json);
+}
+
+int web_client_api_request_v1_charts(struct web_client *w, char *url)
+{
+ (void)url;
+
+ buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ rrd_stats_api_v1_charts(w->response.data);
+ return 200;
+}
+
+int web_client_api_request_v1_chart(struct web_client *w, char *url)
+{
+ return web_client_api_request_single_chart(w, url, rrd_stats_api_v1_chart);
+}
+
int web_client_api_request_v1_badge(struct web_client *w, char *url) {
int ret = 400;
buffer_flush(w->response.data);
}
int web_client_api_request_v1(struct web_client *w, char *url) {
- static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0, hash_alarms = 0, hash_alarm_log = 0;
+ static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0, hash_alarms = 0, hash_alarm_log = 0, hash_alarm_variables = 0;
if(unlikely(hash_data == 0)) {
hash_data = simple_hash("data");
hash_badge = simple_hash("badge.svg");
hash_alarms = simple_hash("alarms");
hash_alarm_log = simple_hash("alarm_log");
+ hash_alarm_variables = simple_hash("alarm_variables");
}
// get the command
else if(hash == hash_alarm_log && !strcmp(tok, "alarm_log"))
return web_client_api_request_v1_alarm_log(w, url);
+ else if(hash == hash_alarm_variables && !strcmp(tok, "alarm_variables"))
+ return web_client_api_request_v1_alarm_variables(w, url);
+
else {
buffer_flush(w->response.data);
buffer_sprintf(w->response.data, "Unsupported v1 API command: %s", tok);