[PATCH 7 of 7] * Add new UDEF definition style to rrd_graph
Peter Stamfest <[email protected]>
| Newsgroups | gmane.comp.db.rrdtool.devel |
|---|---|
| Message-ID | <[email protected]> |
# HG changeset patch # User Peter Stamfest <[email protected]> # 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;