【GO】prometheus - Go语言中文社区

【GO】prometheus


参考资料
[1] prometheus包的使用
[2] Prometheus监控安装及使用
[3] Prometheus Client教程
[4] 使用 Prometheus 对 Go 应用程序进行监测
[5] 带你读《Prometheus监控实战》
[6] Prometheus
https://eddycjy.com/posts/pro...
https://yunlzheng.gitbook.io/...

1. 简介

prometheus包提供了用于实现监控代码的metric原型和用于注册metric的registry。子包(promhttp)允许通过HTTP来暴露注册的metric或将注册的metric推送到Pushgateway。

Metrics
prometheus一共有5种metric类型,前四种为:Counter,Gauge,Summary 和Histogram,每种类型都有对应的vector版本:GaugeVec, CounterVec, SummaryVec, HistogramVec,vector版本细化了prometheus数据模型,增加了label维度。第5种metric为Untyped,它的运作方式类似Gauge,区别在于它只向prometheus服务器发送类型信号。

只有基础metric类型实现了Metric接口,metric和它们的vector版本都实现了collector接口。collector负责一系列metrics的采集,但是为了方便,metric也可以“收集自己”。注意:Gauge, Counter, Summary, Histogram, 和Untyped自身就是接口,而GaugeVec, CounterVec, SummaryVec, HistogramVec, 和UntypedVec则不是接口。

为了创建metric和它们的vector版本,需要选择合适的opts结构体,如GaugeOpts, CounterOpts, SummaryOpts, HistogramOpts, 或UntypedOpts.
Custom Collectors and constant Metrics

实现自己的metric,一般只需要实现自己的collector即可。如果已经有了现成的metric(prometheus上下文之外创建的),则无需使用Metric类型接口,只需要在采集期间将现有的metric映射到prometheus metric即可,此时可以使用 NewConstMetric, NewConstHistogram, and NewConstSummary (以及对应的Must… 版本)来创建metric实例,以上操作在collect方法中实现。describe方法用于返回独立的Desc实例,NewDesc用于创建这些metric实例。(NewDesc用于创建prometheus识别的metric)

如果只需要调用一个函数来收集一个float值作为metric,那么推荐使用GaugeFunc, CounterFunc, 或UntypedFunc。
Advanced Uses of the Registry
MustRegister 是注册collector最通用的方式。如果需要捕获注册时产生的错误,可以使用Register 函数,该函数会返回错误。
如果注册的collector与已经注册的metric不兼容或不一致时就会返回错误。registry用于使收集的metric与prometheus数据模型保持一致。不一致的错误会在注册时而非采集时检测到。前者会在系统的启动时检测到,而后者只会在采集时发生(可能不会在首次采集时发生),这也是为什么collector和metric必须向Registry describe它们的原因。
以上提到的registry都被称为默认registry,可以在全局变量DefaultRegisterer中找到。使用NewRegistry可以创建custom registry,或者可以自己实现Registerer 或Gatherer接口。custom registry的Register和Unregister运作方式类似,默认registry则使用全局函数Register和Unregister。
custom registry的使用方式还有很多:可以使用NewPedanticRegistry来注册特殊的属性;可以避免由DefaultRegisterer限制的全局状态属性;也可以同时使用多个registry来暴露不同的metrics。
DefaultRegisterer注册了Go runtime metrics (通过NewGoCollector)和用于process metrics 的collector(通过NewProcessCollector)。通过custom registry可以自己决定注册的collector。
HTTP Exposition
Registry实现了Gather接口。调用Gather接口可以通过某种方式暴露采集的metric。通常metric endpoint使用http来暴露metric。通过http暴露metric的工具为promhttp子包。

函数和类型说明:

func Register(c Collector) error:使用DefaultRegisterer来注册传入的Collector
func Unregister(c Collector) bool:使用DefaultRegisterer来移除传入的Collector的注册信息
type AlreadyRegisteredError:该类型实现了error接口,由Register返回,用于判断用于注册的collector是否已经被注册过
type Collector:用于采集prometheus metric,如果运行多个相同的实例,则需要使用ConstLabels来注册这些实例。实现collector接口需要实现Describe和Collect方法,并注册collector。
type Registerer:负责collector的注册和去注册,实现custom registrer时应该实现该接口
// MustRegister implements Registerer.
func (r *Registry) MustRegister(cs ...Collector) {
  for _, c := range cs {
    if err := r.Register(c); err != nil {
      panic(err)
    }
  }
}

2. 示例

https://blog.csdn.net/runner6...
https://www.cnblogs.com/FG123...

[1] 下载案例
git clone https://github.com/crockitwoo...

[2] 建立go.mod

$ cd go-prometheus-example
$ touch go.mod

键入以下内容:

module go-prometheus-example
go 1.12
$ go mod tidy

[3] 修改main.go

将"github.com/crockitwood/go-prometheus-example/monitor"改为"go-prometheus-example/monitor"

[4] 编译运行

$ go build
$ ./go-prometheus-example

[5] 访问网址

http://localhost:8080/hello
http://localhost:8080/query
http://localhost:8080/metrics

