2025-10-21 09:41:18 +02:00
|
|
|
package cmd
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"log/slog"
|
|
|
|
|
"net/http"
|
|
|
|
|
"os"
|
|
|
|
|
"strings"
|
|
|
|
|
|
2025-10-25 22:20:36 +02:00
|
|
|
// enable to debug with roumon
|
|
|
|
|
//_ "net/http/pprof"
|
|
|
|
|
// then: roumon -host=localhost -port=9187
|
|
|
|
|
|
2025-10-21 09:41:18 +02:00
|
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
|
|
|
)
|
|
|
|
|
|
2025-10-23 12:14:33 +02:00
|
|
|
// Main program. starts 2 goroutines: our exporter and the http server
|
|
|
|
|
// for the prometheus metrics. The exporter reports measurement
|
|
|
|
|
// results to prometheus metrics directly
|
2025-10-21 09:41:18 +02:00
|
|
|
func Run() {
|
|
|
|
|
conf, err := InitConfig(os.Stdout)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-22 13:53:27 +02:00
|
|
|
if conf.Showversion {
|
|
|
|
|
fmt.Printf("This is io-exporter version %s\n", Version)
|
|
|
|
|
os.Exit(0)
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-25 22:20:36 +02:00
|
|
|
if conf.Showhelp {
|
|
|
|
|
fmt.Println(Usage)
|
|
|
|
|
os.Exit(0)
|
|
|
|
|
}
|
2025-10-21 12:10:25 +02:00
|
|
|
setLogger(os.Stdout, conf.Debug)
|
2025-10-21 09:41:18 +02:00
|
|
|
|
2025-10-23 12:14:33 +02:00
|
|
|
metrics := NewMetrics(conf)
|
|
|
|
|
alloc := NewAlloc()
|
|
|
|
|
exporter := NewExporter(conf, alloc, metrics)
|
2025-10-21 09:41:18 +02:00
|
|
|
|
2025-10-23 12:39:09 +02:00
|
|
|
wg := exporter.RunIOchecks()
|
2025-10-21 09:41:18 +02:00
|
|
|
|
|
|
|
|
http.Handle("/metrics", promhttp.HandlerFor(
|
|
|
|
|
metrics.registry,
|
|
|
|
|
promhttp.HandlerOpts{},
|
|
|
|
|
))
|
|
|
|
|
|
2025-10-23 12:14:33 +02:00
|
|
|
slog.Info(" ╭──")
|
|
|
|
|
slog.Info(" │ io-exporter starting up", "version", Version)
|
|
|
|
|
slog.Info(" │ serving metrics", "host", "localhost", "port", conf.Port)
|
|
|
|
|
slog.Info(" │ test setup", "file", conf.File, "labels", strings.Join(conf.Label, ","))
|
|
|
|
|
slog.Info(" │ measuring", "read", conf.ReadMode, "write", conf.WriteMode, "timeout(s)", conf.Timeout)
|
|
|
|
|
slog.Info(" │ debugging", "enabled", conf.Debug)
|
|
|
|
|
slog.Info(" ╰──")
|
2025-10-22 18:02:26 +02:00
|
|
|
|
2025-10-21 11:03:23 +02:00
|
|
|
if err := http.ListenAndServe(fmt.Sprintf(":%d", conf.Port), nil); err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
2025-10-23 12:39:09 +02:00
|
|
|
|
|
|
|
|
wg.Wait()
|
2025-10-21 09:41:18 +02:00
|
|
|
}
|
2025-10-22 18:02:26 +02:00
|
|
|
|
2025-10-23 12:14:33 +02:00
|
|
|
func report(err error, fd *os.File) bool {
|
2025-10-23 17:42:05 +02:00
|
|
|
failure := err.Error()
|
|
|
|
|
if err.Error() == "context deadline exceeded" {
|
|
|
|
|
failure = "operation timed out"
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-23 20:08:10 +02:00
|
|
|
slog.Error("io error", "error", failure)
|
2025-10-22 18:02:26 +02:00
|
|
|
|
2025-10-23 12:14:33 +02:00
|
|
|
if fd != nil {
|
|
|
|
|
if err := fd.Close(); err != nil {
|
2025-10-23 17:42:05 +02:00
|
|
|
|
|
|
|
|
slog.Debug("failed to close filehandle", "error", failure)
|
2025-10-23 12:14:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
2025-10-22 18:02:26 +02:00
|
|
|
|
2025-10-23 12:14:33 +02:00
|
|
|
return false
|
2025-10-22 18:02:26 +02:00
|
|
|
}
|