Welcome to mirror list, hosted at ThFree Co, Russian Federation.

metrics.go « limithandler « middleware « internal - gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 6628044a04b29a6c6333cf1ece976bfbf024bd5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package limithandler

import (
	"context"
	"strings"
	"time"

	grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
	"github.com/prometheus/client_golang/prometheus"
)

const acquireDurationLogThreshold = 10 * time.Millisecond

var (
	histogramEnabled   = false
	histogramVec       *prometheus.HistogramVec
	inprogressGaugeVec = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Namespace: "gitaly",
			Subsystem: "rate_limiting",
			Name:      "in_progress",
			Help:      "Gauge of number of number of concurrent invocations currently in progress for this endpoint",
		},
		[]string{"system", "grpc_service", "grpc_method"},
	)

	queuedGaugeVec = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Namespace: "gitaly",
			Subsystem: "rate_limiting",
			Name:      "queued",
			Help:      "Gauge of number of number of invocations currently queued for this endpoint",
		},
		[]string{"system", "grpc_service", "grpc_method"},
	)
)

type promMonitor struct {
	queuedGauge     prometheus.Gauge
	inprogressGauge prometheus.Gauge
	histogram       prometheus.Observer
}

func init() {
	prometheus.MustRegister(inprogressGaugeVec, queuedGaugeVec)
}

func splitMethodName(fullMethodName string) (string, string) {
	fullMethodName = strings.TrimPrefix(fullMethodName, "/") // remove leading slash
	if i := strings.Index(fullMethodName, "/"); i >= 0 {
		return fullMethodName[:i], fullMethodName[i+1:]
	}
	return "unknown", "unknown"
}

// EnableAcquireTimeHistogram enables histograms for acquisition times
func EnableAcquireTimeHistogram(buckets []float64) {
	histogramEnabled = true
	histogramOpts := prometheus.HistogramOpts{
		Namespace: "gitaly",
		Subsystem: "rate_limiting",
		Name:      "acquiring_seconds",
		Help:      "Histogram of lock acquisition latency (seconds) for endpoint rate limiting",
		Buckets:   buckets,
	}

	histogramVec = prometheus.NewHistogramVec(
		histogramOpts,
		[]string{"system", "grpc_service", "grpc_method"},
	)

	prometheus.Register(histogramVec)
}

func (c *promMonitor) Queued(ctx context.Context) {
	c.queuedGauge.Inc()
}

func (c *promMonitor) Dequeued(ctx context.Context) {
	c.queuedGauge.Dec()
}

func (c *promMonitor) Enter(ctx context.Context, acquireTime time.Duration) {
	c.inprogressGauge.Inc()

	if acquireTime > acquireDurationLogThreshold {
		logger := grpc_logrus.Extract(ctx)
		logger.WithField("acquire_ms", acquireTime.Seconds()*1000).Info("Rate limit acquire wait")
	}

	if c.histogram != nil {
		c.histogram.Observe(acquireTime.Seconds())
	}
}

func (c *promMonitor) Exit(ctx context.Context) {
	c.inprogressGauge.Dec()
}

// NewPromMonitor creates a new ConcurrencyMonitor that tracks limiter
// activity in Prometheus.
func NewPromMonitor(system string, fullMethod string) ConcurrencyMonitor {
	serviceName, methodName := splitMethodName(fullMethod)

	queuedGauge := queuedGaugeVec.WithLabelValues(serviceName, methodName, system)
	inprogressGauge := inprogressGaugeVec.WithLabelValues(serviceName, methodName, system)

	var histogram prometheus.Observer
	if histogramVec != nil {
		histogram = histogramVec.WithLabelValues(system, serviceName, methodName)
	}

	return &promMonitor{queuedGauge, inprogressGauge, histogram}
}