123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- package prometheus
- import (
- "sync"
- "github.com/prometheus/client_golang/prometheus"
- dto "github.com/prometheus/client_model/go"
- "github.com/prometheus/common/expfmt"
- "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)
- var _ metrics.MetricsStreamer = (*Registry)(nil)
- type Registry struct {
- rg PrometheusRegistry
- m *sync.Mutex
- subregistries map[string]*Registry
- tags map[string]string
- prefix string
- nameSanitizer func(string) string
- streamFormat expfmt.Format
- }
- // 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),
- streamFormat: StreamCompact,
- }
- if opts != nil {
- r.prefix = opts.Prefix
- r.tags = opts.Tags
- r.streamFormat = opts.StreamFormat
- 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)
- }
|