87 lines
1.8 KiB
Go
87 lines
1.8 KiB
Go
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
|
|
}
|