package main import ( "context" "encoding/json" "flag" "io" "log" "net/http" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) type Metrics struct { TempNozzle int `json:"temp_nozzle"` TempBed int `json:"temp_bed"` Material string `json:"material"` ZPosition float64 `json:"pos_z_mm"` PrintingSpeed int `json:"printing_speed"` FlowFactor int `json:"flow_factor"` } type Config struct { QueryHostname string QueryInterval int Port string Path string } var ( opsFlowFactor = prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: "prusa_connect", Name: "flow_factor", Help: "Current flow factor, as a percentage", }) opsPrintSpeed = prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: "prusa_connect", Name: "printing_speed", Help: "Current print speed, as a percentage", }) opsZPosition = prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: "prusa_connect", Name: "z_position", Help: "Depth, in MM, of the Z head", }) opsBed = prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: "prusa_connect", Name: "temp_bed", Help: "Temperature, in celsius, of the print bed", }) opsNozzle = prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: "prusa_connect", Name: "temp_nozzle", Help: "Temperature, in celsius, of the print nozzle", }) ) func recordMetrics(ctx context.Context, config Config) { go func() { for { select { case <-ctx.Done(): log.Print("exiting!") return default: time.Sleep(time.Second * time.Duration(config.QueryInterval)) res, err := http.Get(config.QueryHostname + "/api/telemetry") if err != nil { log.Printf("error retrieving telemetry: %v", err) break } b, err := io.ReadAll(res.Body) if err != nil { log.Printf("error retrieving telemetry: %v", err) break } t := &Metrics{} err = json.Unmarshal(b, t) if err != nil { log.Printf("error parsing telemetry: %v", err) break } opsFlowFactor.Set(float64(t.FlowFactor)) opsPrintSpeed.Set(float64(t.PrintingSpeed)) opsZPosition.Set(t.ZPosition) opsBed.Set(float64(t.TempBed)) opsNozzle.Set(float64(t.TempNozzle)) } } }() } func main() { var hostname string flag.StringVar(&hostname, "hostname", "localhost", "Hostname the Prusa Connect API is available at (assumes http)") var queryInterval int flag.IntVar(&queryInterval, "interval", 2, "How often, in seconds, to query the API") var port string flag.StringVar(&port, "port", "2112", "Local port to export metrics on") var path string flag.StringVar(&path, "path", "metrics", "Local path to export metrics on") flag.Parse() if queryInterval < 1 { log.Fatalf("query interval must be greater than 0; %d received", queryInterval) } config := Config{ QueryHostname: "http://" + hostname, QueryInterval: queryInterval, Port: port, Path: path, } r := prometheus.NewRegistry() r.MustRegister(opsNozzle) r.MustRegister(opsBed) r.MustRegister(opsZPosition) r.MustRegister(opsPrintSpeed) r.MustRegister(opsFlowFactor) recordMetrics(context.Background(), config) log.Printf("starting exporter on :%v", config.Port) http.Handle("/"+config.Path, promhttp.HandlerFor(r, promhttp.HandlerOpts{})) http.ListenAndServe(":"+config.Port, nil) }