diff --git a/cmd/gqgmcd/main.go b/cmd/gqgmcd/main.go
index 0e2d09a6edaf2829fce4df61da08bfe71b7901a7..0ab09850a09b216d0f4f07293f327d30f3e60af0 100644
--- a/cmd/gqgmcd/main.go
+++ b/cmd/gqgmcd/main.go
@@ -13,7 +13,9 @@ import (
 	"log"
 	"net/http"
 	"path"
+	"time"
 
+	"github.com/prometheus/client_golang/prometheus"
 	"github.com/prometheus/client_golang/prometheus/promhttp"
 	"gitlab.com/lyda/gqgmc/devices/geiger"
 )
@@ -30,6 +32,7 @@ type indexPage struct {
 	Serial  string
 	Volts   int16
 	CPM     uint16
+	CPS     uint16
 }
 
 var gc geiger.Counter
@@ -50,18 +53,98 @@ func staticHandler(w http.ResponseWriter, r *http.Request) {
 	http.ServeFile(w, r, staticFile)
 }
 
+// Metrics collects the metrics.
+type Metrics struct {
+	CPM,
+	CPS,
+	Volts,
+	Errors *prometheus.HistogramVec
+}
+
+var metrics = &Metrics{
+	CPM: prometheus.NewHistogramVec(prometheus.HistogramOpts{
+		Namespace: "gqgmc",
+		Subsystem: "geiger",
+		Name:      "cpm",
+		Help:      "CPM readings",
+		Buckets:   []float64{50, 99, 999, 1999},
+	}, []string{"serial"}),
+	CPS: prometheus.NewHistogramVec(prometheus.HistogramOpts{
+		Namespace: "gqgmc",
+		Subsystem: "geiger",
+		Name:      "cps",
+		Help:      "CPS readings",
+		Buckets:   []float64{1, 2, 16, 33},
+	}, []string{"serial"}),
+	Volts: prometheus.NewHistogramVec(prometheus.HistogramOpts{
+		Namespace: "gqgmc",
+		Subsystem: "power",
+		Name:      "volts",
+		Help:      "Voltage readings",
+		Buckets:   []float64{22, 27, 42, 50},
+	}, []string{"serial"}),
+	Errors: prometheus.NewHistogramVec(prometheus.HistogramOpts{
+		Namespace: "gqgmc",
+		Subsystem: "sys",
+		Name:      "errors",
+		Help:      "Error counts",
+		Buckets:   []float64{1, 10, 100},
+	}, []string{"serial"}),
+}
+
+func gatherMetrics() {
+	var (
+		cpm, cps uint16
+		volts    int16
+		errCt    float64
+		err      error
+	)
+
+	for {
+		if cpm, err = gc.GetCPM(); err != nil {
+			log.Printf("gc.GetCPM error: %s\n", err)
+			errCt++
+		} else {
+			metrics.CPM.WithLabelValues(gc.Version()).Observe(float64(cpm))
+		}
+		if cps, err = gc.GetCPS(); err != nil {
+			log.Printf("gc.GetCPS error: %s\n", err)
+			errCt++
+		} else {
+			metrics.CPS.WithLabelValues(gc.Version()).Observe(float64(cps))
+		}
+		if volts, err = gc.Volts(); err != nil {
+			log.Printf("gc.Volts error: %s\n", err)
+			errCt++
+		} else {
+			metrics.Volts.WithLabelValues(gc.Version()).Observe(float64(volts))
+		}
+		metrics.Errors.WithLabelValues(gc.Version()).Observe(errCt)
+		time.Sleep(5 * time.Second)
+	}
+}
+
 func main() {
 	flag.Parse()
 
 	gc, _ = geiger.New(geiger.Config{Model: *model, Device: *device})
+
 	indexPg.Model = gc.Model()
 	indexPg.Version = gc.Version()
 	indexPg.Serial = gc.Serial()
+
+	prometheus.MustRegister(metrics.CPM)
+	prometheus.MustRegister(metrics.CPS)
+	prometheus.MustRegister(metrics.Volts)
+	prometheus.MustRegister(metrics.Errors)
+
 	http.HandleFunc("/", indexHandler)
 	http.HandleFunc("/favicon.ico", staticHandler)
 	http.HandleFunc("/robots.txt", staticHandler)
 	http.HandleFunc("/humans.txt", staticHandler)
 	http.Handle("/metrics", promhttp.Handler())
 	http.Handle("/static", http.StripPrefix("/static/", http.FileServer(http.Dir(*staticDir))))
+
+	go gatherMetrics()
 	log.Fatal(http.ListenAndServe(*addr, nil))
 }