72 lines
2.0 KiB
Go
72 lines
2.0 KiB
Go
package probe
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const netDevPath = "/proc/net/dev"
|
|
|
|
// InterfaceStats contains received and transmitted byte counters.
|
|
type InterfaceStats struct {
|
|
Name string
|
|
RXBytes uint64
|
|
TXBytes uint64
|
|
}
|
|
|
|
// ReadInterfaceStats reads byte counters for a network interface.
|
|
func ReadInterfaceStats(ctx context.Context, name string) (InterfaceStats, error) {
|
|
if err := ctx.Err(); err != nil {
|
|
return InterfaceStats{}, fmt.Errorf("checking context before reading interface stats: %w", err)
|
|
}
|
|
data, err := os.ReadFile(netDevPath)
|
|
if err != nil {
|
|
return InterfaceStats{}, fmt.Errorf("reading %s: %w", netDevPath, err)
|
|
}
|
|
if err := ctx.Err(); err != nil {
|
|
return InterfaceStats{}, fmt.Errorf("checking context after reading interface stats: %w", err)
|
|
}
|
|
stats, err := parseNetDev(data, name)
|
|
if err != nil {
|
|
return InterfaceStats{}, err
|
|
}
|
|
return stats, nil
|
|
}
|
|
|
|
func parseNetDev(data []byte, name string) (InterfaceStats, error) {
|
|
scanner := bufio.NewScanner(bytes.NewReader(data))
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
if !strings.Contains(line, ":") {
|
|
continue
|
|
}
|
|
parts := strings.SplitN(line, ":", 2)
|
|
if strings.TrimSpace(parts[0]) != name {
|
|
continue
|
|
}
|
|
fields := strings.Fields(parts[1])
|
|
if len(fields) < 16 {
|
|
return InterfaceStats{}, fmt.Errorf("parsing interface %s stats: expected at least 16 fields, got %d", name, len(fields))
|
|
}
|
|
rxBytes, err := strconv.ParseUint(fields[0], 10, 64)
|
|
if err != nil {
|
|
return InterfaceStats{}, fmt.Errorf("parsing interface %s rx bytes: %w", name, err)
|
|
}
|
|
txBytes, err := strconv.ParseUint(fields[8], 10, 64)
|
|
if err != nil {
|
|
return InterfaceStats{}, fmt.Errorf("parsing interface %s tx bytes: %w", name, err)
|
|
}
|
|
return InterfaceStats{Name: name, RXBytes: rxBytes, TXBytes: txBytes}, nil
|
|
}
|
|
if err := scanner.Err(); err != nil {
|
|
return InterfaceStats{}, fmt.Errorf("scanning %s contents: %w", netDevPath, err)
|
|
}
|
|
return InterfaceStats{}, errors.New("interface not found")
|
|
}
|