浅谈prometheus client golang

含类型精讲+接口示例+源码节选

Prometheus:

prometheus是什么,网上已经有很多文章了,prometheus的部署和启动可以参照这个链接。prometheus为使用者提供了http接口,使用者可以使用PromQl通过get或post来从prometheus进行query。prometheus http api传送
示例:

命名规则

在https://github.com/prometheus/common/blob/master/model/metric.go定义了prometheus metric的命名规则,即只能为大小写字母,数字,’_’,’:’,并且名字不能为空string,其他的字符均不可出现

    func IsValidMetricName(n LabelValue) bool {if len(n) == 0 {return false}for i, b := range n {if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || b == ':' || (b >= '0' && b <= '9' && i > 0)) {return false}}return true}

Client golang四种类型:

counter

计数器,并且只能增长和重置。例如:一个网站的总访问量,机器的运行时长

gauge

测量值,或瞬时记录值,可以增加,也可以减少。例如:一个视频的同时观看人数,当前运行的进程数

histogram

  • 直方图,一个histogram会生成三个指标,分别是_count,_sum,_bucket。暂时为了好理解,先把_sum指标理解为Gauge,然后_count指标就是对Gauge值修改的总次数,而_bucket指标分成了几个桶子,把每次修改的值放进桶子里,不过会把值分几个层次,进入不同的桶,每个桶子里面的个数,就是直方图的纵坐标(实际情况是这个桶之前所有桶里面的个数是这个桶的纵坐标),而桶子的划分条件,就是横坐标。
  • 举个铁球做例子,我们一共有1000个大小不同的铁球,质量从1kg-100kg不等,假设我分5个桶,每个桶存储不同质量的铁球,第一个桶0-20kg,第二个20-40kg,后面依此。然后1000个铁球,就是histogram的count,而1000个铁球的总质量就是histogram的sum,那么bucket就是那五个桶,当然几个桶,桶的规则怎样都是可以设计的,这五个桶每个的0-20,20-40…就是横坐标,而每个桶中的个数,就是纵坐标。根据这些数据就可以形成一个直方图。
  • 因为直方图能够分出数据的质量,所以应用直方图的例子如:页面的响应时间,一块业务代码的时延
  • 一个不错的例子:传送门
  • 刚接触的可能会懵懵的,不过不太复杂,建议多去实践一下。

summary

  • 概要,summary和histogram类似也会产生三个指标,分别是_count,_sum,和{quantile} ,count和sum与histogram的概念相同,quantile的含义是分位数,我们都知道中位数,那么中位数其实就是一个五分quantile,而summary可以在定义时指定很多分位数,如五分数,九分数,九九分数。九分数的概念就是比这个数小的数占百分之九十。
  • summary和histogram类似也可以用来描述页面响应时间这类型的值,但差别是,histogram可以很容易看出来长尾值,比如投票很多时候都是去掉一个最高分,去掉一个最低分这种,长尾值就是很影响平均数的值,所有直方图能够很容易分析出问题数据。 而summary更能发现百分之多少的页面响应时间是多少,更能分析出页面响应时间的总体情况。

比较

  • summary和histogram都很容易看出平均数(即_sum/_count),但是histogram容易发现影响平均数的极端值,而histogram可以直接得到分位数,两种结构可以由开发者根据数据需求自行抉择。
  • histogram由clinet go直接算出分位数,而summary虽然可以算出分位数,但是更多是由开发者计算,或者调用prometheus的api获取histogram的分位数,prometheus处理函数传送门。

四种类型的接口(go):

下面图片可传送:

Counter

counter.Inc(), counter.Add(123)

Gauge

gauge.Set(), gauge.Inc(), gauge.Dec(), gauge.Add(123) , gauge.Sub(321)

Histogram

histogram.Observer(123)//添加此数据到此histogram实例(使其观察)

Summary

summary.Observer(123)

