Collect HDD metrics only when scraped (best practice for exporters)
parent
f66a0fd663
commit
c2cf39dd43
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
@ -45,12 +46,11 @@ var (
|
||||||
Help: "temperature in celsius",
|
Help: "temperature in celsius",
|
||||||
}, []string{"temptype", "chip", "adaptor"})
|
}, []string{"temptype", "chip", "adaptor"})
|
||||||
|
|
||||||
hddtemperature = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
hddTempDesc = prometheus.NewDesc(
|
||||||
Namespace: "sensor",
|
"sensor_hddsmart_temperature_celsius",
|
||||||
Subsystem: "hddsmart",
|
"temperature in celsius",
|
||||||
Name: "temperature_celsius",
|
[]string{"device", "id"},
|
||||||
Help: "temperature in celsius",
|
nil)
|
||||||
}, []string{"device", "id"})
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -58,7 +58,6 @@ func init() {
|
||||||
prometheus.MustRegister(voltages)
|
prometheus.MustRegister(voltages)
|
||||||
prometheus.MustRegister(powers)
|
prometheus.MustRegister(powers)
|
||||||
prometheus.MustRegister(temperature)
|
prometheus.MustRegister(temperature)
|
||||||
prometheus.MustRegister(hddtemperature)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -69,8 +68,14 @@ func main() {
|
||||||
)
|
)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
prometheus.EnableCollectChecks(true)
|
||||||
|
hddcollector := NewHddCollector(*hddtempAddress)
|
||||||
|
if err := hddcollector.Init(); err != nil {
|
||||||
|
log.Printf("error readding hddtemps: %v", err)
|
||||||
|
}
|
||||||
|
prometheus.MustRegister(hddcollector)
|
||||||
|
|
||||||
go collectLm()
|
go collectLm()
|
||||||
go collectHdd(*hddtempAddress)
|
|
||||||
|
|
||||||
http.Handle(*metricsPath, prometheus.Handler())
|
http.Handle(*metricsPath, prometheus.Handler())
|
||||||
|
|
||||||
|
@ -110,46 +115,107 @@ func collectLm() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectHdd(address string) {
|
type (
|
||||||
for {
|
HddCollector struct {
|
||||||
conn, err := net.Dial("tcp", address)
|
address string
|
||||||
if err != nil {
|
conn net.Conn
|
||||||
log.Printf("Error connecting to hddtemp address '%s': %v", address, err)
|
buf bytes.Buffer
|
||||||
} else {
|
}
|
||||||
var buf bytes.Buffer
|
|
||||||
_, err := io.Copy(&buf, conn)
|
HddTemperature struct {
|
||||||
if err != nil {
|
Device string
|
||||||
log.Printf("Error reading from hddtemp socket: %v", err)
|
Id string
|
||||||
} else {
|
TemperatureCelsius float64
|
||||||
parseHddTemps(buf.String())
|
}
|
||||||
}
|
)
|
||||||
if err := conn.Close(); err != nil {
|
|
||||||
log.Printf("Error closing hddtemp socket: %v", err)
|
func NewHddCollector(address string) *HddCollector {
|
||||||
}
|
return &HddCollector{
|
||||||
}
|
address: address,
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseHddTemps(s string) {
|
func (h *HddCollector) Init() error {
|
||||||
|
conn, err := net.Dial("tcp", h.address)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error connecting to hddtemp address '%s': %v", h.address, err)
|
||||||
|
}
|
||||||
|
h.conn = conn
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HddCollector) readTempsFromConn() (string, error) {
|
||||||
|
_, err := io.Copy(&h.buf, h.conn)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Error reading from hddtemp socket: %v", err)
|
||||||
|
}
|
||||||
|
return h.buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HddCollector) Close() error {
|
||||||
|
if err := h.conn.Close(); err != nil {
|
||||||
|
return fmt.Errorf("Error closing hddtemp socket: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHddTemps(s string) ([]HddTemperature, error) {
|
||||||
|
var hddtemps []HddTemperature
|
||||||
if len(s) < 1 || s[0] != '|' {
|
if len(s) < 1 || s[0] != '|' {
|
||||||
log.Printf("Error parsing output from hddtemp: %s", s)
|
return nil, fmt.Errorf("Error parsing output from hddtemp: %s", s)
|
||||||
}
|
}
|
||||||
for _, item := range strings.Split(s[1:len(s)-1], "||") {
|
for _, item := range strings.Split(s[1:len(s)-1], "||") {
|
||||||
pieces := strings.Split(item, "|")
|
hddtemp, err := parseHddTemp(item)
|
||||||
if len(pieces) != 4 {
|
if err != nil {
|
||||||
log.Printf("Error parsing item from hddtemp, expected 4 tokens: %s", item)
|
return nil, fmt.Errorf("Error parsing output from hddtemp: %v", err)
|
||||||
} else if pieces[3] != "C" {
|
|
||||||
log.Printf("Error parsing item from hddtemp, I only speak Celsius", item)
|
|
||||||
} else {
|
} else {
|
||||||
dev, id, temp := pieces[0], pieces[1], pieces[2]
|
hddtemps = append(hddtemps, hddtemp)
|
||||||
ftemp, err := strconv.ParseFloat(temp, 64)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error parsing temperature as float: %s", temp)
|
|
||||||
} else {
|
|
||||||
hddtemperature.WithLabelValues(dev, id).Set(ftemp)
|
|
||||||
// TODO handle unit F
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return hddtemps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHddTemp(s string) (HddTemperature, error) {
|
||||||
|
pieces := strings.Split(s, "|")
|
||||||
|
if len(pieces) != 4 {
|
||||||
|
return HddTemperature{}, fmt.Errorf("error parsing item from hddtemp, expected 4 tokens: %s", s)
|
||||||
|
}
|
||||||
|
if pieces[3] != "C" {
|
||||||
|
return HddTemperature{}, fmt.Errorf("error parsing item from hddtemp, I only speak Celsius", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
dev, id, temp := pieces[0], pieces[1], pieces[2]
|
||||||
|
ftemp, err := strconv.ParseFloat(temp, 64)
|
||||||
|
if err != nil {
|
||||||
|
return HddTemperature{}, fmt.Errorf("Error parsing temperature as float: %s", temp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return HddTemperature{Device: dev, Id: id, TemperatureCelsius: ftemp}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe implements prometheus.Collector.
|
||||||
|
func (e *HddCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||||
|
ch <- hddTempDesc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect implements prometheus.Collector.
|
||||||
|
func (h *HddCollector) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
tempsString, err := h.readTempsFromConn()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error reading temps from hddtemp daemon: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hddtemps, err := parseHddTemps(tempsString)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error parsing temps from hddtemp daemon: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ht := range hddtemps {
|
||||||
|
ch <- prometheus.MustNewConstMetric(hddTempDesc,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
ht.TemperatureCelsius,
|
||||||
|
ht.Device,
|
||||||
|
ht.Id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue