diff --git a/cmd/rest-server/main.go b/cmd/rest-server/main.go index d29b292..14c36a4 100644 --- a/cmd/rest-server/main.go +++ b/cmd/rest-server/main.go @@ -30,6 +30,7 @@ func init() { flags.StringVar(&restserver.Config.Path, "path", restserver.Config.Path, "data directory") flags.BoolVar(&restserver.Config.TLS, "tls", restserver.Config.TLS, "turn on TLS support") flags.BoolVar(&restserver.Config.AppendOnly, "append-only", restserver.Config.AppendOnly, "enable append only mode") + flags.BoolVar(&restserver.Config.Prometheus, "prometheus", restserver.Config.AppendOnly, "enable Prometheus metrics") } var version = "manually" diff --git a/handlers.go b/handlers.go index 4aceb4a..168f553 100644 --- a/handlers.go +++ b/handlers.go @@ -13,9 +13,10 @@ import ( "path/filepath" "strings" "time" - "goji.io/middleware" "goji.io/pat" + "github.com/miolini/datacounter" + "github.com/prometheus/client_golang/prometheus" ) func isHashed(dir string) bool { @@ -317,8 +318,15 @@ func GetBlob(w http.ResponseWriter, r *http.Request) { return } - http.ServeContent(w, r, "", time.Unix(0, 0), file) + wc := datacounter.NewResponseWriterCounter(w) + http.ServeContent(wc, r, "", time.Unix(0, 0), file) file.Close() + + if Config.Prometheus { + labels := prometheus.Labels{"repo": getRepo(r), "type": pat.Param(r, "type")} + metricBlobReadTotal.With(labels).Inc() + metricBlobReadBytesTotal.With(labels).Add(float64(wc.Count())) + } } // SaveBlob saves a blob to the repository. @@ -342,7 +350,8 @@ func SaveBlob(w http.ResponseWriter, r *http.Request) { return } - if _, err := io.Copy(tf, r.Body); err != nil { + written, err := io.Copy(tf, r.Body) + if err != nil { tf.Close() os.Remove(path) if Config.Debug { @@ -370,6 +379,12 @@ func SaveBlob(w http.ResponseWriter, r *http.Request) { http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } + + if Config.Prometheus { + labels := prometheus.Labels{"repo": getRepo(r), "type": pat.Param(r, "type")} + metricBlobWriteTotal.With(labels).Inc() + metricBlobWriteBytesTotal.With(labels).Add(float64(written)) + } } // DeleteBlob deletes a blob from the repository. diff --git a/metrics.go b/metrics.go new file mode 100644 index 0000000..0a0f321 --- /dev/null +++ b/metrics.go @@ -0,0 +1,44 @@ +package restserver + +import "github.com/prometheus/client_golang/prometheus" + + +var metricBlobWriteTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "rest_server_blob_write_total", + Help: "Total number of blobs written", + }, + []string{"repo", "type"}, +) + +var metricBlobWriteBytesTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "rest_server_blob_write_bytes_total", + Help: "Total number of bytes written to blobs", + }, + []string{"repo", "type"}, +) + +var metricBlobReadTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "rest_server_blob_read_total", + Help: "Total number of blobs read", + }, + []string{"repo", "type"}, +) + +var metricBlobReadBytesTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "rest_server_blob_read_bytes_total", + Help: "Total number of bytes read from blobs", + }, + []string{"repo", "type"}, +) + +func init() { + // These are always initialized, but only updated if Config.Prometheus is set + prometheus.MustRegister(metricBlobWriteTotal) + prometheus.MustRegister(metricBlobWriteBytesTotal) + prometheus.MustRegister(metricBlobReadTotal) + prometheus.MustRegister(metricBlobReadBytesTotal) +} diff --git a/mux.go b/mux.go index c5069a5..86d3c70 100644 --- a/mux.go +++ b/mux.go @@ -8,6 +8,7 @@ import ( goji "goji.io" "github.com/gorilla/handlers" + "github.com/prometheus/client_golang/prometheus/promhttp" "goji.io/pat" ) @@ -19,6 +20,7 @@ var Config = struct { CPUProfile string Debug bool AppendOnly bool + Prometheus bool }{ Path: "/tmp/restic", Listen: ":8000", @@ -53,6 +55,10 @@ func NewMux() *goji.Mux { mux.Use(logHandler) } + if Config.Prometheus { + mux.Handle(pat.Get("/metrics"), promhttp.Handler()) + } + mux.HandleFunc(pat.Head("/config"), CheckConfig) mux.HandleFunc(pat.Head("/:repo/config"), CheckConfig) mux.HandleFunc(pat.Get("/config"), GetConfig)