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 }