Prometheus Exporter开发"/>
Prometheus Exporter开发
Prometheus Exporter开发
Exporter数据格式介绍
Exporter徒手开发
Exporter4种指标类型演示
Exporter自定义注册表
Exporter 基于Collector的模块开发
Exporter介绍
数据格式
通讯协议
HTTP协议服务端实现了gzip
数据格式
text/plain:文本协议
数据格式
prometheus是拉取数据的监控模型它对客户端暴露的数据格式要求如下
Exporter徒手开发
package mainimport ("fmt""net/http"
)func HelloHandler(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "lexporter_request_count{user=\"admin\"} 1000")
}func main() {http.HandleFunc("/metrics", HelloHandler)http.ListenAndServe(":8050", nil)
}
SDK 软件开发套件(Software development kit)
Prometheus 提供了专门的Handler
package mainimport ("net/http""github/prometheus/client_golang/prometheus/promhttp"
)func main() { // Serve the default Prometheus metrics registry over HTTP on /metricshttp.Handle("/metrics", promhttp.Handler())http.ListenAndServe(":8050", nil)
}
指标类型
Exporter 4种指标类型演示
Gauges
是最常见的Metric类型,也就是我们说的实时指标,值是什么就返回什么,并不会进行加工处理
SDK提供了该指标的构造函数: NewGauge
queueLength := prometheus.NewGauge(prometheus.GaugeOpts{// Namespace,Subsystem,Name 会拼接成指标的名称: wu123_mcube_demo_queue _length// 其中Name是必填参数Namespace: "wu123",Subsystem: "mcube_demo",Name: "queue_length",// 指标的描述信息Help: "The number of items in the queue.",// 指标的标签ConstLabels: map[string]string{"module": "http-server",},})
Set: 设置指定的值
Inc: +1.
Dec:-1
Add: +n
Sub:-n
# HELP wu123_mcube_demo_queue_length The number of items in the queue.
# TYPE wu123_mcube_demo_queue_length gauge
wu123_mcube_demo_queue_length{module="http-server"} 100
// 测试用例
func TestGauge(t *test.T) {queueLength := prometheus.NewGauge(prometheus.GaugeOpts{// Namespace,Subsystem,Name 会拼接成指标的名称: magedu _mcube_demo_queue _length// 其中Name是必填参数Namespace: "magedu",Subsystem: "mcube_demo",Name: "queue_length",// 指标的描述信息Help: "The number of items in the queue.",// 指标的标签ConstLabels: map[string]string{"module": "http-server",},})queueLength.Set(100)
...
}
Counter
Counters是计算器指标 用于统计次数使用通过 prometheus.NewCounter0 函数来初始化指标对象
totalRequests := prometheus.NewCounter(prometheus.CounterOpts{Name: "http_requests_total",Help: "The total number of handled HTTP requests.",})
lnc: +1:计数器增加1
Add: +n:计数器增加23.
# HELP http_requests_total The total number of handled HTTP requests.
# TYPE http_requests_total counter
http_requests_total 10
func TestCounter(t *testing.T) {totalRequests := prometheus.NewCounter(prometheus.CounterOpts{Name: "http_requests_total",Help: "The total number of handled HTTP requests.",})for i := 0; i < 10; i++ {totalRequests .Inc()}
...
}
Histogram概念
Histograms 被叫主直方图或者柱状图,主要用于统计指标值的一个分布情况
Bucket: 设置横轴区间只设置上限 不设下限
0~100
0~90
0~80
0~70
0~60
在监控里面,Histograms 典型的应用场景 就是统计 请求耗时分布,比如
0~100ms 请求个数
0~500ms 请求个数
0~5000ms 请求个数
为什么不用平均值来进行统计? 不合适
Histograms用法
我们使用NewHistogram初始化一个直方图类型的指标:
requestDurations := prometheus.NewHistogram(prometheus.HistogramOpts{Name: "http reguest duration seconds",Help: "A histogram of the HTTP request durations in seconds.",// Bucket 配置:第一个 bucket 包括所有在 0.05s 内完成的请求,最后一个包括所有在10s内完成的请求。Buckets: []float64{0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10},})
observe: 加入样板进行统计
Histograms演示
le="+Inf",表示小于正无穷,也就是统计所有的含义
后缀_sum,参加统计的值的求和
后缀_count 参加统计的值得总数
# HELP http_request_duration seconds A histogram of the HTTP request durations in seconds.
# TYPE http_request_duration seconds histogram
http_request_duration_seconds_bucket{le="0.05"} 2
http_request_duration_seconds_bucket{le="0.1"} 2
http_request_duration_seconds_bucket{le="0.25"} 2
http_request_duration_seconds_bucket{le="0.5"} 4
http_request_duration_seconds_bucket{le="1"} 6
http_request_duration_seconds_bucket{le="2.5"} 6
http_request_duration_seconds_bucket{le="5"} 6
http_request_duration_seconds_bucket{le="10"} 7
http_request_duration_seconds_bucket{le="+Inf"} 8
http_request_duration_seconds_sum 18.53
http_request_duration_seconds_count 8
func TestHistogram(t *testing.T) {requestDurations := prometheus.NewHistogram(prometheus.HistogramOpts{Name: "http_request_duration _seconds",Help: "A histogram of the HTTP request durations in seconds.",// Bucket 配置:第一个 bucket 包括所有在 0.05 内完成的请求,最后一个包括所有在10s内完成的请求Buckets: []float64(0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10),})//添加值for _, v := range []float64(0.01, 0.02, 0.3, 0.4, 0.6, 0.7, 5.5, 11){requestDurations.Observe(v)
...
}
指标的值是怎么来的?
自己理解:
0~0.05 | 0~0.1 | 0~0.25 | 0~0.5 | 0~1 | 0~2.5 | 0~5 | 0~10 | 0~+Inf | |
---|---|---|---|---|---|---|---|---|---|
0.01 | √ | √ | √ | √ | √ | √ | √ | √ | √ |
0.02 | √ | √ | √ | √ | √ | √ | √ | √ | √ |
0.3 | √ | √ | √ | √ | √ | √ | |||
0.4 | √ | √ | √ | √ | √ | √ | |||
0.6 | √ | √ | √ | √ | √ | ||||
0.7 | √ | √ | √ | √ | √ | ||||
5.5 | √ | √ | |||||||
11 | √ | ||||||||
总计 | 2 | 2 | 2 | 4 | 6 | 6 | 6 | 7 | 8 |
sum:这8个数据的值
count表示:总共有8个数据
Histograms与分位数
n%的在哪?比如说89分
histogram_quantile是服务端把histogram转换为quantile的,但是会有精度损失
客户端怎么算这个值呢?直接算好上传到服务端,不会有精度损失。
就是summary
Summaries
Observe,用于统计数据
用NewSummary来构建该类指标
这种类型的指标 就是用于计算分位数(quantile)的,因此他需要配置一个核心参:你需要统计那个(百)分位的数据
requestDurations := prometheus.NewSummary(prometheus.SummaryOpts{Name : "http_request_duration_seconds",Help: "A summary of the HTTP request durations in seconds .",Objectives: map[float64]float64{0.5: 0.05, // 第50个百分位数,最大绝对误差为0.05。0.9: 0.01, // 第90个百分位数,最大绝对误差为0.01。0.99: 0.001, // 第99个百分位数,最大绝对误差为0.001。},}
0.5 50%的请求在哪个区间以下
func TestSummary(t *testing.T) {requestDurations := prometheus.NewSummary(prometheus.SummaryOpts{Name: "http_request_duration_seconds",Help: "A summary of the HTTP request durations in seconds.",Objectives: map[fioat64]float64{0.5: 0.05, // 第50个百分位数,最大绝对误差为0.05。0.9: 0.01, // 第99个百分位数,最大绝对误差为0.01。0.99: 0.001, // 第98个百分位数,最大绝对误差为8.001。},})//添加值for _, v := range []float64{0.01, 0.2, 0.3, 0.4, 0.6, 0.7, 5.5, 11} {requestDurations.Observe(v)}
...
}
指标标签
标签分为2类:
静态标签:constLabels,在指标创建时,就提前声明好,采集过程中永不变动
动态标签: variableLabels,用于在指标的收集过程中动态补充标签,比如kafka集群的exporter 需要动态补充instance id
要让你的指标支持动态标签 有专门的构造函数对应关系如下!
。NewGauge() 变成NewGaugeVec()
。NewCounter() 变成NewCounterVec()
。NewSummary() 变成NewSummaryVec()
。NewHistogram() 变成NewHistogramVec()
指标标签
# HELP wu123_mcube_demo_queue_length The number of items in the queue.
# TYPE wu123_mcube_demo_queue_length gauge
wu123_mcube_demo_queue_length{instance_id="rm_001",instance_name="kafka01",module="http-server"} 100
下面以NewGaugeVec为例进行讲解
NewGaugeVec相比于NewGauge只多出了一个labelNames的参数
func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec
一定声明了labelNames,我们在为指标设置值得时候就必须带上对应个数的标签(一一对应,二维数组)
queueLeneth.WithLabelValues("rm_001", "kafka01").Set(100)
module是静态标签
指标注册
Prometheus 定义了一个注册表的接口
// 指标注册接口
type Registerer interface {// 注册采集器,有异常会报错Register(Collector) error// 注册采集器,有异常会panicMustRegister(...Collector)// 注销该采集器Unregister(Collector) bool
}
默认注册表
Prometheus 实现了一个默认的Registerer对象 也就是默认注册表
var (defaultRegistry = NewRegistry()DefaultRegisterer Registerer = defaultRegistryDefaultGatherer Gatherer = defaultRegistry
)
我们通过prometheus提供的MustRegister可以将我们自定义指标注册进去
// 在默认的注册表中注册该指标
prometheus.MustRegister(temp)
prometheus.Register()
prometheus.Unregister()
默认注册表
package mainimport ("net/http""github/prometheus/client_golang/prometheus""github/prometheus/client_golang/prometheus/promhttp"
)
func main() {// 创建一个gauge类型的指标queueLength := prometheus.NewGauge(prometheus.GaugeOpts{// Namespace,Subsystem,Name 会拼接成指标的名称: magedu _mcube_demo_queue _length// 其中Name是必填参数Namespace: "wu123",Subsystem: "mcube_demo",Name: "queue_length",// 指标的描述信息Help: "The number of items in the queue.",// 指标的标签ConstLabels: map[string]string{"module": "http-server",},})// 在默认的注册表中注册该指标prometheus.MustRegister(queueLength)// 设置gauge的值为100queueLength.Set(100)// Serve the default Prometheus metrics registry over HTTP on /metricshttp.Handle("/metrics", promhttp.Handler())http.ListenAndServe(":8050", nil)
}
默认注册表添加了很多其他指标的采集
我不想要添加默认指标,怎么做?
自定义注册表
使用NewRegistry()创建一个全新的注册表
通过注册表对象的MustRegister把指标注册到自定义的注册表中
暴露指标的时候必须通过调用 promhttp.HandleFor() 函数来创建一个专门针对我们自定义注册表的 HTTP 处理器,我们还需要在promhttp.HandlerOpts 配置对象的 Registry 字段中传递我们的注册表对象
...
// 暴露指标
http.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{Registry: registry}))
http.ListenAndServe(":8050", nil)
自定义注册表
# HELP wu123_mcube_demo_queue_length The number of items in the queue.
# TYPE wu123_mcube_demo_queue_length gauge
wu123_mcube_demo_queue_length{module="http-server"} 100
func main() {// 创建一个自定义的注册表registry := promprometheus.NewRegistry()// 创建一个gauge类型的指标queueLength := prometheus.NewGauge(prometheus.GaugeOpts{// Namespace,Subsystem,Name 会拼接成指标的名称: magedu _mcube_demo_queue _length// 其中Name是必填参数Namespace: "wu123",Subsystem: "mcube_demo",Name: "queue_length",// 指标的描述信息Help: "The number of items in the queue.",// 指标的标签ConstLabels: map[string]string{"module": "http-server",},})// 设置gauge的值为100queueLength.Set(100)// 在自定义的注册表中注册该指标registry.MustRegister(queueLength)
}
我想要添加默认指标,怎么做
其实Prometheus在客户端中默认有如下Collector供我们选择
只需把我们需要的添加到我们自定义的注册表中即可
// 添加 process 和 Go 运行时指标到我们自定义的注册表中registry.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
registry.MustRegister(prometheus.NewGoCollector())
Collector接口解读
# HELP wu123_mcube_demo_queue_length The number of items in the queue.
# TYPE wu123_mcube_demo_queue_length gauge
wu123_mcube_demo_queue_length{instance_id="rm_001",instance_name="kafka01",module="http-server"} 100
下面是Collector接口声明:
type Collector interface {// 指标的一些描述信息,就是# 标识的那部分// 注意这里使用的是指针,因为描述信息 全局存储一份就可以了Describe(chan<- *Desc)// 指标的数据,比如 promhttp_metric_handler_errors_total{cause="gathering"} 0// 这里没有使用指针,因为每次采集的值都是独立的Collect(chan<- Metric)
}
Collector开发
func NewDemoCollector() *DemoColector {return &DemoCollector{queueLengthDesc: prometheus.NewDesc("wu123 mcube demo queue length","The number of items in the queue.",// 动态标签的key列表[]string{"instnace_id","instnace_name"},// 静态标签prometheus.Labels{"module": "http-server"},),// 动态标的value列表,这里必须与声明的动态标签的key一一对应labelValues: []string{"mq 001", "kafka01"},}
}type DemoCollector struct {queueLengthDesc *prometheus.DesclabelValues []string
}func (c *DemoCollector) Describe(ch chan<- *prometheus.Desc) {ch <- c.queueLengthDesc
}func (c *DemoCollector) Collect(ch chan<- prometheus.Metric) {ch <- prometheus.MustNewConstMetric(c.queuelengthDesc, prometheus.GaugeValue, 100, c.labelValues...)
}
Collector注册
package mainimport ("net/http""github/prometheus/client_golang/prometheus""github/prometheus/client_golang/prometheus/promhttp"
)func main() {// 创建一个自定义的注册表registry := promprometheus.NewRegistry()// 可选:添加process和Go运行时指标到我们自定义的注册表中 registry.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))registry.MustRegister(prometheus.NewGoCollector())// 在自定义的注册表中注册采集器registry.MustRegister(NewDemoCollector())// Serve the default Prometheus metrics registry over HTTP on /metricshttp.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{Registry: registry}))http.ListenAndServe(":8050", nil)
mcube-demo/protocol
metric_test.go
http.go
grpc.go
问题解答
使用场景?
内存开销怎么样?
gc的情况?
埋点
为了更好的观测程序
内容介绍
被监控端部署exporter,exporter会收集对应系统或者程序的指标生成prometheus识别的格式,对应通过IP:端口/metrics网页形式暴露,prometheus就可以收集起来,最后可以通过grafana图形界面展示。这里是exporter的开发,也是收集器的开发
更多推荐
Prometheus Exporter开发
发布评论