From 8e5aef37a56ba9b8e7ca5b8db173ebd22bcfe510 Mon Sep 17 00:00:00 2001 From: Teemu Toivola Date: Mon, 1 Feb 2021 22:44:34 +0200 Subject: [PATCH] add configuration option BarColumnShowsRate to have the bar column in image list outputs be scaled according to the average rate column values when those values are visible, disabled by default (issue #170) --- CHANGES | 3 +++ UPGRADE.md | 2 +- cfg/vnstat.conf | 4 ++++ man/vnstat.conf.5 | 14 ++++++++++++- src/cfg.c | 11 ++++++++++ src/cfgoutput.c | 4 ++++ src/common.h | 5 ++++- src/image.c | 50 ++++++++++++++++++++++++++++++--------------- src/image.h | 2 +- src/misc.c | 27 +++++++++++++++++++++--- tests/image_tests.c | 6 ++++-- 11 files changed, 103 insertions(+), 25 deletions(-) diff --git a/CHANGES b/CHANGES index 6db50f9..9ff61d2 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,9 @@ - Add --initdb to daemon for creating a new empty database without having the daemon process staying running, doesn't discard data if a database already exists + - Add configuration option BarColumnShowsRate to have the bar column + in image list outputs be scaled according to the average rate column + values when those values are visible, disabled by default 2.6 / 20-Jan-2020 diff --git a/UPGRADE.md b/UPGRADE.md index 4283dc9..3041031 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,7 +1,7 @@ # New configuration settings - * 2.7: EstimateBarVisible, EstimateStyle, ImageScale + * 2.7: BarColumnShowsRate, EstimateBarVisible, EstimateStyle, ImageScale * 2.4 - 2.6: (none) diff --git a/cfg/vnstat.conf b/cfg/vnstat.conf index a6b0c96..0857cf5 100644 --- a/cfg/vnstat.conf +++ b/cfg/vnstat.conf @@ -179,6 +179,10 @@ ImageScale 100 # (0 = not shown, 1 = continuation of existing bar, 2 = separate bar) EstimateStyle 1 +# bar column in list outputs shows rate if OutputStyle is 3 +# (1 = enabled, 0 = disabled) +BarColumnShowsRate 0 + # image colors CBackground "FFFFFF" CEdge "AEAEAE" diff --git a/man/vnstat.conf.5 b/man/vnstat.conf.5 index bef97ce..93b272a 100644 --- a/man/vnstat.conf.5 +++ b/man/vnstat.conf.5 @@ -1,4 +1,4 @@ -.TH VNSTAT.CONF 5 "JANUARY 2020" "version 2.6" "User Manuals" +.TH VNSTAT.CONF 5 "FEBRUARY 2021" "version 2.7" "User Manuals" .SH NAME vnstat.conf \- vnStat configuration file @@ -372,6 +372,18 @@ resolution. .SH IMAGE OUTPUT RELATED KEYWORDS +.TP +.B BarColumnShowsRate +The bar column represents traffic rate in list outputs when enabled. Requires +also that +.B OutputStyle +has been configured to show the traffic rate column by using the value 3. +Enabling this option will automatically cause +.B EstimateStyle +to have the value 0. Visually this option affects only the color legend text and +the last line on the list if that line represents the currently ongoing time +period. 1 = enabled, 0 = disabled. + .TP .B CBackground Background color. diff --git a/src/cfg.c b/src/cfg.c index 229473c..c35cf96 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -73,6 +73,7 @@ int loadcfg(const char *cfgfile) {"TransparentBg", 0, &cfg.transbg, 0, 0}, {"ImageScale", 0, &cfg.imagescale, 0, 0}, {"EstimateStyle", 0, &cfg.estimatestyle, 0, 0}, + {"BarColumnShowsRate", 0, &cfg.barshowsrate, 0, 0}, {"CBackground", cfg.cbg, 0, 8, 0}, {"CEdge", cfg.cedge, 0, 8, 0}, {"CHeader", cfg.cheader, 0, 8, 0}, @@ -202,6 +203,7 @@ void validatecfg(void) validatebool("TransparentBg", &cfg.transbg, TRANSBG); validateint("ImageScale", &cfg.imagescale, IMAGESCALE, 50, 500); validateint("EstimateStyle", &cfg.estimatestyle, ESTIMATESTYLE, 0, 2); + validatebool("BarColumnShowsRate", &cfg.barshowsrate, BARSHOWSRATE); validatebool("HourlyRate", &cfg.hourlyrate, HOURLYRATE); validatebool("SummaryRate", &cfg.summaryrate, SUMMARYRATE); validatebool("TrafficlessEntries", &cfg.trafficlessentries, TRAFFICLESSENTRIES); @@ -283,6 +285,14 @@ void validatecfg(void) printe(PT_Config); } } + + /* affects only image output */ + if (cfg.barshowsrate && cfg.estimatebarvisible) { + cfg.estimatestyle = 0; + if (debug) { + printf("BarColumnShowsRate and EstimateBarVisible both enabled -> EstimateStyle set to 0\n"); + } + } } void defaultcfg(void) @@ -358,6 +368,7 @@ void defaultcfg(void) cfg.transbg = TRANSBG; cfg.imagescale = IMAGESCALE; cfg.estimatestyle = ESTIMATESTYLE; + cfg.barshowsrate = BARSHOWSRATE; strncpy_nt(cfg.cbg, CBACKGROUND, 8); strncpy_nt(cfg.cedge, CEDGE, 8); strncpy_nt(cfg.cheader, CHEADER, 8); diff --git a/src/cfgoutput.c b/src/cfgoutput.c index 4e3912f..7d40fd1 100644 --- a/src/cfgoutput.c +++ b/src/cfgoutput.c @@ -195,6 +195,10 @@ void printcfgfile(void) printf("# (0 = not shown, 1 = continuation of existing bar, 2 = separate bar)\n"); printf("EstimateStyle %d\n\n", cfg.estimatestyle); + printf("# bar column in list outputs shows rate if OutputStyle is 3\n"); + printf("# (1 = enabled, 0 = disabled)\n"); + printf("BarColumnShowsRate %d\n\n", cfg.barshowsrate); + printf("# image colors\n"); printf("CBackground \"%s\"\n", cfg.cbg); printf("CEdge \"%s\"\n", cfg.cedge); diff --git a/src/common.h b/src/common.h index 097e30f..838ad4e 100644 --- a/src/common.h +++ b/src/common.h @@ -251,6 +251,9 @@ and most can be changed later from the config file. /* 0 = not shown, 1 = continuation of existing bar, 2 = separate bar */ #define ESTIMATESTYLE 1 +/* bar column in list outputs shows rate when rate column is visible */ +#define BARSHOWSRATE 0 + /* default colors */ #define CBACKGROUND "FFFFFF" #define CEDGE "AEAEAE" @@ -282,7 +285,7 @@ typedef struct { int32_t unitmode, rateunitmode, rateunit, bvar, qmode, sampletime, hourlyrate, summaryrate; int32_t monthrotate, monthrotateyears, maxbw, spacecheck, trafficlessentries, transbg, ostyle; int32_t defaultdecimals, hourlydecimals, hourlystyle, is64bit, waldb, dbsynchronous, imagescale; - int32_t estimatebarvisible, estimatestyle; + int32_t estimatebarvisible, estimatestyle, barshowsrate; char cfgfile[512], logfile[512], pidfile[512]; char daemonuser[33], daemongroup[33]; int32_t timesyncwait, updateinterval, pollinterval, saveinterval, offsaveinterval, savestatus; diff --git a/src/image.c b/src/image.c index 8b91d24..a713263 100644 --- a/src/image.c +++ b/src/image.c @@ -211,18 +211,25 @@ void layoutinit(IMAGECONTENT *ic, char *title, const int width, const int height gdImageString(ic->im, gdFontGetTiny(), width - 114 - ic->showedge, height - 12 - ic->showedge, (unsigned char *)"vnStat / Teemu Toivola", ic->cvnstat); } -void drawlegend(IMAGECONTENT *ic, const int x, const int y) +void drawlegend(IMAGECONTENT *ic, const int x, const int y, const short israte) { if (!ic->showlegend) { return; } - /* color legend */ - gdImageString(ic->im, gdFontGetSmall(), x, y, (unsigned char *)"rx tx", ic->ctext); - gdImageFilledRectangle(ic->im, x - 12, y + 4, x - 6, y + 10, ic->crx); - gdImageRectangle(ic->im, x - 12, y + 4, x - 6, y + 10, ic->ctext); - gdImageFilledRectangle(ic->im, x + 30, y + 4, x + 36, y + 10, ic->ctx); - gdImageRectangle(ic->im, x + 30, y + 4, x + 36, y + 10, ic->ctext); + if (!israte) { + gdImageString(ic->im, gdFontGetSmall(), x, y, (unsigned char *)"rx tx", ic->ctext); + gdImageFilledRectangle(ic->im, x - 12, y + 4, x - 6, y + 10, ic->crx); + gdImageRectangle(ic->im, x - 12, y + 4, x - 6, y + 10, ic->ctext); + gdImageFilledRectangle(ic->im, x + 30, y + 4, x + 36, y + 10, ic->ctx); + gdImageRectangle(ic->im, x + 30, y + 4, x + 36, y + 10, ic->ctext); + } else { + gdImageString(ic->im, gdFontGetSmall(), x - 12, y, (unsigned char *)"rx tx rate", ic->ctext); + gdImageFilledRectangle(ic->im, x - 22, y + 4, x - 16, y + 10, ic->crx); + gdImageRectangle(ic->im, x - 22, y + 4, x - 16, y + 10, ic->ctext); + gdImageFilledRectangle(ic->im, x + 8, y + 4, x + 14, y + 10, ic->ctx); + gdImageRectangle(ic->im, x + 8, y + 4, x + 14, y + 10, ic->ctext); + } } void drawbar(IMAGECONTENT *ic, const int x, const int y, const int len, const uint64_t rx, const uint64_t tx, const uint64_t max, const short isestimate) @@ -542,7 +549,7 @@ void drawhourly(IMAGECONTENT *ic, const int rate) layoutinit(ic, buffer, width, height); if (drawhours(ic, 12, 46 - headermod, rate)) { - drawlegend(ic, 242, 183 - headermod); + drawlegend(ic, 242, 183 - headermod, 0); } } @@ -551,7 +558,7 @@ void drawlist(IMAGECONTENT *ic, const char *listname) ListType listtype = LT_None; int textx, texty, offsetx = 0, offsety = 0; int width, height, headermod, i = 1, rowcount = 0; - int estimatevisible = 0; + int estimateavailable = 0, estimatevisible = 0; int32_t limit; uint64_t e_rx = 0, e_tx = 0, e_secs = 0; char buffer[512], datebuff[16], daybuff[16]; @@ -611,12 +618,15 @@ void drawlist(IMAGECONTENT *ic, const char *listname) datalist_i = datalist; - if (strlen(ic->dataend) == 0 && datainfo.count > 0 && (listtype == LT_Day || listtype == LT_Month || listtype == LT_Year)) { - estimatevisible = 1; + if (strlen(ic->dataend) == 0 && datainfo.count > 0 && listtype != LT_Top) { getestimates(&e_rx, &e_tx, listtype, ic->interface.updated, &datalist); if (cfg.estimatestyle > 0 && e_rx + e_tx > datainfo.max) { datainfo.max = e_rx + e_tx; } + estimateavailable = 1; + if (listtype == LT_Day || listtype == LT_Month || listtype == LT_Year) { + estimatevisible = 1; + } } if (listtype == LT_Top) { @@ -694,16 +704,20 @@ void drawlist(IMAGECONTENT *ic, const char *listname) if (datainfo.count) { if (listtype == LT_Top) { if (cfg.ostyle <= 2) { - drawlegend(ic, 398, 40 - headermod); + drawlegend(ic, 398, 40 - headermod, 0); } current = time(NULL); d = localtime(¤t); strftime(daybuff, 16, stampformat, d); } else { // everything else if (cfg.ostyle > 2) { - drawlegend(ic, 432, 40 - headermod); + if (estimateavailable && cfg.barshowsrate) { + drawlegend(ic, 432, 40 - headermod, 1); + } else { + drawlegend(ic, 432, 40 - headermod, 0); + } } else { - drawlegend(ic, 385, 40 - headermod); + drawlegend(ic, 385, 40 - headermod, 0); } } } @@ -788,7 +802,11 @@ void drawlist(IMAGECONTENT *ic, const char *listname) } } else { // everything else if (cfg.ostyle > 2) { - drawbar(ic, textx + 400, texty + 4, 78, datalist_i->rx, datalist_i->tx, datainfo.max, 0); + if (datalist_i->next == NULL && estimateavailable && cfg.barshowsrate) { + drawbar(ic, textx + 400, texty + 4, 78, e_rx, e_tx, datainfo.max, 0); + } else { + drawbar(ic, textx + 400, texty + 4, 78, datalist_i->rx, datalist_i->tx, datainfo.max, 0); + } } else { drawbar(ic, textx + 304, texty + 4, 170, datalist_i->rx, datalist_i->tx, datainfo.max, 0); } @@ -911,7 +929,7 @@ void drawsummary(IMAGECONTENT *ic, const int layout, const int rate) } drawsummary_alltime(ic, 385, 57 - headermod); - drawlegend(ic, 410, 155 - headermod); + drawlegend(ic, 410, 155 - headermod, 0); drawsummary_digest(ic, 100, 30 - headermod, "day"); drawsummary_digest(ic, 100, 113 - headermod, "month"); diff --git a/src/image.h b/src/image.h index 23372d6..e3f09c2 100644 --- a/src/image.h +++ b/src/image.h @@ -38,7 +38,7 @@ void scaleimage(IMAGECONTENT *ic); void colorinit(IMAGECONTENT *ic); void colorinitcheck(const char *color, const int value, const char *cfgtext, const int *rgb); void layoutinit(IMAGECONTENT *ic, char *title, const int width, const int height); -void drawlegend(IMAGECONTENT *ic, const int x, const int y); +void drawlegend(IMAGECONTENT *ic, const int x, const int y, const short israte); void drawbar(IMAGECONTENT *ic, const int x, const int y, const int len, const uint64_t rx, const uint64_t tx, const uint64_t max, const short isestimate); void drawpole(IMAGECONTENT *ic, const int x, const int y, const int len, const uint64_t rx, const uint64_t tx, const uint64_t max); void drawdonut(IMAGECONTENT *ic, const int x, const int y, const float rxp, const float txp); diff --git a/src/misc.c b/src/misc.c index 3151c5b..1900df1 100644 --- a/src/misc.c +++ b/src/misc.c @@ -446,6 +446,7 @@ int issametimeslot(const ListType listtype, const time_t entry, const time_t upd return 0; } +// TODO: tests uint64_t getperiodseconds(const ListType listtype, const time_t entry, const time_t updated, const short isongoing) { struct tm e, u; @@ -486,6 +487,7 @@ uint64_t getperiodseconds(const ListType listtype, const time_t entry, const tim return seconds; } +// TODO: tests void getestimates(uint64_t *rx, uint64_t *tx, const ListType listtype, const time_t updated, dbdatalist **dbdata) { struct tm u; @@ -511,9 +513,28 @@ void getestimates(uint64_t *rx, uint64_t *tx, const ListType listtype, const tim return; } - if (listtype == LT_Day) { - div = (uint64_t)(u.tm_hour * 60 + u.tm_min); - mult = 1440; + /* LT_5min and LT_Hour don't have the estimate line visible in outputs */ + /* but are used by BarColumnShowsRate which requires "past" values for */ + /* full hours / 5 minutes for the bar to show correctly */ + if (listtype == LT_5min) { + div = (uint64_t)((u.tm_min % 5 * 60) + u.tm_sec); + if (div == 0) { + div = 1; + mult = 1; + } else { + mult = 300; + } + } else if (listtype == LT_Hour) { + div = (uint64_t)(u.tm_min * 60 + u.tm_sec); + if (div == 0) { + div = 1; + mult = 1; + } else { + mult = 3600; + } + } else if (listtype == LT_Day) { + div = (uint64_t)(u.tm_hour * 3600 + u.tm_min * 60 + u.tm_sec); + mult = 86400; } else if (listtype == LT_Month) { div = (uint64_t)mosecs(datalist_i->timestamp, updated); mult = (uint64_t)(dmonth(u.tm_mon) * 86400); diff --git a/tests/image_tests.c b/tests/image_tests.c index a056353..02f7b5c 100644 --- a/tests/image_tests.c +++ b/tests/image_tests.c @@ -420,7 +420,8 @@ START_TEST(libgd_output_comparison) pngout = fopen("vnstati_libgd_comparison_check.png", "w"); ck_assert_ptr_ne(pngout, NULL); - drawlegend(&ic, 40, 30); + drawlegend(&ic, 40, 30, 0); + drawlegend(&ic, 240, 30, 1); /* line 1 */ x = 40; @@ -645,7 +646,8 @@ START_TEST(element_output_check) gdImageString(ic.im, gdFontGetSmall(), 1020, 100, (unsigned char *)"Small - The quick brown fox jumps over the lazy dog", ic.ctext); gdImageString(ic.im, gdFontGetTiny(), 1020, 120, (unsigned char *)"Tiny - The quick brown fox jumps over the lazy dog", ic.ctext); - drawlegend(&ic, 1230, 140); + drawlegend(&ic, 1130, 140, 0); + drawlegend(&ic, 1330, 140, 1); drawbar(&ic, 1050, 160, 400, 50, 50, 100, 0); drawbar(&ic, 1050, 180, 400, 25, 75, 100, 0);