// 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 !nopowersupplyclass
// +build linux
package collector
import (
"errors"
"fmt"
"os"
"regexp"
"strings"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs/sysfs"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
powerSupplyClassIgnoredPowerSupplies = kingpin . Flag ( "collector.powersupply.ignored-supplies" , "Regexp of power supplies to ignore for powersupplyclass collector." ) . Default ( "^$" ) . String ( )
)
type powerSupplyClassCollector struct {
subsystem string
ignoredPattern * regexp . Regexp
metricDescs map [ string ] * prometheus . Desc
logger log . Logger
}
func init ( ) {
registerCollector ( "powersupplyclass" , defaultEnabled , NewPowerSupplyClassCollector )
}
func NewPowerSupplyClassCollector ( logger log . Logger ) ( Collector , error ) {
pattern := regexp . MustCompile ( * powerSupplyClassIgnoredPowerSupplies )
return & powerSupplyClassCollector {
subsystem : "power_supply" ,
ignoredPattern : pattern ,
metricDescs : map [ string ] * prometheus . Desc { } ,
logger : logger ,
} , nil
}
func ( c * powerSupplyClassCollector ) Update ( ch chan <- prometheus . Metric ) error {
powerSupplyClass , err := getPowerSupplyClassInfo ( c . ignoredPattern )
if err != nil {
if errors . Is ( err , os . ErrNotExist ) {
return ErrNoData
}
return fmt . Errorf ( "could not get power_supply class info: %w" , err )
}
for _ , powerSupply := range powerSupplyClass {
for name , value := range map [ string ] * int64 {
"authentic" : powerSupply . Authentic ,
"calibrate" : powerSupply . Calibrate ,
"capacity" : powerSupply . Capacity ,
"capacity_alert_max" : powerSupply . CapacityAlertMax ,
"capacity_alert_min" : powerSupply . CapacityAlertMin ,
"cyclecount" : powerSupply . CycleCount ,
"online" : powerSupply . Online ,
"present" : powerSupply . Present ,
"time_to_empty_seconds" : powerSupply . TimeToEmptyNow ,
"time_to_full_seconds" : powerSupply . TimeToFullNow ,
} {
if value != nil {
pushPowerSupplyMetric ( ch , c . subsystem , name , float64 ( * value ) , powerSupply . Name , prometheus . GaugeValue )
}
}
for name , value := range map [ string ] * int64 {
"current_boot" : powerSupply . CurrentBoot ,
"current_max" : powerSupply . CurrentMax ,
"current_ampere" : powerSupply . CurrentNow ,
"energy_empty" : powerSupply . EnergyEmpty ,
"energy_empty_design" : powerSupply . EnergyEmptyDesign ,
"energy_full" : powerSupply . EnergyFull ,
"energy_full_design" : powerSupply . EnergyFullDesign ,
"energy_watthour" : powerSupply . EnergyNow ,
"voltage_boot" : powerSupply . VoltageBoot ,
"voltage_max" : powerSupply . VoltageMax ,
"voltage_max_design" : powerSupply . VoltageMaxDesign ,
"voltage_min" : powerSupply . VoltageMin ,
"voltage_min_design" : powerSupply . VoltageMinDesign ,
"voltage_volt" : powerSupply . VoltageNow ,
"voltage_ocv" : powerSupply . VoltageOCV ,
"charge_control_limit" : powerSupply . ChargeControlLimit ,
"charge_control_limit_max" : powerSupply . ChargeControlLimitMax ,
"charge_counter" : powerSupply . ChargeCounter ,
"charge_empty" : powerSupply . ChargeEmpty ,
"charge_empty_design" : powerSupply . ChargeEmptyDesign ,
"charge_full" : powerSupply . ChargeFull ,
"charge_full_design" : powerSupply . ChargeFullDesign ,
"charge_ampere" : powerSupply . ChargeNow ,
"charge_term_current" : powerSupply . ChargeTermCurrent ,
"constant_charge_current" : powerSupply . ConstantChargeCurrent ,
"constant_charge_current_max" : powerSupply . ConstantChargeCurrentMax ,
"constant_charge_voltage" : powerSupply . ConstantChargeVoltage ,
"constant_charge_voltage_max" : powerSupply . ConstantChargeVoltageMax ,
"precharge_current" : powerSupply . PrechargeCurrent ,
"input_current_limit" : powerSupply . InputCurrentLimit ,
"power_watt" : powerSupply . PowerNow ,
} {
if value != nil {
pushPowerSupplyMetric ( ch , c . subsystem , name , float64 ( * value ) / 1e6 , powerSupply . Name , prometheus . GaugeValue )
}
}
for name , value := range map [ string ] * int64 {
"temp_celsius" : powerSupply . Temp ,
"temp_alert_max_celsius" : powerSupply . TempAlertMax ,
"temp_alert_min_celsius" : powerSupply . TempAlertMin ,
"temp_ambient_celsius" : powerSupply . TempAmbient ,
"temp_ambient_max_celsius" : powerSupply . TempAmbientMax ,
"temp_ambient_min_celsius" : powerSupply . TempAmbientMin ,
"temp_max_celsius" : powerSupply . TempMax ,
"temp_min_celsius" : powerSupply . TempMin ,
} {
if value != nil {
pushPowerSupplyMetric ( ch , c . subsystem , name , float64 ( * value ) / 10.0 , powerSupply . Name , prometheus . GaugeValue )
}
}
var (
keys [ ] string
values [ ] string
)
for name , value := range map [ string ] string {
"power_supply" : powerSupply . Name ,
"capacity_level" : powerSupply . CapacityLevel ,
"charge_type" : powerSupply . ChargeType ,
"health" : powerSupply . Health ,
"manufacturer" : powerSupply . Manufacturer ,
"model_name" : powerSupply . ModelName ,
"serial_number" : powerSupply . SerialNumber ,
"status" : powerSupply . Status ,
"technology" : powerSupply . Technology ,
"type" : powerSupply . Type ,
"usb_type" : powerSupply . UsbType ,
"scope" : powerSupply . Scope ,
} {
if value != "" {
keys = append ( keys , name )
values = append ( values , strings . ToValidUTF8 ( value , "<22> " ) )
}
}
fieldDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , c . subsystem , "info" ) ,
"info of /sys/class/power_supply/<power_supply>." ,
keys ,
nil ,
)
ch <- prometheus . MustNewConstMetric ( fieldDesc , prometheus . GaugeValue , 1.0 , values ... )
}
return nil
}
func pushPowerSupplyMetric ( ch chan <- prometheus . Metric , subsystem string , name string , value float64 , powerSupplyName string , valueType prometheus . ValueType ) {
fieldDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , name ) ,
fmt . Sprintf ( "%s value of /sys/class/power_supply/<power_supply>." , name ) ,
[ ] string { "power_supply" } ,
nil ,
)
ch <- prometheus . MustNewConstMetric ( fieldDesc , valueType , value , powerSupplyName )
}
func getPowerSupplyClassInfo ( ignore * regexp . Regexp ) ( sysfs . PowerSupplyClass , error ) {
fs , err := sysfs . NewFS ( * sysPath )
if err != nil {
return nil , err
}
powerSupplyClass , err := fs . PowerSupplyClass ( )
if err != nil {
return powerSupplyClass , fmt . Errorf ( "error obtaining power_supply class info: %w" , err )
}
for device := range powerSupplyClass {
if ignore . MatchString ( device ) {
delete ( powerSupplyClass , device )
}
}
return powerSupplyClass , nil
}