GitLab is used only for code review, issue tracking and project management. Canonical locations for source code are still https://gitweb.torproject.org/ https://git.torproject.org/ and git-rw.torproject.org.

Verified Commit e3135a66 authored by Philipp Winter's avatar Philipp Winter
Browse files

Make metrics more idiomatic to Prometheus.

Our metrics aren't implemented in the way Prometheus recommends.  This
patch makes use of labels and renames our metrics to change that.  For
example, instead of having two metrics called cache_hits and
cache_misses, we now have a single metric called cache_total and it
accepts a "type" label that can take on the values "hit" or "miss".

This patch fixes #10.
parent 76dfe653
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"path" "path"
"time" "time"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/time/rate" "golang.org/x/time/rate"
) )
...@@ -99,14 +100,14 @@ func testBridgeLines(req *TestRequest) *TestResult { ...@@ -99,14 +100,14 @@ func testBridgeLines(req *TestRequest) *TestResult {
for _, bridgeLine := range req.BridgeLines { for _, bridgeLine := range req.BridgeLines {
if entry := cache.IsCached(bridgeLine); entry != nil { if entry := cache.IsCached(bridgeLine); entry != nil {
numCached++ numCached++
metrics.CacheHits.Inc() metrics.Cache.With(prometheus.Labels{"type": "hit"}).Inc()
result.Bridges[bridgeLine] = &BridgeTest{ result.Bridges[bridgeLine] = &BridgeTest{
Functional: entry.Error == "", Functional: entry.Error == "",
LastTested: entry.Time, LastTested: entry.Time,
Error: entry.Error, Error: entry.Error,
} }
} else { } else {
metrics.CacheMisses.Inc() metrics.Cache.With(prometheus.Labels{"type": "miss"}).Inc()
remainingBridgeLines = append(remainingBridgeLines, bridgeLine) remainingBridgeLines = append(remainingBridgeLines, bridgeLine)
} }
} }
...@@ -127,9 +128,9 @@ func testBridgeLines(req *TestRequest) *TestResult { ...@@ -127,9 +128,9 @@ func testBridgeLines(req *TestRequest) *TestResult {
for bridgeLine, bridgeTest := range partialResult.Bridges { for bridgeLine, bridgeTest := range partialResult.Bridges {
cache.AddEntry(bridgeLine, errors.New(bridgeTest.Error), bridgeTest.LastTested) cache.AddEntry(bridgeLine, errors.New(bridgeTest.Error), bridgeTest.LastTested)
if bridgeTest.Functional { if bridgeTest.Functional {
metrics.NumFunctionalBridges.Inc() metrics.BridgeStatus.With(prometheus.Labels{"status": "functional"}).Inc()
} else { } else {
metrics.NumDysfunctionalBridges.Inc() metrics.BridgeStatus.With(prometheus.Labels{"status": "dysfunctional"}).Inc()
} }
result.Bridges[bridgeLine] = bridgeTest result.Bridges[bridgeLine] = bridgeTest
} }
...@@ -160,7 +161,11 @@ func testBridgeLines(req *TestRequest) *TestResult { ...@@ -160,7 +161,11 @@ func testBridgeLines(req *TestRequest) *TestResult {
func BridgeState(w http.ResponseWriter, r *http.Request) { func BridgeState(w http.ResponseWriter, r *http.Request) {
metrics.ApiNumRequests.Inc() reqStatus := "invalid"
defer func() {
metrics.Requests.With(prometheus.Labels{"type": "api", "status": reqStatus}).Inc()
}()
b, err := ioutil.ReadAll(r.Body) b, err := ioutil.ReadAll(r.Body)
defer r.Body.Close() defer r.Body.Close()
if err != nil { if err != nil {
...@@ -181,8 +186,8 @@ func BridgeState(w http.ResponseWriter, r *http.Request) { ...@@ -181,8 +186,8 @@ func BridgeState(w http.ResponseWriter, r *http.Request) {
http.Error(w, "no bridge lines given", http.StatusBadRequest) http.Error(w, "no bridge lines given", http.StatusBadRequest)
return return
} }
reqStatus = "valid"
metrics.ApiNumValidRequests.Inc()
if len(req.BridgeLines) > MaxBridgesPerReq { if len(req.BridgeLines) > MaxBridgesPerReq {
log.Printf("Got %d bridges in request but we only allow <= %d.", len(req.BridgeLines), MaxBridgesPerReq) log.Printf("Got %d bridges in request but we only allow <= %d.", len(req.BridgeLines), MaxBridgesPerReq)
http.Error(w, fmt.Sprintf("maximum of %d bridge lines allowed", MaxBridgesPerReq), http.StatusBadRequest) http.Error(w, fmt.Sprintf("maximum of %d bridge lines allowed", MaxBridgesPerReq), http.StatusBadRequest)
...@@ -203,7 +208,11 @@ func BridgeState(w http.ResponseWriter, r *http.Request) { ...@@ -203,7 +208,11 @@ func BridgeState(w http.ResponseWriter, r *http.Request) {
func BridgeStateWeb(w http.ResponseWriter, r *http.Request) { func BridgeStateWeb(w http.ResponseWriter, r *http.Request) {
metrics.WebNumRequests.Inc() reqStatus := "invalid"
defer func() {
metrics.Requests.With(prometheus.Labels{"type": "web", "status": reqStatus}).Inc()
}()
r.ParseForm() r.ParseForm()
// Rate-limit Web requests to prevent someone from abusing this service // Rate-limit Web requests to prevent someone from abusing this service
// as a port scanner. // as a port scanner.
...@@ -216,8 +225,8 @@ func BridgeStateWeb(w http.ResponseWriter, r *http.Request) { ...@@ -216,8 +225,8 @@ func BridgeStateWeb(w http.ResponseWriter, r *http.Request) {
SendHtmlResponse(w, "No bridge line given.") SendHtmlResponse(w, "No bridge line given.")
return return
} }
reqStatus = "valid"
metrics.WebNumValidRequests.Inc()
result := testBridgeLines(&TestRequest{BridgeLines: []string{bridgeLine}}) result := testBridgeLines(&TestRequest{BridgeLines: []string{bridgeLine}})
bridgeResult, exists := result.Bridges[bridgeLine] bridgeResult, exists := result.Bridges[bridgeLine]
if !exists { if !exists {
......
...@@ -10,19 +10,14 @@ const ( ...@@ -10,19 +10,14 @@ const (
) )
type Metrics struct { type Metrics struct {
OrconnLaunched prometheus.Counter OrconnLaunched prometheus.Counter
CacheHits prometheus.Counter CacheSize prometheus.Gauge
CacheMisses prometheus.Counter PendingReqs prometheus.Gauge
CacheSize prometheus.Gauge FracFunctional prometheus.Gauge
PendingReqs prometheus.Gauge TorTestTime prometheus.Histogram
FracFunctional prometheus.Gauge Cache *prometheus.CounterVec
ApiNumRequests prometheus.Counter Requests *prometheus.CounterVec
ApiNumValidRequests prometheus.Counter BridgeStatus *prometheus.CounterVec
WebNumRequests prometheus.Counter
WebNumValidRequests prometheus.Counter
NumFunctionalBridges prometheus.Counter
NumDysfunctionalBridges prometheus.Counter
TorTestTime prometheus.Histogram
} }
var metrics *Metrics var metrics *Metrics
...@@ -50,59 +45,38 @@ func InitMetrics() { ...@@ -50,59 +45,38 @@ func InitMetrics() {
Help: "The fraction of functional bridges currently in the cache", Help: "The fraction of functional bridges currently in the cache",
}) })
metrics.CacheHits = promauto.NewCounter(prometheus.CounterOpts{
Namespace: PrometheusNamespace,
Name: "cache_hits",
Help: "The number of requests that hit the cache",
})
metrics.CacheMisses = promauto.NewCounter(prometheus.CounterOpts{
Namespace: PrometheusNamespace,
Name: "cache_misses",
Help: "The number of requests that missed the cache",
})
metrics.CacheSize = promauto.NewGauge(prometheus.GaugeOpts{ metrics.CacheSize = promauto.NewGauge(prometheus.GaugeOpts{
Namespace: PrometheusNamespace, Namespace: PrometheusNamespace,
Name: "cache_size", Name: "cache_size",
Help: "The number of cached elements", Help: "The number of cached elements",
}) })
metrics.ApiNumRequests = promauto.NewCounter(prometheus.CounterOpts{ metrics.Cache = promauto.NewCounterVec(
Namespace: PrometheusNamespace, prometheus.CounterOpts{
Name: "api_num_requests", Namespace: PrometheusNamespace,
Help: "The number of API requests", Name: "cache_total",
}) Help: "The number of cache hits and misses",
},
metrics.ApiNumValidRequests = promauto.NewCounter(prometheus.CounterOpts{ []string{"type"},
Namespace: PrometheusNamespace, )
Name: "api_num_validrequests",
Help: "The number of valid API requests", metrics.Requests = promauto.NewCounterVec(
}) prometheus.CounterOpts{
Namespace: PrometheusNamespace,
metrics.WebNumRequests = promauto.NewCounter(prometheus.CounterOpts{ Name: "requests_total",
Namespace: PrometheusNamespace, Help: "The type and status of requests",
Name: "web_num_requests", },
Help: "The number of Web requests", []string{"type", "status"},
}) )
metrics.WebNumValidRequests = promauto.NewCounter(prometheus.CounterOpts{ metrics.BridgeStatus = promauto.NewCounterVec(
Namespace: PrometheusNamespace, prometheus.CounterOpts{
Name: "web_num_valid_requests", Namespace: PrometheusNamespace,
Help: "The number of valid Web requests", Name: "bridge_status_total",
}) Help: "The number of functional and dysfunctional bridges",
},
metrics.NumFunctionalBridges = promauto.NewCounter(prometheus.CounterOpts{ []string{"status"},
Namespace: PrometheusNamespace, )
Name: "num_functional_bridges",
Help: "The number of functional bridges",
})
metrics.NumDysfunctionalBridges = promauto.NewCounter(prometheus.CounterOpts{
Namespace: PrometheusNamespace,
Name: "num_dysfunctional_bridges",
Help: "The number of dysfunctional bridges",
})
buckets := []float64{} buckets := []float64{}
TorTestTimeout.Seconds() TorTestTimeout.Seconds()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment