blob: 21ebc0d6d312b29c3f99a6c95d1c819710494550 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package prometheus
import (
"bytes"
"sync"
)
import (
prom "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/expfmt"
)
import (
"dubbo.apache.org/dubbo-go/v3/metrics"
)
func init() {
metrics.SetRegistry("prometheus", func(rc *metrics.ReporterConfig) metrics.MetricRegistry {
return &promMetricRegistry{r: prom.DefaultRegisterer}
})
}
type promMetricRegistry struct {
r prom.Registerer // for convenience of testing
vecs sync.Map
}
func (p *promMetricRegistry) getOrComputeVec(key string, supplier func() interface{}) interface{} {
v, ok := p.vecs.Load(key)
if !ok {
v, ok = p.vecs.LoadOrStore(key, supplier())
if !ok {
p.r.MustRegister(v.(prom.Collector)) // only registe collector which stored success
}
}
return v
}
func (p *promMetricRegistry) Counter(m *metrics.MetricId) metrics.CounterMetric {
vec := p.getOrComputeVec(m.Name, func() interface{} {
return prom.NewCounterVec(prom.CounterOpts{
Name: m.Name,
Help: m.Desc,
}, m.TagKeys())
}).(*prom.CounterVec)
return vec.With(m.Tags)
}
func (p *promMetricRegistry) Gauge(m *metrics.MetricId) metrics.GaugeMetric {
vec := p.getOrComputeVec(m.Name, func() interface{} {
return prom.NewGaugeVec(prom.GaugeOpts{
Name: m.Name,
Help: m.Desc,
}, m.TagKeys())
}).(*prom.GaugeVec)
return vec.With(m.Tags)
}
func (p *promMetricRegistry) Histogram(m *metrics.MetricId) metrics.ObservableMetric {
vec := p.getOrComputeVec(m.Name, func() interface{} {
return prom.NewHistogramVec(prom.HistogramOpts{
Name: m.Name,
Help: m.Desc,
}, m.TagKeys())
}).(*prom.HistogramVec)
return vec.With(m.Tags)
}
func (p *promMetricRegistry) Summary(m *metrics.MetricId) metrics.ObservableMetric {
vec := p.getOrComputeVec(m.Name, func() interface{} {
return prom.NewSummaryVec(prom.SummaryOpts{
Name: m.Name,
Help: m.Desc,
}, m.TagKeys())
}).(*prom.SummaryVec)
return vec.With(m.Tags)
}
func (p *promMetricRegistry) Rt(m *metrics.MetricId, opts *metrics.RtOpts) metrics.ObservableMetric {
var supplier func() interface{}
if opts != nil && opts.Aggregate {
supplier = func() interface{} {
// TODO set default aggregate config from config
return NewAggRtVec(&RtOpts{
Name: m.Name,
Help: m.Desc,
bucketNum: opts.BucketNum,
timeWindowSeconds: opts.TimeWindowSeconds,
}, m.TagKeys())
}
} else {
supplier = func() interface{} {
return NewRtVec(&RtOpts{
Name: m.Name,
Help: m.Desc,
}, m.TagKeys())
}
}
vec := p.getOrComputeVec(m.Name, supplier).(*RtVec)
return vec.With(m.Tags)
}
func (p *promMetricRegistry) Export() {
// use promauto export global, TODO move here
}
func (p *promMetricRegistry) Scrape() (string, error) {
r := p.r.(prom.Gatherer)
gathering, err := r.Gather()
if err != nil {
return "", err
}
out := &bytes.Buffer{}
for _, mf := range gathering {
if _, err := expfmt.MetricFamilyToText(out, mf); err != nil {
return "", err
}
}
return out.String(), nil
}