Update procfs to v0.0.3 (#1395)

procfs v0.0.3 is a requirement for
https://github.com/prometheus/node_exporter/pull/1357

Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com>
This commit is contained in:
Benjamin Drung 2019-06-25 19:27:07 +02:00 committed by Ben Kochie
commit 4f074dfbc7
16 changed files with 1559 additions and 173 deletions

View file

@ -0,0 +1,370 @@
// Copyright 2019 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !windows
package sysfs
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/prometheus/procfs/internal/util"
)
const infinibandClassPath = "class/infiniband"
// InfiniBandCounters contains counter values from files in
// /sys/class/infiniband/<Name>/ports/<Port>/counters or
// /sys/class/infiniband/<Name>/ports/<Port>/counters_ext
// for a single port of one InfiniBand device.
type InfiniBandCounters struct {
LegacyPortMulticastRcvPackets *uint64 // counters_ext/port_multicast_rcv_packets
LegacyPortMulticastXmitPackets *uint64 // counters_ext/port_multicast_xmit_packets
LegacyPortRcvData64 *uint64 // counters_ext/port_rcv_data_64
LegacyPortRcvPackets64 *uint64 // counters_ext/port_rcv_packets_64
LegacyPortUnicastRcvPackets *uint64 // counters_ext/port_unicast_rcv_packets
LegacyPortUnicastXmitPackets *uint64 // counters_ext/port_unicast_xmit_packets
LegacyPortXmitData64 *uint64 // counters_ext/port_xmit_data_64
LegacyPortXmitPackets64 *uint64 // counters_ext/port_xmit_packets_64
LinkDowned *uint64 // counters/link_downed
LinkErrorRecovery *uint64 // counters/link_error_recovery
MulticastRcvPackets *uint64 // counters/multicast_rcv_packets
MulticastXmitPackets *uint64 // counters/multicast_xmit_packets
PortRcvConstraintErrors *uint64 // counters/port_rcv_constraint_errors
PortRcvData *uint64 // counters/port_rcv_data
PortRcvDiscards *uint64 // counters/port_rcv_discards
PortRcvErrors *uint64 // counters/port_rcv_errors
PortRcvPackets *uint64 // counters/port_rcv_packets
PortXmitConstraintErrors *uint64 // counters/port_xmit_constraint_errors
PortXmitData *uint64 // counters/port_xmit_data
PortXmitDiscards *uint64 // counters/port_xmit_discards
PortXmitPackets *uint64 // counters/port_xmit_packets
PortXmitWait *uint64 // counters/port_xmit_wait
UnicastRcvPackets *uint64 // counters/unicast_rcv_packets
UnicastXmitPackets *uint64 // counters/unicast_xmit_packets
}
// InfiniBandPort contains info from files in
// /sys/class/infiniband/<Name>/ports/<Port>
// for a single port of one InfiniBand device.
type InfiniBandPort struct {
Name string
Port uint
State string // String representation from /sys/class/infiniband/<Name>/ports/<Port>/state
StateID uint // ID from /sys/class/infiniband/<Name>/ports/<Port>/state
PhysState string // String representation from /sys/class/infiniband/<Name>/ports/<Port>/phys_state
PhysStateID uint // String representation from /sys/class/infiniband/<Name>/ports/<Port>/phys_state
Rate uint64 // in bytes/second from /sys/class/infiniband/<Name>/ports/<Port>/rate
Counters InfiniBandCounters
}
// InfiniBandDevice contains info from files in /sys/class/infiniband for a
// single InfiniBand device.
type InfiniBandDevice struct {
Name string
BoardID string // /sys/class/infiniband/<Name>/board_id
FirmwareVersion string // /sys/class/infiniband/<Name>/fw_ver
HCAType string // /sys/class/infiniband/<Name>/hca_type
Ports map[uint]InfiniBandPort
}
// InfiniBandClass is a collection of every InfiniBand device in
// /sys/class/infiniband.
//
// The map keys are the names of the InfiniBand devices.
type InfiniBandClass map[string]InfiniBandDevice
// InfiniBandClass returns info for all InfiniBand devices read from
// /sys/class/infiniband.
func (fs FS) InfiniBandClass() (InfiniBandClass, error) {
path := fs.sys.Path(infinibandClassPath)
dirs, err := ioutil.ReadDir(path)
if err != nil {
return nil, fmt.Errorf("failed to list InfiniBand devices at %q: %v", path, err)
}
ibc := make(InfiniBandClass, len(dirs))
for _, d := range dirs {
device, err := fs.parseInfiniBandDevice(d.Name())
if err != nil {
return nil, err
}
ibc[device.Name] = *device
}
return ibc, nil
}
// Parse one InfiniBand device.
func (fs FS) parseInfiniBandDevice(name string) (*InfiniBandDevice, error) {
path := fs.sys.Path(infinibandClassPath, name)
device := InfiniBandDevice{Name: name}
for _, f := range [...]string{"board_id", "fw_ver", "hca_type"} {
name := filepath.Join(path, f)
value, err := util.SysReadFile(name)
if err != nil {
return nil, fmt.Errorf("failed to read file %q: %v", name, err)
}
switch f {
case "board_id":
device.BoardID = value
case "fw_ver":
device.FirmwareVersion = value
case "hca_type":
device.HCAType = value
}
}
portsPath := filepath.Join(path, "ports")
ports, err := ioutil.ReadDir(portsPath)
if err != nil {
return nil, fmt.Errorf("failed to list InfiniBand ports at %q: %v", portsPath, err)
}
device.Ports = make(map[uint]InfiniBandPort, len(ports))
for _, d := range ports {
port, err := fs.parseInfiniBandPort(name, d.Name())
if err != nil {
return nil, err
}
device.Ports[port.Port] = *port
}
return &device, nil
}
// Parse InfiniBand state. Expected format: "<id>: <string-representation>"
func parseState(s string) (uint, string, error) {
parts := strings.Split(s, ":")
if len(parts) != 2 {
return 0, "", fmt.Errorf("failed to split %s into 'ID: NAME'", s)
}
name := strings.TrimSpace(parts[1])
value, err := strconv.ParseUint(strings.TrimSpace(parts[0]), 10, 32)
if err != nil {
return 0, name, fmt.Errorf("failed to convert %s into uint", strings.TrimSpace(parts[0]))
}
id := uint(value)
return id, name, nil
}
// Parse rate (example: "100 Gb/sec (4X EDR)") and return it as bytes/second
func parseRate(s string) (uint64, error) {
parts := strings.Split(s, "Gb/sec")
if len(parts) != 2 {
return 0, fmt.Errorf("failed to split '%s' by 'Gb/sec'", s)
}
value, err := strconv.ParseFloat(strings.TrimSpace(parts[0]), 32)
if err != nil {
return 0, fmt.Errorf("failed to convert %s into uint", strings.TrimSpace(parts[0]))
}
// Convert Gb/s into bytes/s
rate := uint64(value * 125000000)
return rate, nil
}
// parseInfiniBandPort scans predefined files in /sys/class/infiniband/<device>/ports/<port>
// directory and gets their contents.
func (fs FS) parseInfiniBandPort(name string, port string) (*InfiniBandPort, error) {
portNumber, err := strconv.ParseUint(port, 10, 32)
if err != nil {
return nil, fmt.Errorf("failed to convert %s into uint", port)
}
ibp := InfiniBandPort{Name: name, Port: uint(portNumber)}
portPath := fs.sys.Path(infinibandClassPath, name, "ports", port)
content, err := ioutil.ReadFile(filepath.Join(portPath, "state"))
if err != nil {
return nil, err
}
id, name, err := parseState(string(content))
if err != nil {
return nil, fmt.Errorf("could not parse state file in %s: %s", portPath, err)
}
ibp.State = name
ibp.StateID = id
content, err = ioutil.ReadFile(filepath.Join(portPath, "phys_state"))
if err != nil {
return nil, err
}
id, name, err = parseState(string(content))
if err != nil {
return nil, fmt.Errorf("could not parse phys_state file in %s: %s", portPath, err)
}
ibp.PhysState = name
ibp.PhysStateID = id
content, err = ioutil.ReadFile(filepath.Join(portPath, "rate"))
if err != nil {
return nil, err
}
ibp.Rate, err = parseRate(string(content))
if err != nil {
return nil, fmt.Errorf("could not parse rate file in %s: %s", portPath, err)
}
counters, err := parseInfiniBandCounters(portPath)
if err != nil {
return nil, err
}
ibp.Counters = *counters
return &ibp, nil
}
func parseInfiniBandCounters(portPath string) (*InfiniBandCounters, error) {
var counters InfiniBandCounters
path := filepath.Join(portPath, "counters")
files, err := ioutil.ReadDir(path)
if err != nil {
return nil, err
}
for _, f := range files {
if f.IsDir() {
continue
}
name := filepath.Join(path, f.Name())
value, err := util.SysReadFile(name)
if err != nil {
return nil, fmt.Errorf("failed to read file %q: %v", name, err)
}
// According to Mellanox, the metrics port_rcv_data, port_xmit_data,
// port_rcv_data_64, and port_xmit_data_64 "are divided by 4 unconditionally"
// as they represent the amount of data being transmitted and received per lane.
// Mellanox cards have 4 lanes per port, so all values must be multiplied by 4
// to get the expected value.
vp := util.NewValueParser(value)
switch f.Name() {
case "link_downed":
counters.LinkDowned = vp.PUInt64()
case "link_error_recovery":
counters.LinkErrorRecovery = vp.PUInt64()
case "multicast_rcv_packets":
counters.MulticastRcvPackets = vp.PUInt64()
case "multicast_xmit_packets":
counters.MulticastXmitPackets = vp.PUInt64()
case "port_rcv_constraint_errors":
counters.PortRcvConstraintErrors = vp.PUInt64()
case "port_rcv_data":
counters.PortRcvData = vp.PUInt64()
*counters.PortRcvData *= 4
case "port_rcv_discards":
counters.PortRcvDiscards = vp.PUInt64()
case "port_rcv_errors":
counters.PortRcvErrors = vp.PUInt64()
case "port_rcv_packets":
counters.PortRcvPackets = vp.PUInt64()
case "port_xmit_constraint_errors":
counters.PortXmitConstraintErrors = vp.PUInt64()
case "port_xmit_data":
counters.PortXmitData = vp.PUInt64()
*counters.PortXmitData *= 4
case "port_xmit_discards":
counters.PortXmitDiscards = vp.PUInt64()
case "port_xmit_packets":
counters.PortXmitPackets = vp.PUInt64()
case "port_xmit_wait":
counters.PortXmitWait = vp.PUInt64()
case "unicast_rcv_packets":
counters.UnicastRcvPackets = vp.PUInt64()
case "unicast_xmit_packets":
counters.UnicastXmitPackets = vp.PUInt64()
}
if err := vp.Err(); err != nil {
// Ugly workaround for handling https://github.com/prometheus/node_exporter/issues/966
// when counters are `N/A (not available)`.
// This was already patched and submitted, see
// https://www.spinics.net/lists/linux-rdma/msg68596.html
// Remove this as soon as the fix lands in the enterprise distros.
if strings.Contains(value, "N/A (no PMA)") {
continue
}
return nil, err
}
}
// Parse legacy counters
path = filepath.Join(portPath, "counters_ext")
files, err = ioutil.ReadDir(path)
if err != nil && !os.IsNotExist(err) {
return nil, err
}
for _, f := range files {
if f.IsDir() {
continue
}
name := filepath.Join(path, f.Name())
value, err := util.SysReadFile(name)
if err != nil {
return nil, fmt.Errorf("failed to read file %q: %v", name, err)
}
vp := util.NewValueParser(value)
switch f.Name() {
case "port_multicast_rcv_packets":
counters.LegacyPortMulticastRcvPackets = vp.PUInt64()
case "port_multicast_xmit_packets":
counters.LegacyPortMulticastXmitPackets = vp.PUInt64()
case "port_rcv_data_64":
counters.LegacyPortRcvData64 = vp.PUInt64()
*counters.LegacyPortRcvData64 *= 4
case "port_rcv_packets_64":
counters.LegacyPortRcvPackets64 = vp.PUInt64()
case "port_unicast_rcv_packets":
counters.LegacyPortUnicastRcvPackets = vp.PUInt64()
case "port_unicast_xmit_packets":
counters.LegacyPortUnicastXmitPackets = vp.PUInt64()
case "port_xmit_data_64":
counters.LegacyPortXmitData64 = vp.PUInt64()
*counters.LegacyPortXmitData64 *= 4
case "port_xmit_packets_64":
counters.LegacyPortXmitPackets64 = vp.PUInt64()
}
if err := vp.Err(); err != nil {
// Ugly workaround for handling https://github.com/prometheus/node_exporter/issues/966
// when counters are `N/A (not available)`.
// This was already patched and submitted, see
// https://www.spinics.net/lists/linux-rdma/msg68596.html
// Remove this as soon as the fix lands in the enterprise distros.
if strings.Contains(value, "N/A (no PMA)") {
continue
}
return nil, err
}
}
return &counters, nil
}

