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.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.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-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
 | 
			
		||||
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 {
 | 
			
		||||
			renderError(w, r, http.StatusNotFound, "malformed file id")
 | 
			
		||||
			return
 | 
			
		||||
		} else {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		// unexpected error
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
			renderError(w, r, http.StatusNotFound, "file not found")
 | 
			
		||||
			return
 | 
			
		||||
		} else {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		// unexpected error
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	w.Header().Set("Content-Type", fu.ContentType)
 | 
			
		||||
	io.Copy(w, file)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										59
									
								
								metrics.go
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								metrics.go
									
									
									
									
									
								
							@ -10,34 +10,45 @@ import (
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/prometheus/client_golang/prometheus"
 | 
			
		||||
	"github.com/prometheus/client_golang/prometheus/promauto"
 | 
			
		||||
	"github.com/prometheus/client_golang/prometheus/promhttp"
 | 
			
		||||
	bolt "go.etcd.io/bbolt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func StartMetricsServer(addr string, db *db.Database) {
 | 
			
		||||
	var (
 | 
			
		||||
		_ = promauto.NewGaugeFunc(prometheus.GaugeOpts{
 | 
			
		||||
			Namespace: "rushlink",
 | 
			
		||||
			Subsystem: "pastes",
 | 
			
		||||
			Name:      "urls_total",
 | 
			
		||||
			Help:      "The current amount of pastes in the database.",
 | 
			
		||||
		}, func() float64 {
 | 
			
		||||
			var metric float64
 | 
			
		||||
			if err := db.Bolt.View(func(tx *bolt.Tx) error {
 | 
			
		||||
				bucket := tx.Bucket([]byte("pastes"))
 | 
			
		||||
				if bucket == nil {
 | 
			
		||||
					return errors.New("bucket 'pastes' could not be found")
 | 
			
		||||
				}
 | 
			
		||||
				metric = float64(bucket.Stats().KeyN)
 | 
			
		||||
				return nil
 | 
			
		||||
			}); err != nil {
 | 
			
		||||
				log.Printf("error: %v", errors.Wrap(err, "fetching pastes_total metric"))
 | 
			
		||||
				return 0
 | 
			
		||||
			}
 | 
			
		||||
			return metric
 | 
			
		||||
		})
 | 
			
		||||
	)
 | 
			
		||||
const metricNamespace = "rushlink"
 | 
			
		||||
 | 
			
		||||
var metricRequestsTotalCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
 | 
			
		||||
	Namespace: metricNamespace,
 | 
			
		||||
	Subsystem: "http",
 | 
			
		||||
	Name:      "requests_total",
 | 
			
		||||
	Help:      "How many HTTP requests processed, partitioned by status code and HTTP method.",
 | 
			
		||||
}, []string{"code", "method"})
 | 
			
		||||
 | 
			
		||||
func metricURLsTotal(database *db.Database) float64 {
 | 
			
		||||
	var metric float64
 | 
			
		||||
	if err := database.Bolt.View(func(tx *bolt.Tx) error {
 | 
			
		||||
		bucket := tx.Bucket([]byte("pastes"))
 | 
			
		||||
		if bucket == nil {
 | 
			
		||||
			return errors.New("bucket 'pastes' could not be found")
 | 
			
		||||
		}
 | 
			
		||||
		metric = float64(bucket.Stats().KeyN)
 | 
			
		||||
		return nil
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		log.Printf("error: %v", errors.Wrap(err, "fetching pastes_total 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.Handle("/metrics", promhttp.Handler()).Methods("GET")
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										33
									
								
								router.go
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								router.go
									
									
									
									
									
								
							@ -5,6 +5,7 @@ import (
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"runtime/debug"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"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) {
 | 
			
		||||
	rl := rushlink{
 | 
			
		||||
		db: db,
 | 
			
		||||
@ -46,6 +78,7 @@ func StartMainServer(addr string, db *db.Database, fs *db.FileStore) {
 | 
			
		||||
	// Initialize Gorilla router
 | 
			
		||||
	router := mux.NewRouter()
 | 
			
		||||
	router.Use(recoveryMiddleware)
 | 
			
		||||
	router.Use(metricsMiddleware)
 | 
			
		||||
	router.HandleFunc("/", rl.indexGetHandler).Methods("GET")
 | 
			
		||||
	router.HandleFunc("/", rl.newPasteHandler).Methods("POST")
 | 
			
		||||
	router.HandleFunc("/{key:[A-Za-z0-9-_]{4,}}", rl.viewPasteHandler).Methods("GET")
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user