/* helper function for buffer handling */
typedef struct stringbuffer_t {
- size_t allocated;
- size_t len;
- unsigned char* data;
- FILE *file;
+ size_t allocated;
+ size_t len;
+ unsigned char *data;
+ FILE *file;
} stringbuffer_t;
-static int addToBuffer(stringbuffer_t *,char*,size_t);
-static void escapeJSON(char*,size_t);
-
-static int rrd_xport_format_xmljson(int,stringbuffer_t *,image_desc_t*,time_t, time_t, unsigned long, unsigned long, char**, rrd_value_t*);
-static int rrd_xport_format_sv(char,stringbuffer_t *,image_desc_t*,time_t, time_t, unsigned long, unsigned long, char**, rrd_value_t*);
-static int rrd_xport_format_addprints(int,stringbuffer_t *,image_desc_t *);
+static int addToBuffer(
+ stringbuffer_t *,
+ char *,
+ size_t);
+static void escapeJSON(
+ char *,
+ size_t);
+
+static int rrd_xport_format_xmljson(
+ int,
+ stringbuffer_t *,
+ image_desc_t *,
+ time_t,
+ time_t,
+ unsigned long,
+ unsigned long,
+ char **,
+ rrd_value_t *);
+static int rrd_xport_format_sv(
+ char,
+ stringbuffer_t *,
+ image_desc_t *,
+ time_t,
+ time_t,
+ unsigned long,
+ unsigned long,
+ char **,
+ rrd_value_t *);
+static int rrd_xport_format_addprints(
+ int,
+ stringbuffer_t *,
+ image_desc_t *);
int rrd_xport(
int argc,
rrd_time_value_t start_tv, end_tv;
char *parsetime_error = NULL;
struct optparse options;
+
optparse_init(&options, argc, argv);
struct optparse_long longopts[] = {
- {"start", 's', OPTPARSE_REQUIRED},
- {"end", 'e', OPTPARSE_REQUIRED},
- {"maxrows",'m', OPTPARSE_REQUIRED},
- {"step", 261, OPTPARSE_REQUIRED},
+ {"start", 's', OPTPARSE_REQUIRED},
+ {"end", 'e', OPTPARSE_REQUIRED},
+ {"maxrows", 'm', OPTPARSE_REQUIRED},
+ {"step", 261, OPTPARSE_REQUIRED},
{"enumds", 262, OPTPARSE_NONE},
- {"json", 263, OPTPARSE_NONE},
+ {"json", 263, OPTPARSE_NONE},
{"showtime", 't', OPTPARSE_NONE},
{"daemon", 'd', OPTPARSE_REQUIRED},
{0}
rrd_parsetime("end-24h", &start_tv);
rrd_parsetime("now", &end_tv);
- int enumds=0;
- int json=0;
- int showtime=0;
-
- int opt;
- while ((opt = optparse_long(&options,longopts,NULL)) != -1){
+ int enumds = 0;
+ int json = 0;
+ int showtime = 0;
+
+ int opt;
+
+ while ((opt = optparse_long(&options, longopts, NULL)) != -1) {
switch (opt) {
case 261:
im.step = atoi(options.optarg);
break;
case 262:
- enumds=1;
+ enumds = 1;
break;
case 263:
- json=1;
+ json = 1;
break;
case 't':
- showtime=1;
+ showtime = 1;
break;
case 's':
if ((parsetime_error = rrd_parsetime(options.optarg, &start_tv))) {
break;
case 'd':
{
- if (im.daemon_addr != NULL)
- {
- rrd_set_error ("You cannot specify --daemon "
- "more than once.");
+ if (im.daemon_addr != NULL) {
+ rrd_set_error("You cannot specify --daemon "
+ "more than once.");
return (-1);
}
im.daemon_addr = strdup(options.optarg);
- if (im.daemon_addr == NULL)
- {
+ if (im.daemon_addr == NULL) {
rrd_set_error("strdup error");
return -1;
}
return (-1);
}
- { /* try to connect to rrdcached */
- int status = rrdc_connect(im.daemon_addr);
- if (status != 0) return status;
+ { /* try to connect to rrdcached */
+ int status = rrdc_connect(im.daemon_addr);
+
+ if (status != 0)
+ return status;
}
- if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data,0) == -1) {
+ if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data, 0) == -1) {
im_free(&im);
return -1;
}
/* and create the export */
if (!xsize) {
- int flags=0;
- if (json) { flags|=1; }
- if (showtime) { flags|=2; }
- if (enumds) { flags|=4; }
- stringbuffer_t buffer={0,0,NULL,stdout};
- rrd_xport_format_xmljson(flags,&buffer,&im,
- *start, *end, *step,
- *col_cnt, *legend_v,
- *data);
+ int flags = 0;
+
+ if (json) {
+ flags |= 1;
+ }
+ if (showtime) {
+ flags |= 2;
+ }
+ if (enumds) {
+ flags |= 4;
+ }
+ stringbuffer_t buffer = { 0, 0, NULL, stdout };
+ rrd_xport_format_xmljson(flags, &buffer, &im,
+ *start, *end, *step,
+ *col_cnt, *legend_v, *data);
}
im_free(&im);
int i = 0, j = 0;
unsigned long dst_row, row_cnt;
- rrd_value_t *dstptr;
+ rrd_value_t *dstptr;
unsigned long xport_counter = 0;
int *ref_list;
case GF_LINE:
case GF_AREA:
case GF_STACK:
- (*col_cnt)+=dolines;
- break;
+ (*col_cnt) += dolines;
+ break;
case GF_XPORT:
- (*col_cnt)++;
+ (*col_cnt)++;
break;
default:
break;
}
/* a list of referenced gdes */
- ref_list = (int*)malloc(sizeof(int) * (*col_cnt));
+ ref_list = (int *) malloc(sizeof(int) * (*col_cnt));
if (ref_list == NULL)
return -1;
/* a list to save pointers to the column's legend entry */
/* this is a return value! */
- legend_list = (char**)malloc(sizeof(char *) * (*col_cnt));
+ legend_list = (char **) malloc(sizeof(char *) * (*col_cnt));
if (legend_list == NULL) {
free(ref_list);
return -1;
}
/* lets find the step size we have to use for xport */
- step_list = (long*)malloc(sizeof(long)*((*col_cnt)+1));
+ step_list = (long *) malloc(sizeof(long) * ((*col_cnt) + 1));
step_list_ptr = step_list;
j = 0;
for (i = 0; i < im->gdes_c; i++) {
- /* decide if we need to handle the output */
- int handle=0;
+ /* decide if we need to handle the output */
+ int handle = 0;
+
switch (im->gdes[i].gf) {
case GF_LINE:
case GF_AREA:
case GF_STACK:
- handle=dolines;
- break;
+ handle = dolines;
+ break;
case GF_XPORT:
- handle=1;
- break;
- default:
- handle=0;
- break;
- }
- /* and now do the real work */
- if (handle) {
+ handle = 1;
+ break;
+ default:
+ handle = 0;
+ break;
+ }
+ /* and now do the real work */
+ if (handle) {
ref_list[xport_counter++] = i;
*step_list_ptr = im->gdes[im->gdes[i].vidx].step;
/* printf("%s:%lu\n",im->gdes[i].legend,*step_list_ptr); */
if (im->gdes[i].legend[0] == '\0')
legend_list[j][0] = '\0';
++j;
- }
+ }
}
- *step_list_ptr=0;
+ *step_list_ptr = 0;
/* find a common step */
*step = rrd_lcd(step_list);
/* printf("step: %lu\n",*step); */
free(step_list);
- *start = im->start - im->start % (*step);
- if ( im->start > *start ) {
- *start = *start + *step;
+ *start = im->start - im->start % (*step);
+ if (im->start > *start) {
+ *start = *start + *step;
}
*end = im->end - im->end % (*step);
- if ( im->end > *end ) {
- *end = *end + *step;
+ if (im->end > *end) {
+ *end = *end + *step;
}
/* room for rearranged data */
/* this is a return value! */
row_cnt = ((*end) - (*start)) / (*step);
if (((*data) =
- (rrd_value_t*)malloc((*col_cnt) * row_cnt * sizeof(rrd_value_t))) == NULL) {
+ (rrd_value_t *) malloc((*col_cnt) * row_cnt *
+ sizeof(rrd_value_t))) == NULL) {
free(ref_list);
free(legend_list);
rrd_set_error("malloc xport data area");
/* fill data structure */
for (dst_row = 0; (int) dst_row < (int) row_cnt; dst_row++) {
for (i = 0; i < (int) (*col_cnt); i++) {
- long vidx = im->gdes[ref_list[i]].vidx;
- time_t now = *start + dst_row * *step;
+ long vidx = im->gdes[ref_list[i]].vidx;
+ time_t now = *start + dst_row * *step;
+
(*dstptr++) = im->gdes[vidx].data[(unsigned long)
floor((double)
- (now - im->gdes[vidx].start)
- /im->gdes[vidx].step)
+ (now -
+ im->gdes[vidx].start)
+ / im->gdes[vidx].step)
* im->gdes[vidx].ds_cnt +
im->gdes[vidx].ds];
}
-int rrd_graph_xport(image_desc_t *im) {
- /* prepare the data for processing */
- unsigned long col_cnt=0;
- time_t start=im->start;
- time_t end=im->end;
- unsigned long step=im->step;
- char **legend_v=NULL;
- rrd_value_t *data=NULL;
- /* initialize buffer */
- stringbuffer_t buffer={0,0,NULL,NULL};
-
- /* check if we have a supported ggraph format */
- switch (im->graph_type) {
- /* allow the following to pass */
- case GTYPE_TIME:
- case GTYPE_XY:
- break;
- default:
- rrd_set_error("Not supported graph type");
- return -1;
- }
-
- /* if we write a file, then open it */
- if (im->graphfile) {
- buffer.file=fopen(im->graphfile,"w");
- }
-
- /* do the data processing */
- if (rrd_xport_fn(im,&start,&end,&step,&col_cnt,&legend_v,&data,1)) { return -1;}
-
- /* fill in some data */
- rrd_infoval_t info;
- info.u_cnt = start;
- grinfo_push(im, sprintf_alloc("graph_start"), RD_I_CNT, info);
- info.u_cnt = end;
- grinfo_push(im, sprintf_alloc("graph_end"), RD_I_CNT, info);
- info.u_cnt = step;
- grinfo_push(im, sprintf_alloc("graph_step"), RD_I_CNT, info);
-
- /* set locale */
-
- /* format it for output */
- int r=0;
- switch(im->imgformat) {
- case IF_XML:
- r=rrd_xport_format_xmljson(2,&buffer,im, start, end, step, col_cnt, legend_v, data);
- break;
- case IF_XMLENUM:
- r=rrd_xport_format_xmljson(6,&buffer,im, start, end, step, col_cnt, legend_v, data);
- break;
- case IF_JSON:
- r=rrd_xport_format_xmljson(1,&buffer,im, start, end, step, col_cnt, legend_v, data);
- break;
- case IF_JSONTIME:
- r=rrd_xport_format_xmljson(3,&buffer,im, start, end, step, col_cnt, legend_v, data);
- break;
- case IF_CSV:
- r=rrd_xport_format_sv(',',&buffer,im, start, end, step, col_cnt, legend_v, data);
- break;
- case IF_TSV:
- r=rrd_xport_format_sv('\t',&buffer,im, start, end, step, col_cnt, legend_v, data);
- break;
- case IF_SSV:
- r=rrd_xport_format_sv(';',&buffer,im, start, end, step, col_cnt, legend_v, data);
- break;
- default:
- break;
- }
-
- /* free legend */
- for (unsigned long j = 0; j < col_cnt; j++) {
- free(legend_v[j]);
- }
- free(legend_v);
- /* free data */
- free(data);
-
- /* handle errors */
- if (r) {
- /* free the buffer */
- if (buffer.data) {free(buffer.data);}
- /* close the file */
- if (buffer.file) {fclose(buffer.file);}
- /* and return with error */
- return r;
- }
-
- /* now do the cleanup */
- if (buffer.file) {
- fclose(buffer.file); buffer.file=NULL;
- im->rendered_image_size=0;
- im->rendered_image=NULL;
- } else {
- im->rendered_image_size=buffer.len;
- im->rendered_image=buffer.data;
- }
-
- /* and print stuff */
- return print_calc(im);
-}
+int rrd_graph_xport(
+ image_desc_t *im)
+{
+ /* prepare the data for processing */
+ unsigned long col_cnt = 0;
+ time_t start = im->start;
+ time_t end = im->end;
+ unsigned long step = im->step;
+ char **legend_v = NULL;
+ rrd_value_t *data = NULL;
+
+ /* initialize buffer */
+ stringbuffer_t buffer = { 0, 0, NULL, NULL };
+
+ /* check if we have a supported ggraph format */
+ switch (im->graph_type) {
+ /* allow the following to pass */
+ case GTYPE_TIME:
+ case GTYPE_XY:
+ break;
+ default:
+ rrd_set_error("Not supported graph type");
+ return -1;
+ }
-static int addToBuffer(stringbuffer_t * sb,char* data,size_t len) {
- /* if len <= 0 we assume a string and calculate the length ourselves */
- if (len<=0) { len=strlen(data); }
- /* if we have got a file, then take the shortcut */
- if (sb->file) {
- sb->len+=len;
- fwrite(data,len,1,sb->file);
- return 0;
- }
- /* if buffer is 0, then initialize */
- if (! sb->data) {
- /* make buffer a multiple of 8192 */
- sb->allocated+=8192;
- sb->allocated-=(sb->allocated%8192);
- /* and allocate it */
- sb->data = (unsigned char *) malloc(sb->allocated);
- if (! sb->data) {
- rrd_set_error("malloc issue");
- return 1;
+ /* if we write a file, then open it */
+ if (im->graphfile) {
+ buffer.file = fopen(im->graphfile, "w");
+ }
+
+ /* do the data processing */
+ if (rrd_xport_fn(im, &start, &end, &step, &col_cnt, &legend_v, &data, 1)) {
+ return -1;
+ }
+
+ /* fill in some data */
+ rrd_infoval_t info;
+
+ info.u_cnt = start;
+ grinfo_push(im, sprintf_alloc("graph_start"), RD_I_CNT, info);
+ info.u_cnt = end;
+ grinfo_push(im, sprintf_alloc("graph_end"), RD_I_CNT, info);
+ info.u_cnt = step;
+ grinfo_push(im, sprintf_alloc("graph_step"), RD_I_CNT, info);
+
+ /* set locale */
+
+ /* format it for output */
+ int r = 0;
+
+ switch (im->imgformat) {
+ case IF_XML:
+ r = rrd_xport_format_xmljson(2, &buffer, im, start, end, step,
+ col_cnt, legend_v, data);
+ break;
+ case IF_XMLENUM:
+ r = rrd_xport_format_xmljson(6, &buffer, im, start, end, step,
+ col_cnt, legend_v, data);
+ break;
+ case IF_JSON:
+ r = rrd_xport_format_xmljson(1, &buffer, im, start, end, step,
+ col_cnt, legend_v, data);
+ break;
+ case IF_JSONTIME:
+ r = rrd_xport_format_xmljson(3, &buffer, im, start, end, step,
+ col_cnt, legend_v, data);
+ break;
+ case IF_CSV:
+ r = rrd_xport_format_sv(',', &buffer, im, start, end, step, col_cnt,
+ legend_v, data);
+ break;
+ case IF_TSV:
+ r = rrd_xport_format_sv('\t', &buffer, im, start, end, step, col_cnt,
+ legend_v, data);
+ break;
+ case IF_SSV:
+ r = rrd_xport_format_sv(';', &buffer, im, start, end, step, col_cnt,
+ legend_v, data);
+ break;
+ default:
+ break;
+ }
+
+ /* free legend */
+ for (unsigned long j = 0; j < col_cnt; j++) {
+ free(legend_v[j]);
}
- /* and initialize the buffer */
- sb->len=0;
- sb->data[0]=0;
- }
- /* and figure out if we need to extend the buffer */
- if (sb->len+len+1>=sb->allocated) {
- /* add so many pages until we have a buffer big enough */
- while(sb->len+len+1>=sb->allocated) {
- sb->allocated+=8192;
+ free(legend_v);
+ /* free data */
+ free(data);
+
+ /* handle errors */
+ if (r) {
+ /* free the buffer */
+ if (buffer.data) {
+ free(buffer.data);
+ }
+ /* close the file */
+ if (buffer.file) {
+ fclose(buffer.file);
+ }
+ /* and return with error */
+ return r;
}
- /* try to resize it */
- unsigned char* resized=(unsigned char*)realloc(sb->data,sb->allocated);
- if (resized) {
- sb->data=resized;
+
+ /* now do the cleanup */
+ if (buffer.file) {
+ fclose(buffer.file);
+ buffer.file = NULL;
+ im->rendered_image_size = 0;
+ im->rendered_image = NULL;
} else {
- free(sb->data);
- sb->data=NULL;
- sb->allocated=0;
- rrd_set_error("realloc issue");
- return -1;
+ im->rendered_image_size = buffer.len;
+ im->rendered_image = buffer.data;
}
- }
- /* and finally add to the buffer */
- memcpy(sb->data+sb->len,data,len);
- sb->len+=len;
- /* and 0 terminate it */
- sb->data[sb->len]=0;
- /* and return */
- return 0;
+
+ /* and print stuff */
+ return print_calc(im);
}
-static int rrd_xport_format_sv(char sep, stringbuffer_t *buffer,image_desc_t *im,time_t start, time_t end, unsigned long step, unsigned long col_cnt, char **legend_v, rrd_value_t* data) {
- /* define the time format */
- char* timefmt=NULL;
- if (im->xlab_user.minsec!=-1.0) { timefmt=im->xlab_user.stst; }
-
- /* row count */
- unsigned long row_cnt=(end-start)/step;
-
- /* estimate buffer size (to avoid multiple allocations) */
- buffer->allocated=
- 1024 /* bytes of overhead /header/footer */
- +(12+19*col_cnt) /* 12 bytes overhead/line plus 19 bytes per column*/
- *(1+row_cnt) /* number of columns + 1 (for header) */
- ;
-
- char buf[256];
-
- /* now start writing the header*/
- if (addToBuffer(buffer,"\"time\"",6)) { return 1; }
- for(unsigned long i=0;i<col_cnt;i++) {
- /* strip leading spaces */
- char *t=legend_v[i]; while (isspace(*t)) { t++;}
- /* and print it */
- snprintf(buf,255,"%c\"%s\"",sep,t);
- if (addToBuffer(buffer,buf,0)) { return 1;}
- }
- if (addToBuffer(buffer,"\r\n",2)) { return 1; }
- /* and now write the data */
- rrd_value_t *ptr=data;
- for(time_t ti=start+step;ti<end;ti+=step) {
- /* write time */
- if (timefmt) {
- struct tm loc;
- localtime_r(&ti,&loc);
- strftime(buf,254,timefmt,&loc);
- } else {
- snprintf(buf,254,"%lld",(long long int)ti);
+static int addToBuffer(
+ stringbuffer_t * sb,
+ char *data,
+ size_t len)
+{
+ /* if len <= 0 we assume a string and calculate the length ourselves */
+ if (len <= 0) {
+ len = strlen(data);
+ }
+ /* if we have got a file, then take the shortcut */
+ if (sb->file) {
+ sb->len += len;
+ fwrite(data, len, 1, sb->file);
+ return 0;
+ }
+ /* if buffer is 0, then initialize */
+ if (!sb->data) {
+ /* make buffer a multiple of 8192 */
+ sb->allocated += 8192;
+ sb->allocated -= (sb->allocated % 8192);
+ /* and allocate it */
+ sb->data = (unsigned char *) malloc(sb->allocated);
+ if (!sb->data) {
+ rrd_set_error("malloc issue");
+ return 1;
+ }
+ /* and initialize the buffer */
+ sb->len = 0;
+ sb->data[0] = 0;
+ }
+ /* and figure out if we need to extend the buffer */
+ if (sb->len + len + 1 >= sb->allocated) {
+ /* add so many pages until we have a buffer big enough */
+ while (sb->len + len + 1 >= sb->allocated) {
+ sb->allocated += 8192;
+ }
+ /* try to resize it */
+ unsigned char *resized =
+ (unsigned char *) realloc(sb->data, sb->allocated);
+ if (resized) {
+ sb->data = resized;
+ } else {
+ free(sb->data);
+ sb->data = NULL;
+ sb->allocated = 0;
+ rrd_set_error("realloc issue");
+ return -1;
+ }
+ }
+ /* and finally add to the buffer */
+ memcpy(sb->data + sb->len, data, len);
+ sb->len += len;
+ /* and 0 terminate it */
+ sb->data[sb->len] = 0;
+ /* and return */
+ return 0;
+}
+
+static int rrd_xport_format_sv(
+ char sep,
+ stringbuffer_t * buffer,
+ image_desc_t *im,
+ time_t start,
+ time_t end,
+ unsigned long step,
+ unsigned long col_cnt,
+ char **legend_v,
+ rrd_value_t *data)
+{
+ /* define the time format */
+ char *timefmt = NULL;
+
+ if (im->xlab_user.minsec != -1.0) {
+ timefmt = im->xlab_user.stst;
+ }
+
+ /* row count */
+ unsigned long row_cnt = (end - start) / step;
+
+ /* estimate buffer size (to avoid multiple allocations) */
+ buffer->allocated = 1024 /* bytes of overhead /header/footer */
+ + (12 + 19 * col_cnt) /* 12 bytes overhead/line plus 19 bytes per column */
+ *(1 + row_cnt) /* number of columns + 1 (for header) */
+ ;
+
+ char buf[256];
+
+ /* now start writing the header */
+ if (addToBuffer(buffer, "\"time\"", 6)) {
+ return 1;
}
- if (addToBuffer(buffer,buf,0)) { return 1; }
- /* write the columns */
- for(unsigned long i=0;i<col_cnt;i++) {
- /* get the value */
- rrd_value_t v=*ptr;ptr++;
- /* and print it */
- if (isnan(v)) {
- snprintf(buf,255,"%c\"NaN\"",sep);
- } else {
- rrd_snprintf(buf,255,"%c\"%0.10e\"",sep,v);
- }
- if (addToBuffer(buffer,buf,0)) { return 1;}
+ for (unsigned long i = 0; i < col_cnt; i++) {
+ /* strip leading spaces */
+ char *t = legend_v[i];
+
+ while (isspace(*t)) {
+ t++;
+ }
+ /* and print it */
+ snprintf(buf, 255, "%c\"%s\"", sep, t);
+ if (addToBuffer(buffer, buf, 0)) {
+ return 1;
+ }
+ }
+ if (addToBuffer(buffer, "\r\n", 2)) {
+ return 1;
+ }
+ /* and now write the data */
+ rrd_value_t *ptr = data;
+
+ for (time_t ti = start + step; ti < end; ti += step) {
+ /* write time */
+ if (timefmt) {
+ struct tm loc;
+
+ localtime_r(&ti, &loc);
+ strftime(buf, 254, timefmt, &loc);
+ } else {
+ snprintf(buf, 254, "%lld", (long long int) ti);
+ }
+ if (addToBuffer(buffer, buf, 0)) {
+ return 1;
+ }
+ /* write the columns */
+ for (unsigned long i = 0; i < col_cnt; i++) {
+ /* get the value */
+ rrd_value_t v = *ptr;
+
+ ptr++;
+ /* and print it */
+ if (isnan(v)) {
+ snprintf(buf, 255, "%c\"NaN\"", sep);
+ } else {
+ rrd_snprintf(buf, 255, "%c\"%0.10e\"", sep, v);
+ }
+ if (addToBuffer(buffer, buf, 0)) {
+ return 1;
+ }
+ }
+ /* and add a newline */
+ if (addToBuffer(buffer, "\r\n", 2)) {
+ return 1;
+ }
}
- /* and add a newline */
- if (addToBuffer(buffer,"\r\n",2)) { return 1; }
- }
- /* and return OK */
- return 0;
+ /* and return OK */
+ return 0;
}
-static int rrd_xport_format_xmljson(int flags,stringbuffer_t *buffer,image_desc_t *im,time_t start, time_t end, unsigned long step, unsigned long col_cnt, char **legend_v, rrd_value_t* data) {
-
- /* define some other stuff based on flags */
- int json=0;
- if (flags &1) { json=1; }
- int showtime=0;
- if (flags &2) { showtime=1;}
- int enumds=0;
- if (flags &4) { enumds=1;}
-
- /* define the time format */
- char* timefmt=NULL;
- /* unfortunately we have to do it this way,
- as when no --x-graph argument is given,
- then the xlab_user is not in a clean state (e.g. zero-filled) */
- if (im->xlab_user.minsec!=-1.0) { timefmt=im->xlab_user.stst; }
-
- /* row count */
- unsigned long row_cnt=(end-start)/step;
-
- /* estimate buffer size (to avoid multiple allocations) */
- /* better estimates are needed here */
- buffer->allocated=
- 1024 /* bytes of overhead /header/footer */
- +(12+19*col_cnt) /* 12 bytes overhead/line plus 19 bytes per column*/
- *(1+row_cnt) /* number of columns + 1 (for header) */
- ;
- char buf[256];
- char dbuf[1024];
-
- rrd_value_t *ptr = data;
- if (json == 0){
- snprintf(buf,sizeof(buf),
- "<?xml version=\"1.0\" encoding=\"%s\"?>\n\n<%s>\n <%s>\n",
- XML_ENCODING,ROOT_TAG,META_TAG);
- addToBuffer(buffer,buf,0);
- }
- else {
- addToBuffer(buffer,"{ \"about\": \"RRDtool graph JSON output\",\n \"meta\": {\n",0);
- }
-
- /* calculate start time */
- if (timefmt) {
- struct tm loc;
- time_t ti=start+step;
- localtime_r(&ti,&loc);
- strftime(dbuf,sizeof(dbuf),timefmt,&loc);
- if (json) {
- snprintf(buf,sizeof(buf)," \"%s\": \"%s\",\n",META_START_TAG,dbuf);
+static int rrd_xport_format_xmljson(
+ int flags,
+ stringbuffer_t * buffer,
+ image_desc_t *im,
+ time_t start,
+ time_t end,
+ unsigned long step,
+ unsigned long col_cnt,
+ char **legend_v,
+ rrd_value_t *data)
+{
+
+ /* define some other stuff based on flags */
+ int json = 0;
+
+ if (flags & 1) {
+ json = 1;
+ }
+ int showtime = 0;
+
+ if (flags & 2) {
+ showtime = 1;
+ }
+ int enumds = 0;
+
+ if (flags & 4) {
+ enumds = 1;
+ }
+
+ /* define the time format */
+ char *timefmt = NULL;
+
+ /* unfortunately we have to do it this way,
+ as when no --x-graph argument is given,
+ then the xlab_user is not in a clean state (e.g. zero-filled) */
+ if (im->xlab_user.minsec != -1.0) {
+ timefmt = im->xlab_user.stst;
+ }
+
+ /* row count */
+ unsigned long row_cnt = (end - start) / step;
+
+ /* estimate buffer size (to avoid multiple allocations) */
+ /* better estimates are needed here */
+ buffer->allocated = 1024 /* bytes of overhead /header/footer */
+ + (12 + 19 * col_cnt) /* 12 bytes overhead/line plus 19 bytes per column */
+ *(1 + row_cnt) /* number of columns + 1 (for header) */
+ ;
+ char buf[256];
+ char dbuf[1024];
+
+ rrd_value_t *ptr = data;
+
+ if (json == 0) {
+ snprintf(buf, sizeof(buf),
+ "<?xml version=\"1.0\" encoding=\"%s\"?>\n\n<%s>\n <%s>\n",
+ XML_ENCODING, ROOT_TAG, META_TAG);
+ addToBuffer(buffer, buf, 0);
} else {
- snprintf(buf,sizeof(buf)," <%s>%s</%s>\n",META_START_TAG,dbuf,META_START_TAG);
+ addToBuffer(buffer,
+ "{ \"about\": \"RRDtool graph JSON output\",\n \"meta\": {\n",
+ 0);
}
- } else {
- if (json) {
- snprintf(buf,sizeof(buf)," \"%s\": %lld,\n",META_START_TAG,(long long int)start+step);
+
+ /* calculate start time */
+ if (timefmt) {
+ struct tm loc;
+ time_t ti = start + step;
+
+ localtime_r(&ti, &loc);
+ strftime(dbuf, sizeof(dbuf), timefmt, &loc);
+ if (json) {
+ snprintf(buf, sizeof(buf), " \"%s\": \"%s\",\n",
+ META_START_TAG, dbuf);
+ } else {
+ snprintf(buf, sizeof(buf), " <%s>%s</%s>\n", META_START_TAG,
+ dbuf, META_START_TAG);
+ }
} else {
- snprintf(buf,sizeof(buf)," <%s>%lld</%s>\n",META_START_TAG,(long long int)start+step,META_START_TAG);
+ if (json) {
+ snprintf(buf, sizeof(buf), " \"%s\": %lld,\n", META_START_TAG,
+ (long long int) start + step);
+ } else {
+ snprintf(buf, sizeof(buf), " <%s>%lld</%s>\n", META_START_TAG,
+ (long long int) start + step, META_START_TAG);
+ }
}
- }
- addToBuffer(buffer,buf,0);
-
- /* calculate end time */
- if (timefmt) {
- struct tm loc;
- time_t ti=end;
- localtime_r(&ti,&loc);
- strftime(dbuf,sizeof(dbuf),timefmt,&loc);
+ addToBuffer(buffer, buf, 0);
+
+ /* calculate end time */
+ if (timefmt) {
+ struct tm loc;
+ time_t ti = end;
+
+ localtime_r(&ti, &loc);
+ strftime(dbuf, sizeof(dbuf), timefmt, &loc);
+ if (json) {
+ snprintf(buf, sizeof(buf), " \"%s\": \"%s\",\n", META_END_TAG,
+ dbuf);
+ } else {
+ snprintf(buf, sizeof(buf), " <%s>%s</%s>\n", META_END_TAG,
+ dbuf, META_END_TAG);
+ }
+ } else {
+ if (json) {
+ snprintf(buf, sizeof(buf), " \"%s\": %lld,\n", META_END_TAG,
+ (long long int) end);
+ } else {
+ snprintf(buf, sizeof(buf), " <%s>%lld</%s>\n", META_END_TAG,
+ (long long int) end, META_END_TAG);
+ }
+ }
+ addToBuffer(buffer, buf, 0);
+ /* print other info */
if (json) {
- snprintf(buf,sizeof(buf)," \"%s\": \"%s\",\n",META_END_TAG,dbuf);
+ snprintf(buf, sizeof(buf), " \"%s\": %lld,\n", META_STEP_TAG,
+ (long long int) step);
+ addToBuffer(buffer, buf, 0);
} else {
- snprintf(buf,sizeof(buf)," <%s>%s</%s>\n",META_END_TAG,dbuf,META_END_TAG);
+ snprintf(buf, sizeof(buf), " <%s>%lld</%s>\n", META_STEP_TAG,
+ (long long int) step, META_STEP_TAG);
+ addToBuffer(buffer, buf, 0);
+ snprintf(buf, sizeof(buf), " <%s>%lu</%s>\n", META_ROWS_TAG,
+ row_cnt, META_ROWS_TAG);
+ addToBuffer(buffer, buf, 0);
+ snprintf(buf, sizeof(buf), " <%s>%lu</%s>\n", META_COLS_TAG,
+ col_cnt, META_COLS_TAG);
+ addToBuffer(buffer, buf, 0);
}
- } else {
+
+ /* start legend */
if (json) {
- snprintf(buf,sizeof(buf)," \"%s\": %lld,\n",META_END_TAG,(long long int)end);
+ snprintf(buf, sizeof(buf), " \"%s\": [\n", LEGEND_TAG);
} else {
- snprintf(buf,sizeof(buf)," <%s>%lld</%s>\n",META_END_TAG,(long long int)end,META_END_TAG);
+ snprintf(buf, sizeof(buf), " <%s>\n", LEGEND_TAG);
}
- }
- addToBuffer(buffer,buf,0);
- /* print other info */
- if (json) {
- snprintf(buf,sizeof(buf)," \"%s\": %lld,\n",META_STEP_TAG,(long long int)step);
- addToBuffer(buffer,buf,0);
- } else {
- snprintf(buf,sizeof(buf)," <%s>%lld</%s>\n",META_STEP_TAG,(long long int)step,META_STEP_TAG);
- addToBuffer(buffer,buf,0);
- snprintf(buf,sizeof(buf)," <%s>%lu</%s>\n",META_ROWS_TAG,row_cnt,META_ROWS_TAG);
- addToBuffer(buffer,buf,0);
- snprintf(buf,sizeof(buf)," <%s>%lu</%s>\n",META_COLS_TAG,col_cnt,META_COLS_TAG);
- addToBuffer(buffer,buf,0);
- }
-
- /* start legend */
- if (json){
- snprintf(buf,sizeof(buf)," \"%s\": [\n", LEGEND_TAG);
- }
- else {
- snprintf(buf,sizeof(buf)," <%s>\n", LEGEND_TAG);
- }
- addToBuffer(buffer,buf,0);
- /* add legend entries */
- for (unsigned long j = 0; j < col_cnt; j++) {
- char *entry = legend_v[j];
- /* I do not know why the legend is "spaced", but let us skip it */
- while(isspace(*entry)){entry++;}
- /* now output it */
- if (json){
- snprintf(buf,sizeof(buf)," \"%s\"", entry);
- addToBuffer(buffer,buf,0);
- if (j < col_cnt -1){
- addToBuffer(buffer,",",1);
- }
- addToBuffer(buffer,"\n",1);
+ addToBuffer(buffer, buf, 0);
+ /* add legend entries */
+ for (unsigned long j = 0; j < col_cnt; j++) {
+ char *entry = legend_v[j];
+
+ /* I do not know why the legend is "spaced", but let us skip it */
+ while (isspace(*entry)) {
+ entry++;
+ }
+ /* now output it */
+ if (json) {
+ snprintf(buf, sizeof(buf), " \"%s\"", entry);
+ addToBuffer(buffer, buf, 0);
+ if (j < col_cnt - 1) {
+ addToBuffer(buffer, ",", 1);
+ }
+ addToBuffer(buffer, "\n", 1);
+ } else {
+ snprintf(buf, sizeof(buf), " <%s>%s</%s>\n",
+ LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
+ addToBuffer(buffer, buf, 0);
+ }
}
- else {
- snprintf(buf,sizeof(buf)," <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry,LEGEND_ENTRY_TAG);
- addToBuffer(buffer,buf,0);
+ /* end legend */
+ if (json) {
+ snprintf(buf, sizeof(buf), " ]\n");
+ } else {
+ snprintf(buf, sizeof(buf), " </%s>\n", LEGEND_TAG);
}
- }
- /* end legend */
- if (json){
- snprintf(buf,sizeof(buf)," ]\n");
- }
- else {
- snprintf(buf,sizeof(buf)," </%s>\n", LEGEND_TAG);
- }
- addToBuffer(buffer,buf,0);
-
- /* add graphs and prints */
- if (rrd_xport_format_addprints(json,buffer,im)) {return -1;}
-
- /* if we have got a trailing , then kill it */
- if (buffer->data) {
- if (buffer->data[buffer->len-2]==',') {
- buffer->data[buffer->len-2]=buffer->data[buffer->len-1];
- buffer->len--;
+ addToBuffer(buffer, buf, 0);
+
+ /* add graphs and prints */
+ if (rrd_xport_format_addprints(json, buffer, im)) {
+ return -1;
}
- }
-
- /* end meta */
- if (json){
- snprintf(buf,sizeof(buf)," },\n");
- } else {
- snprintf(buf,sizeof(buf)," </%s>\n", META_TAG);
- }
- addToBuffer(buffer,buf,0);
-
-
- /* start data */
- if (json){
- snprintf(buf,sizeof(buf)," \"%s\": [\n",DATA_TAG);
- } else {
- snprintf(buf,sizeof(buf)," <%s>\n", DATA_TAG);
- }
- addToBuffer(buffer,buf,0);
- /* iterate over data */
- for (time_t ti = start+step; ti <= end; ti += step) {
- if (timefmt) {
- struct tm loc;
- localtime_r(&ti,&loc);
- strftime(dbuf,sizeof(dbuf),timefmt,&loc);
- } else {
- snprintf(dbuf,sizeof(dbuf),"%lld",(long long int)ti);
+
+ /* if we have got a trailing , then kill it */
+ if (buffer->data) {
+ if (buffer->data[buffer->len - 2] == ',') {
+ buffer->data[buffer->len - 2] = buffer->data[buffer->len - 1];
+ buffer->len--;
+ }
}
- if (json){
- addToBuffer(buffer," [ ",0);
- if(showtime){
- addToBuffer(buffer,"\"",1);
- addToBuffer(buffer,dbuf,0);
- addToBuffer(buffer,"\",",2);
- }
+
+ /* end meta */
+ if (json) {
+ snprintf(buf, sizeof(buf), " },\n");
+ } else {
+ snprintf(buf, sizeof(buf), " </%s>\n", META_TAG);
}
- else {
- if (showtime) {
- snprintf(buf,sizeof(buf),
- " <%s><%s>%s</%s>", DATA_ROW_TAG,COL_TIME_TAG, dbuf, COL_TIME_TAG);
- } else {
- snprintf(buf,sizeof(buf),
- " <%s>", DATA_ROW_TAG);
- }
- addToBuffer(buffer,buf,0);
+ addToBuffer(buffer, buf, 0);
+
+
+ /* start data */
+ if (json) {
+ snprintf(buf, sizeof(buf), " \"%s\": [\n", DATA_TAG);
+ } else {
+ snprintf(buf, sizeof(buf), " <%s>\n", DATA_TAG);
}
- for (unsigned long j = 0; j < col_cnt; j++) {
- rrd_value_t newval = DNAN;
- newval = *ptr;
- if (json){
- if (isnan(newval) || isinf(newval)){
- addToBuffer(buffer,"null",0);
- } else {
- rrd_snprintf(buf,sizeof(buf),"%0.10e",newval);
- addToBuffer(buffer,buf,0);
- }
- if (j < col_cnt -1){
- addToBuffer(buffer,", ",0);
- }
- }
- else {
- if (isnan(newval)) {
- if (enumds) {
- snprintf(buf,sizeof(buf),"<%s%lu>NaN</%s%lu>", COL_DATA_TAG,j,COL_DATA_TAG,j);
- } else {
- snprintf(buf,sizeof(buf),"<%s>NaN</%s>", COL_DATA_TAG,COL_DATA_TAG);
- }
- } else {
- if (enumds) {
- rrd_snprintf(buf,sizeof(buf),"<%s%lu>%0.10e</%s%lu>", COL_DATA_TAG,j,newval,COL_DATA_TAG,j);
- } else {
- rrd_snprintf(buf,sizeof(buf),"<%s>%0.10e</%s>", COL_DATA_TAG,newval,COL_DATA_TAG);
- }
- }
- addToBuffer(buffer,buf,0);
- }
- ptr++;
+ addToBuffer(buffer, buf, 0);
+ /* iterate over data */
+ for (time_t ti = start + step; ti <= end; ti += step) {
+ if (timefmt) {
+ struct tm loc;
+
+ localtime_r(&ti, &loc);
+ strftime(dbuf, sizeof(dbuf), timefmt, &loc);
+ } else {
+ snprintf(dbuf, sizeof(dbuf), "%lld", (long long int) ti);
+ }
+ if (json) {
+ addToBuffer(buffer, " [ ", 0);
+ if (showtime) {
+ addToBuffer(buffer, "\"", 1);
+ addToBuffer(buffer, dbuf, 0);
+ addToBuffer(buffer, "\",", 2);
+ }
+ } else {
+ if (showtime) {
+ snprintf(buf, sizeof(buf),
+ " <%s><%s>%s</%s>", DATA_ROW_TAG, COL_TIME_TAG,
+ dbuf, COL_TIME_TAG);
+ } else {
+ snprintf(buf, sizeof(buf), " <%s>", DATA_ROW_TAG);
+ }
+ addToBuffer(buffer, buf, 0);
+ }
+ for (unsigned long j = 0; j < col_cnt; j++) {
+ rrd_value_t newval = DNAN;
+
+ newval = *ptr;
+ if (json) {
+ if (isnan(newval) || isinf(newval)) {
+ addToBuffer(buffer, "null", 0);
+ } else {
+ rrd_snprintf(buf, sizeof(buf), "%0.10e", newval);
+ addToBuffer(buffer, buf, 0);
+ }
+ if (j < col_cnt - 1) {
+ addToBuffer(buffer, ", ", 0);
+ }
+ } else {
+ if (isnan(newval)) {
+ if (enumds) {
+ snprintf(buf, sizeof(buf), "<%s%lu>NaN</%s%lu>",
+ COL_DATA_TAG, j, COL_DATA_TAG, j);
+ } else {
+ snprintf(buf, sizeof(buf), "<%s>NaN</%s>",
+ COL_DATA_TAG, COL_DATA_TAG);
+ }
+ } else {
+ if (enumds) {
+ rrd_snprintf(buf, sizeof(buf),
+ "<%s%lu>%0.10e</%s%lu>", COL_DATA_TAG, j,
+ newval, COL_DATA_TAG, j);
+ } else {
+ rrd_snprintf(buf, sizeof(buf), "<%s>%0.10e</%s>",
+ COL_DATA_TAG, newval, COL_DATA_TAG);
+ }
+ }
+ addToBuffer(buffer, buf, 0);
+ }
+ ptr++;
+ }
+ if (json) {
+ addToBuffer(buffer,
+ (ti <= end - (time_t) step ? " ],\n" : " ]\n"), 0);
+ } else {
+ snprintf(buf, sizeof(buf), "</%s>\n", DATA_ROW_TAG);
+ addToBuffer(buffer, buf, 0);
+ }
}
- if (json){
- addToBuffer(buffer,(ti <= end-(time_t)step ? " ],\n" : " ]\n"),0);
+ /* end data */
+ if (json) {
+ addToBuffer(buffer, " ]\n", 0);
+ } else {
+ snprintf(buf, sizeof(buf), " </%s>\n", DATA_TAG);
+ addToBuffer(buffer, buf, 0);
}
- else {
- snprintf(buf,sizeof(buf),"</%s>\n", DATA_ROW_TAG);
- addToBuffer(buffer,buf,0);
+
+ /* end all */
+ if (json) {
+ addToBuffer(buffer, "}\n", 0);
+ } else {
+ snprintf(buf, sizeof(buf), "</%s>\n", ROOT_TAG);
+ addToBuffer(buffer, buf, 0);
}
- }
- /* end data */
- if (json){
- addToBuffer(buffer," ]\n",0);
- }
- else {
- snprintf(buf,sizeof(buf)," </%s>\n",DATA_TAG);
- addToBuffer(buffer,buf,0);
- }
-
- /* end all */
- if (json){
- addToBuffer(buffer,"}\n",0);
- } else {
- snprintf(buf,sizeof(buf),"</%s>\n", ROOT_TAG);
- addToBuffer(buffer,buf,0);
- }
- return 0;
+ return 0;
}
-static void escapeJSON(char* txt,size_t len) {
- char *tmp=(char*)malloc(len+2);
- size_t l=strlen(txt);
- size_t pos=0;
- /* now iterate over the chars */
- for(size_t i=0;(i<l)&&(pos<len);i++,pos++) {
- switch (txt[i]) {
- case '"':
- case '\\':
- tmp[pos]='\\';pos++;
- tmp[pos]=txt[i];
- break;
- default:
- tmp[pos]=txt[i];
- break;
+static void escapeJSON(
+ char *txt,
+ size_t len)
+{
+ char *tmp = (char *) malloc(len + 2);
+ size_t l = strlen(txt);
+ size_t pos = 0;
+
+ /* now iterate over the chars */
+ for (size_t i = 0; (i < l) && (pos < len); i++, pos++) {
+ switch (txt[i]) {
+ case '"':
+ case '\\':
+ tmp[pos] = '\\';
+ pos++;
+ tmp[pos] = txt[i];
+ break;
+ default:
+ tmp[pos] = txt[i];
+ break;
+ }
}
- }
- /* 0 terminate it */
- tmp[pos]=0;
- /* and copy back over txt */
- strncpy(txt,tmp,len);
- /* and release tmp */
- free(tmp);
+ /* 0 terminate it */
+ tmp[pos] = 0;
+ /* and copy back over txt */
+ strncpy(txt, tmp, len);
+ /* and release tmp */
+ free(tmp);
}
-static int rrd_xport_format_addprints(int flags,stringbuffer_t *buffer,image_desc_t *im) {
- /* initialize buffer */
- stringbuffer_t prints={1024,0,NULL,NULL};
- stringbuffer_t rules={1024,0,NULL,NULL};
- stringbuffer_t gprints={4096,0,NULL,NULL};
- char buf[256];
- char dbuf[1024];
- char* val;
- char* timefmt=NULL;
- if (im->xlab_user.minsec!=-1.0) { timefmt=im->xlab_user.stst; }
-
- /* avoid calling escapeJSON() with garbage */
- memset(dbuf, 0, sizeof(dbuf));
-
- /* define some other stuff based on flags */
- int json=0;
- if (flags &1) { json=1; }
- // int showtime=0; if (flags &2) { showtime=1;} -> unused here
- // int enumds=0; if (flags &4) { enumds=1;} -> unused here
-
- /* define some values */
- time_t now = time(NULL);
- struct tm tmvdef;
- localtime_r(&now, &tmvdef);
- double printval=DNAN;
-
- /* iterate over all fields and start the work writing to the correct buffers */
- for (long i = 0; i < im->gdes_c; i++) {
- long vidx = im->gdes[i].vidx;
- char* entry;
- switch (im->gdes[i].gf) {
- case GF_PRINT:
- case GF_GPRINT: {
- /* PRINT and GPRINT can now print VDEF generated values.
- * There's no need to do any calculations on them as these
- * calculations were already made.
- * we do not support the deprecated version here
- */
- printval=DNAN;
- /* decide to which buffer we print to*/
- stringbuffer_t *usebuffer=&gprints;
- char* usetag="gprint";
- if (im->gdes[i].gf==GF_PRINT) {
- usebuffer=&prints;
- usetag="print";
- }
- /* get the value */
- if (im->gdes[vidx].gf == GF_VDEF) { /* simply use vals */
- printval = im->gdes[vidx].vf.val;
- localtime_r(&im->gdes[vidx].vf.when, &tmvdef);
- } else {
- int max_ii = ((im->gdes[vidx].end - im->gdes[vidx].start)
- / im->gdes[vidx].step * im->gdes[vidx].ds_cnt);
- printval = DNAN;
- long validsteps = 0;
- for (long ii = im->gdes[vidx].ds;
- ii < max_ii; ii += im->gdes[vidx].ds_cnt) {
- if (!finite(im->gdes[vidx].data[ii]))
- continue;
- if (isnan(printval)) {
- printval = im->gdes[vidx].data[ii];
- validsteps++;
- continue;
- }
-
- switch (im->gdes[i].cf) {
- case CF_HWPREDICT:
- case CF_MHWPREDICT:
- case CF_DEVPREDICT:
- case CF_DEVSEASONAL:
- case CF_SEASONAL:
- case CF_AVERAGE:
- validsteps++;
- printval += im->gdes[vidx].data[ii];
- break;
- case CF_MINIMUM:
- printval = min(printval, im->gdes[vidx].data[ii]);
- break;
- case CF_FAILURES:
- case CF_MAXIMUM:
- printval = max(printval, im->gdes[vidx].data[ii]);
- break;
- case CF_LAST:
- printval = im->gdes[vidx].data[ii];
- }
- }
- if (im->gdes[i].cf == CF_AVERAGE || im->gdes[i].cf > CF_LAST) {
- if (validsteps > 1) {
- printval = (printval / validsteps);
- }
- }
- }
- /* we handle PRINT and GPRINT the same - format now*/
- if (im->gdes[i].strftm) {
- if (im->gdes[vidx].vf.never == 1) {
- time_clean(buf, im->gdes[i].format);
- } else {
- strftime(dbuf,sizeof(dbuf), im->gdes[i].format, &tmvdef);
- }
- } else if (bad_format_print(im->gdes[i].format)) {
- rrd_set_error
- ("bad format for PRINT in \"%s'", im->gdes[i].format);
- return -1;
- } else {
- rrd_snprintf(dbuf,sizeof(dbuf), im->gdes[i].format, printval,"");
- }
- /* print */
- if (json) {
- escapeJSON(dbuf,sizeof(dbuf));
- snprintf(buf,sizeof(buf),",\n { \"%s\": \"%s\" }",usetag,dbuf);
- } else {
- snprintf(buf,sizeof(buf)," <%s>%s</%s>\n",usetag,dbuf,usetag);
- }
- addToBuffer(usebuffer,buf,0); }
- break;
- case GF_COMMENT:
- if (json) {
- strncpy(dbuf,im->gdes[i].legend,sizeof(dbuf));
- escapeJSON(dbuf,sizeof(dbuf));
- snprintf(buf,sizeof(buf),",\n { \"comment\": \"%s\" }",dbuf);
- } else {
- snprintf(buf,sizeof(buf)," <comment>%s</comment>\n",im->gdes[i].legend);
- }
- addToBuffer(&gprints,buf,0);
- break;
- case GF_LINE:
- entry = im->gdes[i].legend;
- /* I do not know why the legend is "spaced", but let us skip it */
- while(isspace(*entry)){entry++;}
- if (json) {
- snprintf(buf,sizeof(buf),",\n { \"line\": \"%s\" }",entry);
- } else {
- snprintf(buf,sizeof(buf)," <line>%s</line>\n",entry);
- }
- addToBuffer(&gprints,buf,0);
- break;
- case GF_AREA:
- if (json) {
- snprintf(buf,sizeof(buf),",\n { \"area\": \"%s\" }",im->gdes[i].legend);
- } else {
- snprintf(buf,sizeof(buf)," <area>%s</area>\n",im->gdes[i].legend);
- }
- addToBuffer(&gprints,buf,0);
- break;
- case GF_STACK:
- if (json) {
- snprintf(buf,sizeof(buf),",\n { \"stack\": \"%s\" }",im->gdes[i].legend);
- } else {
- snprintf(buf,sizeof(buf)," <stack>%s</stack>\n",im->gdes[i].legend);
- }
- addToBuffer(&gprints,buf,0);
- break;
- case GF_TEXTALIGN:
- val="";
- switch (im->gdes[i].txtalign) {
- case TXA_LEFT: val="left"; break;
- case TXA_RIGHT: val="right"; break;
- case TXA_CENTER: val="center"; break;
- case TXA_JUSTIFIED: val="justified"; break;
- }
- if (json) {
- snprintf(buf,sizeof(buf),",\n { \"align\": \"%s\" }",val);
- } else {
- snprintf(buf,sizeof(buf)," <align>%s</align>\n",val);
- }
- addToBuffer(&gprints,buf,0);
- break;
- case GF_HRULE:
- /* This does not work as expected - Tobi please help!!! */
- rrd_snprintf(dbuf,sizeof(dbuf),"%0.10e",im->gdes[i].vf.val);
- /* and output it */
- if (json) {
- snprintf(buf,sizeof(buf),",\n { \"hrule\": \"%s\" }",dbuf);
- } else {
- snprintf(buf,sizeof(buf)," <hrule>%s</hrule>\n",dbuf);
- }
- addToBuffer(&rules,buf,0);
- break;
- case GF_VRULE:
- if (timefmt) {
- struct tm loc;
- localtime_r(&im->gdes[i].xrule,&loc);
- strftime(dbuf,254,timefmt,&loc);
- } else {
- snprintf(dbuf,254,"%lld",(long long int)im->gdes[i].vf.when);
- }
- /* and output it */
- if (json) {
- snprintf(buf,sizeof(buf),",\n { \"vrule\": \"%s\" }",dbuf);
- } else {
- snprintf(buf,sizeof(buf)," <vrule>%s</vrule>\n",dbuf);
- }
- addToBuffer(&rules,buf,0);
- break;
- default:
- break;
+static int rrd_xport_format_addprints(
+ int flags,
+ stringbuffer_t * buffer,
+ image_desc_t *im)
+{
+ /* initialize buffer */
+ stringbuffer_t prints = { 1024, 0, NULL, NULL };
+ stringbuffer_t rules = { 1024, 0, NULL, NULL };
+ stringbuffer_t gprints = { 4096, 0, NULL, NULL };
+ char buf[256];
+ char dbuf[1024];
+ char *val;
+ char *timefmt = NULL;
+
+ if (im->xlab_user.minsec != -1.0) {
+ timefmt = im->xlab_user.stst;
}
- }
- /* now add prints */
- if (prints.len) {
- if (json){
- snprintf(buf,sizeof(buf)," \"%s\": [\n","prints");
- addToBuffer(buffer,buf,0);
- addToBuffer(buffer,(char*)prints.data+2,prints.len-2);
- addToBuffer(buffer,"\n ],\n",0);
- } else {
- snprintf(buf,sizeof(buf)," <%s>\n", "prints");
- addToBuffer(buffer,buf,0);
- addToBuffer(buffer,(char*)prints.data,prints.len);
- snprintf(buf,sizeof(buf)," </%s>\n", "prints");
- addToBuffer(buffer,buf,0);
+
+ /* avoid calling escapeJSON() with garbage */
+ memset(dbuf, 0, sizeof(dbuf));
+
+ /* define some other stuff based on flags */
+ int json = 0;
+
+ if (flags & 1) {
+ json = 1;
}
- free(prints.data);
- }
- /* now add gprints */
- if (gprints.len) {
- if (json){
- snprintf(buf,sizeof(buf)," ,\"%s\": [\n","gprints");
- addToBuffer(buffer,buf,0);
- addToBuffer(buffer,(char*)gprints.data+2,gprints.len-2);
- addToBuffer(buffer,"\n ]\n",0);
- } else {
- snprintf(buf,sizeof(buf)," <%s>\n", "gprints");
- addToBuffer(buffer,buf,0);
- addToBuffer(buffer,(char*)gprints.data,gprints.len);
- snprintf(buf,sizeof(buf)," </%s>\n", "gprints");
- addToBuffer(buffer,buf,0);
+ // int showtime=0; if (flags &2) { showtime=1;} -> unused here
+ // int enumds=0; if (flags &4) { enumds=1;} -> unused here
+
+ /* define some values */
+ time_t now = time(NULL);
+ struct tm tmvdef;
+
+ localtime_r(&now, &tmvdef);
+ double printval = DNAN;
+
+ /* iterate over all fields and start the work writing to the correct buffers */
+ for (long i = 0; i < im->gdes_c; i++) {
+ long vidx = im->gdes[i].vidx;
+ char *entry;
+
+ switch (im->gdes[i].gf) {
+ case GF_PRINT:
+ case GF_GPRINT:{
+ /* PRINT and GPRINT can now print VDEF generated values.
+ * There's no need to do any calculations on them as these
+ * calculations were already made.
+ * we do not support the deprecated version here
+ */
+ printval = DNAN;
+ /* decide to which buffer we print to */
+ stringbuffer_t *usebuffer = &gprints;
+ char *usetag = "gprint";
+
+ if (im->gdes[i].gf == GF_PRINT) {
+ usebuffer = &prints;
+ usetag = "print";
+ }
+ /* get the value */
+ if (im->gdes[vidx].gf == GF_VDEF) { /* simply use vals */
+ printval = im->gdes[vidx].vf.val;
+ localtime_r(&im->gdes[vidx].vf.when, &tmvdef);
+ } else {
+ int max_ii =
+ ((im->gdes[vidx].end - im->gdes[vidx].start)
+ / im->gdes[vidx].step * im->gdes[vidx].ds_cnt);
+
+ printval = DNAN;
+ long validsteps = 0;
+
+ for (long ii = im->gdes[vidx].ds;
+ ii < max_ii; ii += im->gdes[vidx].ds_cnt) {
+ if (!finite(im->gdes[vidx].data[ii]))
+ continue;
+ if (isnan(printval)) {
+ printval = im->gdes[vidx].data[ii];
+ validsteps++;
+ continue;
+ }
+
+ switch (im->gdes[i].cf) {
+ case CF_HWPREDICT:
+ case CF_MHWPREDICT:
+ case CF_DEVPREDICT:
+ case CF_DEVSEASONAL:
+ case CF_SEASONAL:
+ case CF_AVERAGE:
+ validsteps++;
+ printval += im->gdes[vidx].data[ii];
+ break;
+ case CF_MINIMUM:
+ printval = min(printval, im->gdes[vidx].data[ii]);
+ break;
+ case CF_FAILURES:
+ case CF_MAXIMUM:
+ printval = max(printval, im->gdes[vidx].data[ii]);
+ break;
+ case CF_LAST:
+ printval = im->gdes[vidx].data[ii];
+ }
+ }
+ if (im->gdes[i].cf == CF_AVERAGE || im->gdes[i].cf > CF_LAST) {
+ if (validsteps > 1) {
+ printval = (printval / validsteps);
+ }
+ }
+ }
+ /* we handle PRINT and GPRINT the same - format now */
+ if (im->gdes[i].strftm) {
+ if (im->gdes[vidx].vf.never == 1) {
+ time_clean(buf, im->gdes[i].format);
+ } else {
+ strftime(dbuf, sizeof(dbuf), im->gdes[i].format, &tmvdef);
+ }
+ } else if (bad_format_print(im->gdes[i].format)) {
+ rrd_set_error
+ ("bad format for PRINT in \"%s'", im->gdes[i].format);
+ return -1;
+ } else {
+ rrd_snprintf(dbuf, sizeof(dbuf), im->gdes[i].format, printval,
+ "");
+ }
+ /* print */
+ if (json) {
+ escapeJSON(dbuf, sizeof(dbuf));
+ snprintf(buf, sizeof(buf), ",\n { \"%s\": \"%s\" }",
+ usetag, dbuf);
+ } else {
+ snprintf(buf, sizeof(buf), " <%s>%s</%s>\n", usetag,
+ dbuf, usetag);
+ }
+ addToBuffer(usebuffer, buf, 0);
+ }
+ break;
+ case GF_COMMENT:
+ if (json) {
+ strncpy(dbuf, im->gdes[i].legend, sizeof(dbuf));
+ escapeJSON(dbuf, sizeof(dbuf));
+ snprintf(buf, sizeof(buf),
+ ",\n { \"comment\": \"%s\" }", dbuf);
+ } else {
+ snprintf(buf, sizeof(buf), " <comment>%s</comment>\n",
+ im->gdes[i].legend);
+ }
+ addToBuffer(&gprints, buf, 0);
+ break;
+ case GF_LINE:
+ entry = im->gdes[i].legend;
+ /* I do not know why the legend is "spaced", but let us skip it */
+ while (isspace(*entry)) {
+ entry++;
+ }
+ if (json) {
+ snprintf(buf, sizeof(buf), ",\n { \"line\": \"%s\" }",
+ entry);
+ } else {
+ snprintf(buf, sizeof(buf), " <line>%s</line>\n",
+ entry);
+ }
+ addToBuffer(&gprints, buf, 0);
+ break;
+ case GF_AREA:
+ if (json) {
+ snprintf(buf, sizeof(buf), ",\n { \"area\": \"%s\" }",
+ im->gdes[i].legend);
+ } else {
+ snprintf(buf, sizeof(buf), " <area>%s</area>\n",
+ im->gdes[i].legend);
+ }
+ addToBuffer(&gprints, buf, 0);
+ break;
+ case GF_STACK:
+ if (json) {
+ snprintf(buf, sizeof(buf), ",\n { \"stack\": \"%s\" }",
+ im->gdes[i].legend);
+ } else {
+ snprintf(buf, sizeof(buf), " <stack>%s</stack>\n",
+ im->gdes[i].legend);
+ }
+ addToBuffer(&gprints, buf, 0);
+ break;
+ case GF_TEXTALIGN:
+ val = "";
+ switch (im->gdes[i].txtalign) {
+ case TXA_LEFT:
+ val = "left";
+ break;
+ case TXA_RIGHT:
+ val = "right";
+ break;
+ case TXA_CENTER:
+ val = "center";
+ break;
+ case TXA_JUSTIFIED:
+ val = "justified";
+ break;
+ }
+ if (json) {
+ snprintf(buf, sizeof(buf), ",\n { \"align\": \"%s\" }",
+ val);
+ } else {
+ snprintf(buf, sizeof(buf), " <align>%s</align>\n",
+ val);
+ }
+ addToBuffer(&gprints, buf, 0);
+ break;
+ case GF_HRULE:
+ /* This does not work as expected - Tobi please help!!! */
+ rrd_snprintf(dbuf, sizeof(dbuf), "%0.10e", im->gdes[i].vf.val);
+ /* and output it */
+ if (json) {
+ snprintf(buf, sizeof(buf), ",\n { \"hrule\": \"%s\" }",
+ dbuf);
+ } else {
+ snprintf(buf, sizeof(buf), " <hrule>%s</hrule>\n",
+ dbuf);
+ }
+ addToBuffer(&rules, buf, 0);
+ break;
+ case GF_VRULE:
+ if (timefmt) {
+ struct tm loc;
+
+ localtime_r(&im->gdes[i].xrule, &loc);
+ strftime(dbuf, 254, timefmt, &loc);
+ } else {
+ snprintf(dbuf, 254, "%lld",
+ (long long int) im->gdes[i].vf.when);
+ }
+ /* and output it */
+ if (json) {
+ snprintf(buf, sizeof(buf), ",\n { \"vrule\": \"%s\" }",
+ dbuf);
+ } else {
+ snprintf(buf, sizeof(buf), " <vrule>%s</vrule>\n",
+ dbuf);
+ }
+ addToBuffer(&rules, buf, 0);
+ break;
+ default:
+ break;
+ }
}
- free(gprints.data);
- }
- /* now add rules */
- if (rules.len) {
- if (json){
- snprintf(buf,sizeof(buf)," ,\"%s\": [\n","rules");
- addToBuffer(buffer,buf,0);
- addToBuffer(buffer,(char*)rules.data+2,rules.len-2);
- addToBuffer(buffer,"\n ]\n",0);
- } else {
- snprintf(buf,sizeof(buf)," <%s>\n", "rules");
- addToBuffer(buffer,buf,0);
- addToBuffer(buffer,(char*)rules.data,rules.len);
- snprintf(buf,sizeof(buf)," </%s>\n", "rules");
- addToBuffer(buffer,buf,0);
+ /* now add prints */
+ if (prints.len) {
+ if (json) {
+ snprintf(buf, sizeof(buf), " \"%s\": [\n", "prints");
+ addToBuffer(buffer, buf, 0);
+ addToBuffer(buffer, (char *) prints.data + 2, prints.len - 2);
+ addToBuffer(buffer, "\n ],\n", 0);
+ } else {
+ snprintf(buf, sizeof(buf), " <%s>\n", "prints");
+ addToBuffer(buffer, buf, 0);
+ addToBuffer(buffer, (char *) prints.data, prints.len);
+ snprintf(buf, sizeof(buf), " </%s>\n", "prints");
+ addToBuffer(buffer, buf, 0);
+ }
+ free(prints.data);
}
- free(rules.data);
- }
- /* and return */
- return 0;
+ /* now add gprints */
+ if (gprints.len) {
+ if (json) {
+ snprintf(buf, sizeof(buf), " ,\"%s\": [\n", "gprints");
+ addToBuffer(buffer, buf, 0);
+ addToBuffer(buffer, (char *) gprints.data + 2, gprints.len - 2);
+ addToBuffer(buffer, "\n ]\n", 0);
+ } else {
+ snprintf(buf, sizeof(buf), " <%s>\n", "gprints");
+ addToBuffer(buffer, buf, 0);
+ addToBuffer(buffer, (char *) gprints.data, gprints.len);
+ snprintf(buf, sizeof(buf), " </%s>\n", "gprints");
+ addToBuffer(buffer, buf, 0);
+ }
+ free(gprints.data);
+ }
+ /* now add rules */
+ if (rules.len) {
+ if (json) {
+ snprintf(buf, sizeof(buf), " ,\"%s\": [\n", "rules");
+ addToBuffer(buffer, buf, 0);
+ addToBuffer(buffer, (char *) rules.data + 2, rules.len - 2);
+ addToBuffer(buffer, "\n ]\n", 0);
+ } else {
+ snprintf(buf, sizeof(buf), " <%s>\n", "rules");
+ addToBuffer(buffer, buf, 0);
+ addToBuffer(buffer, (char *) rules.data, rules.len);
+ snprintf(buf, sizeof(buf), " </%s>\n", "rules");
+ addToBuffer(buffer, buf, 0);
+ }
+ free(rules.data);
+ }
+ /* and return */
+ return 0;
}