github.com/netdata/go.d.plugin@v0.58.1/modules/upsd/collect.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package upsd 4 5 import ( 6 "errors" 7 "strconv" 8 "strings" 9 ) 10 11 func (u *Upsd) collect() (map[string]int64, error) { 12 if u.conn == nil { 13 conn, err := u.establishConnection() 14 if err != nil { 15 return nil, err 16 } 17 u.conn = conn 18 } 19 20 upsUnits, err := u.conn.upsUnits() 21 if err != nil { 22 if !errors.Is(err, errUpsdCommand) { 23 _ = u.conn.disconnect() 24 u.conn = nil 25 } 26 return nil, err 27 } 28 29 u.Debugf("found %d UPS units", len(upsUnits)) 30 31 mx := make(map[string]int64) 32 33 u.collectUPSUnits(mx, upsUnits) 34 35 return mx, nil 36 } 37 38 func (u *Upsd) establishConnection() (upsdConn, error) { 39 conn := u.newUpsdConn(u.Config) 40 41 if err := conn.connect(); err != nil { 42 return nil, err 43 } 44 45 if u.Username != "" && u.Password != "" { 46 if err := conn.authenticate(u.Username, u.Password); err != nil { 47 _ = conn.disconnect() 48 return nil, err 49 } 50 } 51 52 return conn, nil 53 } 54 55 func (u *Upsd) collectUPSUnits(mx map[string]int64, upsUnits []upsUnit) { 56 seen := make(map[string]bool) 57 58 for _, ups := range upsUnits { 59 seen[ups.name] = true 60 u.Debugf("collecting metrics UPS '%s'", ups.name) 61 62 if !u.upsUnits[ups.name] { 63 u.upsUnits[ups.name] = true 64 u.addUPSCharts(ups) 65 } 66 67 writeVar(mx, ups, varBatteryCharge) 68 writeVar(mx, ups, varBatteryRuntime) 69 writeVar(mx, ups, varBatteryVoltage) 70 writeVar(mx, ups, varBatteryVoltageNominal) 71 72 writeVar(mx, ups, varInputVoltage) 73 writeVar(mx, ups, varInputVoltageNominal) 74 writeVar(mx, ups, varInputCurrent) 75 writeVar(mx, ups, varInputCurrentNominal) 76 writeVar(mx, ups, varInputFrequency) 77 writeVar(mx, ups, varInputFrequencyNominal) 78 79 writeVar(mx, ups, varOutputVoltage) 80 writeVar(mx, ups, varOutputVoltageNominal) 81 writeVar(mx, ups, varOutputCurrent) 82 writeVar(mx, ups, varOutputCurrentNominal) 83 writeVar(mx, ups, varOutputFrequency) 84 writeVar(mx, ups, varOutputFrequencyNominal) 85 86 writeVar(mx, ups, varUpsLoad) 87 writeVar(mx, ups, varUpsRealPowerNominal) 88 writeVar(mx, ups, varUpsTemperature) 89 writeUpsLoadUsage(mx, ups) 90 writeUpsStatus(mx, ups) 91 } 92 93 for name := range u.upsUnits { 94 if !seen[name] { 95 delete(u.upsUnits, name) 96 u.removeUPSCharts(name) 97 } 98 } 99 } 100 101 func writeVar(mx map[string]int64, ups upsUnit, v string) { 102 s, ok := ups.vars[v] 103 if !ok { 104 return 105 } 106 n, err := strconv.ParseFloat(s, 64) 107 if err != nil { 108 return 109 } 110 mx[prefix(ups)+v] = int64(n * varPrecision) 111 } 112 113 func writeUpsLoadUsage(mx map[string]int64, ups upsUnit) { 114 if hasVar(ups.vars, varUpsRealPower) { 115 pow, _ := strconv.ParseFloat(ups.vars[varUpsRealPower], 64) 116 mx[prefix(ups)+"ups.load.usage"] = int64(pow * varPrecision) 117 return 118 } 119 120 if !hasVar(ups.vars, varUpsLoad) || !hasVar(ups.vars, varUpsRealPowerNominal) { 121 return 122 } 123 load, err := strconv.ParseFloat(ups.vars[varUpsLoad], 64) 124 if err != nil { 125 return 126 } 127 nomPower, err := strconv.ParseFloat(ups.vars[varUpsRealPowerNominal], 64) 128 if err != nil || nomPower == 0 { 129 return 130 } 131 mx[prefix(ups)+"ups.load.usage"] = int64((load / 100 * nomPower) * varPrecision) 132 } 133 134 // https://networkupstools.org/docs/developer-guide.chunked/ar01s04.html#_status_data 135 var upsStatuses = map[string]bool{ 136 "OL": true, 137 "OB": true, 138 "LB": true, 139 "HB": true, 140 "RB": true, 141 "CHRG": true, 142 "DISCHRG": true, 143 "BYPASS": true, 144 "CAL": true, 145 "OFF": true, 146 "OVER": true, 147 "TRIM": true, 148 "BOOST": true, 149 "FSD": true, 150 } 151 152 func writeUpsStatus(mx map[string]int64, ups upsUnit) { 153 if !hasVar(ups.vars, varUpsStatus) { 154 return 155 } 156 157 px := prefix(ups) + "ups.status." 158 159 for st := range upsStatuses { 160 mx[px+st] = 0 161 } 162 mx[px+"other"] = 0 163 164 for _, st := range strings.Split(ups.vars[varUpsStatus], " ") { 165 if _, ok := upsStatuses[st]; ok { 166 mx[px+st] = 1 167 } else { 168 mx[px+"other"] = 1 169 } 170 } 171 } 172 173 func hasVar(vars map[string]string, v string) bool { 174 _, ok := vars[v] 175 return ok 176 } 177 178 func prefix(ups upsUnit) string { 179 return "ups_" + ups.name + "_" 180 }