package stats import ( "fmt" "os/exec" "github.com/go-errors/errors" "github.com/goccy/go-json" ) const ( vnstatBin = "/usr/bin/vnstat" ) type VnstatTrafficRecord struct { Date struct { Year uint `json:"year"` Month uint `json:"month"` Day uint `json:"day"` } `json:"date"` Time struct { Hour uint `json:"hour"` Minute uint `json:"minute"` } `json:"time"` Rx uint64 `json:"rx"` Tx uint64 `json:"tx"` } type vnstatResponse struct { Interfaces []struct { Name string `json:"name"` Traffic struct { FiveMinute []VnstatTrafficRecord `json:"fiveminute"` Hour []VnstatTrafficRecord `json:"hour"` Day []VnstatTrafficRecord `json:"day"` Month []VnstatTrafficRecord `json:"month"` } `json:"traffic"` } `json:"interfaces"` } func VnstatMonthlyTraffic(ifname string) ([]VnstatTrafficRecord, error) { resp, err := callVnstat("--json", "m") if err != nil { return nil, errors.WrapPrefix(err, "failed to run vnstat", 0) } for _, iface := range resp.Interfaces { if iface.Name == ifname { return iface.Traffic.Month, nil } } return nil, errors.New(fmt.Sprintf("interface %s not found", ifname)) } func VnstatDailyTraffic(ifname string) ([]VnstatTrafficRecord, error) { resp, err := callVnstat("--json", "d") if err != nil { return nil, errors.WrapPrefix(err, "failed to run vnstat", 0) } for _, iface := range resp.Interfaces { if iface.Name == ifname { return iface.Traffic.Day, nil } } return nil, errors.New(fmt.Sprintf("interface %s not found", ifname)) } func callVnstat(args ...string) (*vnstatResponse, error) { cmd := exec.Command(vnstatBin, args...) cmd.Stdin = nil output, err := cmd.Output() if err != nil { return nil, err } var resp vnstatResponse err = json.Unmarshal(output, &resp) if err != nil { return nil, errors.Wrap(err, 0) } return &resp, nil }