dubbo.apache.org/dubbo-go/v3@v3.1.1/metrics/prometheus/rt_vec.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 prometheus
    19  
    20  import (
    21  	"bytes"
    22  	"sync"
    23  )
    24  
    25  import (
    26  	prom "github.com/prometheus/client_golang/prometheus"
    27  )
    28  
    29  import (
    30  	"dubbo.apache.org/dubbo-go/v3/metrics/util/aggregate"
    31  )
    32  
    33  type rtMetric struct {
    34  	nameSuffix string
    35  	helpPrefix string
    36  	valueFunc  func(*aggregate.Result) float64
    37  }
    38  
    39  func (m *rtMetric) desc(opts *RtOpts, labels []string) *prom.Desc {
    40  	return prom.NewDesc(prom.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name+m.nameSuffix), m.helpPrefix+opts.Help, labels, opts.ConstLabels)
    41  }
    42  
    43  var (
    44  	rtMetrics  = make([]*rtMetric, 5)
    45  	aggMetrics = make([]*rtMetric, 3)
    46  )
    47  
    48  func init() {
    49  	rtMetrics[0] = &rtMetric{nameSuffix: "_sum", helpPrefix: "Sum ", valueFunc: func(r *aggregate.Result) float64 { return r.Total }}
    50  	rtMetrics[1] = &rtMetric{nameSuffix: "_last", helpPrefix: "Last ", valueFunc: func(r *aggregate.Result) float64 { return r.Last }}
    51  	rtMetrics[2] = &rtMetric{nameSuffix: "_min", helpPrefix: "Min ", valueFunc: func(r *aggregate.Result) float64 { return r.Min }}
    52  	rtMetrics[3] = &rtMetric{nameSuffix: "_max", helpPrefix: "Max ", valueFunc: func(r *aggregate.Result) float64 { return r.Max }}
    53  	rtMetrics[4] = &rtMetric{nameSuffix: "_avg", helpPrefix: "Average ", valueFunc: func(r *aggregate.Result) float64 { return r.Avg }}
    54  
    55  	aggMetrics[0] = &rtMetric{nameSuffix: "_avg_milliseconds_aggregate", helpPrefix: "The average ", valueFunc: func(r *aggregate.Result) float64 { return r.Avg }}
    56  	aggMetrics[1] = &rtMetric{nameSuffix: "_min_milliseconds_aggregate", helpPrefix: "The minimum ", valueFunc: func(r *aggregate.Result) float64 { return r.Min }}
    57  	aggMetrics[2] = &rtMetric{nameSuffix: "_max_milliseconds_aggregate", helpPrefix: "The maximum ", valueFunc: func(r *aggregate.Result) float64 { return r.Max }}
    58  }
    59  
    60  type RtOpts struct {
    61  	Namespace         string
    62  	Subsystem         string
    63  	Name              string
    64  	Help              string
    65  	ConstLabels       prom.Labels
    66  	bucketNum         int   // only for aggRt
    67  	timeWindowSeconds int64 // only for aggRt
    68  }
    69  
    70  type observer interface {
    71  	Observe(val float64)
    72  	result() *aggregate.Result
    73  }
    74  
    75  type aggResult struct {
    76  	agg *aggregate.TimeWindowAggregator
    77  }
    78  
    79  func (r *aggResult) Observe(val float64) {
    80  	r.agg.Add(val)
    81  }
    82  
    83  func (r *aggResult) result() *aggregate.Result {
    84  	return r.agg.Result()
    85  }
    86  
    87  type valueResult struct {
    88  	mtx sync.RWMutex
    89  	val *aggregate.Result
    90  }
    91  
    92  func (r *valueResult) Observe(val float64) {
    93  	r.mtx.Lock()
    94  	defer r.mtx.Unlock()
    95  	r.val.Update(val)
    96  }
    97  
    98  func (r *valueResult) result() *aggregate.Result {
    99  	res := aggregate.NewResult()
   100  	r.mtx.RLock()
   101  	res.Merge(r.val)
   102  	r.mtx.RUnlock()
   103  	return res.Get()
   104  }
   105  
   106  type Rt struct {
   107  	tags map[string]string
   108  	obs  observer
   109  }
   110  
   111  func (r *Rt) Observe(val float64) {
   112  	r.obs.Observe(val)
   113  }
   114  
   115  func buildKey(m map[string]string, labNames []string) string {
   116  	var buffer bytes.Buffer
   117  	for _, label := range labNames {
   118  		if buffer.Len() != 0 {
   119  			buffer.WriteString("_")
   120  		}
   121  		buffer.WriteString(m[label])
   122  	}
   123  	return buffer.String()
   124  }
   125  
   126  func buildLabelValues(m map[string]string, labNames []string) []string {
   127  	values := make([]string, len(labNames))
   128  	for i, label := range labNames {
   129  		values[i] = m[label]
   130  	}
   131  	return values
   132  }
   133  
   134  type RtVec struct {
   135  	opts       *RtOpts
   136  	labelNames []string
   137  	aggMap     sync.Map
   138  	initFunc   func(tags map[string]string) *Rt
   139  	metrics    []*rtMetric
   140  }
   141  
   142  func NewRtVec(opts *RtOpts, labNames []string) *RtVec {
   143  	return &RtVec{
   144  		opts:       opts,
   145  		labelNames: labNames,
   146  		metrics:    rtMetrics,
   147  		initFunc: func(tags map[string]string) *Rt {
   148  			return &Rt{
   149  				tags: tags,
   150  				obs:  &valueResult{val: aggregate.NewResult()},
   151  			}
   152  		},
   153  	}
   154  }
   155  
   156  func NewAggRtVec(opts *RtOpts, labNames []string) *RtVec {
   157  	return &RtVec{
   158  		opts:       opts,
   159  		labelNames: labNames,
   160  		metrics:    aggMetrics,
   161  		initFunc: func(tags map[string]string) *Rt {
   162  			return &Rt{
   163  				tags: tags,
   164  				obs:  &aggResult{agg: aggregate.NewTimeWindowAggregator(opts.bucketNum, opts.timeWindowSeconds)},
   165  			}
   166  		},
   167  	}
   168  }
   169  
   170  func (r *RtVec) With(tags map[string]string) prom.Observer {
   171  	k := buildKey(tags, r.labelNames)
   172  	return r.computeIfAbsent(k, func() *Rt {
   173  		return r.initFunc(tags)
   174  	})
   175  }
   176  
   177  func (r *RtVec) computeIfAbsent(k string, supplier func() *Rt) *Rt {
   178  	v, ok := r.aggMap.Load(k)
   179  	if !ok {
   180  		v, _ = r.aggMap.LoadOrStore(k, supplier())
   181  	}
   182  	return v.(*Rt)
   183  }
   184  
   185  func (r *RtVec) Collect(ch chan<- prom.Metric) {
   186  	r.aggMap.Range(func(_, val interface{}) bool {
   187  		v := val.(*Rt)
   188  		res := v.obs.result()
   189  		for _, m := range r.metrics {
   190  			ch <- prom.MustNewConstMetric(m.desc(r.opts, r.labelNames), prom.GaugeValue, m.valueFunc(res), buildLabelValues(v.tags, r.labelNames)...)
   191  		}
   192  		return true
   193  	})
   194  }
   195  
   196  func (r *RtVec) Describe(ch chan<- *prom.Desc) {
   197  	for _, m := range r.metrics {
   198  		ch <- m.desc(r.opts, r.labelNames)
   199  	}
   200  }