Prometheus 实战于源码分析之collector

2024-05-10 18:08

本文主要是介绍Prometheus 实战于源码分析之collector,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在prometheus里面有很多的exporter,每个exporter里面的都有一个collector,我在这里先写分析一下prometheus自身的监控系统,采集自己的监控数据。
先看接口

type Collector interface {Describe(chan<- *Desc)Collect(chan<- Metric)
}

有很多数据类型实现了这个接口

Gauge

type Gauge interface {MetricCollector// Set sets the Gauge to an arbitrary value.Set(float64)// Inc increments the Gauge by 1.Inc()// Dec decrements the Gauge by 1.Dec()// Add adds the given value to the Gauge. (The value can be// negative, resulting in a decrease of the Gauge.)Add(float64)// Sub subtracts the given value from the Gauge. (The value can be// negative, resulting in an increase of the Gauge.)Sub(float64)
}

Histogram

type Histogram interface {MetricCollector// Observe adds a single observation to the histogram.Observe(float64)
}

Counter

type Counter interface {MetricCollector// Set is used to set the Counter to an arbitrary value. It is only used// if you have to transfer a value from an external counter into this// Prometheus metric. Do not use it for regular handling of a// Prometheus counter (as it can be used to break the contract of// monotonically increasing values).//// Deprecated: Use NewConstMetric to create a counter for an external// value. A Counter should never be set.Set(float64)// Inc increments the counter by 1.Inc()// Add adds the given value to the counter. It panics if the value is <// 0.Add(float64)
}

Summary

type Summary interface {MetricCollector// Observe adds a single observation to the summary.Observe(float64)
}

这是Collector接口还有一个prometheus自己的一个实现selfCollector

type selfCollector struct {self Metric
}// init provides the selfCollector with a reference to the metric it is supposed
// to collect. It is usually called within the factory function to create a
// metric. See example.
func (c *selfCollector) init(self Metric) {c.self = self
}// Describe implements Collector.
func (c *selfCollector) Describe(ch chan<- *Desc) {ch <- c.self.Desc()
}// Collect implements Collector.
func (c *selfCollector) Collect(ch chan<- Metric) {ch <- c.self
}

当执行selfCollector的Collect方法就是返回本身的Metric。还记得第一篇说的注册吗?prometheus.MustRegister(configSuccess)注册这个configSuccess

configSuccess = prometheus.NewGauge(prometheus.GaugeOpts{Namespace: "prometheus",Name:      "config_last_reload_successful",Help:      "Whether the last configuration reload attempt was successful.",})

在NewGauge里面,本质上就创建一个value。这个value里面有selfCollector,就是上面的selfCollector

type value struct {valBits uint64selfCollectordesc       *DescvalType    ValueTypelabelPairs []*dto.LabelPair
}

创建完Gauge后就可以注册MustRegister(…Collector),具体看

func (r *Registry) MustRegister(cs ...Collector) {for _, c := range cs {if err := r.Register(c); err != nil {panic(err)}}
}

再深入看一下Register方法

    if len(newDescIDs) == 0 {return errors.New("collector has no descriptors")}if existing, exists := r.collectorsByID[collectorID]; exists {return AlreadyRegisteredError{ExistingCollector: existing,NewCollector:      c,}}// If the collectorID is new, but at least one of the descs existed// before, we are in trouble.if duplicateDescErr != nil {return duplicateDescErr}// Only after all tests have passed, actually register.r.collectorsByID[collectorID] = cfor hash := range newDescIDs {r.descIDs[hash] = struct{}{}}for name, dimHash := range newDimHashesByName {r.dimHashesByName[name] = dimHash}

就是注册到collectorsByID这map里面,collectorsByID map[uint64]Collector 它的key是descID,值就是我们注册的collector。
通过这个map去维护collector。取消注册的方法是删除

    r.mtx.RLock()if _, exists := r.collectorsByID[collectorID]; !exists {r.mtx.RUnlock()return false}r.mtx.RUnlock()r.mtx.Lock()defer r.mtx.Unlock()delete(r.collectorsByID, collectorID)for id := range descIDs {delete(r.descIDs, id)}

现在已经把collector的结构和注册讲完了,那么采集就变的顺理成章了,Gather()方法采集数据

    wg.Add(len(r.collectorsByID))go func() {wg.Wait()close(metricChan)}()for _, collector := range r.collectorsByID {go func(collector Collector) {defer wg.Done()collector.Collect(metricChan)}(collector)}

循环遍历执行collecto去采集,把结果放到metricChan,然后就参数解析封装了,这里涉及到了数据类型,和上面接口组合是对应的

        dtoMetric := &dto.Metric{}if err := metric.Write(dtoMetric); err != nil {errs = append(errs, fmt.Errorf("error collecting metric %v: %s", desc, err,))continue}...metricFamily.Metric = append(metricFamily.Metric, dtoMetric)    

上面的write方法在需要解释一下,如果是value类型

func (v *value) Write(out *dto.Metric) error {val := math.Float64frombits(atomic.LoadUint64(&v.valBits))return populateMetric(v.valType, val, v.labelPairs, out)
}func populateMetric(t ValueType,v float64,labelPairs []*dto.LabelPair,m *dto.Metric,
) error {m.Label = labelPairsswitch t {case CounterValue:m.Counter = &dto.Counter{Value: proto.Float64(v)}case GaugeValue:m.Gauge = &dto.Gauge{Value: proto.Float64(v)}case UntypedValue:m.Untyped = &dto.Untyped{Value: proto.Float64(v)}default:return fmt.Errorf("encountered unknown type %v", t)}return nil
}

如果是其它类型,在自己的
这里写图片描述
这里还有补充一下对于指标的定义

type Metric struct {
    Label            []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"`
    Gauge            *Gauge       `protobuf:"bytes,2,opt,name=gauge" json:"gauge,omitempty"`
    Counter          *Counter     `protobuf:"bytes,3,opt,name=counter" json:"counter,omitempty"`
    Summary          *Summary     `protobuf:"bytes,4,opt,name=summary" json:"summary,omitempty"`
    Untyped          *Untyped     `protobuf:"bytes,5,opt,name=untyped" json:"untyped,omitempty"`
    Histogram        *Histogram   `protobuf:"bytes,7,opt,name=histogram" json:"histogram,omitempty"`
    TimestampMs      *int64       `protobuf:"varint,6,opt,name=timestamp_ms" json:"timestamp_ms,omitempty"`
    XXX_unrecognized []byte       `json:"-"`
}

这篇关于Prometheus 实战于源码分析之collector的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/977174

相关文章

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

Java程序进程起来了但是不打印日志的原因分析

《Java程序进程起来了但是不打印日志的原因分析》:本文主要介绍Java程序进程起来了但是不打印日志的原因分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java程序进程起来了但是不打印日志的原因1、日志配置问题2、日志文件权限问题3、日志文件路径问题4、程序

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++