Path: blob/main/components/ide-metrics/pkg/metrics/aggregated-histograms.go
2500 views
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package metrics56import (7"errors"8"sync"910"github.com/gitpod-io/gitpod/common-go/log"11"github.com/prometheus/client_golang/prometheus"12)1314type AggregatedHistograms struct {15Labels []string1617desc *prometheus.Desc18upperBounds []float641920mu sync.RWMutex21histograms map[string]*aggregatedHistogram22}2324func NewAggregatedHistograms(name string, help string, labels []string, upperBounds []float64) *AggregatedHistograms {25return &AggregatedHistograms{26desc: prometheus.NewDesc(27name,28help,29labels,30nil,31),32Labels: labels,33upperBounds: upperBounds,34histograms: make(map[string]*aggregatedHistogram),35}36}3738type aggregatedHistogram struct {39count uint6440sum float6441buckets map[float64]uint6442labelValues []string43}4445func (h *AggregatedHistograms) Describe(descs chan<- *prometheus.Desc) {46descs <- h.desc47}4849func (h *AggregatedHistograms) Collect(metrics chan<- prometheus.Metric) {50for _, m := range h.collect() {51metrics <- m52}53}5455func (h *AggregatedHistograms) collect() (metrics []prometheus.Metric) {56h.mu.RLock()57defer h.mu.RUnlock()58for _, histogram := range h.histograms {59metric, err := prometheus.NewConstHistogram(60h.desc,61histogram.count,62histogram.sum,63histogram.buckets,64histogram.labelValues...,65)66if err != nil {67log.WithError(err).Error("aggregated histogram: failed to collect")68} else {69metrics = append(metrics, metric)70}71}72return73}7475func (h *AggregatedHistograms) Add(labelValues []string, count uint64, sum float64, buckets []uint64) error {76if len(labelValues) != len(h.Labels) {77return errors.New("invalid labels")78}79if len(buckets) != len(h.upperBounds) {80return errors.New("invalid buckets")81}82var key string83for _, v := range labelValues {84key = key + v + ":"85}8687h.mu.Lock()88defer h.mu.Unlock()89histogram := h.histograms[key]90if histogram == nil {91histogram = &aggregatedHistogram{92labelValues: labelValues,93buckets: make(map[float64]uint64, len(h.upperBounds)),94}95h.histograms[key] = histogram96}97histogram.count = histogram.count + count98histogram.sum = histogram.sum + sum99for i, upperBound := range h.upperBounds {100histogram.buckets[upperBound] = histogram.buckets[upperBound] + buckets[i]101}102return nil103}104105106