mirror of
https://github.com/gitpod-io/gitpod.git
synced 2025-12-08 17:36:30 +00:00
105 lines
2.4 KiB
Go
105 lines
2.4 KiB
Go
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
|
|
// Licensed under the GNU Affero General Public License (AGPL).
|
|
// See License.AGPL.txt in the project root for license information.
|
|
|
|
package metrics
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
|
|
"github.com/gitpod-io/gitpod/common-go/log"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
)
|
|
|
|
type AggregatedHistograms struct {
|
|
Labels []string
|
|
|
|
desc *prometheus.Desc
|
|
upperBounds []float64
|
|
|
|
mu sync.RWMutex
|
|
histograms map[string]*aggregatedHistogram
|
|
}
|
|
|
|
func NewAggregatedHistograms(name string, help string, labels []string, upperBounds []float64) *AggregatedHistograms {
|
|
return &AggregatedHistograms{
|
|
desc: prometheus.NewDesc(
|
|
name,
|
|
help,
|
|
labels,
|
|
nil,
|
|
),
|
|
Labels: labels,
|
|
upperBounds: upperBounds,
|
|
histograms: make(map[string]*aggregatedHistogram),
|
|
}
|
|
}
|
|
|
|
type aggregatedHistogram struct {
|
|
count uint64
|
|
sum float64
|
|
buckets map[float64]uint64
|
|
labelValues []string
|
|
}
|
|
|
|
func (h *AggregatedHistograms) Describe(descs chan<- *prometheus.Desc) {
|
|
descs <- h.desc
|
|
}
|
|
|
|
func (h *AggregatedHistograms) Collect(metrics chan<- prometheus.Metric) {
|
|
for _, m := range h.collect() {
|
|
metrics <- m
|
|
}
|
|
}
|
|
|
|
func (h *AggregatedHistograms) collect() (metrics []prometheus.Metric) {
|
|
h.mu.RLock()
|
|
defer h.mu.RUnlock()
|
|
for _, histogram := range h.histograms {
|
|
metric, err := prometheus.NewConstHistogram(
|
|
h.desc,
|
|
histogram.count,
|
|
histogram.sum,
|
|
histogram.buckets,
|
|
histogram.labelValues...,
|
|
)
|
|
if err != nil {
|
|
log.WithError(err).Error("aggregated histogram: failed to collect")
|
|
} else {
|
|
metrics = append(metrics, metric)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (h *AggregatedHistograms) Add(labelValues []string, count uint64, sum float64, buckets []uint64) error {
|
|
if len(labelValues) != len(h.Labels) {
|
|
return errors.New("invalid labels")
|
|
}
|
|
if len(buckets) != len(h.upperBounds) {
|
|
return errors.New("invalid buckets")
|
|
}
|
|
var key string
|
|
for _, v := range labelValues {
|
|
key = key + v + ":"
|
|
}
|
|
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
histogram := h.histograms[key]
|
|
if histogram == nil {
|
|
histogram = &aggregatedHistogram{
|
|
labelValues: labelValues,
|
|
buckets: make(map[float64]uint64, len(h.upperBounds)),
|
|
}
|
|
h.histograms[key] = histogram
|
|
}
|
|
histogram.count = histogram.count + count
|
|
histogram.sum = histogram.sum + sum
|
|
for i, upperBound := range h.upperBounds {
|
|
histogram.buckets[upperBound] = histogram.buckets[upperBound] + buckets[i]
|
|
}
|
|
return nil
|
|
}
|