Prometheus 生态是一款优秀的开源监控解决方案,其中包括如下组件
通过配置各个采集任务,采集各个 expoter 或 pushgateway 数据,保存到其内部的时间序列数据库(TSDB)中.并根据规则对采集到的数据指标进行计算或重新保存为新的数据指标,判断是否达到阈值并向 Alertmanager 推送告警信息.
接收 Prometheus 推送过来的告警信息,通过告警路由,向集成的组件/工具发送告警信息.
- 各种 Exporter
 
收集系统或进程信息,转换为 Prometheus 可以识别的数据指标,以 http 或 https 服务的方式暴露给 Prometheus.
- [Pushgateway]
 
收集系统或进程信息,转换为 Prometheus 可以识别的数据指标,向 Prometheus 推送数据指标.
本篇文章主要内容为根据 Prometheus client_golang 官方文档总结的 Prometheus client_golang 简单使用方法.
包结构
prometheus/client_golang 包结构如下:
| 包路径 | 简介 | 
|---|---|
| api | api 包提供了 Prometheus HTTP API | 
| api/prometheus/v1 | v1 包提供了 v1 版本的 Prometheus HTTP API,详见 http://prometheus.io/docs/querying/api/ | 
| examples/random | 一个简单的示例,将具有不同类型的随机分布(均匀,正态和指数)的虚构 RPC 延迟公开为 Prometheus 数据指标 | 
| examples/simple | 一个使用 Prometheus 工具的最小示例 | 
| prometheus | prometheus 包是 prometheus/client_golang 的核心包 | 
| prometheus/graphite | graphite 包提供了将 Prometheus 数据指标推送到 Graphite 服务的相关代码 | 
| prometheus/internal | 内部包 | 
| prometheus/promauto | promauto 包提供了 Prometheus 指标的基本数据类型及其 …Vec 和 …Func 变体数据类型的构造函数 | 
| prometheus/promhttp | promhttp 包提供了 HTTP 服务端和客户端相关工具 | 
| prometheus/push | push 包提供了将指标推送到 Pushgateway 的函数 | 
| prometheus/testutil | testutil 包提供了测试使用 prometheus/client_golang 编写的代码的帮助程序 | 
| prometheus/testutil/promlint | promlint 包为 Prometheus 数据指标提供一个参考. | 
prometheus 包
导入方式 import "github.com/prometheus/client_golang/prometheus".
prometheus 包是 prometheus/client_golang 的核心包.它为工具代码提供原生数据指标用于监控,并为数据指标对象提供了注册表.promauto 为数据指标提供自动注册的构造函数,promhttp 子包允许通过 HTTP 公开已注册的数据指标,push 子包可以将已注册的数据指标推送到 Pushgateway.
示例如下:
1  | package main  | 
数据指标
prometheus 包提供了四种基本的数据指标类型,Counter,Gauge,Histogram 和 Summary.可以在Prometheus docs 中找到对这四种度量标准类型的更全面的描述.
除了四种基本的数据指标类型外,Prometheus 数据模型的一个非常重要的部分是沿着称为 “标签” 的维度对数据指标样本进行划分,这就产生了数据指标向量(metric vectors).prometheus 分为为四种基本数据指标类型提供了相应的数据指标向量,分别是 CounterVec,GaugeVec,HistogramVec 和 SummaryVec.
数据指标向量的方法如下:
1  | Collect(ch chan<- Metric) // 实现 Collector 接口的 Collect() 方法  | 
要创建 Metrics 及其向量版本的实例,您需要一个合适的…Opts结构,即 GaugeOpts,CounterOpts,SummaryOpts 或 HistogramOpts.结构体如下:
1  | // 其中 GaugeOpts, CounterOpts 实际上均为 Opts 的别名  | 
这里需要注意的是 Counter,Gauge,Histogram,Summary 都继承了 Metric 和 Collector 接口,其本身是接口类型.而 CounterVec,GaugeVec,HistogramVec, SummaryVec 均继承自 metricVec 结构体,其本身的是结构体,而它们只实现了 Collector 接口.
自定义 Collectors 和常量指标
prometheus 包提供了 NewConstMetric(),NewConstHistogram(),NewConstSummary() 及其各自的 Must… 版本的函数 “动态” 创建 Metric 实例.其中 NewConstMetric() 函数用于创建仅以 float64 数据作为其值的数据指标类型对象,如 Counter,Gauge 及 Untyped 特殊类型对象.Metric 实例的创建在 Collect() 方法中进行.
prometheus 包提供了 NewDesc() 函数创建用于描述以上 Metric 实例的 Desc 对象,其中主要包含  Metric 实例的名称与帮助信息.
prometheus 包还提供了 NewCounterFunc(),NewGaugeFunc() 或 NewUntypedFunc() 函数用于创建实现了 CounterFunc, GaugeFunc, UntypedFunc 接口的 valueFunc 对象,用于只需要以传入函数的浮点数返回值作为数据指标值创建数据指标的场景.
Registry 的高级用法
prometheus 包提供了 MustRegister() 函数用于注册 Collector,但如果注册过程中发生错误,程序会引发 panics.而使用 Register() 函数可以实现注册 Collector 的同时处理可能发生的错误.
prometheus 包中所有的注册都是在默认的注册表上进行的,可以在全局变量 DefaultRegisterer 中找到该对象.prometheus 包提供了 NewRegistry() 函数用于创建自定义注册表,甚至可以自己实现 Registerer 或 Gatherer 接口.
 prometheus 通过 NewGoCollector() 和 NewProcessCollector() 函数创建 Go 运行时数据指标的 Collector 和进程数据指标的 Collector.而这两个 Collector 已在默认的注册表 DefaultRegisterer 中注册.使用自定义注册表,您可以控制并自行决定要注册的 Collector.
