exporter-go-mystrom/main.go

155 lines
4.6 KiB
Go
Raw Normal View History

2021-12-23 16:46:18 +01:00
//go:generate stringer -type MystromReqStatus main.go
2021-03-18 15:33:22 +01:00
package main
import (
"flag"
"fmt"
"net/http"
"os"
2021-12-23 16:36:04 +01:00
"strings"
2021-03-18 15:33:22 +01:00
"time"
2021-11-12 12:03:52 +01:00
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/common/log"
2021-12-23 15:17:58 +01:00
2021-12-23 16:36:04 +01:00
"mystrom-exporter/pkg/mystrom"
2021-12-23 15:17:58 +01:00
"mystrom-exporter/pkg/version"
2021-03-18 15:33:22 +01:00
)
2021-12-23 16:46:18 +01:00
// -- MystromRequestStatusType represents the request to MyStrom device status
type MystromReqStatus uint32
2021-03-18 15:33:22 +01:00
2021-12-23 16:46:18 +01:00
const (
OK MystromReqStatus = iota
ERROR_SOCKET
ERROR_TIMEOUT
ERROR_PARSING_VALUE
)
2021-03-18 15:33:22 +01:00
const namespace = "mystrom_exporter"
2021-03-18 15:33:22 +01:00
var (
listenAddress = flag.String("web.listen-address", ":9452",
"Address to listen on")
metricsPath = flag.String("web.metrics-path", "/metrics",
2021-12-23 16:36:04 +01:00
"Path under which to expose exporters own metrics")
devicePath = flag.String("web.device-path", "/device",
"Path under which the metrics of the devices are fetched")
2021-12-23 15:17:58 +01:00
showVersion = flag.Bool("version", false,
"Show version information.")
2021-03-18 15:33:22 +01:00
)
2021-12-23 16:36:04 +01:00
var (
mystromDurationCounterVec *prometheus.CounterVec
mystromRequestsCounterVec *prometheus.CounterVec
)
var landingPage = []byte(`<html>
<head><title>myStrom switch report Exporter</title></head>
<body>
<h1>myStrom Exporter</h1>
<p><a href='` + *metricsPath + `'>Metrics</a></p>
</body>
</html>`)
2021-03-18 15:33:22 +01:00
func main() {
flag.Parse()
2021-12-23 16:36:04 +01:00
// -- show version information
2021-12-23 15:17:58 +01:00
if *showVersion {
v, err := version.Print("mystrom_exporter")
if err != nil {
log.Fatalf("Failed to print version information: %#v", err)
}
fmt.Fprintln(os.Stdout, v)
os.Exit(0)
}
2021-12-23 16:36:04 +01:00
// -- create a new registry for the exporter telemetry
telemetryRegistry := setupMetrics()
2021-03-18 15:33:22 +01:00
2021-12-23 16:36:04 +01:00
router := http.NewServeMux()
router.Handle(*metricsPath, promhttp.HandlerFor(telemetryRegistry, promhttp.HandlerOpts{}))
router.HandleFunc(*devicePath, scrapeHandler)
2021-12-23 16:36:04 +01:00
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write(landingPage)
2021-03-18 15:33:22 +01:00
})
2021-12-23 16:36:04 +01:00
log.Infoln("Listening on address " + *listenAddress)
log.Fatal(http.ListenAndServe(*listenAddress, router))
}
2021-11-12 12:03:52 +01:00
func scrapeHandler(w http.ResponseWriter, r *http.Request) {
2021-12-23 16:36:04 +01:00
target := r.URL.Query().Get("target")
if target == "" {
http.Error(w, "'target' parameter must be specified", http.StatusBadRequest)
return
}
log.Infof("got scrape request for target '%v'", target)
exporter := mystrom.NewExporter(target)
2021-12-23 16:36:04 +01:00
start := time.Now()
gatherer, err := exporter.Scrape()
2021-12-23 16:36:04 +01:00
duration := time.Since(start).Seconds()
if err != nil {
2021-12-23 16:36:04 +01:00
if strings.Contains(fmt.Sprintf("%v", err), "unable to connect with target") {
2021-12-23 16:46:18 +01:00
mystromRequestsCounterVec.WithLabelValues(target, ERROR_SOCKET.String()).Inc()
2021-12-23 16:36:04 +01:00
} else if strings.Contains(fmt.Sprintf("%v", err), "i/o timeout") {
2021-12-23 16:46:18 +01:00
mystromRequestsCounterVec.WithLabelValues(target, ERROR_TIMEOUT.String()).Inc()
} else {
mystromRequestsCounterVec.WithLabelValues(target, ERROR_PARSING_VALUE.String()).Inc()
2021-12-23 16:36:04 +01:00
}
http.Error(
w,
fmt.Sprintf("failed to scrape target '%v': %v", target, err),
http.StatusInternalServerError,
)
log.Error(err)
return
}
2021-12-23 16:36:04 +01:00
mystromDurationCounterVec.WithLabelValues(target).Add(duration)
2021-12-23 16:46:18 +01:00
mystromRequestsCounterVec.WithLabelValues(target, OK.String()).Inc()
2021-12-23 16:36:04 +01:00
promhttp.HandlerFor(gatherer, promhttp.HandlerOpts{}).ServeHTTP(w, r)
}
// -- setupMetrics creates a new registry for the exporter telemetry
func setupMetrics() *prometheus.Registry {
registry := prometheus.NewRegistry()
registry.MustRegister(prometheus.NewGoCollector())
registry.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
mystromDurationCounterVec = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Name: "request_duration_seconds_total",
Help: "Total duration of mystrom successful requests by target in seconds",
},
[]string{"target"})
registry.MustRegister(mystromDurationCounterVec)
mystromRequestsCounterVec = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Name: "requests_total",
Help: "Number of mystrom request by status and target",
},
[]string{"target", "status"})
registry.MustRegister(mystromRequestsCounterVec)
// -- make the build information is available through a metric
buildInfo := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: namespace,
Name: "build_info",
Help: "A metric with a constant '1' value labeled by build information.",
},
[]string{"version", "revision", "branch", "goversion", "builddate", "builduser"},
)
buildInfo.WithLabelValues(version.Version, version.Revision, version.Branch, version.GoVersion, version.BuildDate, version.BuildUser).Set(1)
registry.MustRegister(buildInfo)
return registry
2021-03-18 15:33:22 +01:00
}