jow- / nlbwmon

Simple conntrack based traffic accounting
ISC License
147 stars 32 forks source link

Daily accounting period? #52

Open milindpatel63 opened 1 year ago

milindpatel63 commented 1 year ago

I have set accounting period to fixed interval with start date 2022-01-01 and interval 1 days. It should reset the accounting period at 12AM every day. But i have noticed, it counts the accounting period from the last commit to database. I restart the router every morning at 6AM. And before restart, i run,

/usr/sbin/nlbw -c commit

So the accounting period for that day is counted after the commit at 6AM.

Can i somehow set accounting period from 12AM to 12AM next day?

DanielRIOT commented 2 months ago

I'm seeing the same thing on my devices.

is your timezone GMT+6 ? ( mine is GMT+2 and the daily accounting sessions end at 02:00 local - and OpenWRT system - time each day )

it seems to call the archiving function ( https://github.com/jow-/nlbwmon/blob/c7616bcfaaef440848152f4dc738c990b2d0b90b/database.c#L609 ) at 00:00 GMT

I messed around by changing my timezone on OpenWRT and found the archiving function was always called x hours late for whatever GMT+x I set. The "time(NULL); " gave the correct local time, but the function was called "late" I added a debug print in the function and then changed the time on the device to a few seconds before i expected to see the "end of accounting period" archive being created : ( I assumed it would be 00:00 local time )

Timezone set to GMT+2 / South Africa-Johannesburg, and I set the system clock to 23:59:50 waited a few minutes but nothing happened, then I changed to clock to 01:59:50, and at 02:00 the archive was made.

Fri May 3 02:00:06 2024 daemon.err nlbwmon[21031]: nlbwmon Archiving database, current TS is: 20240502, next TS is 20240503 , time() is: Fri May 3 02:00:06 2024

DanielRIOT commented 1 month ago

I made a patch that seems to work OK, but there may be better places or ways in the nlbwmon codebase to put this logic.. ( and one could use the shorthand If styles to make the patch more compact.. The archive action seems to be the one responsible to restarting counters "interval_timestamp"'s lowest time resolution is 1 day so we only need to advance it or retard it by 1 to have the counter reset happen "now" or "later". This will advance or delay the database archive action based on the local time vs time until GMT 00:00.

--- a/database.c
+++ b/database.c
@@ -608,13 +608,40 @@ database_cleanup(void)
 int
 database_archive(struct dbhandle *h)
 {
-   uint32_t next_ts = interval_timestamp(&h->db->interval, 0);
-   uint32_t curr_ts = db_timestamp(h->db);
+   time_t nowGMT, nowloc;
+   nowGMT = time(NULL);
+   int tsoffset = 0;
+   struct tm * tmploc = gmtime(&nowGMT);
+   nowloc = mktime(tmploc); 
+   double timeDiffS = difftime(nowGMT,nowloc); // offset in seconds from GMT ( "+" is GMT+, "-" is GMT- )
+   if(timeDiffS>0){ // local time is GMT +, run earlier                
+       if( (nowGMT%86400) > (86400 - abs((int)timeDiffS) )) // "%86400 is "seconds since midnight"
+       {
+       // local time has already gone past midnight
+           tsoffset = 1;
+       }else{
+           tsoffset = 0;
+       }
+   }
+   else if(timeDiffS<0){ // local time is GMT -,run later      
+       if( (nowGMT%86400) < abs((int)timeDiffS) ) // "%86400 is "seconds since midnight"
+       {
+           tsoffset = -1;
+       }else{
+           tsoffset = 0;
+       }
+   }
+   else // we are at GMT
+   {
+       tsoffset = 0;
+   }
+       
+   uint32_t next_ts = interval_timestamp(&h->db->interval, tsoffset); // YYYYMMDD of "now" but needs to br adjusted based on timezone
+   uint32_t curr_ts = db_timestamp(h->db); // YYYYMMDD of when the DB was created
    int err;
-
+                   
    if (next_ts > curr_ts) {
        err = database_save(h, opt.db.directory, curr_ts, opt.db.compress);
-
        if (err)
            return err;