3. Prometheus 四大度量指标

  • Counter (计数器)类型代表一个累积的指标数据,其单调递增,只增不减。在应用场景中,像是请求次数、错误数量等等,就非常适合用 Counter 来做指标类型,另外 Counter 类型,只有在被采集端重新启动时才会归零。
  • Gauge (仪表盘)类型代表一个可以任意变化的指标数据,其可增可减。在应用场景中,像是 Go 应用程序运行时的 Goroutine 的数量就可以用该类型来表示,因为其是浮动的数值,并非固定的,侧重于反馈当前的情况。
    Histogram(累计直方图) 类型将会在一段时间范围内对数据进行采样(通常是请求持续时间或响应大小等等),并将其计入可配置的存储桶(bucket)中,后续可通过指定区间筛选样本,也可以统计样本总数。
  • Summary(摘要) 类型将会在一段时间范围内对数据进行采样,但是与 Histogram 类型不同的是 Summary 类型将会存储分位数(在客户端进行计算),而不像 Histogram 类型,根据所设置的区间情况统计存储。

Prometheus通过指标名称(metrics name)以及对应的一组标签(labelset)唯一定义一条时间序列。指标名称反映了监控样本的基本标识,而label则在这个基本特征上为采集到的数据提供了多种特征维度。用户可以基于这些特征维度过滤,聚合,统计从而产生新的计算后的一条时间序列。

4. 查询

func HandleGetQueryResp(c *gin.Context){
   //queryString:="promhttp_metric_handler_requests_total"
   //queryString:="cpu_total_info"
   queryString:="cpu_total_info{}[5m]"
   fmt.Println("queryString=",queryString)
   // create prom client
   newClient, err := api.NewClient(api.Config{Address: "http://localhost:9090"})
   //newClient, err := api.NewClient(api.Config{Address: "http://localhost:10086/metrics"})
   if nil != err {
      fmt.Println("NewClient err=",err)
      return
   }

   // create prom client http api
   promAPI := v1.NewAPI(newClient)
   // instant value, type is vector
   resp, _, err := promAPI.Query(context.TODO(), queryString, time.Time{})
   //resp, _,err := promAPI.LabelValues(context.TODO(), queryString,time.Time{},time.Time{})
   if nil != err {
      fmt.Println("Query err=",err)
      return
   }
 
   cpuValue := resp.(model.Matrix)
   fmt.Println("cpuValue=",cpuValue)
   fmt.Println("len=",cpuValue.Len())
   fmt.Println("cpuValue[0].Metric.String()=",cpuValue[0].Metric.String())
   byts,err:=cpuValue[0].Values[0].Value.MarshalJSON()
   fmt.Println("byts=",string(byts))
   fmt.Println("cpuValue[0].Metric.Values=",cpuValue[0].Values)
   zer:=cpuValue[0].Metric["cpu"]
   fmt.Println("cpuValue[0].Metric[cpu]=",zer)
   for a,b:= range cpuValue[0].Metric{
      fmt.Println("a=",a)
      fmt.Println("b=",b)
   }
   c.JSON(http.StatusOK, resp)
   return
}

resp结果:

[{"metric":{
    "__name__":"cpu_total_info",
    "instance":"localhost:10086",
    "job":"cpu",
    "nice":"nice",
    "user":"user"
    },
    "values":
        [[1610368090.67,"1"], # 时间,值
        [1610368300.67,"16"]]
}]

[
 {
   "metric":{
     "__name__":"disk_info",
     "disk_file_system":"general",
     "disk_label":"free",
     "disk_mount_point":"total",
     "instance":"localhost:10086",
     "job":"cpu","node_ip":"1.1.1.1"
    },
    "values":[
      [1610419795.669,"22778143113216"],
      [1610419900.669,"40493879795712"]
    ]
 },
 {
    "metric":{
      "__name__":"disk_info",
      "disk_file_system":"general",
      "disk_label":"total",
      "disk_mount_point":"total",
      "instance":"localhost:10086",
      "job":"cpu","node_ip":"1.1.1.1"
    },
    "values":[
      [1610419795.669,"63494033448960"],
      [1610419900.669,"112878281687040"]
    ]
  },
  {
    "metric":{
      "__name__":"disk_info",
      "disk_file_system":"general",
      "disk_label":"used",
      "disk_mount_point":"total",
      "instance":"localhost:10086",
      "job":"cpu","node_ip":"1.1.1.1"
    },
    "values":[
      [1610419795.669,"40715890335744"],
      [1610419900.669,"72384401891328"]
    ]
  },
  {
   "metric":{
     "__name__":"disk_info",
     "disk_file_system":"general",
     "disk_label":"used_rate",
     "disk_mount_point":"total",
     "instance":"localhost:10086",
     "job":"cpu","node_ip":"1.1.1.1"
    },
    "values":[
     [1610419795.669,"64.12553766721038"],
     [1610419900.669,"64.12606642260637"]
     ]
  }
]
版权声明:本文来源Segmentfault,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://segmentfault.com/a/1190000040054698
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-13 14:10:07
  • 阅读 ( 893 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