From 8c750ebef55b7d6551b1fd73401df61aacf9b43f Mon Sep 17 00:00:00 2001 From: Nick Cabatoff Date: Sun, 17 Jul 2016 19:01:08 -0400 Subject: [PATCH] add hddtemp metric --- README.md | 14 +++++++++- sensor-exporter/main.go | 61 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8168a67..247967f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,14 @@ # sensor-exporter -Prometheus exporter for sensor data like temperature and fan speed +Prometheus exporter for sensor data like temperature and fan speed. + +## Inputs + +lm-sensors (http://www.lm-sensors.org) to get metrics like CPU/MB temp and +CPU/Chassis fan speed. You'll likely need to install lm-sensor dev package +(libsensors4-dev on my Ubuntu 14 system) in order to build the dependant +package github.com/md14454/gosensors. + +hddtemp (http://www.guzu.net/linux/hddtemp.php) to get HDD temperature from +SMART data. Since hddtemp must run as root to collect this data, rather than +call it directly we expect the user to run it in daemon mode with its -d flag. +Then we connect to a port it listens on to fetch the data. diff --git a/sensor-exporter/main.go b/sensor-exporter/main.go index 9e70a0a..8ea4ba7 100644 --- a/sensor-exporter/main.go +++ b/sensor-exporter/main.go @@ -1,9 +1,14 @@ package main import ( + "bytes" "flag" + "io" + "log" + "net" "net/http" _ "net/http/pprof" + "strconv" "strings" "time" @@ -25,21 +30,31 @@ var ( Name: "temperature_celsius", Help: "temperature in celsius", }, []string{"temptype", "chip", "adaptor"}) + + hddtemperature = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "sensor", + Subsystem: "hddsmart", + Name: "temperature_celsius", + Help: "temperature in celsius", + }, []string{"device", "id"}) ) func init() { prometheus.MustRegister(fanspeed) prometheus.MustRegister(temperature) + prometheus.MustRegister(hddtemperature) } func main() { var ( - listenAddress = flag.String("web.listen-address", ":9255", "Address on which to expose metrics and web interface.") - metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.") + listenAddress = flag.String("web.listen-address", ":9255", "Address on which to expose metrics and web interface.") + metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.") + hddtempAddress = flag.String("hddtemp-address", "localhost:7634", "Address to fetch hdd metrics from.") ) flag.Parse() - go collect() + go collectLm() + go collectHdd(*hddtempAddress) http.Handle(*metricsPath, prometheus.Handler()) @@ -55,7 +70,7 @@ func main() { http.ListenAndServe(*listenAddress, nil) } -func collect() { +func collectLm() { gosensors.Init() defer gosensors.Cleanup() for { @@ -74,3 +89,41 @@ func collect() { time.Sleep(1 * time.Second) } } + +func collectHdd(address string) { + for { + conn, err := net.Dial("tcp", address) + if err != nil { + log.Printf("Error connecting to hddtemp address '%s': %v", address, err) + } else { + var buf bytes.Buffer + _, err := io.Copy(&buf, conn) + if err != nil { + log.Printf("Error reading from hddtemp socket: %v", err) + } else { + parseHddTemps(buf.String()) + } + } + time.Sleep(1 * time.Second) + } +} + +func parseHddTemps(s string) { + if len(s) < 1 || s[0] != '|' { + log.Printf("Error parsing output from hddtemp: %s", s) + } + for _, item := range strings.Split(s[1:len(s)-1], "||") { + pieces := strings.Split(item, "|") + if len(pieces) != 4 { + log.Printf("Error parsing item from hddtemp, expected 4 tokens: %s", item) + } else { + dev, id, temp := pieces[0], pieces[1], pieces[2] + 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) + } + } + } +}