HTTP 公开数据指标
注册表(Registry 结构体)实现了 Gatherer 接口,实现了 Gather() 方法.Gather() 方法的调用者可以以某种方式公开收集的数据指标.通常通过 /metrics 入口以 HTTP 方式提供.通过 HTTP 公开数据指标的工具在 promhttp 包中.
推送数据指标到 Pushgateway
在 push 子包中可以找到用于推送到 Pushgateway 的函数.
promauto 包
导入方式: import "github.com/prometheus/client_golang/prometheus/promauto"
promauto 包提供了 Prometheus 指标的基本数据类型及其 …Vec 和 …Func 变体数据类型的构造函数.与 prometheus 包中提供的构造函数不同的是,promauto 包中的构造函数返回已经注册的 Collector 对象.
promauto 包中包含三组构造函数,New<Metric>, New<Metric>Vec 与 New<Metric>Func.
promauto 包中 NewXXX 函数,其实都是调用了 prometheus 包中对应的 NewXXX 函数创建了 Collector 对象,并将此 Collector 对象在 prometheus.DefaultRegisterer 中调用 MustRegister() 方法注册.因此如果注册失败,所有构造函数都会引发 panics.
以 promauto.NewCounter() 为例,源代码如下:
1  | // github.com/prometheus/client_golang@v1.7.1/prometheus/promauto/auto.go#L167  | 
示例如下:
1  | // 通过 `promauto` 包中方法创建的 Collector 对象 histogramRegistered 已被注册,可直接被公开为数据指标  | 
同时,promauto 包还提供了 With() 函数.该函数返回创建 Collector 的工厂对象.通过该工厂对象创建的 Collector 都在传入的 Registerer 中进行注册.
1  | func With(r prometheus.Registerer) Factory { return Factory{r} }  | 
示例如下:
1  | var (  | 
promhttp 包
promhttp 包允许创建 http.Handler 实例通过 HTTP 公开 Prometheus 数据指标.
Handler() 与 HandlerFor() 函数
promhttp 包提供了 Handler() 函数使用默认的 prometheus.DefaultGatherer 返回一个 http.Handler.它将第一个错误报告为 HTTP 错误,没有错误记录.返回的 http.Handler 已使用 InstrumentMetricHandler() 函数和默认的 prometheus.DefaultRegisterer 进行检测.如果调用多个 Handler() 函数创建多个 http.Handler,则用于检测的数据指标将在它们之间共享,从而提供全局采集计数.如 promhttp_metric_handler_requests_total 和 promhttp_metric_handler_requests_in_flight 数据指标.
promhttp 包提供了HandlerFor() 函数,您可以为自定义注册表或实现 Gatherer 接口的任何内容创建处理程序,还允许通过传入 HandlerOpts 对象自定义错误处理行为或记录错误的对象.
InstrumentHandlerX 包装器函数
promhttp 包提供了通过中间件来检测 http.Handler 实例的工具.中间件包装器遵循 InstrumentHandlerX 命名方案,其中 X 描述了中间件的预期用途.有关详细信息,请参见每个函数的文档注释.
promhttp 包提供以下中间件包装器:
func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler) http.HandlerFunc
InstrumentHandlerCounter 包装传入的 http.Handler,并通过传入的 prometheus.CounterVec 记录不同请求方法或响应状态分组的计数结果.
CounterVec 可以通过 HTTP 状态码或方法对 CounterVec 中带有相应标签实例的数据指标进行分组,其允许的标签名称是 "code" 和 "method",否则该函数会引发 panics.对于未分区的计数,可使用不带标签的 CounterVec.如果装饰的 Handler 未设置状态码,默认为 200.
func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc
InstrumentHandlerDuration 包装传入的 http.Handler,并通过传入的 prometheus.ObserverVec 记录不同请求方法或响应状态分组的持续时间.持续时间以秒为单位.
与 CounterVec 类似,ObserverVec 可以通过 HTTP 状态码或方法对 ObserverVec 中带有相应标签实例的数据指标进行分组,其默认允许的标签名称是 "code" 和 "method",如果除 method,code 外有其它标签,需要在包装器中调用 CurryWith() 或 MustCurryWith() 传入标签的值,否则该函数会引发 panics.对于未分区的计数,可使用不带标签的 ObserverVec.如果装饰的 Handler 未设置状态码,默认为 200.
func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handler
InstrumentHandlerInFlight 包装传入的 http.Handler,它通过传入的 prometheus.Gauge 记录处理的请求数
func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc
InstrumentHandlerRequestSize 包装传入的 http.Handler,它通过传入的 prometheus.ObserverVec 记录不同请求方法或响应状态分组的请求大小.请求大小以字节为单位.
与 CounterVec 类似,ObserverVec 可以通过 HTTP 状态码或方法对 ObserverVec 中带有相应标签实例的数据指标进行分组,其默认允许的标签名称是 "code" 和 "method",如果除 method,code 外有其它标签,需要在包装器中调用 CurryWith() 或 MustCurryWith() 传入标签的值,否则该函数会引发 panics.对于未分区的计数,可使用不带标签的 ObserverVec.如果装饰的 Handler 未设置状态码,默认为 200.
func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler) http.Handler
InstrumentHandlerResponseSize 包装传入的 http.Handler,它通过传入的 prometheus.ObserverVec 记录不同请求方法或响应状态分组的响应大小.响应大小以字节为单位.
与 CounterVec 类似,ObserverVec 可以通过 HTTP 状态码或方法对 ObserverVec 中带有相应标签实例的数据指标进行分组,其默认允许的标签名称是 "code" 和 "method",如果除 method,code 外有其它标签,需要在包装器中调用 CurryWith() 或 MustCurryWith() 传入标签的值,否则该函数会引发 panics.对于未分区的计数,可使用不带标签的 ObserverVec.如果装饰的 Handler 未设置状态码,默认为 200.
func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc
InstrumentHandlerResponseSize 包装传入的 http.Handler,它通过传入的 prometheus.ObserverVec 记录不同请求方法或响应状态分组的写入响应头部的时间.持续时间以秒为单位.
与 CounterVec 类似,ObserverVec 可以通过 HTTP 状态码或方法对 ObserverVec 中带有相应标签实例的数据指标进行分组,其默认允许的标签名称是 "code" 和 "method",如果除 method,code 外有其它标签,需要在包装器中调用 CurryWith() 或 MustCurryWith() 传入标签的值,否则该函数会引发 panics.对于未分区的计数,可使用不带标签的 ObserverVec.如果装饰的 Handler 未设置状态码,默认为 200.
func InstrumentMetricHandler(reg prometheus.Registerer, handler http.Handler) http.Handler
InstrumentMetricHandler 通常与 HandlerFor 函数返回的 http.Handler 一起使用.它使用两个数据指标为传入的 http.Handler 进行包装: promhttp_metric_handler_requests_total(CounterVec 类型) 对按 HTTP 响应状态码分组的请求进行计数,promhttp_metric_handler_requests_in_flight(Gauge 类型) 跟踪同时进行的请求数量.
如上两个数据指标对于查看多少数据指标采集请求发送到监控目标上以及它们的重复率(同时有多少个采集请求)非常有用.
示例
中间件包装器示例如下:
1  | func main() {  | 
push 包
push 包提供了将数据指标推送到 Pushgateway 的函数,它使用构造其函数 New() 创建 Pusher 对象,然后使用其实例方法添加各种选项,最后调用 Add() 或 Push() 方法向 Pushgateway 推送数据指标.
1  | push.New("http://example.org/metrics", "my_job").Gatherer(myRegistry).Push()  | 
源码解析如下:
1  | // github.com/prometheus/client_golang/prometheus/push/push.go  |