forked from electricdusk/rushlink
metrics: Add http_requests metric
This commit is contained in:
parent
0cfad96b68
commit
cf956501ac
1
go.sum
1
go.sum
@ -41,6 +41,7 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
|
|||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
|
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
|
||||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||||
|
github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
@ -50,9 +50,9 @@ func (rl *rushlink) uploadFileGetHandler(w http.ResponseWriter, r *http.Request)
|
|||||||
if badID {
|
if badID {
|
||||||
renderError(w, r, http.StatusNotFound, "malformed file id")
|
renderError(w, r, http.StatusNotFound, "malformed file id")
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
// unexpected error
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath := rl.fs.FilePath(fu.ID, fu.FileName)
|
filePath := rl.fs.FilePath(fu.ID, fu.FileName)
|
||||||
@ -62,9 +62,9 @@ func (rl *rushlink) uploadFileGetHandler(w http.ResponseWriter, r *http.Request)
|
|||||||
log.Printf("error: %v should exist according to the database, but it doesn't", filePath)
|
log.Printf("error: %v should exist according to the database, but it doesn't", filePath)
|
||||||
renderError(w, r, http.StatusNotFound, "file not found")
|
renderError(w, r, http.StatusNotFound, "file not found")
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
// unexpected error
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", fu.ContentType)
|
w.Header().Set("Content-Type", fu.ContentType)
|
||||||
io.Copy(w, file)
|
io.Copy(w, file)
|
||||||
|
59
metrics.go
59
metrics.go
@ -10,34 +10,45 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
bolt "go.etcd.io/bbolt"
|
bolt "go.etcd.io/bbolt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func StartMetricsServer(addr string, db *db.Database) {
|
const metricNamespace = "rushlink"
|
||||||
var (
|
|
||||||
_ = promauto.NewGaugeFunc(prometheus.GaugeOpts{
|
var metricRequestsTotalCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||||
Namespace: "rushlink",
|
Namespace: metricNamespace,
|
||||||
Subsystem: "pastes",
|
Subsystem: "http",
|
||||||
Name: "urls_total",
|
Name: "requests_total",
|
||||||
Help: "The current amount of pastes in the database.",
|
Help: "How many HTTP requests processed, partitioned by status code and HTTP method.",
|
||||||
}, func() float64 {
|
}, []string{"code", "method"})
|
||||||
var metric float64
|
|
||||||
if err := db.Bolt.View(func(tx *bolt.Tx) error {
|
func metricURLsTotal(database *db.Database) float64 {
|
||||||
bucket := tx.Bucket([]byte("pastes"))
|
var metric float64
|
||||||
if bucket == nil {
|
if err := database.Bolt.View(func(tx *bolt.Tx) error {
|
||||||
return errors.New("bucket 'pastes' could not be found")
|
bucket := tx.Bucket([]byte("pastes"))
|
||||||
}
|
if bucket == nil {
|
||||||
metric = float64(bucket.Stats().KeyN)
|
return errors.New("bucket 'pastes' could not be found")
|
||||||
return nil
|
}
|
||||||
}); err != nil {
|
metric = float64(bucket.Stats().KeyN)
|
||||||
log.Printf("error: %v", errors.Wrap(err, "fetching pastes_total metric"))
|
return nil
|
||||||
return 0
|
}); err != nil {
|
||||||
}
|
log.Printf("error: %v", errors.Wrap(err, "fetching pastes_total metric"))
|
||||||
return metric
|
return 0
|
||||||
})
|
}
|
||||||
)
|
return metric
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartMetricsServer starts sering Prometheus metrics exports on addr
|
||||||
|
func StartMetricsServer(addr string, database *db.Database, fs *db.FileStore) {
|
||||||
|
prometheus.MustRegister(metricRequestsTotalCounter)
|
||||||
|
|
||||||
|
prometheus.MustRegister(prometheus.NewGaugeFunc(prometheus.GaugeOpts{
|
||||||
|
Namespace: metricNamespace,
|
||||||
|
Subsystem: "pastes",
|
||||||
|
Name: "urls_total",
|
||||||
|
Help: "The current amount of pastes in the database.",
|
||||||
|
}, func() float64 { return metricURLsTotal(database) }))
|
||||||
|
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.Handle("/metrics", promhttp.Handler()).Methods("GET")
|
router.Handle("/metrics", promhttp.Handler()).Methods("GET")
|
||||||
|
33
router.go
33
router.go
@ -5,6 +5,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.hashru.nl/dsprenkels/rushlink/internal/db"
|
"gitea.hashru.nl/dsprenkels/rushlink/internal/db"
|
||||||
@ -37,6 +38,37 @@ func recoveryMiddleware(next http.Handler) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type statusResponseWriter struct {
|
||||||
|
Inner http.ResponseWriter
|
||||||
|
StatusCode int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *statusResponseWriter) Header() http.Header {
|
||||||
|
return w.Inner.Header()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *statusResponseWriter) Write(buf []byte) (int, error) {
|
||||||
|
if w.StatusCode == 0 {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
return w.Inner.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *statusResponseWriter) WriteHeader(statusCode int) {
|
||||||
|
w.StatusCode = statusCode
|
||||||
|
w.Inner.WriteHeader(statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func metricsMiddleware(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
srw := statusResponseWriter{Inner: w}
|
||||||
|
next.ServeHTTP(&srw, r)
|
||||||
|
status := strconv.Itoa(srw.StatusCode)
|
||||||
|
metricRequestsTotalCounter.WithLabelValues(status, r.Method).Inc()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartMainServer starts the main http server listening on addr.
|
||||||
func StartMainServer(addr string, db *db.Database, fs *db.FileStore) {
|
func StartMainServer(addr string, db *db.Database, fs *db.FileStore) {
|
||||||
rl := rushlink{
|
rl := rushlink{
|
||||||
db: db,
|
db: db,
|
||||||
@ -46,6 +78,7 @@ func StartMainServer(addr string, db *db.Database, fs *db.FileStore) {
|
|||||||
// Initialize Gorilla router
|
// Initialize Gorilla router
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.Use(recoveryMiddleware)
|
router.Use(recoveryMiddleware)
|
||||||
|
router.Use(metricsMiddleware)
|
||||||
router.HandleFunc("/", rl.indexGetHandler).Methods("GET")
|
router.HandleFunc("/", rl.indexGetHandler).Methods("GET")
|
||||||
router.HandleFunc("/", rl.newPasteHandler).Methods("POST")
|
router.HandleFunc("/", rl.newPasteHandler).Methods("POST")
|
||||||
router.HandleFunc("/{key:[A-Za-z0-9-_]{4,}}", rl.viewPasteHandler).Methods("GET")
|
router.HandleFunc("/{key:[A-Za-z0-9-_]{4,}}", rl.viewPasteHandler).Methods("GET")
|
||||||
|
Loading…
Reference in New Issue
Block a user