From: Teemu Toivola Date: Tue, 17 Jan 2017 19:47:13 +0000 (+0200) Subject: add new configuration options for data retention durations X-Git-Tag: v2.0~98^2~62 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6f4bf96a63198e06fbb6d942c5ca0b9c8f7f5aa4;p=vnstat add new configuration options for data retention durations --- diff --git a/README.md b/README.md index 380973a..a04610e 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,14 @@ configurable durations. Yearly and 5 minute resolution statistics are also plann * write support is no longer included in code * full data import from vnStat 1.x database format including reconstructed yearly data * legacy database is not kept in memory for each interface during daemon runtime + * new configuration options for data retention durations + * the daemon doesn't however yet use these new options ##### TODO * `grep TODO src/* tests/*` * continue daemon refactoring * add missing sanity checks to daemon - * rewrite disabled tests * all outputs (text and image) * use of 5 minute resolution statistics * old data cleanup, everything gets currently stored forever diff --git a/cfg/vnstat.conf b/cfg/vnstat.conf index c127b29..895bc81 100644 --- a/cfg/vnstat.conf +++ b/cfg/vnstat.conf @@ -1,4 +1,4 @@ -# vnStat 1.17 config file +# vnStat 2.0 config file ## # default interface @@ -76,6 +76,14 @@ BootVariation 15 # log days without traffic to daily list (1 = enabled, 0 = disabled) TrafficlessDays 1 +# data retention durations (-1 = unlimited, 0 = log disabled) +5MinuteHours 48 +HourlyDays 2 +DailyDays 30 +MonthlyMonths 12 +YearlyYears -1 +TopDayEntries 10 + # vnstatd ## diff --git a/src/cfg.c b/src/cfg.c index 0195059..e1289f7 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -87,7 +87,15 @@ void printcfgfile(void) printf("BootVariation %d\n\n", cfg.bvar); printf("# log days without traffic to daily list (1 = enabled, 0 = disabled)\n"); - printf("TrafficlessDays %d\n", cfg.traflessday); + printf("TrafficlessDays %d\n\n", cfg.traflessday); + + printf("# data retention durations (-1 = unlimited, 0 = log disabled)\n"); + printf("5MinuteHours %2d\n", cfg.fiveminutehours); + printf("HourlyDays %2d\n", cfg.hourlydays); + printf("DailyDays %2d\n", cfg.dailydays); + printf("MonthlyMonths %2d\n", cfg.monthlymonths); + printf("YearlyYears %2d\n", cfg.yearlyyears); + printf("TopDayEntries %2d\n", cfg.topdayentries); printf("\n\n"); @@ -200,6 +208,12 @@ int loadcfg(const char *cfgfile) { "UseFileLocking", 0, &cfg.flock, 0, 0 }, { "BootVariation", 0, &cfg.bvar, 0, 0 }, { "TrafficlessDays", 0, &cfg.traflessday, 0, 0 }, + { "5MinuteHours", 0, &cfg.fiveminutehours, 0, 0 }, + { "HourlyDays", 0, &cfg.hourlydays, 0, 0 }, + { "DailyDays", 0, &cfg.dailydays, 0, 0 }, + { "MonthlyMonths", 0, &cfg.monthlymonths, 0, 0 }, + { "YearlyYears", 0, &cfg.yearlyyears, 0, 0 }, + { "TopDayEntries", 0, &cfg.topdayentries, 0, 0 }, { "DaemonUser", cfg.daemonuser, 0, 33, 0 }, { "DaemonGroup", cfg.daemongroup, 0, 33, 0 }, { "UpdateInterval", 0, &cfg.updateinterval, 0, 0 }, @@ -297,69 +311,72 @@ int loadcfg(const char *cfgfile) void validatecfg(void) { + const char *invalidvalue = "Invalid value for"; + const char *resettingto = "resetting to"; + if (cfg.unitmode<0 || cfg.unitmode>1) { cfg.unitmode = UNITMODE; - snprintf(errorstring, 512, "Invalid value for UnitMode, resetting to \"%d\".", cfg.unitmode); + snprintf(errorstring, 512, "%s UnitMode, %s \"%d\".", invalidvalue, resettingto, cfg.unitmode); printe(PT_Config); } if (cfg.rateunitmode<0 || cfg.rateunitmode>1) { cfg.rateunitmode = RATEUNITMODE; - snprintf(errorstring, 512, "Invalid value for RateUnitMode, resetting to \"%d\".", cfg.rateunitmode); + snprintf(errorstring, 512, "%s RateUnitMode, %s \"%d\".", invalidvalue, resettingto, cfg.rateunitmode); printe(PT_Config); } if (cfg.ostyle<0 || cfg.ostyle>3) { cfg.ostyle = OSTYLE; - snprintf(errorstring, 512, "Invalid value for OutputStyle, resetting to \"%d\".", cfg.ostyle); + snprintf(errorstring, 512, "%s OutputStyle, %s \"%d\".", invalidvalue, resettingto, cfg.ostyle); printe(PT_Config); } if (cfg.bvar<0 || cfg.bvar>300) { cfg.bvar = BVAR; - snprintf(errorstring, 512, "Invalid value for BootVariation, resetting to \"%d\".", cfg.bvar); + snprintf(errorstring, 512, "%s BootVariation, %s \"%d\".", invalidvalue, resettingto, cfg.bvar); printe(PT_Config); } if (cfg.sampletime<2 || cfg.sampletime>600) { cfg.sampletime = DEFSAMPTIME; - snprintf(errorstring, 512, "Invalid value for Sampletime, resetting to \"%d\".", cfg.sampletime); + snprintf(errorstring, 512, "%s Sampletime, %s \"%d\".", invalidvalue, resettingto, cfg.sampletime); printe(PT_Config); } if (cfg.monthrotate<1 || cfg.monthrotate>28) { cfg.monthrotate = MONTHROTATE; - snprintf(errorstring, 512, "Invalid value for MonthRotate, resetting to \"%d\".", cfg.monthrotate); + snprintf(errorstring, 512, "%s MonthRotate, %s \"%d\".", invalidvalue, resettingto, cfg.monthrotate); printe(PT_Config); } if (cfg.maxbw<0 || cfg.maxbw>BWMAX) { cfg.maxbw = DEFMAXBW; - snprintf(errorstring, 512, "Invalid value for MaxBandwidth, resetting to \"%d\".", cfg.maxbw); + snprintf(errorstring, 512, "%s MaxBandwidth, %s \"%d\".", invalidvalue, resettingto, cfg.maxbw); printe(PT_Config); } if (cfg.spacecheck<0 || cfg.spacecheck>1) { cfg.spacecheck = USESPACECHECK; - snprintf(errorstring, 512, "Invalid value for CheckDiskSpace, resetting to \"%d\".", cfg.spacecheck); + snprintf(errorstring, 512, "%s CheckDiskSpace, %s \"%d\".", invalidvalue, resettingto, cfg.spacecheck); printe(PT_Config); } if (cfg.flock<0 || cfg.flock>1) { cfg.flock = USEFLOCK; - snprintf(errorstring, 512, "Invalid value for UseFileLocking, resetting to \"%d\".", cfg.flock); + snprintf(errorstring, 512, "%s UseFileLocking, %s \"%d\".", invalidvalue, resettingto, cfg.flock); printe(PT_Config); } if (cfg.dbdir[0] != '/') { strncpy_nt(cfg.dbdir, DATABASEDIR, 512); - snprintf(errorstring, 512, "DatabaseDir doesn't start with \"/\", resetting to default."); + snprintf(errorstring, 512, "DatabaseDir doesn't start with \"/\", %s default.", resettingto); printe(PT_Config); } if (cfg.pollinterval<2 || cfg.pollinterval>60) { cfg.pollinterval = POLLINTERVAL; - snprintf(errorstring, 512, "Invalid value for PollInterval, resetting to \"%d\".", cfg.pollinterval); + snprintf(errorstring, 512, "%s PollInterval, %s \"%d\".", invalidvalue, resettingto, cfg.pollinterval); printe(PT_Config); } @@ -369,7 +386,7 @@ void validatecfg(void) } else { cfg.updateinterval = UPDATEINTERVAL; } - snprintf(errorstring, 512, "Invalid value for UpdateInterval, resetting to \"%d\".", cfg.updateinterval); + snprintf(errorstring, 512, "%s UpdateInterval, %s \"%d\".", invalidvalue, resettingto, cfg.updateinterval); printe(PT_Config); } @@ -379,7 +396,7 @@ void validatecfg(void) } else { cfg.saveinterval = SAVEINTERVAL; } - snprintf(errorstring, 512, "Invalid value for SaveInterval, resetting to \"%d\".", cfg.saveinterval); + snprintf(errorstring, 512, "%s SaveInterval, %s \"%d\".", invalidvalue, resettingto, cfg.saveinterval); printe(PT_Config); } @@ -389,85 +406,121 @@ void validatecfg(void) } else { cfg.offsaveinterval = OFFSAVEINTERVAL; } - snprintf(errorstring, 512, "Invalid value for OfflineSaveInterval, resetting to \"%d\".", cfg.offsaveinterval); + snprintf(errorstring, 512, "%s OfflineSaveInterval, %s \"%d\".", invalidvalue, resettingto, cfg.offsaveinterval); printe(PT_Config); } if (cfg.savestatus<0 || cfg.savestatus>1) { cfg.savestatus = SAVESTATUS; - snprintf(errorstring, 512, "Invalid value for SaveOnStatusChange, resetting to \"%d\".", cfg.savestatus); + snprintf(errorstring, 512, "%s SaveOnStatusChange, %s \"%d\".", invalidvalue, resettingto, cfg.savestatus); printe(PT_Config); } if (cfg.uselogging<0 || cfg.uselogging>2) { cfg.uselogging = USELOGGING; - snprintf(errorstring, 512, "Invalid value for UseLogging, resetting to \"%d\".", cfg.uselogging); + snprintf(errorstring, 512, "%s UseLogging, %s \"%d\".", invalidvalue, resettingto, cfg.uselogging); printe(PT_Config); } if (cfg.createdirs<0 || cfg.createdirs>2) { cfg.createdirs = CREATEDIRS; - snprintf(errorstring, 512, "Invalid value for CreateDirs, resetting to \"%d\".", cfg.createdirs); + snprintf(errorstring, 512, "%s CreateDirs, %s \"%d\".", invalidvalue, resettingto, cfg.createdirs); printe(PT_Config); } if (cfg.updatefileowner<0 || cfg.updatefileowner>2) { cfg.updatefileowner = UPDATEFILEOWNER; - snprintf(errorstring, 512, "Invalid value for UpdateFileOwner, resetting to \"%d\".", cfg.updatefileowner); + snprintf(errorstring, 512, "%s UpdateFileOwner, %s \"%d\".", invalidvalue, resettingto, cfg.updatefileowner); printe(PT_Config); } if (cfg.logfile[0] != '/') { strncpy_nt(cfg.logfile, LOGFILE, 512); - snprintf(errorstring, 512, "LogFile doesn't start with \"/\", resetting to default."); + snprintf(errorstring, 512, "LogFile doesn't start with \"/\", %s default.", resettingto); printe(PT_Config); } if (cfg.pidfile[0] != '/') { strncpy_nt(cfg.pidfile, PIDFILE, 512); - snprintf(errorstring, 512, "PidFile doesn't start with \"/\", resetting to default."); + snprintf(errorstring, 512, "PidFile doesn't start with \"/\", %s default.", resettingto); printe(PT_Config); } if (cfg.transbg<0 || cfg.transbg>1) { cfg.transbg = TRANSBG; - snprintf(errorstring, 512, "Invalid value for TransparentBg, resetting to \"%d\".", cfg.transbg); + snprintf(errorstring, 512, "%s TransparentBg, %s \"%d\".", invalidvalue, resettingto, cfg.transbg); printe(PT_Config); } if (cfg.hourlyrate<0 || cfg.hourlyrate>1) { cfg.hourlyrate = HOURLYRATE; - snprintf(errorstring, 512, "Invalid value for HourlyRate, resetting to \"%d\".", cfg.hourlyrate); + snprintf(errorstring, 512, "%s HourlyRate, %s \"%d\".", invalidvalue, resettingto, cfg.hourlyrate); printe(PT_Config); } if (cfg.summaryrate<0 || cfg.summaryrate>1) { cfg.summaryrate = SUMMARYRATE; - snprintf(errorstring, 512, "Invalid value for SummaryRate, resetting to \"%d\".", cfg.summaryrate); + snprintf(errorstring, 512, "%s SummaryRate, %s \"%d\".", invalidvalue, resettingto, cfg.summaryrate); printe(PT_Config); } if (cfg.slayout<0 || cfg.slayout>1) { cfg.slayout = SUMMARYLAYOUT; - snprintf(errorstring, 512, "Invalid value for SummaryLayout, resetting to \"%d\".", cfg.slayout); + snprintf(errorstring, 512, "%s SummaryLayout, %s \"%d\".", invalidvalue, resettingto, cfg.slayout); printe(PT_Config); } if (cfg.traflessday<0 || cfg.traflessday>1) { cfg.traflessday = TRAFLESSDAY; - snprintf(errorstring, 512, "Invalid value for TrafficlessDays, resetting to \"%d\".", cfg.transbg); + snprintf(errorstring, 512, "%s TrafficlessDays, %s \"%d\".", invalidvalue, resettingto, cfg.traflessday); + printe(PT_Config); + } + + if (cfg.fiveminutehours<-1) { + cfg.fiveminutehours = FIVEMINUTEHOURS; + snprintf(errorstring, 512, "%s 5MinuteHours, %s \"%d\".", invalidvalue, resettingto, cfg.fiveminutehours); + printe(PT_Config); + } + + if (cfg.hourlydays<-1) { + cfg.hourlydays = HOURLYDAYS; + snprintf(errorstring, 512, "%s HourlyDays, %s \"%d\".", invalidvalue, resettingto, cfg.hourlydays); + printe(PT_Config); + } + + if (cfg.dailydays<-1) { + cfg.dailydays = DAILYDAYS; + snprintf(errorstring, 512, "%s DailyDays, %s \"%d\".", invalidvalue, resettingto, cfg.dailydays); + printe(PT_Config); + } + + if (cfg.monthlymonths<-1) { + cfg.monthlymonths = MONTHLYMONTHS; + snprintf(errorstring, 512, "%s MonthlyMonths, %s \"%d\".", invalidvalue, resettingto, cfg.monthlymonths); + printe(PT_Config); + } + + if (cfg.yearlyyears<-1) { + cfg.yearlyyears = YEARLYYEARS; + snprintf(errorstring, 512, "%s YearlyYears, %s \"%d\".", invalidvalue, resettingto, cfg.yearlyyears); + printe(PT_Config); + } + + if (cfg.topdayentries<-1) { + cfg.topdayentries = TOPDAYENTRIES; + snprintf(errorstring, 512, "%s TopDayEntries, %s \"%d\".", invalidvalue, resettingto, cfg.topdayentries); printe(PT_Config); } if (cfg.bwdetection<0 || cfg.bwdetection>1) { cfg.bwdetection = BWDETECT; - snprintf(errorstring, 512, "Invalid value for BandwidthDetection, resetting to \"%d\".", cfg.bwdetection); + snprintf(errorstring, 512, "%s BandwidthDetection, %s \"%d\".", invalidvalue, resettingto, cfg.bwdetection); printe(PT_Config); } if (cfg.bwdetectioninterval<0 || cfg.bwdetectioninterval>30) { cfg.bwdetectioninterval = BWDETECTINTERVAL; - snprintf(errorstring, 512, "Invalid value for BandwidthDetectionInterval, resetting to \"%d\".", cfg.bwdetectioninterval); + snprintf(errorstring, 512, "%s BandwidthDetectionInterval, %s \"%d\".", invalidvalue, resettingto, cfg.bwdetectioninterval); printe(PT_Config); } } @@ -494,6 +547,14 @@ void defaultcfg(void) cfg.slayout = SUMMARYLAYOUT; cfg.traflessday = TRAFLESSDAY; cfg.utflocale = UTFLOCALE; + + cfg.fiveminutehours = FIVEMINUTEHOURS; + cfg.hourlydays = HOURLYDAYS; + cfg.dailydays = DAILYDAYS; + cfg.monthlymonths = MONTHLYMONTHS; + cfg.yearlyyears = YEARLYYEARS; + cfg.topdayentries = TOPDAYENTRIES; + strncpy_nt(cfg.dbdir, DATABASEDIR, 512); strncpy_nt(cfg.iface, DEFIFACE, 32); strncpy_nt(cfg.locale, LOCALE, 32); diff --git a/src/common.h b/src/common.h index 3016729..4231a14 100644 --- a/src/common.h +++ b/src/common.h @@ -148,6 +148,14 @@ and most can be changed later from the config file. /* log trafficless days by default */ #define TRAFLESSDAY 1 +/* data retention defaults */ +#define FIVEMINUTEHOURS 48 +#define HOURLYDAYS 2 +#define DAILYDAYS 30 +#define MONTHLYMONTHS 12 +#define YEARLYYEARS -1 +#define TOPDAYENTRIES 10 + /* assume that locale can be UTF-n when enabled */ #define UTFLOCALE 1 @@ -231,6 +239,7 @@ typedef struct { char daemonuser[33], daemongroup[33]; int32_t updateinterval, pollinterval, saveinterval, offsaveinterval, savestatus, uselogging; int32_t createdirs, updatefileowner, bwdetection, bwdetectioninterval, utflocale; + int32_t fiveminutehours, hourlydays, dailydays, monthlymonths, yearlyyears, topdayentries; } CFG; /* internal interface information structure */ diff --git a/src/dbsql.c b/src/dbsql.c index 24403b4..a868895 100644 --- a/src/dbsql.c +++ b/src/dbsql.c @@ -502,6 +502,7 @@ int db_addtraffic_dated(const char *iface, const uint64_t rx, const uint64_t tx, } /* time specific */ + /* TODO: skip if feature disabled in configuration */ for (i=0; i<5; i++) { snprintf(datebuffer, 512, datadates[i], nowdate); sqlite3_snprintf(1024, sql, "insert or ignore into %s (interface, date, rx, tx) values (%"PRId64", %s, 0, 0);", datatables[i], (int64_t)ifaceid, datebuffer); @@ -591,47 +592,61 @@ int db_removeoldentries(void) return 0; } - /* TODO: read cleanup limits from configuration and actually use this function somewhere */ + /* TODO: actually use this function somewhere */ /* running this about once every hour during cache flush would keep the fiveminute table from accumulating too much excess data */ - sqlite3_snprintf(512, sql, "delete from fiveminute where date < datetime('now', '-48 hours', 'localtime');"); - if (!db_exec(sql)) { - db_rollbacktransaction(); - return 0; + if (cfg.fiveminutehours > 0) { + sqlite3_snprintf(512, sql, "delete from fiveminute where date < datetime('now', '-%d hours', 'localtime');", cfg.fiveminutehours); + if (!db_exec(sql)) { + db_rollbacktransaction(); + return 0; + } } - sqlite3_snprintf(512, sql, "delete from hour where date < datetime('now', '-7 days', 'localtime');"); - if (!db_exec(sql)) { - db_rollbacktransaction(); - return 0; + if (cfg.hourlydays > 0) { + sqlite3_snprintf(512, sql, "delete from hour where date < datetime('now', '-%d days', 'localtime');", cfg.hourlydays); + if (!db_exec(sql)) { + db_rollbacktransaction(); + return 0; + } } - sqlite3_snprintf(512, sql, "delete from day where date < date('now', '-30 days', 'localtime');"); - if (!db_exec(sql)) { - db_rollbacktransaction(); - return 0; + if (cfg.dailydays > 0) { + sqlite3_snprintf(512, sql, "delete from day where date < date('now', '-%d days', 'localtime');", cfg.dailydays); + if (!db_exec(sql)) { + db_rollbacktransaction(); + return 0; + } } - sqlite3_snprintf(512, sql, "delete from month where date < date('now', '-12 months', 'localtime');"); - if (!db_exec(sql)) { - db_rollbacktransaction(); - return 0; + if (cfg.monthlymonths > 0) { + sqlite3_snprintf(512, sql, "delete from month where date < date('now', '-%d months', 'localtime');", cfg.monthlymonths); + if (!db_exec(sql)) { + db_rollbacktransaction(); + return 0; + } } - sqlite3_snprintf(512, sql, "delete from year where date < date('now', '-10 years', 'localtime');"); - if (!db_exec(sql)) { - db_rollbacktransaction(); - return 0; + if (cfg.yearlyyears > 0) { + sqlite3_snprintf(512, sql, "delete from year where date < date('now', '-%d years', 'localtime');", cfg.yearlyyears); + if (!db_exec(sql)) { + db_rollbacktransaction(); + return 0; + } } /* TODO: rewrite to handle entries per interface and use select for getting entry list */ /* as the syntax below works only when sqlite is compiled with SQLITE_ENABLE_UPDATE_DELETE_LIMIT */ /* causing failure in at least in Ubuntu <= 12.04, RHEL, Fedora and CentOS */ - /*sqlite3_snprintf(512, sql, "delete from top order by rx+tx desc limit -1 offset 10;"); - if (!db_exec(sql)) { - db_rollbacktransaction(); - return 0; - }*/ + /* + if (cfg.topdayentries > 0) { + sqlite3_snprintf(512, sql, "delete from top order by rx+tx desc limit -1 offset %d;", cfg.topdayentries); + if (!db_exec(sql)) { + db_rollbacktransaction(); + return 0; + } + } + */ return db_committransaction(); }