github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/selfmonitor/metrics_vector_imp.go (about)

     1  // Copyright 2024 iLogtail Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //	http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package selfmonitor
    16  
    17  import (
    18  	"fmt"
    19  	"sync"
    20  	"unsafe"
    21  
    22  	"github.com/alibaba/ilogtail/pkg/helper/pool"
    23  	"github.com/alibaba/ilogtail/pkg/protocol"
    24  )
    25  
    26  const (
    27  	defaultTagValue = "-"
    28  )
    29  
    30  var (
    31  	DefaultCacheFactory = NewMapCache
    32  )
    33  
    34  // SetMetricVectorCacheFactory allows users to set the cache factory for the metric vector, like Prometheus SDK.
    35  func SetMetricVectorCacheFactory(factory func(MetricSet) MetricVectorCache) {
    36  	DefaultCacheFactory = factory
    37  }
    38  
    39  type (
    40  	CumulativeCounterMetricVector = MetricVector[CounterMetric]
    41  	AverageMetricVector           = MetricVector[CounterMetric]
    42  	MaxMetricVector               = MetricVector[GaugeMetric]
    43  	CounterMetricVector           = MetricVector[CounterMetric]
    44  	GaugeMetricVector             = MetricVector[GaugeMetric]
    45  	LatencyMetricVector           = MetricVector[LatencyMetric]
    46  	StringMetricVector            = MetricVector[StringMetric]
    47  )
    48  
    49  // Deprecated: use NewCounterMetricVector instead.
    50  // NewCumulativeCounterMetricVector creates a new CounterMetricVector.
    51  // Note that MetricVector doesn't expose Collect API by default. Plugins Developers should be careful to collect metrics manually.
    52  func NewCumulativeCounterMetricVector(metricName string, constLabels map[string]string, labelNames []string) CumulativeCounterMetricVector {
    53  	return NewMetricVector[CounterMetric](metricName, CumulativeCounterType, constLabels, labelNames)
    54  }
    55  
    56  // NewCounterMetricVector creates a new DeltaMetricVector.
    57  // Note that MetricVector doesn't expose Collect API by default. Plugins Developers should be careful to collect metrics manually.
    58  func NewCounterMetricVector(metricName string, constLabels map[string]string, labelNames []string) CounterMetricVector {
    59  	return NewMetricVector[CounterMetric](metricName, CounterType, constLabels, labelNames)
    60  }
    61  
    62  // NewAverageMetricVector creates a new AverageMetricVector.
    63  // Note that MetricVector doesn't expose Collect API by default. Plugins Developers should be careful to collect metrics manually.
    64  func NewAverageMetricVector(metricName string, constLabels map[string]string, labelNames []string) AverageMetricVector {
    65  	return NewMetricVector[CounterMetric](metricName, AverageType, constLabels, labelNames)
    66  }
    67  
    68  // NewMaxMetricVector creates a new MaxMetricVector.
    69  // Note that MetricVector doesn't expose Collect API by default. Plugins Developers should be careful to collect metrics manually.
    70  func NewMaxMetricVector(metricName string, constLabels map[string]string, labelNames []string) MaxMetricVector {
    71  	return NewMetricVector[GaugeMetric](metricName, MaxType, constLabels, labelNames)
    72  }
    73  
    74  // NewGaugeMetricVector creates a new GaugeMetricVector.
    75  // Note that MetricVector doesn't expose Collect API by default. Plugins Developers should be careful to collect metrics manually.
    76  func NewGaugeMetricVector(metricName string, constLabels map[string]string, labelNames []string) GaugeMetricVector {
    77  	return NewMetricVector[GaugeMetric](metricName, GaugeType, constLabels, labelNames)
    78  }
    79  
    80  // NewStringMetricVector creates a new StringMetricVector.
    81  // Note that MetricVector doesn't expose Collect API by default. Plugins Developers should be careful to collect metrics manually.
    82  func NewStringMetricVector(metricName string, constLabels map[string]string, labelNames []string) StringMetricVector {
    83  	return NewMetricVector[StringMetric](metricName, StringType, constLabels, labelNames)
    84  }
    85  
    86  // NewLatencyMetricVector creates a new LatencyMetricVector.
    87  // Note that MetricVector doesn't expose Collect API by default. Plugins Developers should be careful to collect metrics manually.
    88  func NewLatencyMetricVector(metricName string, constLabels map[string]string, labelNames []string) LatencyMetricVector {
    89  	return NewMetricVector[LatencyMetric](metricName, LatencyType, constLabels, labelNames)
    90  }
    91  
    92  // NewCumulativeCounterMetricVectorAndRegister creates a new CounterMetricVector and register it to the MetricsRecord.
    93  func NewCumulativeCounterMetricVectorAndRegister(mr *MetricsRecord, metricName string, constLabels map[string]string, labelNames []string) CumulativeCounterMetricVector {
    94  	v := NewMetricVector[CounterMetric](metricName, CumulativeCounterType, constLabels, labelNames)
    95  	mr.RegisterMetricCollector(v)
    96  	return v
    97  }
    98  
    99  // NewAverageMetricVectorAndRegister creates a new AverageMetricVector and register it to the MetricsRecord.
   100  func NewAverageMetricVectorAndRegister(mr *MetricsRecord, metricName string, constLabels map[string]string, labelNames []string) AverageMetricVector {
   101  	v := NewMetricVector[CounterMetric](metricName, AverageType, constLabels, labelNames)
   102  	mr.RegisterMetricCollector(v)
   103  	return v
   104  }
   105  
   106  // NewCounterMetricVectorAndRegister creates a new DeltaMetricVector and register it to the MetricsRecord.
   107  func NewCounterMetricVectorAndRegister(mr *MetricsRecord, metricName string, constLabels map[string]string, labelNames []string) CounterMetricVector {
   108  	v := NewMetricVector[CounterMetric](metricName, CounterType, constLabels, labelNames)
   109  	mr.RegisterMetricCollector(v)
   110  	return v
   111  }
   112  
   113  // NewGaugeMetricVectorAndRegister creates a new GaugeMetricVector and register it to the MetricsRecord.
   114  func NewGaugeMetricVectorAndRegister(mr *MetricsRecord, metricName string, constLabels map[string]string, labelNames []string) GaugeMetricVector {
   115  	v := NewMetricVector[GaugeMetric](metricName, GaugeType, constLabels, labelNames)
   116  	mr.RegisterMetricCollector(v)
   117  	return v
   118  }
   119  
   120  // NewLatencyMetricVectorAndRegister creates a new LatencyMetricVector and register it to the MetricsRecord.
   121  func NewLatencyMetricVectorAndRegister(mr *MetricsRecord, metricName string, constLabels map[string]string, labelNames []string) LatencyMetricVector {
   122  	v := NewMetricVector[LatencyMetric](metricName, LatencyType, constLabels, labelNames)
   123  	mr.RegisterMetricCollector(v)
   124  	return v
   125  }
   126  
   127  // NewStringMetricVectorAndRegister creates a new StringMetricVector and register it to the MetricsRecord.
   128  func NewStringMetricVectorAndRegister(mr *MetricsRecord, metricName string, constLabels map[string]string, labelNames []string) StringMetricVector {
   129  	v := NewMetricVector[StringMetric](metricName, StringType, constLabels, labelNames)
   130  	mr.RegisterMetricCollector(v)
   131  	return v
   132  }
   133  
   134  // NewCumulativeCounterMetric creates a new CounterMetric.
   135  func NewCumulativeCounterMetric(n string, lables ...*protocol.Log_Content) CounterMetric {
   136  	return NewCumulativeCounterMetricVector(n, convertLabels(lables), nil).WithLabels()
   137  }
   138  
   139  // NewAverageMetric creates a new AverageMetric.
   140  func NewAverageMetric(n string, lables ...*protocol.Log_Content) CounterMetric {
   141  	return NewAverageMetricVector(n, convertLabels(lables), nil).WithLabels()
   142  }
   143  
   144  // NewCounterMetric creates a new DeltaMetric.
   145  func NewCounterMetric(n string, lables ...*protocol.Log_Content) CounterMetric {
   146  	return NewCounterMetricVector(n, convertLabels(lables), nil).WithLabels()
   147  }
   148  
   149  // NewGaugeMetric creates a new GaugeMetric.
   150  func NewGaugeMetric(n string, lables ...*protocol.Log_Content) GaugeMetric {
   151  	return NewGaugeMetricVector(n, convertLabels(lables), nil).WithLabels()
   152  }
   153  
   154  // NewStringMetric creates a new StringMetric.
   155  func NewStringMetric(n string, lables ...*protocol.Log_Content) StringMetric {
   156  	return NewStringMetricVector(n, convertLabels(lables), nil).WithLabels()
   157  }
   158  
   159  // NewLatencyMetric creates a new LatencyMetric.
   160  func NewLatencyMetric(n string, lables ...*protocol.Log_Content) LatencyMetric {
   161  	return NewLatencyMetricVector(n, convertLabels(lables), nil).WithLabels()
   162  }
   163  
   164  // NewCumulativeCounterMetricAndRegister creates a new CounterMetric and register it's metricVector to the MetricsRecord.
   165  func NewCumulativeCounterMetricAndRegister(c *MetricsRecord, n string, lables ...*protocol.Log_Content) CounterMetric {
   166  	mv := NewCumulativeCounterMetricVector(n, convertLabels(lables), nil)
   167  	c.RegisterMetricCollector(mv.(MetricCollector))
   168  	return mv.WithLabels()
   169  }
   170  
   171  // NewCounterMetricAndRegister creates a new DeltaMetric and register it's metricVector to the MetricsRecord.
   172  func NewCounterMetricAndRegister(c *MetricsRecord, n string, lables ...*protocol.Log_Content) CounterMetric {
   173  	mv := NewCounterMetricVector(n, convertLabels(lables), nil)
   174  	c.RegisterMetricCollector(mv.(MetricCollector))
   175  	return mv.WithLabels()
   176  }
   177  
   178  // NewAverageMetricAndRegister creates a new AverageMetric and register it's metricVector to the MetricsRecord.
   179  func NewAverageMetricAndRegister(c *MetricsRecord, n string, lables ...*protocol.Log_Content) CounterMetric {
   180  	mv := NewAverageMetricVector(n, convertLabels(lables), nil)
   181  	c.RegisterMetricCollector(mv.(MetricCollector))
   182  	return mv.WithLabels()
   183  }
   184  
   185  // NewMaxMetricAndRegister creates a new MaxMetric and register it's metricVector to the MetricsRecord.
   186  func NewMaxMetricAndRegister(c *MetricsRecord, n string, lables ...*protocol.Log_Content) GaugeMetric {
   187  	mv := NewMaxMetricVector(n, convertLabels(lables), nil)
   188  	c.RegisterMetricCollector(mv.(MetricCollector))
   189  	return mv.WithLabels()
   190  }
   191  
   192  // NewGaugeMetricAndRegister creates a new GaugeMetric and register it's metricVector to the MetricsRecord.
   193  func NewGaugeMetricAndRegister(c *MetricsRecord, n string, lables ...*protocol.Log_Content) GaugeMetric {
   194  	mv := NewGaugeMetricVector(n, convertLabels(lables), nil)
   195  	c.RegisterMetricCollector(mv.(MetricCollector))
   196  	return mv.WithLabels()
   197  }
   198  
   199  // NewLatencyMetricAndRegister creates a new LatencyMetric and register it's metricVector to the MetricsRecord.
   200  func NewLatencyMetricAndRegister(c *MetricsRecord, n string, lables ...*protocol.Log_Content) LatencyMetric {
   201  	mv := NewLatencyMetricVector(n, convertLabels(lables), nil)
   202  	c.RegisterMetricCollector(mv.(MetricCollector))
   203  	return mv.WithLabels()
   204  }
   205  
   206  // NewStringMetricAndRegister creates a new StringMetric and register it's metricVector to the MetricsRecord.
   207  func NewStringMetricAndRegister(c *MetricsRecord, n string, lables ...*protocol.Log_Content) StringMetric {
   208  	mv := NewStringMetricVector(n, convertLabels(lables), nil)
   209  	c.RegisterMetricCollector(mv.(MetricCollector))
   210  	return mv.WithLabels()
   211  }
   212  
   213  var (
   214  	_ MetricCollector             = (*MetricVectorImpl[CounterMetric])(nil)
   215  	_ MetricSet                   = (*MetricVectorImpl[StringMetric])(nil)
   216  	_ MetricVector[CounterMetric] = (*MetricVectorImpl[CounterMetric])(nil)
   217  	_ MetricVector[GaugeMetric]   = (*MetricVectorImpl[GaugeMetric])(nil)
   218  	_ MetricVector[LatencyMetric] = (*MetricVectorImpl[LatencyMetric])(nil)
   219  	_ MetricVector[StringMetric]  = (*MetricVectorImpl[StringMetric])(nil)
   220  )
   221  
   222  type MetricVectorAndCollector[T Metric] interface {
   223  	MetricVector[T]
   224  	MetricCollector
   225  }
   226  
   227  type MetricVectorImpl[T Metric] struct {
   228  	*metricVector
   229  }
   230  
   231  // NewMetricVector creates a new MetricVector.
   232  // It returns a MetricVectorAndCollector, which is a MetricVector and a MetricCollector.
   233  // For plugin developers, they should use MetricVector APIs to create metrics.
   234  // For agent itself, it uses MetricCollector APIs to collect metrics.
   235  func NewMetricVector[T Metric](metricName string, metricType SelfMetricType, constLabels map[string]string, labelNames []string) MetricVectorAndCollector[T] {
   236  	return &MetricVectorImpl[T]{
   237  		metricVector: newMetricVector(metricName, metricType, constLabels, labelNames),
   238  	}
   239  }
   240  
   241  func (m *MetricVectorImpl[T]) WithLabels(labels ...LabelPair) T {
   242  	return m.metricVector.WithLabels(labels...).(T)
   243  }
   244  
   245  // MetricVectorCache is a cache for MetricVector.
   246  type MetricVectorCache interface {
   247  	// return a metric with the given label values.
   248  	// Note that the label values are sorted according to the label keys in MetricSet.
   249  	WithLabelValues([]string) Metric
   250  
   251  	MetricCollector
   252  }
   253  
   254  type metricVector struct {
   255  	name        string // metric name
   256  	metricType  SelfMetricType
   257  	constLabels []LabelPair // constLabels is the labels that are not changed when the metric is created.
   258  	labelKeys   []string    // labelNames is the names of the labels. The values of the labels can be changed.
   259  
   260  	indexPool pool.GenericPool[string] // index is []string, which is sorted according to labelNames.
   261  	cache     MetricVectorCache        // collector is a map[string]Metric, key is the index of the metric.
   262  }
   263  
   264  func newMetricVector(
   265  	metricName string,
   266  	metricType SelfMetricType,
   267  	constLabels map[string]string,
   268  	labelNames []string,
   269  ) *metricVector {
   270  	mv := &metricVector{
   271  		name:       metricName,
   272  		metricType: metricType,
   273  		labelKeys:  labelNames,
   274  		indexPool:  pool.NewGenericPool(func() []string { return make([]string, 0, 10) }),
   275  	}
   276  
   277  	for k, v := range constLabels {
   278  		mv.constLabels = append(mv.constLabels, LabelPair{Key: k, Value: v})
   279  	}
   280  
   281  	mv.cache = DefaultCacheFactory(mv)
   282  	return mv
   283  }
   284  
   285  func (v *metricVector) Name() string {
   286  	return v.name
   287  }
   288  
   289  func (v *metricVector) Type() SelfMetricType {
   290  	return v.metricType
   291  }
   292  
   293  func (v *metricVector) ConstLabels() []LabelPair {
   294  	return v.constLabels
   295  }
   296  
   297  func (v *metricVector) LabelKeys() []string {
   298  	return v.labelKeys
   299  }
   300  
   301  func (v *metricVector) WithLabels(labels ...LabelPair) Metric {
   302  	labelValues, err := v.buildLabelValues(labels)
   303  	if err != nil {
   304  		return newErrorMetric(v.metricType, err)
   305  	}
   306  	defer v.indexPool.Put(labelValues)
   307  	return v.cache.WithLabelValues(*labelValues)
   308  }
   309  
   310  func (v *metricVector) Collect() []Metric {
   311  	return v.cache.Collect()
   312  }
   313  
   314  // buildLabelValues return the index
   315  func (v *metricVector) buildLabelValues(labels []LabelPair) (*[]string, error) {
   316  	if len(labels) > len(v.labelKeys) {
   317  		return nil, fmt.Errorf("too many labels, expected %d, got %d. defined labels: %v",
   318  			len(v.labelKeys), len(labels), v.labelKeys)
   319  	}
   320  
   321  	index := v.indexPool.Get()
   322  	for range v.labelKeys {
   323  		*index = append(*index, defaultTagValue)
   324  	}
   325  
   326  	for d, tag := range labels {
   327  		if v.labelKeys[d] == tag.Key { // fast path
   328  			(*index)[d] = tag.Value
   329  		} else {
   330  			err := v.slowConstructIndex(index, tag)
   331  			if err != nil {
   332  				v.indexPool.Put(index)
   333  				return nil, err
   334  			}
   335  		}
   336  	}
   337  
   338  	return index, nil
   339  }
   340  
   341  func (v *metricVector) slowConstructIndex(index *[]string, tag LabelPair) error {
   342  	for i, tagName := range v.labelKeys {
   343  		if tagName == tag.Key {
   344  			(*index)[i] = tag.Value
   345  			return nil
   346  		}
   347  	}
   348  	return fmt.Errorf("undefined label: %s in %v", tag.Key, v.labelKeys)
   349  }
   350  
   351  type MapCache struct {
   352  	MetricSet
   353  	bytesPool pool.GenericPool[byte]
   354  	sync.Map
   355  }
   356  
   357  func NewMapCache(metricSet MetricSet) MetricVectorCache {
   358  	return &MapCache{
   359  		MetricSet: metricSet,
   360  		bytesPool: pool.NewGenericPool(func() []byte { return make([]byte, 0, 128) }),
   361  	}
   362  }
   363  
   364  func (v *MapCache) WithLabelValues(labelValues []string) Metric {
   365  	buffer := v.bytesPool.Get()
   366  	for _, tagValue := range labelValues {
   367  		*buffer = append(*buffer, '|')
   368  		*buffer = append(*buffer, tagValue...)
   369  	}
   370  
   371  	/* #nosec G103 */
   372  	k := *(*string)(unsafe.Pointer(buffer))
   373  	acV, loaded := v.Load(k)
   374  	if loaded {
   375  		metric := acV.(Metric)
   376  		v.bytesPool.Put(buffer)
   377  		return metric
   378  	}
   379  
   380  	newMetric := newMetric(v.Type(), v, labelValues)
   381  	acV, loaded = v.LoadOrStore(k, newMetric)
   382  	if loaded {
   383  		v.bytesPool.Put(buffer)
   384  	}
   385  	return acV.(Metric)
   386  }
   387  
   388  func (v *MapCache) Collect() []Metric {
   389  	res := make([]Metric, 0, 10)
   390  	v.Range(func(key, value interface{}) bool {
   391  		res = append(res, value.(Metric))
   392  		return true
   393  	})
   394  	return res
   395  }
   396  
   397  func convertLabels(labels []*protocol.Log_Content) map[string]string {
   398  	if len(labels) == 0 {
   399  		return nil
   400  	}
   401  
   402  	l := make(map[string]string)
   403  	for _, label := range labels {
   404  		l[label.Key] = label.Value
   405  	}
   406  
   407  	return l
   408  }