diff --git a/src/dbjson.c b/src/dbjson.c index 61bde18..1e5b0c7 100644 --- a/src/dbjson.c +++ b/src/dbjson.c @@ -124,7 +124,7 @@ void jsonpercentile(const interfaceinfo *interface) { percentiledata pdata; - if (!getpercentiledata(&pdata, interface->name)) { + if (!getpercentiledata(&pdata, interface->name, 0)) { exit(EXIT_FAILURE); } diff --git a/src/dbshow.c b/src/dbshow.c index 78cb4cb..e85dd6f 100644 --- a/src/dbshow.c +++ b/src/dbshow.c @@ -884,7 +884,7 @@ void show95thpercentile(const interfaceinfo *interface) printf(" \"5MinuteHours\" is currently set at %d.\n\n", cfg.fiveminutehours); } - if (!getpercentiledata(&pdata, interface->name)) { + if (!getpercentiledata(&pdata, interface->name, 0)) { exit(EXIT_FAILURE); } @@ -922,7 +922,7 @@ void show95thpercentile(const interfaceinfo *interface) showpercentiledataminavgmaxtable(&pdata, 7); indent(7); - printf(" 95th %% %s |", gettrafficrate(pdata.rxpercentile, 300, 15)); + printf(" 95th %% %s |", gettrafficrate(pdata.rxpercentile, 300, 15)); printf("%s |", gettrafficrate(pdata.txpercentile, 300, 15)); printf("%s\n", gettrafficrate(pdata.sumpercentile, 300, 15)); @@ -932,23 +932,23 @@ void show95thpercentile(const interfaceinfo *interface) void showpercentiledataminavgmaxtable(const percentiledata *pdata, const int indentation) { indent(indentation); - printf(" rx | tx | total\n"); + printf(" rx | tx | total\n"); indent(indentation); - printf("--------------------------+----------------+---------------\n"); + printf("----------------------------+----------------+---------------\n"); indent(indentation); - printf("minimum %s |", gettrafficrate(pdata->minrx, 300, 15)); + printf("minimum %s |", gettrafficrate(pdata->minrx, 300, 15)); printf("%s |", gettrafficrate(pdata->mintx, 300, 15)); printf("%s\n", gettrafficrate(pdata->min, 300, 15)); indent(indentation); - printf("average %s |", gettrafficrate(pdata->sumrx, (time_t)(pdata->count * 300), 15)); + printf("average %s |", gettrafficrate(pdata->sumrx, (time_t)(pdata->count * 300), 15)); printf("%s |", gettrafficrate(pdata->sumtx, (time_t)(pdata->count * 300), 15)); printf("%s\n", gettrafficrate(pdata->sumrx + pdata->sumtx, (time_t)(pdata->count * 300), 15)); indent(indentation); - printf("maximum %s |", gettrafficrate(pdata->maxrx, 300, 15)); + printf("maximum %s |", gettrafficrate(pdata->maxrx, 300, 15)); printf("%s |", gettrafficrate(pdata->maxtx, 300, 15)); printf("%s\n", gettrafficrate(pdata->max, 300, 15)); indent(indentation); - printf("--------------------------+----------------+---------------\n"); + printf("----------------------------+----------------+---------------\n"); } int showbar(const uint64_t rx, const uint64_t tx, const uint64_t max, const int len) @@ -1054,12 +1054,13 @@ int showalert(const char *interface, const AlertOutput output, const AlertExit a printf(" \"5MinuteHours\" is currently set at %d.\n\n", cfg.fiveminutehours); } - if (!getpercentiledata(&pdata, ifaceinfo.name)) { + if (!getpercentiledata(&pdata, ifaceinfo.name, limit)) { exit(EXIT_FAILURE); } timestamp = pdata.dataend; } + // "limit" and "used" are always in either bytes or bytes/second switch (condition) { case AC_None: return 0; @@ -1119,12 +1120,6 @@ int showalert(const char *interface, const AlertOutput output, const AlertExit a break; } - // cfg.rateunit and cfg.rateunitmode are set for AT_Percentile in parsealertargs() - // TODO: should everything else also follow this logic? - if (type == AT_Percentile && cfg.rateunit == 1) { - used *= 8; // bytes to bits - } - if (debug) { printf("used: %" PRIu64 "\nlimit: %" PRIu64 "\n", used, limit); } @@ -1264,13 +1259,33 @@ int showalert(const char *interface, const AlertOutput output, const AlertExit a } } } else { - // TODO: check that these center the text well enough - printf(" %s", getratestring(used, 14, 2)); - printf(" of %s (%0.1f%%)\n\n", getratestring(limit, 0, 0), percentage); + // TODO: make these center the text in all cases + printf(" "); + if (condition == AC_RX) { + printf("rx"); + } else if (condition == AC_TX) { + printf("tx"); + } else if (condition == AC_Total) { + printf("total"); + } + printf(" - %s ", gettrafficrate(used, 1, 0)); + if (percentage <= 100000.0) { + printf("(%0.1f%%)", percentage); + } else { + printf("(%s)", ">100000%"); + } + printf(" of %s limit\n\n", gettrafficrate(limit, 1, 0)); cfg.ostyle = 1; - showpercentiledataminavgmaxtable(&pdata, 6); - - printf(" %4" PRIu32 " entries", pdata.count); + showpercentiledataminavgmaxtable(&pdata, 5); + + printf(" %4" PRIu32 " entries", pdata.count); + if (condition == AC_RX) { + printf(", %" PRIu32 " (%0.1f%%) over limit", pdata.countrxoveruserlimit, (float)pdata.countrxoveruserlimit / (float)pdata.count * 100.0); + } else if (condition == AC_TX) { + printf(", %" PRIu32 " (%0.1f%%) over limit", pdata.counttxoveruserlimit, (float)pdata.counttxoveruserlimit / (float)pdata.count * 100.0); + } else if (condition == AC_Total) { + printf(", %" PRIu32 " (%0.1f%%) over limit", pdata.countsumoveruserlimit, (float)pdata.countsumoveruserlimit / (float)pdata.count * 100.0); + } if (pdata.count == pdata.countexpectation) { printf(", 100%% coverage\n"); } else { diff --git a/src/dbxml.c b/src/dbxml.c index c993e6a..bdca779 100644 --- a/src/dbxml.c +++ b/src/dbxml.c @@ -108,7 +108,7 @@ void xmlpercentile(const interfaceinfo *interface) { percentiledata pdata; - if (!getpercentiledata(&pdata, interface->name)) { + if (!getpercentiledata(&pdata, interface->name, 0)) { exit(EXIT_FAILURE); } diff --git a/src/percentile.c b/src/percentile.c index fa360b3..cef3cd2 100644 --- a/src/percentile.c +++ b/src/percentile.c @@ -3,7 +3,7 @@ #include "percentile.h" // TODO: tests -int getpercentiledata(percentiledata *pdata, const char *iface) +int getpercentiledata(percentiledata *pdata, const char *iface, const uint64_t userlimitbytespersecond) { uint32_t entry = 0, entrylimit; uint64_t *rxdata, *txdata, *sumdata; @@ -12,6 +12,11 @@ int getpercentiledata(percentiledata *pdata, const char *iface) dbdatalist *datalist = NULL, *datalist_i = NULL; dbdatalistinfo datainfo; + pdata->userlimitbytespersecond = userlimitbytespersecond; + pdata->countrxoveruserlimit = 0; + pdata->counttxoveruserlimit = 0; + pdata->countsumoveruserlimit = 0; + if (!db_getdata_range(&datalist, &datainfo, iface, "month", 1, "", "")) { printf("Error: Failed to fetch month data for 95th percentile.\n"); return 0; @@ -80,6 +85,19 @@ int getpercentiledata(percentiledata *pdata, const char *iface) rxdata[entry] = datalist_i->rx; txdata[entry] = datalist_i->tx; sumdata[entry] = datalist_i->rx + datalist_i->tx; + + if (userlimitbytespersecond > 0) { + if (rxdata[entry] > userlimitbytespersecond * 300) { + pdata->countrxoveruserlimit++; + } + if (txdata[entry] > userlimitbytespersecond * 300) { + pdata->counttxoveruserlimit++; + } + if (sumdata[entry] > userlimitbytespersecond * 300) { + pdata->countsumoveruserlimit++; + } + } + datalist_i = datalist_i->next; entry++; } diff --git a/src/percentile.h b/src/percentile.h index f7a7954..c7f56ab 100644 --- a/src/percentile.h +++ b/src/percentile.h @@ -9,9 +9,11 @@ typedef struct percentiledata { uint64_t min, max; uint64_t sumrx, sumtx; uint64_t rxpercentile, txpercentile, sumpercentile; + uint64_t userlimitbytespersecond; + uint32_t countrxoveruserlimit, counttxoveruserlimit, countsumoveruserlimit; } percentiledata; -int getpercentiledata(percentiledata *pdata, const char *iface); +int getpercentiledata(percentiledata *pdata, const char *iface, const uint64_t userlimitbytespersecond); int compare_uint64_t(const void *a, const void *b); #endif diff --git a/src/vnstat_func.c b/src/vnstat_func.c index 7b0487e..5635006 100644 --- a/src/vnstat_func.c +++ b/src/vnstat_func.c @@ -50,6 +50,8 @@ void initparams(PARAMS *p) p->alerttype = 0; p->alertcondition = 0; p->alertlimit = 0; + p->alertrateunit = -1; + p->alertrateunitmode = -1; /* load default config */ defaultcfg(); @@ -779,13 +781,17 @@ int parsealertargs(PARAMS *p, char **argv) // override configuration to use same units as user gave as parameter if (u > 2) { cfg.rateunit = 1; + p->alertrateunit = 1; } else { cfg.rateunit = 0; + p->alertrateunit = 0; } if (u == 0 || u == 3) { cfg.rateunitmode = 0; + p->alertrateunitmode = 0; } else { cfg.rateunitmode = 1; + p->alertrateunitmode = 1; } } @@ -805,6 +811,14 @@ int parsealertargs(PARAMS *p, char **argv) p->alertlimit = alertlimit * unitmultiplier; + if (p->alerttype == AT_Percentile && cfg.rateunit == 1) { + if (p->alertlimit < 8) { + printf("Error: Limit needs to be at least 8 bits per second.\n"); + return 0; + } + p->alertlimit /= 8; + } + if (debug) { printf("Alert unit %s is %d %d = %" PRIu64 "\n", argv[currentarg], u, i, unitmultiplier); printf("Alert real limit is %" PRIu64 " * %" PRIu64 " = %" PRIu64 "\n", alertlimit, unitmultiplier, p->alertlimit); @@ -881,6 +895,11 @@ void handleshowalert(PARAMS *p) validateinterface(p); + if (p->alertrateunit > -1 && p->alertrateunitmode > -1) { + cfg.rateunit = p->alertrateunit; + cfg.rateunitmode = p->alertrateunitmode; + } + alert = showalert(p->interface, p->alertoutput, p->alertexit, p->alerttype, p->alertcondition, p->alertlimit); if ((alert || p->alertexit == AE_Always_Exit_1) && p->alertexit != AE_Always_Exit_0) { diff --git a/src/vnstat_func.h b/src/vnstat_func.h index 69cd091..78fedf6 100644 --- a/src/vnstat_func.h +++ b/src/vnstat_func.h @@ -11,6 +11,7 @@ typedef struct { char definterface[MAXIFPARAMLEN], cfgfile[512], *ifacelist, jsonmode, xmlmode; char databegin[18], dataend[18]; unsigned int alert, alertoutput, alertexit, alerttype, alertcondition; + int alertrateunit, alertrateunitmode; uint64_t alertlimit; } PARAMS;