From: Etienne Buira Date: Mon, 16 Mar 2015 20:55:12 +0000 (+0100) Subject: rrd_graph: Add possibility to graph timestamp data X-Git-Tag: v1.5.0~7^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f0cc37d13228c4c73ca97c8fdf73327391f30f84;p=thirdparty%2Frrdtool-1.x.git rrd_graph: Add possibility to graph timestamp data RRA records hold both a value and a timestamp, this patch permits to represent the _value_ (g?print/axis) as timestamps. --- diff --git a/doc/rrdgraph.pod b/doc/rrdgraph.pod index 362ae663..0e7802a9 100644 --- a/doc/rrdgraph.pod +++ b/doc/rrdgraph.pod @@ -213,11 +213,30 @@ If you have set --y-grid to 'none' not only the labels get suppressed, also the space reserved for the labels is removed. You can still add space manually if you use the --units-length command to explicitly reserve space. +[B<--left-axis-formatter> I] + +Specify what formater to use to render axis values. + +=over + +=item B + +The default, values are expressed as numeric quantities. + +=item B + +Values are interpreted as unix timestamps (number of seconds since 1970-01-01 +00:00:00 UTC) and expressed using strftime format (default +is '%Y-%m-%d %H:%M:%S'). See also B<--units-length> and B<--left-axis-format>. + +=back + [B<--left-axis-format> I] By default the format of the axis labels gets determined automatically. If you want to do this your self, use this option with the same %lf arguments -you know from the PRINT and GPRINT commands. +you know from the PRINT and GPRINT commands, or others if using different +formatter. [B<-Y>|B<--alt-y-grid>] @@ -270,11 +289,31 @@ A second axis will be drawn to the right of the graph. It is tied to the left axis via the scale and shift parameters. You can also define a label for the right axis. +[B<--right-axis-formatter> I] + +Specify what formater to use to render axis values. + +=over + +=item B + +The default, values are expressed as numeric quantities. + +=item B + +Values are interpreted as unix timestamps (number of seconds since 1970-01-01 +00:00:00 UTC) and expressed using strftime format (default +is '%Y-%m-%d %H:%M:%S'). See also B<--units-length> and B<--right-axis-format>. + +=back + + [B<--right-axis-format> I] By default the format of the axis labels gets determined automatically. If you want to do this your self, use this option with the same %lf arguments -you know from the PRINT and GPRINT commands. +you know from the PRINT and GPRINT commands, or others if using different +formatter. =head2 Legend diff --git a/doc/rrdgraph_graph.pod b/doc/rrdgraph_graph.pod index 1801a713..183ee39c 100644 --- a/doc/rrdgraph_graph.pod +++ b/doc/rrdgraph_graph.pod @@ -6,7 +6,7 @@ rrdgraph_graph - rrdtool graph command reference =head1 SYNOPSIS -BB<:>IB<:>I +BB<:>IB<:>I[B<:strftime>|B<:valstrftime>] BB<:>IB<:>I @@ -40,11 +40,11 @@ Similarly, no report is generated if you don't use print options. =head2 PRINT -=head3 BIB<:>I[B<:strftime>] +=head3 BIB<:>I[B<:strftime>|B<:valstrftime>] -Depending on the context, either the value component or the time -component of a B is printed using I. It is an error -to specify a I generated by a B or B. +Depending on the context, either the value component (no suffix or valstrftime) +or the time component (strftime) of a B is printed using I. It is +an error to specify a I generated by a B or B. Any text in I is printed literally with one exception: The percent character introduces a formatter string. This string @@ -87,7 +87,8 @@ will all use the same magnitude unit except for zero values. If you PRINT a VDEF value, you can also print the time associated with it by appending the string B<:strftime> to the format. Note that RRDtool uses the strftime function of your OSs C library. This means that the conversion specifier may vary. Check the manual page if you are uncertain. The following is a list of -conversion specifiers usually supported across the board. +conversion specifiers usually supported across the board. Formatting values +interpreted as timestamps with B<:valstrftime> is done likewise. =over diff --git a/src/rrd_graph.c b/src/rrd_graph.c index 0ae82977..eaddea0d 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -224,6 +224,8 @@ gfx_color_t graph_col[] = /* default colors */ {0.00, 0.00, 0.00, 1.00} /* frame */ }; +const char default_timestamp_fmt[] = "%Y-%m-%d %H:%M:%S"; + /* #define DEBUG */ @@ -1631,6 +1633,23 @@ time_t find_next_time( } +static int timestamp_to_tm(struct tm *tm, double timestamp) +{ + time_t ts; + + if (timestamp < LLONG_MIN || timestamp > LLONG_MAX) + return 1; + + ts = (long long int) timestamp; + + if (ts != (long long int) timestamp) + return 1; + + gmtime_r(&ts, tm); + + return 0; +} + /* calculate values required for PRINT and GPRINT functions */ @@ -1707,22 +1726,24 @@ int print_calc( } } /* prepare printval */ - if (!im->gdes[i].strftm && (percent_s = strstr(im->gdes[i].format, "%S")) != NULL) { - /* Magfact is set to -1 upon entry to print_calc. If it - * is still less than 0, then we need to run auto_scale. - * Otherwise, put the value into the correct units. If - * the value is 0, then do not set the symbol or magnification - * so next the calculation will be performed again. */ - if (magfact < 0.0) { + if (!im->gdes[i].strftm && im->gdes[i].vformatter == VALUE_FORMATTER_NUMERIC) { + if ((percent_s = strstr(im->gdes[i].format, "%S")) != NULL) { + /* Magfact is set to -1 upon entry to print_calc. If it + * is still less than 0, then we need to run auto_scale. + * Otherwise, put the value into the correct units. If + * the value is 0, then do not set the symbol or magnification + * so next the calculation will be performed again. */ + if (magfact < 0.0) { + auto_scale(im, &printval, &si_symb, &magfact); + if (printval == 0.0) + magfact = -1.0; + } else { + printval /= magfact; + } + *(++percent_s) = 's'; + } else if (strstr(im->gdes[i].format, "%s") != NULL) { auto_scale(im, &printval, &si_symb, &magfact); - if (printval == 0.0) - magfact = -1.0; - } else { - printval /= magfact; } - *(++percent_s) = 's'; - } else if (!im->gdes[i].strftm && strstr(im->gdes[i].format, "%s") != NULL) { - auto_scale(im, &printval, &si_symb, &magfact); } if (im->gdes[i].gf == GF_PRINT) { @@ -1736,12 +1757,41 @@ int print_calc( strftime(prline.u_str, FMT_LEG_LEN, im->gdes[i].format, &tmvdef); } - } else if (bad_format_print(im->gdes[i].format)) { - return -1; } else { - prline.u_str = - sprintf_alloc(im->gdes[i].format, printval, si_symb); + struct tm tmval; + switch(im->gdes[i].vformatter) { + case VALUE_FORMATTER_NUMERIC: + if (bad_format_print(im->gdes[i].format)) { + return -1; + } else { + prline.u_str = + sprintf_alloc(im->gdes[i].format, printval, si_symb); + } + break; + case VALUE_FORMATTER_TIMESTAMP: + if (!isfinite(printval) || timestamp_to_tm(&tmval, printval)) { + prline.u_str = sprintf_alloc("%.0f", printval); + } else { + const char *fmt; + if (im->gdes[i].format == NULL || im->gdes[i].format[0] == '\0') + fmt = default_timestamp_fmt; + else + fmt = im->gdes[i].format; + prline.u_str = (char*) malloc(FMT_LEG_LEN*sizeof(char)); + if (!prline.u_str) + return -1; + if (0 == strftime(prline.u_str, FMT_LEG_LEN, fmt, &tmval)) { + free(prline.u_str); + return -1; + } + } + break; + default: + rrd_set_error("Unsupported print value formatter"); + return -1; + } } + grinfo_push(im, sprintf_alloc ("print[%ld]", prline_cnt++), RD_I_STR, prline); @@ -1757,12 +1807,33 @@ int print_calc( FMT_LEG_LEN, im->gdes[i].format, &tmvdef); } } else { - if (bad_format_print(im->gdes[i].format)) { - return -1; + struct tm tmval; + switch(im->gdes[i].vformatter) { + case VALUE_FORMATTER_NUMERIC: + if (bad_format_print(im->gdes[i].format)) { + return -1; + } + snprintf(im->gdes[i].legend, + FMT_LEG_LEN - 2, + im->gdes[i].format, printval, si_symb); + break; + case VALUE_FORMATTER_TIMESTAMP: + if (!isfinite(printval) || timestamp_to_tm(&tmval, printval)) { + snprintf(im->gdes[i].legend, FMT_LEG_LEN, "%.0f", printval); + } else { + const char *fmt; + if (im->gdes[i].format == NULL || im->gdes[i].format[0] == '\0') + fmt = default_timestamp_fmt; + else + fmt = im->gdes[i].format; + if (0 == strftime(im->gdes[i].legend, FMT_LEG_LEN, fmt, &tmval)) + return -1; + } + break; + default: + rrd_set_error("Unsupported gprint value formatter"); + return -1; } - snprintf(im->gdes[i].legend, - FMT_LEG_LEN - 2, - im->gdes[i].format, printval, si_symb); } graphelement = 1; } @@ -2168,65 +2239,110 @@ int draw_horizontal_grid( if (i % im->ygrid_scale.labfact == 0 || (nlabels == 1 && (YN < im->yorigin - im->ysize || YN > im->yorigin))) { - if (im->symbol == ' ') { - if (im->primary_axis_format == NULL || im->primary_axis_format[0] == '\0') { - if (im->extra_flags & ALTYGRID) { - snprintf(graph_label, sizeof graph_label, - im->ygrid_scale.labfmt, - scaledstep * (double) i); - } else { - if (MaxY < 10) { - snprintf(graph_label, sizeof graph_label, "%4.1f", + switch(im->primary_axis_formatter) { + case VALUE_FORMATTER_NUMERIC: + if (im->symbol == ' ') { + if (im->primary_axis_format == NULL || im->primary_axis_format[0] == '\0') { + if (im->extra_flags & ALTYGRID) { + snprintf(graph_label, sizeof graph_label, + im->ygrid_scale.labfmt, scaledstep * (double) i); } else { - snprintf(graph_label, sizeof graph_label,"%4.0f", - scaledstep * (double) i); + if (MaxY < 10) { + snprintf(graph_label, sizeof graph_label, "%4.1f", + scaledstep * (double) i); + } else { + snprintf(graph_label, sizeof graph_label,"%4.0f", + scaledstep * (double) i); + } } + } else { + snprintf(graph_label, sizeof graph_label, im->primary_axis_format, + scaledstep * (double) i); } } else { - snprintf(graph_label, sizeof graph_label, im->primary_axis_format, - scaledstep * (double) i); - } - } else { - char sisym = (i == 0 ? ' ' : im->symbol); - if (im->primary_axis_format == NULL || im->primary_axis_format[0] == '\0') { - if (im->extra_flags & ALTYGRID) { - snprintf(graph_label,sizeof graph_label, - im->ygrid_scale.labfmt, - scaledstep * (double) i, sisym); - } else { - if (MaxY < 10) { - snprintf(graph_label, sizeof graph_label,"%4.1f %c", + char sisym = (i == 0 ? ' ' : im->symbol); + if (im->primary_axis_format == NULL || im->primary_axis_format[0] == '\0') { + if (im->extra_flags & ALTYGRID) { + snprintf(graph_label,sizeof graph_label, + im->ygrid_scale.labfmt, scaledstep * (double) i, sisym); } else { - snprintf(graph_label, sizeof graph_label, "%4.0f %c", - scaledstep * (double) i, sisym); + if (MaxY < 10) { + snprintf(graph_label, sizeof graph_label,"%4.1f %c", + scaledstep * (double) i, sisym); + } else { + snprintf(graph_label, sizeof graph_label, "%4.0f %c", + scaledstep * (double) i, sisym); + } } + } else { + sprintf(graph_label, im->primary_axis_format, + scaledstep * (double) i, sisym); } - } else { - sprintf(graph_label, im->primary_axis_format, - scaledstep * (double) i, sisym); } + break; + case VALUE_FORMATTER_TIMESTAMP: + { + struct tm tm; + const char *yfmt; + if (im->primary_axis_format == NULL || im->primary_axis_format[0] == '\0') + yfmt = default_timestamp_fmt; + else + yfmt = im->primary_axis_format; + if (timestamp_to_tm(&tm, im->ygrid_scale.gridstep*i)) + snprintf(graph_label, sizeof graph_label, "%f", + im->ygrid_scale.gridstep * i); + else + if (0 == strftime(graph_label, sizeof graph_label, yfmt, &tm)) + graph_label[0] = '\0'; + } + break; + default: + rrd_set_error("Unsupported left axis value formatter"); + return -1; } nlabels++; if (im->second_axis_scale != 0){ char graph_label_right[100]; double sval = im->ygrid_scale.gridstep*(double)i*im->second_axis_scale+im->second_axis_shift; - if (im->second_axis_format == NULL || im->second_axis_format[0] == '\0') { - if (!second_axis_magfact){ - double dummy = im->ygrid_scale.gridstep*(double)(sgrid+egrid)/2.0*im->second_axis_scale+im->second_axis_shift; - auto_scale(im,&dummy,&second_axis_symb,&second_axis_magfact); - } - sval /= second_axis_magfact; + switch(im->second_axis_formatter) { + case VALUE_FORMATTER_NUMERIC: + if (im->second_axis_format == NULL || im->second_axis_format[0] == '\0') { + if (!second_axis_magfact){ + double dummy = im->ygrid_scale.gridstep*(double)(sgrid+egrid)/2.0*im->second_axis_scale+im->second_axis_shift; + auto_scale(im,&dummy,&second_axis_symb,&second_axis_magfact); + } + sval /= second_axis_magfact; - if(MaxY < 10) { - snprintf(graph_label_right, sizeof graph_label_right, "%5.1f %s",sval,second_axis_symb); - } else { - snprintf(graph_label_right, sizeof graph_label_right, "%5.0f %s",sval,second_axis_symb); + if(MaxY < 10) { + snprintf(graph_label_right, sizeof graph_label_right, "%5.1f %s",sval,second_axis_symb); + } else { + snprintf(graph_label_right, sizeof graph_label_right, "%5.0f %s",sval,second_axis_symb); + } } - } - else { - snprintf(graph_label_right, sizeof graph_label_right, im->second_axis_format,sval,""); + else { + snprintf(graph_label_right, sizeof graph_label_right, im->second_axis_format,sval,""); + } + break; + case VALUE_FORMATTER_TIMESTAMP: + { + struct tm tm; + const char *yfmt; + if (im->second_axis_format == NULL || im->second_axis_format[0] == '\0') + yfmt = default_timestamp_fmt; + else + yfmt = im->second_axis_format; + if (timestamp_to_tm(&tm, sval)) + snprintf(graph_label_right, sizeof graph_label_right, "%f", sval); + else + if (0 == strftime(graph_label_right, sizeof graph_label, yfmt, &tm)) + graph_label_right[0] = '\0'; + } + break; + default: + rrd_set_error("Unsupported right axis value formatter"); + return -1; } gfx_text ( im, X1+7, Y0, @@ -2770,7 +2886,7 @@ void axis_paint( } -void grid_paint( +int grid_paint( image_desc_t *im) { long i; @@ -2802,6 +2918,8 @@ void grid_paint( res = horizontal_log_grid(im); } else { res = draw_horizontal_grid(im); + if (res < 0) + return -1; } /* dont draw horizontal grid if there is no min and max val */ @@ -3026,6 +3144,7 @@ void grid_paint( } } } + return 0; } @@ -3898,7 +4017,8 @@ int graph_paint_timestring( /* grid_paint also does the text */ if (!(im->extra_flags & ONLY_GRAPH)) - grid_paint(im); + if (grid_paint(im)) + return -1; if (!(im->extra_flags & ONLY_GRAPH)) axis_paint(im); /* the RULES are the last thing to paint ... */ @@ -4128,6 +4248,7 @@ int gdes_alloc( 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].vformatter = VALUE_FORMATTER_NUMERIC; im->gdes[im->gdes_c - 1].rrd[0] = '\0'; im->gdes[im->gdes_c - 1].ds = -1; im->gdes[im->gdes_c - 1].cf_reduce = CF_AVERAGE; @@ -4426,7 +4547,9 @@ void rrd_graph_init( im->second_axis_shift = 0; /* no shift by default */ im->second_axis_legend = NULL; im->second_axis_format = NULL; + im->second_axis_formatter = VALUE_FORMATTER_NUMERIC; im->primary_axis_format = NULL; + im->primary_axis_formatter = VALUE_FORMATTER_NUMERIC; im->yorigin = 0; im->yOriginLegend = 0; im->yOriginLegendY = 0; @@ -4555,6 +4678,8 @@ void rrd_graph_options( { "week-fmt", required_argument, 0, 1010}, { "graph-type", required_argument, 0, 1011}, { "left-axis-format", required_argument, 0, 1012}, + { "left-axis-formatter",required_argument, 0, 1013}, + { "right-axis-formatter",required_argument,0, 1014}, { 0, 0, 0, 0} }; /* *INDENT-ON* */ @@ -4781,9 +4906,6 @@ void rrd_graph_options( } break; case 1004: - if (bad_format_axis(optarg)){ - return; - } im->second_axis_format=strdup(optarg); if (!im->second_axis_format) { rrd_set_error("cannot allocate memory for second_axis_format"); @@ -4791,15 +4913,32 @@ void rrd_graph_options( } break; case 1012: - if (bad_format_axis(optarg)){ - return; - } im->primary_axis_format=strdup(optarg); if (!im->primary_axis_format) { rrd_set_error("cannot allocate memory for primary_axis_format"); return; } break; + case 1013: + if (!strcmp(optarg, "numeric")) { + im->primary_axis_formatter = VALUE_FORMATTER_NUMERIC; + } else if (!strcmp(optarg, "timestamp")) { + im->primary_axis_formatter = VALUE_FORMATTER_TIMESTAMP; + } else { + rrd_set_error("Unknown left axis formatter"); + return; + } + break; + case 1014: + if (!strcmp(optarg, "numeric")) { + im->second_axis_formatter = VALUE_FORMATTER_NUMERIC; + } else if (!strcmp(optarg, "timestamp")) { + im->second_axis_formatter = VALUE_FORMATTER_TIMESTAMP; + } else { + rrd_set_error("Unknown right axis formatter"); + return; + } + break; case 'v': im->ylegend=strdup(optarg); if (!im->ylegend) { @@ -5050,6 +5189,33 @@ void rrd_graph_options( pango_layout_context_changed(im->layout); + if (im->primary_axis_format != NULL && im->primary_axis_format[0] != '\0') { + switch(im->primary_axis_formatter) { + case VALUE_FORMATTER_NUMERIC: + if (bad_format_axis(im->primary_axis_format)) + return; + break; + case VALUE_FORMATTER_TIMESTAMP: + break; + default: + rrd_set_error("Unchecked left axis formatter"); + return; + } + } + + if (im->second_axis_format != NULL && im->second_axis_format[0] != '\0') { + switch(im->second_axis_formatter) { + case VALUE_FORMATTER_NUMERIC: + if (bad_format_axis(im->second_axis_format)) + return; + break; + case VALUE_FORMATTER_TIMESTAMP: + break; + default: + rrd_set_error("Unchecked right axis formatter"); + return; + } + } if (im->logarithmic && im->minval <= 0) { rrd_set_error diff --git a/src/rrd_graph.h b/src/rrd_graph.h index 1429d086..faf629b3 100644 --- a/src/rrd_graph.h +++ b/src/rrd_graph.h @@ -191,6 +191,11 @@ typedef struct ylab_t { int lfac[4]; /* associated label spacing */ } ylab_t; +enum value_formatter_en { + VALUE_FORMATTER_NUMERIC, /* printf */ + VALUE_FORMATTER_TIMESTAMP, /* strftime */ +}; + /* this structure describes the elements which can make up a graph. because they are quite diverse, not all elements will use all the possible parts of the structure. */ @@ -220,7 +225,8 @@ typedef struct graph_desc_t { double gradheight; char format[FMT_LEG_LEN + 5]; /* format for PRINT AND GPRINT */ char legend[FMT_LEG_LEN + 5]; /* legend */ - int strftm; /* should the VDEF legend be formated with strftime */ + int strftm; /* should the VDEF legend be the time component formated with strftime */ + enum value_formatter_en vformatter; /* what value formatter to use (if !strftm) */ double leg_x, leg_y; /* location of legend */ double yrule; /* value for y rule line and for VDEF */ time_t xrule; /* time for x rule line and for VDEF */ @@ -281,7 +287,9 @@ typedef struct image_desc_t { double second_axis_shift; /* how much is it shifted vs the first axis */ char *second_axis_legend; /* label to put on the seond axis */ char *second_axis_format; /* format for the numbers on the scond axis */ + enum value_formatter_en second_axis_formatter; /* How to format axis values */ char *primary_axis_format; /* format for the numbers on the primary axis */ + enum value_formatter_en primary_axis_formatter; /* How to format axis values */ double ygridstep; /* user defined step for y grid */ int ylabfact; /* every how many y grid shall a label be written ? */ double tabwidth; /* tabwdith */ @@ -415,7 +423,7 @@ void vertical_grid( image_desc_t *); void axis_paint( image_desc_t *); -void grid_paint( +int grid_paint( image_desc_t *); int lazy_check( image_desc_t *); diff --git a/src/rrd_graph_helper.c b/src/rrd_graph_helper.c index 2cf5f71c..566cdbfa 100644 --- a/src/rrd_graph_helper.c +++ b/src/rrd_graph_helper.c @@ -253,6 +253,9 @@ int parseArguments(const char* origarg, parsedargs_t* pa) { } else if ((poscnt>0)&&(strcmp(field,"strftime")==0)) { key="strftime"; value="1"; + } else if ((poscnt>0)&&(strcmp(field,"valstrftime")==0)) { + key="vformatter"; + value="timestamp"; } else if ((poscnt>0)&&(strcmp(field,"skipscale")==0)) { key="skipscale"; value="1"; @@ -362,7 +365,7 @@ int parse_color( const char *const string, struct gfx_color_t *c) #define PARSE_DASHES (PARSE_FIELD1|(1ULL<<20)) #define PARSE_HEIGHT (PARSE_FIELD1|(1ULL<<21)) #define PARSE_FORMAT (PARSE_FIELD1|(1ULL<<22)) -#define PARSE_STRFTIME (PARSE_FIELD1|(1ULL<<23)) +#define PARSE_STRFTIMEVFMT (PARSE_FIELD1|(1ULL<<23)) #define PARSE_FRACTION (PARSE_FIELD1|(1ULL<<24)) /* VNAME Special cases for generic parsing */ #define PARSE_VNAMEDEF (PARSE_VNAME|(1ULL<<57)) @@ -470,9 +473,18 @@ static graph_desc_t* newGraphDescription(image_desc_t *const im,enum gf_en gf,pa dprintfparsed("got format: %s\n",format); } } - if (bitscmp(PARSE_STRFTIME)) { + if (bitscmp(PARSE_STRFTIMEVFMT)) { char *strft=getKeyValueArgument("strftime",1,pa); + char *frmtr=getKeyValueArgument("vformatter",1,pa); gdp->strftm=(strft)?1:0; + if (frmtr != NULL) { + if (strcmp(frmtr,"timestamp") == 0) { + gdp->vformatter = VALUE_FORMATTER_TIMESTAMP; + } else { + rrd_set_error("Unsupported vformatter: %s", frmtr); + return NULL; + } + } dprintfparsed("got strftime: %s\n",strft); } if (bitscmp(PARSE_STACK)) { @@ -1206,7 +1218,7 @@ int parse_gprint(enum gf_en gf,parsedargs_t*pa,image_desc_t *const im) { PARSE_VNAMEREF |PARSE_CF |PARSE_FORMAT - |PARSE_STRFTIME + |PARSE_STRFTIMEVFMT ); if (!gdp) { return 1;} /* here we parse pos arguments locally */ diff --git a/tests/Makefile.am b/tests/Makefile.am index dfd245b6..0dc1b1a3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,7 +4,7 @@ TESTS = modify1 modify2 modify3 modify4 modify5 \ dump-restore \ create-with-source-1 create-with-source-2 create-with-source-3 \ create-with-source-4 create-with-source-and-mapping-1 \ - create-from-template-1 dcounter1 + create-from-template-1 dcounter1 vformatter1 EXTRA_DIST = Makefile.am \ alltests functions \ modify1 modify-test1.create.dump modify-test1.mod1.dump \ @@ -15,7 +15,7 @@ EXTRA_DIST = Makefile.am \ rrdcreate \ tune1 tune1-testa-mod1.dump tune1-testa-mod2.dump tune1-testorg.dump \ tune2 tune2-testa-mod1.dump tune2-testorg.dump \ - valgrind-supressions dcounter1 dcounter1.output + valgrind-supressions dcounter1 dcounter1.output vformatter1 # NB: AM_TESTS_ENVIRONMENT not available until automake 1.12 TESTS_ENVIRONMENT = \ BASEDIR=${abs_srcdir} ; export BASEDIR ; \ diff --git a/tests/Makefile.in b/tests/Makefile.in index f04d0f83..f20bbe92 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -530,7 +530,7 @@ TESTS = modify1 modify2 modify3 modify4 modify5 \ dump-restore \ create-with-source-1 create-with-source-2 create-with-source-3 \ create-with-source-4 create-with-source-and-mapping-1 \ - create-from-template-1 dcounter1 + create-from-template-1 dcounter1 vformatter1 EXTRA_DIST = Makefile.am \ alltests functions \ @@ -542,7 +542,7 @@ EXTRA_DIST = Makefile.am \ rrdcreate \ tune1 tune1-testa-mod1.dump tune1-testa-mod2.dump tune1-testorg.dump \ tune2 tune2-testa-mod1.dump tune2-testorg.dump \ - valgrind-supressions dcounter1 dcounter1.output + valgrind-supressions dcounter1 dcounter1.output vformatter1 # NB: AM_TESTS_ENVIRONMENT not available until automake 1.12 TESTS_ENVIRONMENT = \ @@ -861,6 +861,13 @@ dcounter1.log: dcounter1 --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +vformatter1.log: vformatter1 + @p='vformatter1'; \ + b='vformatter1'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) .test.log: @p='$<'; \ $(am__set_b); \ diff --git a/tests/vformatter1 b/tests/vformatter1 new file mode 100755 index 00000000..587dfdf2 --- /dev/null +++ b/tests/vformatter1 @@ -0,0 +1,43 @@ +#!/bin/bash + +. $(dirname $0)/functions + +export TZ=UTC + +function rtest() { + testname="$1" + xpected="$2" + shift 2 || exit 1 + diff -u <(echo -e "$xpected") <($RRDTOOL "$@") + report "$testname" + #&& echo "OK: $testname" || echo "FAIL: $testname" +} + +$RRDTOOL create vfmt1.rrd --start 1420070400 --step 60s DS:v:GAUGE:60:U:U RRA:LAST:0:1:10 || exit 1 + +declare -a graphargs +graphargs=(graph /dev/null --start 1420070400 --end 1420071000 'DEF:dv=vfmt1.rrd:v:LAST' 'VDEF:v=dv,LAST') + +rtest "No data, numeric" '0x0\n-nan' "${graphargs[@]}" 'PRINT:v:%0.1lf' + +rtest "No data, sampling timestamp" '0x0\n---------- --:--:--' "${graphargs[@]}" 'PRINT:v:%F %T:strftime' + +rtest "No data, value timestamp" '0x0\n-nan' "${graphargs[@]}" 'PRINT:v:%F %T:valstrftime' + + +$RRDTOOL update vfmt1.rrd --template v -- 1420070460:0 || exit 1 + +rtest "Zero, numeric" '0x0\n0.0' "${graphargs[@]}" 'PRINT:v:%0.1lf' + +rtest "Zero, sampling timestamp" '0x0\n2015-01-01 00:01:00' "${graphargs[@]}" 'PRINT:v:%F %T:strftime' + +rtest "Zero, value timestamp" '0x0\n1970-01-01 00:00:00' "${graphargs[@]}" 'PRINT:v:%F %T:valstrftime' + +$RRDTOOL update vfmt1.rrd --template v -- 1420070520:3000 || exit 1 + +rtest "3000, numeric" '0x0\n3000.0' "${graphargs[@]}" 'PRINT:v:%0.1lf' + +rtest "3000, sampling timestamp" '0x0\n2015-01-01 00:02:00' "${graphargs[@]}" 'PRINT:v:%F %T:strftime' + +rtest "3000, value timestamp" '0x0\n1970-01-01 00:50:00' "${graphargs[@]}" 'PRINT:v:%F %T:valstrftime' +