dubbo.apache.org/dubbo-go/v3@v3.1.1/metrics/api.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package metrics
    19  
    20  import (
    21  	"encoding/json"
    22  	"sync"
    23  )
    24  
    25  import (
    26  	"github.com/dubbogo/gost/log/logger"
    27  )
    28  
    29  import (
    30  	"dubbo.apache.org/dubbo-go/v3/common"
    31  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    32  	"dubbo.apache.org/dubbo-go/v3/metrics/util/aggregate"
    33  )
    34  
    35  const (
    36  	DefaultCompression       = 100
    37  	DefaultBucketNum         = 10
    38  	DefaultTimeWindowSeconds = 120
    39  )
    40  
    41  var (
    42  	registries = make(map[string]func(*common.URL) MetricRegistry)
    43  	collectors = make([]CollectorFunc, 0)
    44  	registry   MetricRegistry
    45  	once       sync.Once
    46  )
    47  
    48  // CollectorFunc used to extend more indicators
    49  type CollectorFunc func(MetricRegistry, *common.URL)
    50  
    51  // Init Metrics module
    52  func Init(url *common.URL) {
    53  	once.Do(func() {
    54  		InitAppInfo(url.GetParam(constant.ApplicationKey, ""), url.GetParam(constant.AppVersionKey, ""))
    55  		// default protocol is already set in metricConfig
    56  		regFunc, ok := registries[url.Protocol]
    57  		if ok {
    58  			registry = regFunc(url)
    59  			for _, co := range collectors {
    60  				co(registry, url)
    61  			}
    62  			registry.Export()
    63  		}
    64  	})
    65  }
    66  
    67  // SetRegistry extend more MetricRegistry, default PrometheusRegistry
    68  func SetRegistry(name string, v func(*common.URL) MetricRegistry) {
    69  	registries[name] = v
    70  }
    71  
    72  // AddCollector add more indicators, like metadata, sla, config-center etc.
    73  func AddCollector(name string, fun CollectorFunc) {
    74  	collectors = append(collectors, fun)
    75  }
    76  
    77  // MetricRegistry data container,data compute、expose、agg
    78  type MetricRegistry interface {
    79  	Counter(*MetricId) CounterMetric        // add or update a counter
    80  	Gauge(*MetricId) GaugeMetric            // add or update a gauge
    81  	Histogram(*MetricId) ObservableMetric   // add a metric num to a histogram
    82  	Summary(*MetricId) ObservableMetric     // add a metric num to a summary
    83  	Rt(*MetricId, *RtOpts) ObservableMetric // add a metric num to a rt
    84  	Export()                                // expose metric data, such as Prometheus http exporter
    85  	// GetMetrics() []*MetricSample // get all metric data
    86  	// GetMetricsString() (string, error) // get text format metric data
    87  }
    88  
    89  type RtOpts struct {
    90  	Aggregate         bool
    91  	BucketNum         int   // only for aggRt
    92  	TimeWindowSeconds int64 // only for aggRt
    93  }
    94  
    95  // multi registry,like micrometer CompositeMeterRegistry
    96  // type CompositeRegistry struct {
    97  // 	rs []MetricRegistry
    98  // }
    99  
   100  // Type metric type, same with micrometer
   101  type Type uint8 // TODO check if Type is is useful
   102  
   103  const (
   104  	Counter Type = iota
   105  	Gauge
   106  	LongTaskTimer
   107  	Timer
   108  	DistributionSummary
   109  	Other
   110  )
   111  
   112  // MetricId
   113  // # HELP dubbo_metadata_store_provider_succeed_total Succeed Store Provider Metadata
   114  // # TYPE dubbo_metadata_store_provider_succeed_total gauge
   115  // dubbo_metadata_store_provider_succeed_total{application_name="provider",hostname="localhost",interface="org.example.DemoService",ip="10.252.156.213",} 1.0
   116  // other properties except value
   117  type MetricId struct {
   118  	Name string
   119  	Desc string
   120  	Tags map[string]string // also named label
   121  	Type Type              // TODO check if this field is useful
   122  }
   123  
   124  func (m *MetricId) TagKeys() []string {
   125  	keys := make([]string, 0, len(m.Tags))
   126  	for k := range m.Tags {
   127  		keys = append(keys, k)
   128  	}
   129  	return keys
   130  }
   131  
   132  func NewMetricId(key *MetricKey, level MetricLevel) *MetricId {
   133  	return &MetricId{Name: key.Name, Desc: key.Desc, Tags: level.Tags()}
   134  }
   135  
   136  // NewMetricIdByLabels create a MetricId by key and labels
   137  func NewMetricIdByLabels(key *MetricKey, labels map[string]string) *MetricId {
   138  	return &MetricId{Name: key.Name, Desc: key.Desc, Tags: labels}
   139  }
   140  
   141  // MetricSample a metric sample,This is the final data presentation,
   142  // not an intermediate result(like summary,histogram they will export to a set of MetricSample)
   143  type MetricSample struct {
   144  	*MetricId
   145  	value float64
   146  }
   147  
   148  // CounterMetric counter metric
   149  type CounterMetric interface {
   150  	Inc()
   151  	Add(float64)
   152  }
   153  
   154  // GaugeMetric gauge metric
   155  type GaugeMetric interface {
   156  	Set(float64)
   157  	Inc()
   158  	Dec()
   159  	Add(float64)
   160  	Sub(float64)
   161  }
   162  
   163  // histogram summary rt metric
   164  type ObservableMetric interface {
   165  	Observe(float64)
   166  }
   167  
   168  type BaseCollector struct {
   169  	R MetricRegistry
   170  }
   171  
   172  func (c *BaseCollector) StateCount(total, succ, fail *MetricKey, level MetricLevel, succed bool) {
   173  	c.R.Counter(NewMetricId(total, level)).Inc()
   174  	if succed {
   175  		c.R.Counter(NewMetricId(succ, level)).Inc()
   176  	} else {
   177  		c.R.Counter(NewMetricId(fail, level)).Inc()
   178  	}
   179  }
   180  
   181  // CounterVec means a set of counters with the same metricKey but different labels
   182  type CounterVec interface {
   183  	Inc(labels map[string]string)
   184  	Add(labels map[string]string, v float64)
   185  }
   186  
   187  // NewCounterVec create a CounterVec default implementation.
   188  func NewCounterVec(metricRegistry MetricRegistry, metricKey *MetricKey) CounterVec {
   189  	return &DefaultCounterVec{
   190  		metricRegistry: metricRegistry,
   191  		metricKey:      metricKey,
   192  	}
   193  }
   194  
   195  // DefaultCounterVec is a default CounterVec implementation.
   196  type DefaultCounterVec struct {
   197  	metricRegistry MetricRegistry
   198  	metricKey      *MetricKey
   199  }
   200  
   201  func (d *DefaultCounterVec) Inc(labels map[string]string) {
   202  	d.metricRegistry.Counter(NewMetricIdByLabels(d.metricKey, labels)).Inc()
   203  }
   204  
   205  func (d *DefaultCounterVec) Add(labels map[string]string, v float64) {
   206  	d.metricRegistry.Counter(NewMetricIdByLabels(d.metricKey, labels)).Add(v)
   207  }
   208  
   209  // GaugeVec means a set of gauges with the same metricKey but different labels
   210  type GaugeVec interface {
   211  	Set(labels map[string]string, v float64)
   212  	Inc(labels map[string]string)
   213  	Dec(labels map[string]string)
   214  	Add(labels map[string]string, v float64)
   215  	Sub(labels map[string]string, v float64)
   216  }
   217  
   218  // NewGaugeVec create a GaugeVec default implementation.
   219  func NewGaugeVec(metricRegistry MetricRegistry, metricKey *MetricKey) GaugeVec {
   220  	return &DefaultGaugeVec{
   221  		metricRegistry: metricRegistry,
   222  		metricKey:      metricKey,
   223  	}
   224  }
   225  
   226  // DefaultGaugeVec is a default GaugeVec implementation.
   227  type DefaultGaugeVec struct {
   228  	metricRegistry MetricRegistry
   229  	metricKey      *MetricKey
   230  }
   231  
   232  func (d *DefaultGaugeVec) Set(labels map[string]string, v float64) {
   233  	d.metricRegistry.Gauge(NewMetricIdByLabels(d.metricKey, labels)).Set(v)
   234  }
   235  
   236  func (d *DefaultGaugeVec) Inc(labels map[string]string) {
   237  	d.metricRegistry.Gauge(NewMetricIdByLabels(d.metricKey, labels)).Inc()
   238  }
   239  
   240  func (d *DefaultGaugeVec) Dec(labels map[string]string) {
   241  	d.metricRegistry.Gauge(NewMetricIdByLabels(d.metricKey, labels)).Dec()
   242  }
   243  
   244  func (d *DefaultGaugeVec) Add(labels map[string]string, v float64) {
   245  	d.metricRegistry.Gauge(NewMetricIdByLabels(d.metricKey, labels)).Add(v)
   246  }
   247  
   248  func (d *DefaultGaugeVec) Sub(labels map[string]string, v float64) {
   249  	d.metricRegistry.Gauge(NewMetricIdByLabels(d.metricKey, labels)).Sub(v)
   250  }
   251  
   252  // RtVec means a set of rt metrics with the same metricKey but different labels
   253  type RtVec interface {
   254  	Record(labels map[string]string, v float64)
   255  }
   256  
   257  // NewRtVec create a RtVec default implementation DefaultRtVec.
   258  func NewRtVec(metricRegistry MetricRegistry, metricKey *MetricKey, rtOpts *RtOpts) RtVec {
   259  	return &DefaultRtVec{
   260  		metricRegistry: metricRegistry,
   261  		metricKey:      metricKey,
   262  		rtOpts:         rtOpts,
   263  	}
   264  }
   265  
   266  // DefaultRtVec is a default RtVec implementation.
   267  //
   268  // If rtOpts.Aggregate is true, it will use the aggregate.TimeWindowAggregator with local aggregation,
   269  // else it will use the aggregate.Result without aggregation.
   270  type DefaultRtVec struct {
   271  	metricRegistry MetricRegistry
   272  	metricKey      *MetricKey
   273  	rtOpts         *RtOpts
   274  }
   275  
   276  func (d *DefaultRtVec) Record(labels map[string]string, v float64) {
   277  	d.metricRegistry.Rt(NewMetricIdByLabels(d.metricKey, labels), d.rtOpts).Observe(v)
   278  }
   279  
   280  // labelsToString convert @labels to json format string for cache key
   281  func labelsToString(labels map[string]string) string {
   282  	labelsJson, err := json.Marshal(labels)
   283  	if err != nil {
   284  		logger.Errorf("json.Marshal(labels) = error:%v", err)
   285  		return ""
   286  	}
   287  	return string(labelsJson)
   288  }
   289  
   290  // QpsMetricVec means a set of qps metrics with the same metricKey but different labels.
   291  type QpsMetricVec interface {
   292  	Record(labels map[string]string)
   293  }
   294  
   295  func NewQpsMetricVec(metricRegistry MetricRegistry, metricKey *MetricKey) QpsMetricVec {
   296  	return &DefaultQpsMetricVec{
   297  		metricRegistry: metricRegistry,
   298  		metricKey:      metricKey,
   299  		mux:            sync.RWMutex{},
   300  		cache:          make(map[string]*aggregate.TimeWindowCounter),
   301  	}
   302  }
   303  
   304  // DefaultQpsMetricVec is a default QpsMetricVec implementation.
   305  //
   306  // It is concurrent safe, and it uses the aggregate.TimeWindowCounter to store and calculate the qps metrics.
   307  type DefaultQpsMetricVec struct {
   308  	metricRegistry MetricRegistry
   309  	metricKey      *MetricKey
   310  	mux            sync.RWMutex
   311  	cache          map[string]*aggregate.TimeWindowCounter // key: metrics labels, value: TimeWindowCounter
   312  }
   313  
   314  func (d *DefaultQpsMetricVec) Record(labels map[string]string) {
   315  	key := labelsToString(labels)
   316  	if key == "" {
   317  		return
   318  	}
   319  	d.mux.RLock()
   320  	twc, ok := d.cache[key]
   321  	d.mux.RUnlock()
   322  	if !ok {
   323  		d.mux.Lock()
   324  		twc, ok = d.cache[key]
   325  		if !ok {
   326  			twc = aggregate.NewTimeWindowCounter(DefaultBucketNum, DefaultTimeWindowSeconds)
   327  			d.cache[key] = twc
   328  		}
   329  		d.mux.Unlock()
   330  	}
   331  	twc.Inc()
   332  	d.metricRegistry.Gauge(NewMetricIdByLabels(d.metricKey, labels)).Set(twc.Count() / float64(twc.LivedSeconds()))
   333  }
   334  
   335  // AggregateCounterVec means a set of aggregate counter metrics with the same metricKey but different labels.
   336  type AggregateCounterVec interface {
   337  	Inc(labels map[string]string)
   338  }
   339  
   340  func NewAggregateCounterVec(metricRegistry MetricRegistry, metricKey *MetricKey) AggregateCounterVec {
   341  	return &DefaultAggregateCounterVec{
   342  		metricRegistry: metricRegistry,
   343  		metricKey:      metricKey,
   344  		mux:            sync.RWMutex{},
   345  		cache:          make(map[string]*aggregate.TimeWindowCounter),
   346  	}
   347  }
   348  
   349  // DefaultAggregateCounterVec is a default AggregateCounterVec implementation.
   350  //
   351  // It is concurrent safe, and it uses the aggregate.TimeWindowCounter to store and calculate the aggregate counter metrics.
   352  type DefaultAggregateCounterVec struct {
   353  	metricRegistry MetricRegistry
   354  	metricKey      *MetricKey
   355  	mux            sync.RWMutex
   356  	cache          map[string]*aggregate.TimeWindowCounter // key: metrics labels, value: TimeWindowCounter
   357  }
   358  
   359  func (d *DefaultAggregateCounterVec) Inc(labels map[string]string) {
   360  	key := labelsToString(labels)
   361  	if key == "" {
   362  		return
   363  	}
   364  	d.mux.RLock()
   365  	twc, ok := d.cache[key]
   366  	d.mux.RUnlock()
   367  	if !ok {
   368  		d.mux.Lock()
   369  		twc, ok = d.cache[key]
   370  		if !ok {
   371  			twc = aggregate.NewTimeWindowCounter(DefaultBucketNum, DefaultTimeWindowSeconds)
   372  			d.cache[key] = twc
   373  		}
   374  		d.mux.Unlock()
   375  	}
   376  	twc.Inc()
   377  	d.metricRegistry.Gauge(NewMetricIdByLabels(d.metricKey, labels)).Set(twc.Count())
   378  }
   379  
   380  // QuantileMetricVec means a set of quantile metrics with the same metricKey but different labels.
   381  type QuantileMetricVec interface {
   382  	Record(labels map[string]string, v float64)
   383  }
   384  
   385  func NewQuantileMetricVec(metricRegistry MetricRegistry, metricKeys []*MetricKey, quantiles []float64) QuantileMetricVec {
   386  	return &DefaultQuantileMetricVec{
   387  		metricRegistry: metricRegistry,
   388  		metricKeys:     metricKeys,
   389  		mux:            sync.RWMutex{},
   390  		cache:          make(map[string]*aggregate.TimeWindowQuantile),
   391  		quantiles:      quantiles,
   392  	}
   393  }
   394  
   395  // DefaultQuantileMetricVec is a default QuantileMetricVec implementation.
   396  //
   397  // It is concurrent safe, and it uses the aggregate.TimeWindowQuantile to store and calculate the quantile metrics.
   398  type DefaultQuantileMetricVec struct {
   399  	metricRegistry MetricRegistry
   400  	metricKeys     []*MetricKey
   401  	mux            sync.RWMutex
   402  	cache          map[string]*aggregate.TimeWindowQuantile // key: metrics labels, value: TimeWindowQuantile
   403  	quantiles      []float64
   404  }
   405  
   406  func (d *DefaultQuantileMetricVec) Record(labels map[string]string, v float64) {
   407  	key := labelsToString(labels)
   408  	if key == "" {
   409  		return
   410  	}
   411  	d.mux.RLock()
   412  	twq, ok := d.cache[key]
   413  	d.mux.RUnlock()
   414  	if !ok {
   415  		d.mux.Lock()
   416  		twq, ok = d.cache[key]
   417  		if !ok {
   418  			twq = aggregate.NewTimeWindowQuantile(DefaultCompression, DefaultBucketNum, DefaultTimeWindowSeconds)
   419  			d.cache[key] = twq
   420  		}
   421  		d.mux.Unlock()
   422  	}
   423  	twq.Add(v)
   424  
   425  	for i, q := range twq.Quantiles(d.quantiles) {
   426  		d.metricRegistry.Gauge(NewMetricIdByLabels(d.metricKeys[i], labels)).Set(q)
   427  	}
   428  }