View file

@ -18,161 +18,275 @@ package sysfs
import (
"fmt"
"io/ioutil"
"os"
"reflect"
"strconv"
"strings"
"path/filepath"
"github.com/prometheus/procfs/internal/util"
)
// PowerSupply contains info from files in /sys/class/power_supply for a single power supply.
// PowerSupply contains info from files in /sys/class/power_supply for a
// single power supply.
type PowerSupply struct {
Name string // Power Supply Name
Authentic *int64 `fileName:"authentic"` // /sys/class/power_suppy/<Name>/authentic
Calibrate *int64 `fileName:"calibrate"` // /sys/class/power_suppy/<Name>/calibrate
Capacity *int64 `fileName:"capacity"` // /sys/class/power_suppy/<Name>/capacity
CapacityAlertMax *int64 `fileName:"capacity_alert_max"` // /sys/class/power_suppy/<Name>/capacity_alert_max
CapacityAlertMin *int64 `fileName:"capacity_alert_min"` // /sys/class/power_suppy/<Name>/capacity_alert_min
CapacityLevel string `fileName:"capacity_level"` // /sys/class/power_suppy/<Name>/capacity_level
ChargeAvg *int64 `fileName:"charge_avg"` // /sys/class/power_suppy/<Name>/charge_avg
ChargeControlLimit *int64 `fileName:"charge_control_limit"` // /sys/class/power_suppy/<Name>/charge_control_limit
ChargeControlLimitMax *int64 `fileName:"charge_control_limit_max"` // /sys/class/power_suppy/<Name>/charge_control_limit_max
ChargeCounter *int64 `fileName:"charge_counter"` // /sys/class/power_suppy/<Name>/charge_counter
ChargeEmpty *int64 `fileName:"charge_empty"` // /sys/class/power_suppy/<Name>/charge_empty
ChargeEmptyDesign *int64 `fileName:"charge_empty_design"` // /sys/class/power_suppy/<Name>/charge_empty_design
ChargeFull *int64 `fileName:"charge_full"` // /sys/class/power_suppy/<Name>/charge_full
ChargeFullDesign *int64 `fileName:"charge_full_design"` // /sys/class/power_suppy/<Name>/charge_full_design
ChargeNow *int64 `fileName:"charge_now"` // /sys/class/power_suppy/<Name>/charge_now
ChargeTermCurrent *int64 `fileName:"charge_term_current"` // /sys/class/power_suppy/<Name>/charge_term_current
ChargeType string `fileName:"charge_type"` // /sys/class/power_supply/<Name>/charge_type
ConstantChargeCurrent *int64 `fileName:"constant_charge_current"` // /sys/class/power_suppy/<Name>/constant_charge_current
ConstantChargeCurrentMax *int64 `fileName:"constant_charge_current_max"` // /sys/class/power_suppy/<Name>/constant_charge_current_max
ConstantChargeVoltage *int64 `fileName:"constant_charge_voltage"` // /sys/class/power_suppy/<Name>/constant_charge_voltage
ConstantChargeVoltageMax *int64 `fileName:"constant_charge_voltage_max"` // /sys/class/power_suppy/<Name>/constant_charge_voltage_max
CurrentAvg *int64 `fileName:"current_avg"` // /sys/class/power_suppy/<Name>/current_avg
CurrentBoot *int64 `fileName:"current_boot"` // /sys/class/power_suppy/<Name>/current_boot
CurrentMax *int64 `fileName:"current_max"` // /sys/class/power_suppy/<Name>/current_max
CurrentNow *int64 `fileName:"current_now"` // /sys/class/power_suppy/<Name>/current_now
CycleCount *int64 `fileName:"cycle_count"` // /sys/class/power_suppy/<Name>/cycle_count
EnergyAvg *int64 `fileName:"energy_avg"` // /sys/class/power_supply/<Name>/energy_avg
EnergyEmpty *int64 `fileName:"energy_empty"` // /sys/class/power_suppy/<Name>/energy_empty
EnergyEmptyDesign *int64 `fileName:"energy_empty_design"` // /sys/class/power_suppy/<Name>/energy_empty_design
EnergyFull *int64 `fileName:"energy_full"` // /sys/class/power_suppy/<Name>/energy_full
EnergyFullDesign *int64 `fileName:"energy_full_design"` // /sys/class/power_suppy/<Name>/energy_full_design
EnergyNow *int64 `fileName:"energy_now"` // /sys/class/power_supply/<Name>/energy_now
Health string `fileName:"health"` // /sys/class/power_suppy/<Name>/health
InputCurrentLimit *int64 `fileName:"input_current_limit"` // /sys/class/power_suppy/<Name>/input_current_limit
Manufacturer string `fileName:"manufacturer"` // /sys/class/power_suppy/<Name>/manufacturer
ModelName string `fileName:"model_name"` // /sys/class/power_suppy/<Name>/model_name
Online *int64 `fileName:"online"` // /sys/class/power_suppy/<Name>/online
PowerAvg *int64 `fileName:"power_avg"` // /sys/class/power_suppy/<Name>/power_avg
PowerNow *int64 `fileName:"power_now"` // /sys/class/power_suppy/<Name>/power_now
PrechargeCurrent *int64 `fileName:"precharge_current"` // /sys/class/power_suppy/<Name>/precharge_current
Present *int64 `fileName:"present"` // /sys/class/power_suppy/<Name>/present
Scope string `fileName:"scope"` // /sys/class/power_suppy/<Name>/scope
SerialNumber string `fileName:"serial_number"` // /sys/class/power_suppy/<Name>/serial_number
Status string `fileName:"status"` // /sys/class/power_supply/<Name>/status
Technology string `fileName:"technology"` // /sys/class/power_suppy/<Name>/technology
Temp *int64 `fileName:"temp"` // /sys/class/power_suppy/<Name>/temp
TempAlertMax *int64 `fileName:"temp_alert_max"` // /sys/class/power_suppy/<Name>/temp_alert_max
TempAlertMin *int64 `fileName:"temp_alert_min"` // /sys/class/power_suppy/<Name>/temp_alert_min
TempAmbient *int64 `fileName:"temp_ambient"` // /sys/class/power_suppy/<Name>/temp_ambient
TempAmbientMax *int64 `fileName:"temp_ambient_max"` // /sys/class/power_suppy/<Name>/temp_ambient_max
TempAmbientMin *int64 `fileName:"temp_ambient_min"` // /sys/class/power_suppy/<Name>/temp_ambient_min
TempMax *int64 `fileName:"temp_max"` // /sys/class/power_suppy/<Name>/temp_max
TempMin *int64 `fileName:"temp_min"` // /sys/class/power_suppy/<Name>/temp_min
TimeToEmptyAvg *int64 `fileName:"time_to_empty_avg"` // /sys/class/power_suppy/<Name>/time_to_empty_avg
TimeToEmptyNow *int64 `fileName:"time_to_empty_now"` // /sys/class/power_suppy/<Name>/time_to_empty_now
TimeToFullAvg *int64 `fileName:"time_to_full_avg"` // /sys/class/power_suppy/<Name>/time_to_full_avg
TimeToFullNow *int64 `fileName:"time_to_full_now"` // /sys/class/power_suppy/<Name>/time_to_full_now
Type string `fileName:"type"` // /sys/class/power_supply/<Name>/type
UsbType string `fileName:"usb_type"` // /sys/class/power_supply/<Name>/usb_type
VoltageAvg *int64 `fileName:"voltage_avg"` // /sys/class/power_supply/<Name>/voltage_avg
VoltageBoot *int64 `fileName:"voltage_boot"` // /sys/class/power_suppy/<Name>/voltage_boot
VoltageMax *int64 `fileName:"voltage_max"` // /sys/class/power_suppy/<Name>/voltage_max
VoltageMaxDesign *int64 `fileName:"voltage_max_design"` // /sys/class/power_suppy/<Name>/voltage_max_design
VoltageMin *int64 `fileName:"voltage_min"` // /sys/class/power_suppy/<Name>/voltage_min
VoltageMinDesign *int64 `fileName:"voltage_min_design"` // /sys/class/power_suppy/<Name>/voltage_min_design
VoltageNow *int64 `fileName:"voltage_now"` // /sys/class/power_supply/<Name>/voltage_now
VoltageOCV *int64 `fileName:"voltage_ocv"` // /sys/class/power_suppy/<Name>/voltage_ocv
Authentic *int64 // /sys/class/power_supply/<Name>/authentic
Calibrate *int64 // /sys/class/power_supply/<Name>/calibrate
Capacity *int64 // /sys/class/power_supply/<Name>/capacity
CapacityAlertMax *int64 // /sys/class/power_supply/<Name>/capacity_alert_max
CapacityAlertMin *int64 // /sys/class/power_supply/<Name>/capacity_alert_min
CapacityLevel string // /sys/class/power_supply/<Name>/capacity_level
ChargeAvg *int64 // /sys/class/power_supply/<Name>/charge_avg
ChargeControlLimit *int64 // /sys/class/power_supply/<Name>/charge_control_limit
ChargeControlLimitMax *int64 // /sys/class/power_supply/<Name>/charge_control_limit_max
ChargeCounter *int64 // /sys/class/power_supply/<Name>/charge_counter
ChargeEmpty *int64 // /sys/class/power_supply/<Name>/charge_empty
ChargeEmptyDesign *int64 // /sys/class/power_supply/<Name>/charge_empty_design
ChargeFull *int64 // /sys/class/power_supply/<Name>/charge_full
ChargeFullDesign *int64 // /sys/class/power_supply/<Name>/charge_full_design
ChargeNow *int64 // /sys/class/power_supply/<Name>/charge_now
ChargeTermCurrent *int64 // /sys/class/power_supply/<Name>/charge_term_current
ChargeType string // /sys/class/power_supply/<Name>/charge_type
ConstantChargeCurrent *int64 // /sys/class/power_supply/<Name>/constant_charge_current
ConstantChargeCurrentMax *int64 // /sys/class/power_supply/<Name>/constant_charge_current_max
ConstantChargeVoltage *int64 // /sys/class/power_supply/<Name>/constant_charge_voltage
ConstantChargeVoltageMax *int64 // /sys/class/power_supply/<Name>/constant_charge_voltage_max
CurrentAvg *int64 // /sys/class/power_supply/<Name>/current_avg
CurrentBoot *int64 // /sys/class/power_supply/<Name>/current_boot
CurrentMax *int64 // /sys/class/power_supply/<Name>/current_max
CurrentNow *int64 // /sys/class/power_supply/<Name>/current_now
CycleCount *int64 // /sys/class/power_supply/<Name>/cycle_count
EnergyAvg *int64 // /sys/class/power_supply/<Name>/energy_avg
EnergyEmpty *int64 // /sys/class/power_supply/<Name>/energy_empty
EnergyEmptyDesign *int64 // /sys/class/power_supply/<Name>/energy_empty_design
EnergyFull *int64 // /sys/class/power_supply/<Name>/energy_full
EnergyFullDesign *int64 // /sys/class/power_supply/<Name>/energy_full_design
EnergyNow *int64 // /sys/class/power_supply/<Name>/energy_now
Health string // /sys/class/power_supply/<Name>/health
InputCurrentLimit *int64 // /sys/class/power_supply/<Name>/input_current_limit
Manufacturer string // /sys/class/power_supply/<Name>/manufacturer
ModelName string // /sys/class/power_supply/<Name>/model_name
Online *int64 // /sys/class/power_supply/<Name>/online
PowerAvg *int64 // /sys/class/power_supply/<Name>/power_avg
PowerNow *int64 // /sys/class/power_supply/<Name>/power_now
PrechargeCurrent *int64 // /sys/class/power_supply/<Name>/precharge_current
Present *int64 // /sys/class/power_supply/<Name>/present
Scope string // /sys/class/power_supply/<Name>/scope
SerialNumber string // /sys/class/power_supply/<Name>/serial_number
Status string // /sys/class/power_supply/<Name>/status
Technology string // /sys/class/power_supply/<Name>/technology
Temp *int64 // /sys/class/power_supply/<Name>/temp
TempAlertMax *int64 // /sys/class/power_supply/<Name>/temp_alert_max
TempAlertMin *int64 // /sys/class/power_supply/<Name>/temp_alert_min
TempAmbient *int64 // /sys/class/power_supply/<Name>/temp_ambient
TempAmbientMax *int64 // /sys/class/power_supply/<Name>/temp_ambient_max
TempAmbientMin *int64 // /sys/class/power_supply/<Name>/temp_ambient_min
TempMax *int64 // /sys/class/power_supply/<Name>/temp_max
TempMin *int64 // /sys/class/power_supply/<Name>/temp_min
TimeToEmptyAvg *int64 // /sys/class/power_supply/<Name>/time_to_empty_avg
TimeToEmptyNow *int64 // /sys/class/power_supply/<Name>/time_to_empty_now
TimeToFullAvg *int64 // /sys/class/power_supply/<Name>/time_to_full_avg
TimeToFullNow *int64 // /sys/class/power_supply/<Name>/time_to_full_now
Type string // /sys/class/power_supply/<Name>/type
UsbType string // /sys/class/power_supply/<Name>/usb_type
VoltageAvg *int64 // /sys/class/power_supply/<Name>/voltage_avg
VoltageBoot *int64 // /sys/class/power_supply/<Name>/voltage_boot
VoltageMax *int64 // /sys/class/power_supply/<Name>/voltage_max
VoltageMaxDesign *int64 // /sys/class/power_supply/<Name>/voltage_max_design
VoltageMin *int64 // /sys/class/power_supply/<Name>/voltage_min
VoltageMinDesign *int64 // /sys/class/power_supply/<Name>/voltage_min_design
VoltageNow *int64 // /sys/class/power_supply/<Name>/voltage_now
VoltageOCV *int64 // /sys/class/power_supply/<Name>/voltage_ocv
}
// PowerSupplyClass is a collection of every power supply in /sys/class/power_supply/.
// PowerSupplyClass is a collection of every power supply in
// /sys/class/power_supply.
//
// The map keys are the names of the power supplies.
type PowerSupplyClass map[string]PowerSupply
// PowerSupplyClass returns info for all power supplies read from /sys/class/power_supply/.
// PowerSupplyClass returns info for all power supplies read from
// /sys/class/power_supply.
func (fs FS) PowerSupplyClass() (PowerSupplyClass, error) {
path := fs.sys.Path("class/power_supply")
powerSupplyDirs, err := ioutil.ReadDir(path)
dirs, err := ioutil.ReadDir(path)
if err != nil {
return PowerSupplyClass{}, fmt.Errorf("cannot access %s dir %s", path, err)
return nil, fmt.Errorf("failed to list power supplies at %q: %v", path, err)
}
powerSupplyClass := PowerSupplyClass{}
for _, powerSupplyDir := range powerSupplyDirs {
powerSupply, err := powerSupplyClass.parsePowerSupply(path + "/" + powerSupplyDir.Name())
psc := make(PowerSupplyClass, len(dirs))
for _, d := range dirs {
ps, err := parsePowerSupply(filepath.Join(path, d.Name()))
if err != nil {
return nil, err
}
powerSupply.Name = powerSupplyDir.Name()
powerSupplyClass[powerSupplyDir.Name()] = *powerSupply
ps.Name = d.Name()
psc[d.Name()] = *ps
}
return powerSupplyClass, nil
return psc, nil
}
func (psc PowerSupplyClass) parsePowerSupply(powerSupplyPath string) (*PowerSupply, error) {
powerSupply := PowerSupply{}
powerSupplyElem := reflect.ValueOf(&powerSupply).Elem()
powerSupplyType := reflect.TypeOf(powerSupply)
func parsePowerSupply(path string) (*PowerSupply, error) {
files, err := ioutil.ReadDir(path)
if err != nil {
return nil, err
}
//start from 1 - skip the Name field
for i := 1; i < powerSupplyElem.NumField(); i++ {
fieldType := powerSupplyType.Field(i)
fieldValue := powerSupplyElem.Field(i)
if fieldType.Tag.Get("fileName") == "" {
panic(fmt.Errorf("field %s does not have a filename tag", fieldType.Name))
var ps PowerSupply
for _, f := range files {
if f.IsDir() {
continue
}
value, err := util.SysReadFile(powerSupplyPath + "/" + fieldType.Tag.Get("fileName"))
name := filepath.Join(path, f.Name())
value, err := util.SysReadFile(name)
if err != nil {
if os.IsNotExist(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
continue
}
return nil, fmt.Errorf("could not access file %s: %s", fieldType.Tag.Get("fileName"), err)
return nil, fmt.Errorf("failed to read file %q: %v", name, err)
}
switch fieldValue.Kind() {
case reflect.String:
fieldValue.SetString(value)
case reflect.Ptr:
var int64ptr *int64
switch fieldValue.Type() {
case reflect.TypeOf(int64ptr):
var intValue int64
if strings.HasPrefix(value, "0x") {
intValue, err = strconv.ParseInt(value[2:], 16, 64)
if err != nil {
return nil, fmt.Errorf("expected hex value for %s, got: %s", fieldType.Name, value)
}
} else {
intValue, err = strconv.ParseInt(value, 10, 64)
if err != nil {
return nil, fmt.Errorf("expected Uint64 value for %s, got: %s", fieldType.Name, value)
}
}
fieldValue.Set(reflect.ValueOf(&intValue))
default:
return nil, fmt.Errorf("unhandled pointer type %q", fieldValue.Type())
}
default:
return nil, fmt.Errorf("unhandled type %q", fieldValue.Kind())
vp := util.NewValueParser(value)
switch f.Name() {
case "authentic":
ps.Authentic = vp.PInt64()
case "calibrate":
ps.Calibrate = vp.PInt64()
case "capacity":
ps.Capacity = vp.PInt64()
case "capacity_alert_max":
ps.CapacityAlertMax = vp.PInt64()
case "capacity_alert_min":
ps.CapacityAlertMin = vp.PInt64()
case "capacity_level":
ps.CapacityLevel = value
case "charge_avg":
ps.ChargeAvg = vp.PInt64()
case "charge_control_limit":
ps.ChargeControlLimit = vp.PInt64()
case "charge_control_limit_max":
ps.ChargeControlLimitMax = vp.PInt64()
case "charge_counter":
ps.ChargeCounter = vp.PInt64()
case "charge_empty":
ps.ChargeEmpty = vp.PInt64()
case "charge_empty_design":
ps.ChargeEmptyDesign = vp.PInt64()
case "charge_full":
ps.ChargeFull = vp.PInt64()
case "charge_full_design":
ps.ChargeFullDesign = vp.PInt64()
case "charge_now":
ps.ChargeNow = vp.PInt64()
case "charge_term_current":
ps.ChargeTermCurrent = vp.PInt64()
case "charge_type":
ps.ChargeType = value
case "constant_charge_current":
ps.ConstantChargeCurrent = vp.PInt64()
case "constant_charge_current_max":
ps.ConstantChargeCurrentMax = vp.PInt64()
case "constant_charge_voltage":
ps.ConstantChargeVoltage = vp.PInt64()
case "constant_charge_voltage_max":
ps.ConstantChargeVoltageMax = vp.PInt64()
case "current_avg":
ps.CurrentAvg = vp.PInt64()
case "current_boot":
ps.CurrentBoot = vp.PInt64()
case "current_max":
ps.CurrentMax = vp.PInt64()
case "current_now":
ps.CurrentNow = vp.PInt64()
case "cycle_count":
ps.CycleCount = vp.PInt64()
case "energy_avg":
ps.EnergyAvg = vp.PInt64()
case "energy_empty":
ps.EnergyEmpty = vp.PInt64()
case "energy_empty_design":
ps.EnergyEmptyDesign = vp.PInt64()
case "energy_full":
ps.EnergyFull = vp.PInt64()
case "energy_full_design":
ps.EnergyFullDesign = vp.PInt64()
case "energy_now":
ps.EnergyNow = vp.PInt64()
case "health":
ps.Health = value
case "input_current_limit":
ps.InputCurrentLimit = vp.PInt64()
case "manufacturer":
ps.Manufacturer = value
case "model_name":
ps.ModelName = value
case "online":
ps.Online = vp.PInt64()
case "power_avg":
ps.PowerAvg = vp.PInt64()
case "power_now":
ps.PowerNow = vp.PInt64()
case "precharge_current":
ps.PrechargeCurrent = vp.PInt64()
case "present":
ps.Present = vp.PInt64()
case "scope":
ps.Scope = value
case "serial_number":
ps.SerialNumber = value
case "status":
ps.Status = value
case "technology":
ps.Technology = value
case "temp":
ps.Temp = vp.PInt64()
case "temp_alert_max":
ps.TempAlertMax = vp.PInt64()
case "temp_alert_min":
ps.TempAlertMin = vp.PInt64()
case "temp_ambient":
ps.TempAmbient = vp.PInt64()
case "temp_ambient_max":
ps.TempAmbientMax = vp.PInt64()
case "temp_ambient_min":
ps.TempAmbientMin = vp.PInt64()
case "temp_max":
ps.TempMax = vp.PInt64()
case "temp_min":
ps.TempMin = vp.PInt64()
case "time_to_empty_avg":
ps.TimeToEmptyAvg = vp.PInt64()
case "time_to_empty_now":
ps.TimeToEmptyNow = vp.PInt64()
case "time_to_full_avg":
ps.TimeToFullAvg = vp.PInt64()
case "time_to_full_now":
ps.TimeToFullNow = vp.PInt64()
case "type":
ps.Type = value
case "usb_type":
ps.UsbType = value
case "voltage_avg":
ps.VoltageAvg = vp.PInt64()
case "voltage_boot":
ps.VoltageBoot = vp.PInt64()
case "voltage_max":
ps.VoltageMax = vp.PInt64()
case "voltage_max_design":
ps.VoltageMaxDesign = vp.PInt64()
case "voltage_min":
ps.VoltageMin = vp.PInt64()
case "voltage_min_design":
ps.VoltageMinDesign = vp.PInt64()
case "voltage_now":
ps.VoltageNow = vp.PInt64()
case "voltage_ocv":
ps.VoltageOCV = vp.PInt64()
}
if err := vp.Err(); err != nil {
return nil, err
}
}
return &powerSupply, nil
return &ps, nil
}