共有接口

    type Metric interface {//获取此metric的描述Desc() *Desc//转化为proto格式的Metric,返回Write(*dto.Metric) error //dto "github.com/prometheus/client_model/go"}

四种类型使用:

client golang的代码均是安全的,使用了sync库下的读写锁和CAS原子操作

    package main//不是伪代码,可以直接go runimport ("net/http""time""log""math""github.com/prometheus/client_golang/prometheus""github.com/prometheus/client_golang/prometheus/promhttp")var (MyTestCounter = prometheus.NewCounter(prometheus.CounterOpts{//因为Name不可以重复,所以建议规则为:"部门名_业务名_模块名_标量名_类型"Name: "my_test_counter",    //唯一id,不可重复Register(),可以Unregister()Help: "my test counter",    //对此Counter的描述})MyTestGauge = prometheus.NewGauge(prometheus.GaugeOpts{Name: "my_test_gauge",Help: "my test gauge",})MyTestHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{Name: "my_test_histogram",Help: "my test histogram",Buckets: prometheus.LinearBuckets(20, 5, 5), //第一个桶20起,每个桶间隔5,共5个桶。 所以20, 25, 30, 35, 40})  MyTestSummary = prometheus.NewSummary(prometheus.SummaryOpts{Name: "my_test_summary",Help: "my test summary",Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, //返回五分数, 九分数, 九九分数}))func main() {//不能注册多次Name相同的Metrics//MustRegister注册失败将直接panic(),如果想捕获error,建议使用Register()prometheus.MustRegister(MyTestCounter)prometheus.MustRegister(MyTestGauge)prometheus.MustRegister(MyTestHistogram)prometheus.MustRegister(MyTestSummary)go func(){var i float64for {i++MyTestCounter.Add(10000)   //每次加常量MyTestGauge.Add(i)          //每次加增量MyTestHistogram.Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10)  //每次观察一个18 - 42的量MyTestSummary.Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10)time.Sleep(time.Second)}}()http.Handle("/metrics", promhttp.Handler()) log.Fatal(http.ListenAndServe("0.0.0.0:8080", nil))//多个进程不可监听同一个端口}

我们看一下瞬时的值(运行之后在控制台输入curl 127.0.0.1:8080/metrics即可获取metrics):

  • 我们重点看下histogram_bucket,le=“20”,代表0-20的值有12个,le=“25”,代表0-25的值有20个,le="+Inf",代表一共有55个值,和histogram的值是相同的,如果想计算30-35的值的个数,需要用le=“35” - le="30"来获取。
  • summary{quantile=“0.5”},代表瞬时,中位数为32.3,summary{quantile=“0.9”},九分数为41.5。
  • histogram的平均数是 sum/count = 1677.5/55 = 30.5
  • summary的平均数是 sum/count = 1677.5/55 = 30.5,因为他们两个每次赋的值相同,所以平均数也肯定相同。他们的区别通过上面的数据,估计读者也应该有个了解了。

放上几张prometheus的图表,很好理解:






图像存在锯齿是因为prometheus默认每15s同步一次数据

Vector类型及其提供的接口:

不论是Counter, Gauge, Histogram, Summary,都有自己的数组形式, 我们可以直接使用。

以下是client go提供的对数组全部操作的接口。

    //metricVec实现了具体结构和接口,提供给四种数组类型调用,部分接口不提供给用户//位于github.com/prometheus/client_golang/prometheus/vec.gotype metricVec struct {*metricMap      curry []curriedLabelValuehashAdd     func(h uint64, s string) uint64hashAddByte func(h uint64, b byte) uint64}//删除匹配的labels,删除成功返回true,如果未找到则返回false,并不是error   //两者的不同:  //  Delete用法: vec.Delete(Labels{"l1": "v1", "l2": "v2"})  //  DeleteLabelValues用法: vec.DeleteLabelValues("v1", "v2")  //如果后者参数的顺序有问题,则返回false,而前者不会  //但是与之带来的是前者的开销要比后者大,因为前者要构建Labels映射func (m *metricVec) DeleteLabelValues(lvs ...string) bool{}  func (m *metricVec) Delete(labels Labels) bool {}   type Observer interface {Observe(float64)}//XXX需要使用Counter,Gauge,Histogram,Summary来代替//以下接口实现于counter.go, gauge.go, histogram.go, summary.go type XXXVec struct {  *metricVec  }  //将返回数组实例,如 NewCounterVec,将返回一个 *CounterVec,//注意,调用时,opts 中, Histogtam的Budket不能有"le", Summary的quantile不能有"quantile",否则painc()func NewXXXVec(opts XXXOpts, labelNames []string) *XXXVec{}  //如果CounterVec则 TTT为Counter,GaugeVec则TTT为Gauge,Histogram和Summary则TTT为Observer  //获取Counter,Gauge,Histogram或Summary,如果存在则返回,不存在则创建,如果name相同,描述不同,则返回error。//用法://  vec.GetMetricWith(Labels{"l1": "v1", "l2": "v2"})//  vec.GetMetricWithLabelValues("v1", "v2")  //很容易因为顺序问题而导致错误或获取不到,所以建议使用前者,但与之带来的是前者会有额外消耗  //如果我们只想获取,如果获取不到不创建新的的话,那么是做不到的,不过我们不保存返回的实例就好了。如果考虑到消耗,也可以使用Delete来移除它   func (v *XXXVec) GetMetricWith(labels Labels) (TTT, error){}   func (v *XXXVec) GetMetricWithLabelValues(lvs ...string)(TTT, error){} //分别为GetMetricWith和GetMetricWithLabelValues的must形式  //即如果出错则panic(),不会返回error  //不建议使用must形式,因为觉得我们自己处理error的能力还是要有的,即使我们捕捉到error之后和它做相同的事func (v *XXXVec) WithLabelValues(lvs ...string) TTT{}    func (v *XXXVec) With(labels Labels) TTT{}   //CurryWith将根据传入的labels,进行匹配,返回xxxVec形式,xxxVec并不是数组类型!//作用为了返回子xxxVec//注意,不要对返回值进行for range,因为不是数组,并且里面的值和方法并不是公开的。//可能的使用情况://  TestHistogramVec := NewHistogramVec(HistogramVecOpts{//      Name : "test_name",//      Help : "test_help",//      Buckets: prometheus.LinearBuckets(20, 5, 5),//  },[]string{"color","size","weight"}) //  TestHistogramVecSon := CurryWith("color":"black")func (v *XXXVec) CurryWith(labels Labels) (TTTVec, error){}     //CurryWith的Must形式,出现异常直接panic()func (v *XXXVec) MustCurryWith(labels Labels) TTTVec{}   

数组的使用:

 package mainimport ("net/http""time""log""math""github.com/prometheus/client_golang/prometheus""github.com/prometheus/client_golang/prometheus/promhttp")var (MyTestHistogramVec = prometheus.NewHistogramVec(prometheus.HistogramOpts{Name: "human_weight_histogram",Help: "human weight histogram",Buckets: prometheus.LinearBuckets(1, 10, 15), //第一个桶1起,每个桶间隔10, 共15个桶。 所以1,11,21,31,...,141},[]string{"sex","age","race"},))func main() {prometheus.MustRegister(MyTestHistogramVec)go func(){var i float64for i < 20 {   //不要太在意赋的什么值了,随便写的,主要为了了解用法MyTestHistogramVec.With(prometheus.Labels{"sex":"man","age":"20","race":"black"}).Observe(90 + math.Floor(400*math.Sin(float64(i*127)*0.1))/10) MyTestHistogramVec.With(prometheus.Labels{"sex":"woman","age":"20","race":"black"}).Observe(70 + math.Floor(400*math.Sin(float64(i*127)*0.1))/10) MyTestHistogramVec.With(prometheus.Labels{"sex":"man","age":"25","race":"black"}).Observe(95 + math.Floor(400*math.Sin(float64(i*127)*0.1))/10) MyTestHistogramVec.With(prometheus.Labels{"sex":"woman","age":"25","race":"black"}).Observe(95 + math.Floor(400*math.Sin(float64(i*127)*0.1))/10) MyTestHistogramVec.With(prometheus.Labels{"sex":"man","age":"20","race":"yellow"}).Observe(90 + math.Floor(400*math.Sin(float64(i*127)*0.1))/10) time.Sleep(time.Second)i++}}()http.Handle("/metrics", promhttp.Handler())    log.Fatal(http.ListenAndServe("0.0.0.0:8080", nil)}

看一下结果

可以发现,有太多项了

下面我们对结果进行过滤

这样就可以对数组,或者Histogram, 或者Summary进行过滤了

promauto:

如果你是一个懒人的话,不想去手动Registor()的话,promauto提供了这种方法。

import ("github.com/prometheus/client_golang/prometheus""github.com/prometheus/client_golang/prometheus/promauto")//这时候你就不需要去调用带Registor字样的方法了。Unregistor除外!//但是因为promauto调用的是MustRegistor(xxx),所以如果注册出现问题会直接panic()var histogram = promauto.NewHistogram(prometheus.HistogramOpts{Name:    "random_numbers",Help:    "A histogram of normally distributed random numbers.",Buckets: prometheus.LinearBuckets(-3, .1, 61),})
    //看两个promauto的实现func NewCounterFunc(opts prometheus.CounterOpts, function func() float64) prometheus.CounterFunc {g := prometheus.NewCounterFunc(opts, function)prometheus.MustRegister(g)return g}func NewSummary(opts prometheus.SummaryOpts) prometheus.Summary {s := prometheus.NewSummary(opts)prometheus.MustRegister(s)return s}func NewHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *prometheus.HistogramVec {h := prometheus.NewHistogramVec(opts, labelNames)prometheus.MustRegister(h)return h}

Timer:

原文链接

    //原文就这么多package prometheusimport "time"// Timer is a helper type to time functions. Use NewTimer to create new// instances.type Timer struct {begin    time.Timeobserver Observer}//  通常使用这种形式来Observe一个函数的运行时间//  已测试,非常好用//    func TimeMe() {//        timer := NewTimer(myHistogram)//        defer timer.ObserveDuration()//        // Do actual work.//    }func NewTimer(o Observer) *Timer {return &Timer{begin:    time.Now(),observer: o,}}func (t *Timer) ObserveDuration() time.Duration {d := time.Since(t.begin)if t.observer != nil {t.observer.Observe(d.Seconds())}return d}

最后附赠几个网络上文档链接

https://godoc.org/github.com/prometheus/client_golang/prometheus
https://ryanyang.gitbook.io/prometheus/
https://s0prometheus0io.icopy.site/docs/introduction/overview/

浅谈prometheus(普罗米修斯) client golang相关推荐

  1. Prometheus 普罗米修斯

    Prometheus 普罗米修斯 Prometheus由go语言开发,是一套开源的监控.报警.时间序列数据库的组合.适合监控docker容器.因为Kubernetes (K8S) 的流行带动了prom ...

  2. 一篇文章搞定Prometheus普罗米修斯监控系统的部署

    Prometheus普罗米修斯监控系统 一.普罗米修斯监控概述 1.1 什么是普罗米修斯监控 二.时间序列数据 2.1 什么是序列数据 2.2 时间序列数据特点 2.3 普罗米修斯特征 三.普罗米修斯 ...

  3. Kubernetes15——Prometheus普罗米修斯UI集群管理

    上传镜像到仓库 docker load -i prometheus-operator-v0.35.0.tar docker images | grep bitnami | awk '{system(& ...

  4. Prometheus普罗米修斯调研笔记

    项目简介: Prometheus是最初在SoundCloud上构建的开源系统监控和警报工具: 开源自2012年,许多公司和组织都采用了Prometheus,都拥有非常活跃的开发人员和用户社区: 现在它 ...

  5. 【监控】Prometheus(普罗米修斯)监控概述

    文章目录 一.监控系统概论 二.基础资源监控 2.1.网络监控 2.2.存储监控 2.3.服务器监控 2.4.中间件监控 2.5.应用程序监控(APM) 三.Prometheus 简介 3.1.什么是 ...

  6. 系统监控——prometheus(普罗米修斯)的部署

    系统监控--prometheus的部署 一.prometheus简介 1.优点 2.组件 3.架构 二.环境包准备 三.安装运行 四.网页访问 五.安装图形化界面 一.prometheus简介 pro ...

  7. Prometheus普罗米修斯部署

    prometheus部署 1.获取Prometheus安装包并解压 [root@localhost /]# wget https://github.com/prometheus/prometheus/ ...

  8. prometheus普罗米修斯集监控外部k8s

    prometheus监控k8s集群 实现思路 pod性能:   使用cadvisor进行实现,监控容器的CPU.内存利用率 Node性能:   使用node-exporter实现,主要监控节点CPU. ...

  9. Prometheus普罗米修斯监控+Alertmanager预警+钉钉预警

    简单实操,可直接拷贝命令执行 前提条件: centos7  10.11.7.95 关闭selinux vi /etc/sysconfig/selinuxSELINUX=disabled setenfo ...

  10. 普罗米修斯监控linux,Prometheus(普罗米修斯)搭建监控

    Prometheus(普罗米修斯) 实验环境:(各个主机,ip,所需服务) docker01 docker02 docker03 1.10 1.20 1.30 NodeEXporter NodeEXp ...

最新文章

  1. python是最好的语言 永远二十岁_Python是世界上最好的语言吗?
  2. CocoaPods 原理分享及遇到的问题改进
  3. 什么原数据更容易平稳_【时间序列】-航空数据预测
  4. 访谈Stuart Davidson:Skyscanner的持续交付推广
  5. 个人博客系统分享(可打包直接上云)
  6. 《C++ Primer》13.1.3节练习
  7. scala与java的区别_Scala学习笔记及与Java不同之处总结
  8. Kafka(一)背景和概念
  9. 那些年,备胎一起追的女神
  10. 数据科学研究的现状与趋势全解
  11. 织梦模板(dedecms) 文章页调用 浏览次数(阅读量,访问量)
  12. GPS卫星同步时钟系统(北斗授时服务器)的技术研究
  13. 景区介绍界面(Android)
  14. 方寸微 T620 存储安全芯片 安全存储 USB3.0 U盘/移动硬盘
  15. 融合差分变异策略和自适应调整权重的改进蝴蝶优化算法
  16. html网页右侧悬浮代码,html悬浮窗口代码
  17. 转转转转转转转转转转转转转转转转转转转转转转转转转
  18. 【soft6星评论】站在5G时代的入口,我们看到了“智慧交通”的含苞待放
  19. 利用Word 中的“从任意文件中恢复文本”转换器来恢复损坏的文档
  20. android app源码大全_[源码和文档分享]基于Android的家庭学校联系平台APP开发与实现...

热门文章

  1. phaser3 之 this.add.add.image
  2. iPhone之手势切换图片
  3. 视频教程-Java IO流精讲下-Java
  4. 群主微信sdk说明地址
  5. LINUX企业应用案例精解 第2版 李晨光
  6. 计算机图形学实验报告几何变换,计算机图形学实验报告几何变换.doc
  7. 计算机专业自主招生有哪些学校,自主招生的学校类型有哪些
  8. 计算机竞赛 自主招生,想参加自主招生,五大学科竞赛如何选取?
  9. python怎么模拟点击网页按钮?
  10. 通过ThreadLoad实现线程范围内的共享变量