aboutsummaryrefslogtreecommitdiffstats
path: root/library/go/core/metrics/prometheus/registry.go
diff options
context:
space:
mode:
authorhcpp <hcpp@ydb.tech>2023-11-08 12:09:41 +0300
committerhcpp <hcpp@ydb.tech>2023-11-08 12:56:14 +0300
commita361f5b98b98b44ea510d274f6769164640dd5e1 (patch)
treec47c80962c6e2e7b06798238752fd3da0191a3f6 /library/go/core/metrics/prometheus/registry.go
parent9478806fde1f4d40bd5a45e7cbe77237dab613e9 (diff)
downloadydb-a361f5b98b98b44ea510d274f6769164640dd5e1.tar.gz
metrics have been added
Diffstat (limited to 'library/go/core/metrics/prometheus/registry.go')
-rw-r--r--library/go/core/metrics/prometheus/registry.go254
1 files changed, 254 insertions, 0 deletions
diff --git a/library/go/core/metrics/prometheus/registry.go b/library/go/core/metrics/prometheus/registry.go
new file mode 100644
index 0000000000..bad45fe617
--- /dev/null
+++ b/library/go/core/metrics/prometheus/registry.go
@@ -0,0 +1,254 @@
+package prometheus
+
+import (
+ "sync"
+
+ "github.com/prometheus/client_golang/prometheus"
+ dto "github.com/prometheus/client_model/go"
+ "github.com/ydb-platform/ydb/library/go/core/metrics"
+ "github.com/ydb-platform/ydb/library/go/core/metrics/internal/pkg/metricsutil"
+ "github.com/ydb-platform/ydb/library/go/core/metrics/internal/pkg/registryutil"
+ "github.com/ydb-platform/ydb/library/go/core/xerrors"
+)
+
+var _ metrics.Registry = (*Registry)(nil)
+
+type Registry struct {
+ rg *prometheus.Registry
+
+ m *sync.Mutex
+ subregistries map[string]*Registry
+
+ tags map[string]string
+ prefix string
+ nameSanitizer func(string) string
+}
+
+// NewRegistry creates new Prometheus backed registry.
+func NewRegistry(opts *RegistryOpts) *Registry {
+ r := &Registry{
+ rg: prometheus.NewRegistry(),
+ m: new(sync.Mutex),
+ subregistries: make(map[string]*Registry),
+ tags: make(map[string]string),
+ }
+
+ if opts != nil {
+ r.prefix = opts.Prefix
+ r.tags = opts.Tags
+ if opts.rg != nil {
+ r.rg = opts.rg
+ }
+ for _, collector := range opts.Collectors {
+ collector(r)
+ }
+ if opts.NameSanitizer != nil {
+ r.nameSanitizer = opts.NameSanitizer
+ }
+ }
+
+ return r
+}
+
+// WithTags creates new sub-scope, where each metric has tags attached to it.
+func (r Registry) WithTags(tags map[string]string) metrics.Registry {
+ return r.newSubregistry(r.prefix, registryutil.MergeTags(r.tags, tags))
+}
+
+// WithPrefix creates new sub-scope, where each metric has prefix added to it name.
+func (r Registry) WithPrefix(prefix string) metrics.Registry {
+ return r.newSubregistry(registryutil.BuildFQName("_", r.prefix, prefix), r.tags)
+}
+
+// ComposeName builds FQ name with appropriate separator.
+func (r Registry) ComposeName(parts ...string) string {
+ return registryutil.BuildFQName("_", parts...)
+}
+
+func (r Registry) Counter(name string) metrics.Counter {
+ name = r.sanitizeName(name)
+ cnt := prometheus.NewCounter(prometheus.CounterOpts{
+ Namespace: r.prefix,
+ Name: name,
+ ConstLabels: r.tags,
+ })
+
+ if err := r.rg.Register(cnt); err != nil {
+ var existErr prometheus.AlreadyRegisteredError
+ if xerrors.As(err, &existErr) {
+ return &Counter{cnt: existErr.ExistingCollector.(prometheus.Counter)}
+ }
+ panic(err)
+ }
+
+ return &Counter{cnt: cnt}
+}
+
+func (r Registry) FuncCounter(name string, function func() int64) metrics.FuncCounter {
+ name = r.sanitizeName(name)
+ cnt := prometheus.NewCounterFunc(prometheus.CounterOpts{
+ Namespace: r.prefix,
+ Name: name,
+ ConstLabels: r.tags,
+ }, func() float64 {
+ return float64(function())
+ })
+
+ if err := r.rg.Register(cnt); err != nil {
+ panic(err)
+ }
+
+ return &FuncCounter{
+ cnt: cnt,
+ function: function,
+ }
+}
+
+func (r Registry) Gauge(name string) metrics.Gauge {
+ name = r.sanitizeName(name)
+ gg := prometheus.NewGauge(prometheus.GaugeOpts{
+ Namespace: r.prefix,
+ Name: name,
+ ConstLabels: r.tags,
+ })
+
+ if err := r.rg.Register(gg); err != nil {
+ var existErr prometheus.AlreadyRegisteredError
+ if xerrors.As(err, &existErr) {
+ return &Gauge{gg: existErr.ExistingCollector.(prometheus.Gauge)}
+ }
+ panic(err)
+ }
+
+ return &Gauge{gg: gg}
+}
+
+func (r Registry) FuncGauge(name string, function func() float64) metrics.FuncGauge {
+ name = r.sanitizeName(name)
+ ff := prometheus.NewGaugeFunc(prometheus.GaugeOpts{
+ Namespace: r.prefix,
+ Name: name,
+ ConstLabels: r.tags,
+ }, function)
+ if err := r.rg.Register(ff); err != nil {
+ panic(err)
+ }
+ return &FuncGauge{
+ ff: ff,
+ function: function,
+ }
+}
+
+func (r Registry) IntGauge(name string) metrics.IntGauge {
+ return &IntGauge{Gauge: r.Gauge(name)}
+}
+
+func (r Registry) FuncIntGauge(name string, function func() int64) metrics.FuncIntGauge {
+ name = r.sanitizeName(name)
+ ff := prometheus.NewGaugeFunc(prometheus.GaugeOpts{
+ Namespace: r.prefix,
+ Name: name,
+ ConstLabels: r.tags,
+ }, func() float64 { return float64(function()) })
+ if err := r.rg.Register(ff); err != nil {
+ panic(err)
+ }
+ return &FuncIntGauge{
+ ff: ff,
+ function: function,
+ }
+}
+
+func (r Registry) Timer(name string) metrics.Timer {
+ name = r.sanitizeName(name)
+ gg := prometheus.NewGauge(prometheus.GaugeOpts{
+ Namespace: r.prefix,
+ Name: name,
+ ConstLabels: r.tags,
+ })
+
+ if err := r.rg.Register(gg); err != nil {
+ var existErr prometheus.AlreadyRegisteredError
+ if xerrors.As(err, &existErr) {
+ return &Timer{gg: existErr.ExistingCollector.(prometheus.Gauge)}
+ }
+ panic(err)
+ }
+
+ return &Timer{gg: gg}
+}
+
+func (r Registry) Histogram(name string, buckets metrics.Buckets) metrics.Histogram {
+ name = r.sanitizeName(name)
+ hm := prometheus.NewHistogram(prometheus.HistogramOpts{
+ Namespace: r.prefix,
+ Name: name,
+ ConstLabels: r.tags,
+ Buckets: metricsutil.BucketsBounds(buckets),
+ })
+
+ if err := r.rg.Register(hm); err != nil {
+ var existErr prometheus.AlreadyRegisteredError
+ if xerrors.As(err, &existErr) {
+ return &Histogram{hm: existErr.ExistingCollector.(prometheus.Observer)}
+ }
+ panic(err)
+ }
+
+ return &Histogram{hm: hm}
+}
+
+func (r Registry) DurationHistogram(name string, buckets metrics.DurationBuckets) metrics.Timer {
+ name = r.sanitizeName(name)
+ hm := prometheus.NewHistogram(prometheus.HistogramOpts{
+ Namespace: r.prefix,
+ Name: name,
+ ConstLabels: r.tags,
+ Buckets: metricsutil.DurationBucketsBounds(buckets),
+ })
+
+ if err := r.rg.Register(hm); err != nil {
+ var existErr prometheus.AlreadyRegisteredError
+ if xerrors.As(err, &existErr) {
+ return &Histogram{hm: existErr.ExistingCollector.(prometheus.Histogram)}
+ }
+ panic(err)
+ }
+
+ return &Histogram{hm: hm}
+}
+
+// Gather returns raw collected Prometheus metrics.
+func (r Registry) Gather() ([]*dto.MetricFamily, error) {
+ return r.rg.Gather()
+}
+
+func (r *Registry) newSubregistry(prefix string, tags map[string]string) *Registry {
+ registryKey := registryutil.BuildRegistryKey(prefix, tags)
+
+ r.m.Lock()
+ defer r.m.Unlock()
+
+ if old, ok := r.subregistries[registryKey]; ok {
+ return old
+ }
+
+ subregistry := &Registry{
+ rg: r.rg,
+ m: r.m,
+ subregistries: r.subregistries,
+ tags: tags,
+ prefix: prefix,
+ nameSanitizer: r.nameSanitizer,
+ }
+
+ r.subregistries[registryKey] = subregistry
+ return subregistry
+}
+
+func (r *Registry) sanitizeName(name string) string {
+ if r.nameSanitizer == nil {
+ return name
+ }
+ return r.nameSanitizer(name)
+}