Netgate Discussion Forum
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Search
    • Register
    • Login

    Vnstat to retain more than 30 days daily stats

    Scheduled Pinned Locked Moved Traffic Monitoring
    vnstat
    8 Posts 4 Posters 1.4k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • P
      pwnell
      last edited by

      Is there any way for me to tell vnstat to retain more than 30 days of daily traffic totals stats? When I need to challenge my ISP it always happens after the billing cycle when I lost the first couple of days of daily stats, so I only have the monthly to go on. If I could retain 60 days of daily totals that would be awesome. Any ideas?

      1 Reply Last reply Reply Quote 0
      • johnpozJ
        johnpoz LAYER 8 Global Moderator
        last edited by

        Simple solution would be just to export it as csv.. Under the display advanced there is an export button

        An intelligent man is sometimes forced to be drunk to spend time with his fools
        If you get confused: Listen to the Music Play
        Please don't Chat/PM me for help, unless mod related
        SG-4860 24.11 | Lab VMs 2.8, 24.11

        1 Reply Last reply Reply Quote 0
        • P
          pwnell
          last edited by

          I’ll script it, thx.

          1 Reply Last reply Reply Quote 0
          • P
            pwnell
            last edited by

            If anyone else needs this - it is really a quick hack I put together last night after midnight so please ignore the horrible code. It is a python script that should be created somewhere on pfSense (mine is in /root), then called from cron once a day - I recommend something like 00:30 each day but it is not important. It will append the daily totals for all interfaces on the cmdline to txt files located at /var/spool/vnstat_daily_<ifacename>.txt. It is idempotent and will only append those lines not yet present and only up to the previous day (as that is the last complete day of stats vnstat has). I am very busy at the moment and might improve it later to output proper CSV - for now I just need the data. Call me lazy. Use and modify as you wish:

            #!/usr/local/bin/python2.7
            
            import os
            import re
            import sys, getopt
            from datetime import datetime, timedelta
            
            
            def present(dte, filename):
                with open(filename) as infile:
                    for line in infile:
                        m = re.match(r'^' + dte + ' .*$', line.strip())
                        if not m:
                            continue
                        return True
                return False
            
            
            def usage():
                print("Usage: python parsevnstat.py -i ifacelist")
                sys.exit(2)
            
            def main(argv):
                try:
                    opts, args = getopt.getopt(argv, 'hi:')
                except:
                  usage()
            
                ifaces = []
                for opt, arg in opts:
                    if opt == "-h":
                        usage()
                    elif opt == "-i":
                        ifaces = arg.split(",")
            
                if len(ifaces) <= 0:
                    usage()
            
                for iface in ifaces:
                    filename = '/var/spool/vnstat_daily_'+iface+'.txt'
            
                    header = False
                    if not os.path.isfile(filename):
                        header = True
                    with open(filename, 'a') as outfile:
                        if header:
                            outfile.write('   day         rx      |     tx      |    total    |   avg. rate\n')
                            outfile.write('-----------------------+-------------+-------------+---------------\n')
                        with os.popen('/usr/local/bin/vnstat -d -i '+iface) as pipe:
                            for line in pipe:
                                m = re.match(r'^(\d\d/\d\d/\d\d) .*$', line.strip())
                                if not m:
                                    continue
                                dte = datetime.strptime(m.group(1), '%m/%d/%y').date()
                                if dte <= (datetime.today() - timedelta(days=1)).date() and not present(m.group(1), filename):
                                    outfile.write(line.strip() + '\n' )
            
            main(sys.argv[1:])
            

            Cron entry:

            30	0	*	*	*	root	/usr/local/bin/python2.7 /root/parsevnstat.py -i em0,em1
            
            1 Reply Last reply Reply Quote 0
            • V
              Vergo
              last edited by

              Starting from vnStat version 2.0, it's possible to freely configure the data retention periods without discarding already existing data. I don't however know which version of vnStat is currently provided by pfSense.

              Regarding that quick hack, it's a good practice to avoid parsing the formatted output as the layout is somewhat version dependent and the date string depends on configuration settings and system locale. Parsing the --json output would be a more fail proof solution. There's also --xml and --oneline available as alternatives.

              1 Reply Last reply Reply Quote 0
              • P
                pwnell
                last edited by

                [2.4.4-RELEASE][root@fw-pwn.local]/root: vnstat --version
                vnStat 1.15 by Teemu Toivola <tst at iki dot fi>
                

                I agree with the json / XML comment, as I said, this was a very quick thing done for me to preserve my history. My region will not change for me (for now) so it will work. But sure - that change will make it much better. Just no time...

                1 Reply Last reply Reply Quote 0
                • P
                  pwnell
                  last edited by

                  Slightly improved version - this uses the raw export format as that is much easier consumed by spreadsheets and bypasses the regional issues.

                  #!/usr/local/bin/python2.7
                  
                  import os
                  import re
                  import sys, getopt
                  from datetime import datetime, timedelta
                  
                  
                  def format_date(dte):
                      return "{0:04d}-{1:02d}-{2:02d}".format(dte.year, dte.month, dte.day)
                  
                  def present(dte, filename):
                      formatted_dte = format_date(dte)
                      with open(filename) as infile:
                          for line in infile:
                              m = re.match(r'^' + formatted_dte + ',.*$', line.strip())
                              if not m:
                                  continue
                              return True
                      return False
                  
                  def format_line(fields,dte):
                      rx = int(fields[3]) + int(fields[5])/1024.0
                      tx = int(fields[4]) + int(fields[6])/1024.0
                      return format_date(dte) + \
                          ',{0:.3f}'.format(rx) + \
                          ',{0:.3f}'.format(tx) + \
                          ',{0:.3f}'.format(rx+tx) + \
                          ',{0:.3f}'.format(rx / 1024.0) + \
                          ',{0:.3f}'.format(tx / 1024.0) + \
                          ',{0:.3f}'.format((rx+tx) / 1024.0),
                      return "{0:04d}-{1:02d}-{2:02d}".format(dte.year, dte.month, dte.day)
                  
                  
                  def usage():
                      print("Usage: python parsevnstat2.py -i ifacelist")
                      sys.exit(2)
                  
                  def main(argv):
                      try:
                          opts, args = getopt.getopt(argv, 'hi:')
                      except:
                        usage()
                  
                      ifaces = []
                      for opt, arg in opts:
                          if opt == "-h":
                              usage()
                          elif opt == "-i":
                              ifaces = arg.split(",")
                  
                      if len(ifaces) <= 0:
                          usage()
                  
                      for iface in ifaces:
                          filename = '/var/spool/vnstat_daily_'+iface+'.csv'
                  
                          header = False
                          if not os.path.isfile(filename):
                              header = True
                          with open(filename, 'a') as outfile:
                              if header:
                                  outfile.write('date,rx_MiB,tx_MiB,tot_MiB,rx_GiB,tx_GiB,tot_GiB\n')
                              lines = []
                              with os.popen('/usr/local/bin/vnstat --exportdb -i '+iface) as pipe:
                                  for line in pipe:
                                      m = re.match(r'^d;.*$', line.strip())
                                      if not m:
                                          continue
                  		    fields = line.strip().split(";")
                  		    if len(fields) != 8:
                  			continue
                                      dte = datetime.fromtimestamp(int(fields[2])).date()
                                      if dte <= (datetime.today() - timedelta(days=1)).date() and not present(dte, filename):
                                          lines.append(format_line(fields,dte))
                  
                  	    for line in sorted(lines):
                              	outfile.write(line + '\n' )
                  
                  main(sys.argv[1:])
                  
                  1 Reply Last reply Reply Quote 0
                  • C
                    chrcoluk
                    last edited by

                    Thanks for this, and also thanks for the other help you gave, I will see if I can make a patch for the GUI to support 60 days worth of data.

                    pfSense CE 2.8.0

                    1 Reply Last reply Reply Quote 0
                    • First post
                      Last post
                    Copyright 2025 Rubicon Communications LLC (Netgate). All rights reserved.