package main import ( "fmt" "os" "strconv" "strings" ) var nicFields = []string{ "rx_packets", "tx_packets", "rx_errors", "tx_errors", "rx_dropped", "tx_dropped", "rx_crc_errors", "rx_missed_errors", "rx_length_errors", "rx_over_errors", "rx_frame_errors", "rx_fifo_errors", "collisions", } type nicCounters struct { stats map[string]uint64 carrierChanges uint64 carrierUp uint64 carrierDown uint64 } func readUint(path string) (uint64, bool) { b, err := os.ReadFile(path) if err != nil { return 0, false } v, err := strconv.ParseUint(strings.TrimSpace(string(b)), 10, 64) if err != nil { return 0, false } return v, true } func readNIC(ifname string) nicCounters { c := nicCounters{stats: make(map[string]uint64, len(nicFields))} base := "/sys/class/net/" + ifname for _, f := range nicFields { if v, ok := readUint(base + "/statistics/" + f); ok { c.stats[f] = v } } c.carrierChanges, _ = readUint(base + "/carrier_changes") c.carrierUp, _ = readUint(base + "/carrier_up_count") c.carrierDown, _ = readUint(base + "/carrier_down_count") return c } func (c nicCounters) diff(prev nicCounters) string { var parts []string for _, f := range nicFields { now, ok := c.stats[f] if !ok { continue } if d := now - prev.stats[f]; d != 0 && !strings.HasSuffix(f, "_packets") { parts = append(parts, fmt.Sprintf("%s=%d", f, d)) } } if d := c.carrierChanges - prev.carrierChanges; d != 0 { parts = append(parts, fmt.Sprintf("carrier_changes=%d", d)) } if d := c.carrierDown - prev.carrierDown; d != 0 { parts = append(parts, fmt.Sprintf("carrier_down=%d", d)) } return strings.Join(parts, " ") }