[rrd-developers] [PATCH 7 of 7] * Add new UDEF definition style to rrd_graph
Peter Stamfest
peter at stamfest.at
Mon Mar 7 20:28:09 CET 2011
# HG changeset patch
# User Peter Stamfest <peter at stamfest.at>
# Date 1299524877 -3600
# Node ID 2c4dd24dac78c2f41f7fc564be569001e012c5c1
# Parent ca194c6734f0c3251b389c4603919f9687588691
* Add new UDEF definition style to rrd_graph
- syntax:
UDEF:x=file:///<FILE>?cf=<CF>&step=<STEP>....
- allowed query parameters:
cf, ds, step, start, end, reduce, cache
- file:/// indicates a relative path (as per the URL definition)
- file://// indicates an absolute path
* This is in preparation for possible other URL style RRD access methods
diff --git a/src/rrd_graph.c b/src/rrd_graph.c
--- a/src/rrd_graph.c
+++ b/src/rrd_graph.c
@@ -239,6 +239,7 @@
conv_if(TICK, GF_TICK);
conv_if(TEXTALIGN, GF_TEXTALIGN);
conv_if(DEF, GF_DEF);
+ conv_if(UDEF, GF_UDEF);
conv_if(CDEF, GF_CDEF);
conv_if(VDEF, GF_VDEF);
conv_if(XPORT, GF_XPORT);
@@ -822,16 +823,16 @@
/* pull the data from the rrd files ... */
for (i = 0; i < (int) im->gdes_c; i++) {
- /* only GF_DEF elements fetch data */
- if (im->gdes[i].gf != GF_DEF)
+ /* only GF_DEF and GF_UDEF elements fetch data */
+ if (im->gdes[i].gf != GF_DEF && im->gdes[i].gf != GF_UDEF )
continue;
skip = 0;
/* do we have it already ? */
for (ii = 0; ii < i; ii++) {
- if (im->gdes[ii].gf != GF_DEF)
+ if (im->gdes[ii].gf != GF_DEF && im->gdes[ii].gf != GF_UDEF)
continue;
- if ((strcmp(im->gdes[i].rrd, im->gdes[ii].rrd) == 0)
+ if (call(im->gdes[i].source, compare_m, im->gdes[ii].source) == 0
&& (im->gdes[i].cf == im->gdes[ii].cf)
&& (im->gdes[i].cf_reduce == im->gdes[ii].cf_reduce)
&& (im->gdes[i].start_orig == im->gdes[ii].start_orig)
@@ -853,47 +854,18 @@
}
if (!skip) {
unsigned long ft_step = im->gdes[i].step; /* ft_step will record what we got from fetch */
- const char *rrd_daemon;
int status;
- if (im->gdes[i].daemon[0] != 0)
- rrd_daemon = im->gdes[i].daemon;
- else
- rrd_daemon = im->daemon_addr;
-
- const char *addr = want_rrdc_connection(rrd_daemon);
- if (addr != NULL) {
- rrdc_connection_t *conn = new_rrdc_connection(addr);
- if (conn != NULL) {
- status = rrdc_fetch (conn, im->gdes[i].rrd,
- cf_to_string (im->gdes[i].cf),
- &im->gdes[i].start,
- &im->gdes[i].end,
- &ft_step,
- &im->gdes[i].ds_cnt,
- &im->gdes[i].ds_namv,
- &im->gdes[i].data);
-
- delete_rrdc_connection(conn);
-
- if (status != 0)
- return (status);
-
- } else {
- // try to read data locally
- }
- }
-
- if ((rrd_fetch_fn(im->gdes[i].rrd,
- im->gdes[i].cf,
- &im->gdes[i].start,
- &im->gdes[i].end,
- &ft_step,
- &im->gdes[i].ds_cnt,
- &im->gdes[i].ds_namv,
- &im->gdes[i].data)) == -1) {
- return -1;
- }
+ status = call(im->gdes[i].source, fetch_m,
+ cf_to_string (im->gdes[i].cf),
+ &im->gdes[i].start,
+ &im->gdes[i].end,
+ &ft_step,
+ &im->gdes[i].ds_cnt,
+ &im->gdes[i].ds_namv,
+ &im->gdes[i].data);
+
+ if (status != 0) return -1;
im->gdes[i].data_first = 1;
@@ -916,8 +888,10 @@
}
}
if (im->gdes[i].ds == -1) {
+ char *rrd = call0(im->gdes[i].source, to_string_m);
rrd_set_error("No DS called '%s' in '%s'",
- im->gdes[i].ds_nam, im->gdes[i].rrd);
+ im->gdes[i].ds_nam, rrd);
+ if (rrd != NULL) free(rrd);
return -1;
}
@@ -946,7 +920,7 @@
long ii;
for (ii = 0; ii < im->gdes_c - 1; ii++) {
- if ((im->gdes[ii].gf == GF_DEF
+ if ((im->gdes[ii].gf == GF_DEF || im->gdes[ii].gf == GF_UDEF
|| im->gdes[ii].gf == GF_VDEF || im->gdes[ii].gf == GF_CDEF)
&& (strcmp(im->gdes[ii].vname, key) == 0)) {
return ii;
@@ -1678,6 +1652,7 @@
case GF_COMMENT:
case GF_TEXTALIGN:
case GF_DEF:
+ case GF_UDEF:
case GF_CDEF:
case GF_VDEF:
#ifdef WITH_PIECHART
@@ -3415,6 +3390,7 @@
case GF_CDEF:
case GF_VDEF:
case GF_DEF:
+ case GF_UDEF:
case GF_PRINT:
case GF_GPRINT:
case GF_COMMENT:
@@ -3879,13 +3855,12 @@
im->gdes[im->gdes_c - 1].legend[0] = '\0';
im->gdes[im->gdes_c - 1].format[0] = '\0';
im->gdes[im->gdes_c - 1].strftm = 0;
- im->gdes[im->gdes_c - 1].rrd[0] = '\0';
+ im->gdes[im->gdes_c - 1].source = NULL;
im->gdes[im->gdes_c - 1].ds = -1;
im->gdes[im->gdes_c - 1].cf_reduce = CF_AVERAGE;
im->gdes[im->gdes_c - 1].cf = CF_AVERAGE;
im->gdes[im->gdes_c - 1].yrule = DNAN;
im->gdes[im->gdes_c - 1].xrule = 0;
- im->gdes[im->gdes_c - 1].daemon[0] = 0;
return 0;
}
diff --git a/src/rrd_graph.h b/src/rrd_graph.h
--- a/src/rrd_graph.h
+++ b/src/rrd_graph.h
@@ -22,6 +22,7 @@
#include "rrd_tool.h"
+#include "rrd_source.h"
#include "rrd_rpncalc.h"
#ifdef WIN32
@@ -57,7 +58,7 @@
enum gf_en { GF_PRINT = 0, GF_GPRINT, GF_COMMENT, GF_HRULE, GF_VRULE, GF_LINE,
GF_AREA,GF_GRAD, GF_STACK, GF_TICK, GF_TEXTALIGN,
- GF_DEF, GF_CDEF, GF_VDEF, GF_SHIFT,
+ GF_DEF, GF_UDEF, GF_CDEF, GF_VDEF, GF_SHIFT,
GF_XPORT
};
@@ -160,10 +161,9 @@
int debug; /* boolean */
char vname[MAX_VNAME_LEN + 1]; /* name of the variable */
long vidx; /* gdes reference */
- char rrd[1024]; /* name of the rrd_file containing data */
+ rrd_base_source_t *source; /* the RRD source to fetch the data from */
char ds_nam[DS_NAM_SIZE]; /* data source name */
long ds; /* data source number */
- char daemon[256];
enum cf_en cf; /* consolidation function */
enum cf_en cf_reduce; /* consolidation function for reduce_data() */
struct gfx_color_t col, col2; /* graph color */
diff --git a/src/rrd_graph_helper.c b/src/rrd_graph_helper.c
--- a/src/rrd_graph_helper.c
+++ b/src/rrd_graph_helper.c
@@ -6,6 +6,7 @@
****************************************************************************/
#include "rrd_graph.h"
+#include "rrd_source.h"
#define dprintf if (gdp->debug) printf
@@ -116,6 +117,12 @@
graph_desc_t *const,
image_desc_t *const);
+int rrd_parse_udef(
+ const char *const,
+ unsigned int *const,
+ graph_desc_t *const,
+ image_desc_t *const);
+
int rrd_parse_vdef(
const char *const,
unsigned int *const,
@@ -371,8 +378,9 @@
switch (im->gdes[gdp->vidx].gf) {
case GF_DEF:
+ case GF_UDEF:
case GF_CDEF:
- dprintf("- vname is of type DEF or CDEF, looking for CF\n");
+ dprintf("- vname is of type DEF, UDEF or CDEF, looking for CF\n");
if (rrd_parse_CF(line, eaten, gdp, &gdp->cf))
return 1;
break;
@@ -415,8 +423,9 @@
switch (im->gdes[gdp->vidx].gf) {
case GF_DEF:
+ case GF_UDEF:
case GF_CDEF:
- dprintf("- vname is of type DEF or CDEF, OK\n");
+ dprintf("- vname is of type DEF, UDEF or CDEF, OK\n");
break;
case GF_VDEF:
rrd_set_error("Cannot shift a VDEF: '%s' in line '%s'\n",
@@ -431,8 +440,9 @@
if ((gdp->shidx = rrd_parse_find_vname(line, eaten, gdp, im)) >= 0) {
switch (im->gdes[gdp->shidx].gf) {
case GF_DEF:
+ case GF_UDEF:
case GF_CDEF:
- rrd_set_error("Offset cannot be a (C)DEF: '%s' in line '%s'\n",
+ rrd_set_error("Offset cannot be a ([CU])DEF: '%s' in line '%s'\n",
im->gdes[gdp->shidx].vname, line);
return 1;
case GF_VDEF:
@@ -476,8 +486,9 @@
switch (im->gdes[gdp->vidx].gf) {
case GF_DEF:
+ case GF_UDEF:
case GF_CDEF:
- dprintf("- vname is of type DEF or CDEF, OK\n");
+ dprintf("- vname is of type DEF, UDEF or CDEF, OK\n");
break;
case GF_VDEF:
rrd_set_error("Cannot xport a VDEF: '%s' in line '%s'\n",
@@ -931,7 +942,10 @@
rrd_time_value_t start_tv, end_tv;
time_t start_tmp = 0, end_tmp = 0;
char *parsetime_error = NULL;
+ char rrd[1024];
+ char using_daemon[256];
+ rrd[0] = using_daemon[0] = 0;
start_tv.type = end_tv.type = ABSOLUTE_TIME;
start_tv.offset = end_tv.offset = 0;
localtime_r(&gdp->start, &start_tv.tm);
@@ -942,13 +956,13 @@
if (rrd_parse_make_vname(line, eaten, gdp, im))
return 1;
- i = scan_for_col(&line[*eaten], sizeof(gdp->rrd) - 1, gdp->rrd);
+ i = scan_for_col(&line[*eaten], sizeof(rrd) - 1, rrd);
if (line[*eaten + i] != ':') {
rrd_set_error("Problems reading database name");
return 1;
}
(*eaten) += ++i;
- dprintf("- using file '%s'\n", gdp->rrd);
+ dprintf("- using file '%s'\n", rrd);
i = 0;
sscanf(&line[*eaten], DS_NAM_FMT ":%n", gdp->ds_nam, &i);
@@ -963,8 +977,14 @@
return 1;
gdp->cf_reduce = gdp->cf;
- if (line[*eaten] == '\0')
+ if (line[*eaten] == '\0') {
+ gdp->source = (rrd_base_source_t *) new_file_source(rrd, NULL);
+ if (gdp->source == NULL) {
+ rrd_set_error("Out of memory");
+ return 1;
+ }
return 0;
+ }
while (1) {
dprintf("- optional parameter follows: %s\n", &line[*eaten]);
@@ -1005,9 +1025,9 @@
dprintf("- done parsing: '%s'\n", &line[*eaten]);
} else if (!strcmp("daemon", command)) {
i = scan_for_col(&line[*eaten],
- sizeof (gdp->daemon), gdp->daemon);
+ sizeof (using_daemon), using_daemon);
(*eaten) += i;
- dprintf("- using daemon '%s'\n", gdp->daemon);
+ dprintf("- using daemon '%s'\n", using_daemon);
} else {
rrd_set_error("Parse error in '%s'", line);
return 1;
@@ -1038,6 +1058,13 @@
return 1;
}
+
+ gdp->source = (rrd_base_source_t *) new_file_source(rrd, using_daemon);
+ if (gdp->source == NULL) {
+ rrd_set_error("Out of memory");
+ return 1;
+ }
+
gdp->start = start_tmp;
gdp->end = end_tmp;
gdp->start_orig = start_tmp;
@@ -1049,6 +1076,149 @@
return 0;
}
+int rrd_parse_udef(
+ const char *const line,
+ unsigned int *const eaten,
+ graph_desc_t *const gdp,
+ image_desc_t *const im)
+{
+ int i = 0, queryLen = 0;
+ rrd_time_value_t start_tv, end_tv;
+ time_t start_tmp = 0, end_tmp = 0;
+ char *parsetime_error = NULL;
+ rrd_base_source_t *source = NULL;
+ int rc = 0;
+ UriQueryListA *queryList = NULL, *p;
+ int itemCount;
+ int cfSetFlag = 0;
+ int cfReduceSetFlag = 0;
+ int dsSetFlag = 0;
+
+
+ start_tv.type = end_tv.type = ABSOLUTE_TIME;
+ start_tv.offset = end_tv.offset = 0;
+ localtime_r(&gdp->start, &start_tv.tm);
+ localtime_r(&gdp->end, &end_tv.tm);
+
+ dprintf("- parsing '%s'\n", &line[*eaten]);
+ dprintf("- from line '%s'\n", line);
+
+ if (rrd_parse_make_vname(line, eaten, gdp, im))
+ return 1;
+
+ source = parse_source_string(&line[*eaten]);
+ if (source == NULL) {
+ rrd_set_error("Problem parsing uri into rrd source");
+ rc = 1;
+ goto out;
+ }
+ *eaten += strlen(&line[*eaten]);
+
+ if (source->uri == NULL) {
+ rrd_set_error("Hm, uri expected, but not available after parsing");
+ rc = 1;
+ goto out;
+ }
+
+ queryLen = source->uri->query.afterLast - source->uri->query.first;
+
+ if (queryLen > 0 &&
+ uriDissectQueryMallocA(&queryList, &itemCount, source->uri->query.first,
+ source->uri->query.afterLast) != URI_SUCCESS) {
+ rrd_set_error("Cannot parse URL query string");
+ rc = 1;
+ goto out;
+ }
+
+ gdp->cf = gdp->cf_reduce = CF_AVERAGE;
+ for (p = queryList ; p ; p = p->next) {
+ if (strcmp(p->key, "ds") == 0) {
+ strncpy(gdp->ds_nam, p->value, sizeof(gdp->ds_nam));
+ dsSetFlag = 1;
+ dprintf("- using DS '%s'\n", gdp->ds_nam);
+ continue;
+ } else if (strcmp(p->key, "cf") == 0) {
+ gdp->cf = cf_conv(p->value);
+ cfSetFlag = 1;
+ continue;
+ } else if (strcmp(p->key, "step") == 0) {
+ sscanf(p->value, "%lu%n", &gdp->step, &i);
+ gdp->step_orig = gdp->step;
+ dprintf("- using step %lu\n", gdp->step);
+
+ continue;
+ } else if (strcmp(p->key, "start") == 0) {
+ if ((parsetime_error = rrd_parsetime(p->value, &start_tv))) {
+ rrd_set_error("start time: %s", parsetime_error);
+ rc = 1;
+ goto out;
+ }
+ dprintf("- done parsing: '%s'\n", p->value);
+ continue;
+ } else if (strcmp(p->key, "end") == 0) {
+ if ((parsetime_error = rrd_parsetime(p->value, &end_tv))) {
+ rrd_set_error("end time: %s", parsetime_error);
+ rc = 1;
+ goto out;
+ }
+ dprintf("- done parsing: '%s'\n", p->value);
+ continue;
+ } else if (strcmp(p->key, "reduce") == 0) {
+ gdp->cf_reduce = cf_conv(p->value);
+ cfReduceSetFlag = 1;
+ continue;
+ }
+ }
+
+ if (!dsSetFlag) {
+ rrd_set_error("Missing DS name. Use 'ds=' query parameter");
+ rc = 1;
+ goto out;
+ }
+
+ if (!cfReduceSetFlag && cfSetFlag)
+ gdp->cf_reduce = gdp->cf;
+
+ uriFreeQueryListA(queryList);
+
+ if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
+ /* error string is set in rrd_parsetime.c */
+ goto out;
+ }
+ if (start_tmp < 3600 * 24 * 365 * 10) {
+ rrd_set_error("the first entry to fetch should be "
+ "after 1980 (%ld)", start_tmp);
+ rc = 1;
+ goto out;
+ }
+
+ if (end_tmp < start_tmp) {
+ rrd_set_error("start (%ld) should be less than end (%ld)",
+ start_tmp, end_tmp);
+ rc = 1;
+ goto out;
+ }
+
+
+
+ gdp->start = start_tmp;
+ gdp->end = end_tmp;
+ gdp->start_orig = start_tmp;
+ gdp->end_orig = end_tmp;
+
+ dprintf("- start time %lu\n", gdp->start);
+ dprintf("- end time %lu\n", gdp->end);
+ rc = 0;
+out:
+ if (rc != 0 && source != NULL) {
+ delete_source_obj(source);
+ source = NULL;
+ }
+
+ gdp->source = source;
+ return rc;
+}
+
int rrd_parse_vdef(
const char *const line,
unsigned int *const eaten,
@@ -1071,8 +1241,8 @@
rrd_set_error("Not a valid vname: %s in line %s", tmpstr, line);
return 1;
}
- if (im->gdes[gdp->vidx].gf != GF_DEF && im->gdes[gdp->vidx].gf != GF_CDEF) {
- rrd_set_error("variable '%s' not DEF nor "
+ if (im->gdes[gdp->vidx].gf != GF_DEF && im->gdes[gdp->vidx].gf != GF_UDEF && im->gdes[gdp->vidx].gf != GF_CDEF) {
+ rrd_set_error("variable '%s' not DEF, UDEF nor "
"CDEF in VDEF '%s'", tmpstr, gdp->vname);
return 1;
}
@@ -1183,6 +1353,10 @@
if (rrd_parse_def(argv[i], &eaten, gdp, im))
return;
break;
+ case GF_UDEF: /* vname=URL?ds=DS&cf=CF[&step=#][&start=#][&end=#] */
+ if (rrd_parse_udef(argv[i], &eaten, gdp, im))
+ return;
+ break;
case GF_CDEF: /* vname=rpn-expression */
if (rrd_parse_cdef(argv[i], &eaten, gdp, im))
return;
More information about the rrd-developers
mailing list