**
简介:
**
Prometheus 是由 SoundCloud 开源监控告警解决方案。它存储的是时序数据,即按相同时序(相同名称和标签),以时间维度存储连续的数据的集合。时序(time series)是由名字(Metric)以及一组key/value标签定义的,具有相同的名字以及标签属于相同时序。
-
metric名字:表示metric的功能,如http_request_total。时序的名字由 ASCII 字符,数字,下划线,以及冒号组成,它必须满足正则表达式 [a-zA-Z_:][a-zA-Z0-9_:]*, 其名字应该具有语义化,一般表示一个可以度量的指标,例如 http_requests_total, 可以表示 http 请求的总数。
-
标签:
-
样本:按照某个时序以时间维度采集的数据,称之为样本。实际的时间序列,每个序列包括一个float64的值和一个毫秒级的时间戳
-
一个 float64 值
-
一个毫秒级的 unix 时间戳
-
-
格式:Prometheus时序格式与OpenTSDB相似:
<metric name>{<label name>=<label value>, ...}
例如:
api_total{api_name="order_info",host="127.0.0.1"} 1000
指标名称:api_total
标 签:api_name="order_info",host="127.0.0.1"
值:1000
指标类型
-
Counter (累加指标)
一个累加指标数据,这个值随着时间只会逐渐的增加,比如程序完成的总任务数量,运行错误发生的总次数。常见的还有交换机中snmp采集的数据流量也属于该类型,代表了持续增加的数据包或者传输字节累加值。
-
Gauge (测量指标)
Gauge代表了采集的一个单一数据,这个数据可以增加也可以减少,比如CPU使用情况,内存使用量,硬盘当前的空间容量等等
-
Summary (概略图)
Histogram和Summary使用的频率较少,两种都是基于采样的方式。另外有一些库对于这两个指标的使用和支持程度不同,有些仅仅实现了部分功能。这两个类型对于某一些业务需求可能比较常见,比如查询单位时间内:总的响应时间低于300ms的占比,或者查询95%用户查询的门限值对应的响应时间是多少。 使用Histogram和Summary指标的时候同时会产生多组数据,_count代表了采样的总数,_sum则代表采样值的和。 _bucket则代表了落入此范围的数据。
-
Histogram (直方图)
Exporter
Exporter是基于Prometheus实施的监控系统中重要的组成部分,承担数据指标的采集工作,官方的exporter列表中已经包含了常见的绝大多数的系统指标监控,网址:https://prometheus.io/docs/instrumenting/exporters/。这些已有的exporter对于监控来说,仅仅需要很少的配置工作就能提供完善的数据指标采集。
废话不多说,现在上代码
package main
import (
"net/http"
"os"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/common/log"
)
// 指标采集器
type ApiExport struct {
ApiName string
ApiSourceDesc *prometheus.Desc
ApiReqTotalDesc *prometheus.Desc
ApiDeviceDesc *prometheus.Desc
ApiBrowserDesc *prometheus.Desc
ApiNetWorkDesc *prometheus.Desc
}
const (
// 接口请求的来源
SOURCE_PC = 1
SOURCE_ANDROID = 2
SOURCE_IOS = 2
// Device
DEVICE_PC = 1
DEVICE_ANDROID_HUAWEI_10 = 2
DEVICE_IOS_11 = 3
// network
NETWORK_2G = 1
NETWORK_3G = 2
NETWORK_4G = 3
NETWORK_5G = 4
// Brower
BROWER_CHROME = 1
BROWER_FIREFOX = 2
BROWER_IE = 3
BROWER_SAFARI = 4
)
// 获取响应指标的数据,测试数据,正式环境需要修改
func (re *ApiExport) getApiSourceInfo() map[string]float64 {
sourceInfo := map[string]float64{
"127.0.0.1": float64(SOURCE_PC),
}
return sourceInfo
}
func (re *ApiExport) getApiTotalInfo() map[string]float64 {
sourceInfo := map[string]float64{
"127.0.0.1": float64(1000),
}
return sourceInfo
}
func (re *ApiExport) getApiDeviceInfo() map[string]float64 {
sourceInfo := map[string]float64{
"127.0.0.1": float64(DEVICE_PC),
}
return sourceInfo
}
func (re *ApiExport) getApiNetWorkInfo() map[string]float64 {
sourceInfo := map[string]float64{
"127.0.0.1": float64(NETWORK_5G),
}
return sourceInfo
}
func (re *ApiExport) getApiBrowerInfo() map[string]float64 {
sourceInfo := map[string]float64{
"127.0.0.1": float64(BROWER_CHROME),
}
return sourceInfo
}
/**
用于传递所有可能的指标的定义描述符
可以在程序运行期间添加新的描述,收集新的指标信息
重复的描述符将被忽略。两个不同的Collector不要设置相同的描述符
路径:github.com/prometheus/client_golang@v1.7.1/prometheus/collector.go
实现Collector接口
*/
func (re *ApiExport) Describe(ch chan<- *prometheus.Desc) {
ch <- re.ApiSourceDesc
ch <- re.ApiBrowserDesc
ch <- re.ApiDeviceDesc
ch <- re.ApiNetWorkDesc
ch <- re.ApiReqTotalDesc
}
/**
Prometheus的注册器调用Collect执行实际的抓取参数的工作,
并将收集的数据传递到Channel中返回
收集的指标信息来自于Describe中传递,可以并发的执行抓取工作,但是必须要保证线程的安全。
路径:github.com/prometheus/client_golang@v1.7.1/prometheus/collector.go
实现Collector接口
*/
func (re *ApiExport) Collect(ch chan<- prometheus.Metric) {
sourceInfo := re.getApiSourceInfo()
for host, source := range sourceInfo {
ch <- prometheus.MustNewConstMetric(
re.ApiSourceDesc,
prometheus.GaugeValue,
source,
host,
)
}
browserInfo := re.getApiBrowerInfo()
for host, source := range browserInfo {
ch <- prometheus.MustNewConstMetric(
re.ApiBrowserDesc,
prometheus.GaugeValue,
source,
host,
)
}
deviceInfo := re.getApiDeviceInfo()
for host, source := range deviceInfo {
ch <- prometheus.MustNewConstMetric(
re.ApiDeviceDesc,
prometheus.GaugeValue,
source,
host,
)
}
networkInfo := re.getApiNetWorkInfo()
for host, source := range networkInfo {
ch <- prometheus.MustNewConstMetric(
re.ApiNetWorkDesc,
prometheus.GaugeValue,
source,
host,
)
}
totalInfo := re.getApiTotalInfo()
for host, source := range totalInfo {
ch <- prometheus.MustNewConstMetric(
re.ApiReqTotalDesc,
prometheus.GaugeValue,
source,
host,
)
}
}
// 新建一个采集器
func NewApiExport(apiName string) *ApiExport {
return &ApiExport{
ApiName: apiName,
ApiSourceDesc: prometheus.NewDesc(
"api_source", // 指标的名称
"help~~~~", // 帮助信息
[]string{"host"}, // label名称数组
prometheus.Labels{"api_name": apiName}, // labels
),
ApiReqTotalDesc: prometheus.NewDesc(
"api_total",
"help~~~~",
[]string{"host"},
prometheus.Labels{"api_name": apiName},
),
ApiDeviceDesc: prometheus.NewDesc(
"api_device",
"help~~~~",
[]string{"host"},
prometheus.Labels{"api_name": apiName},
),
ApiBrowserDesc: prometheus.NewDesc(
"api_browser",
"help~~~~",
[]string{"host"},
prometheus.Labels{"api_name": apiName},
),
ApiNetWorkDesc: prometheus.NewDesc(
"api_network",
"help~~~~",
[]string{"host"},
prometheus.Labels{"api_name": apiName},
),
}
}
func main() {
order_api := NewApiExport("order_info")
// 注册一个采集器
reg := prometheus.NewPedanticRegistry()
reg.MustRegister(order_api)
gatherers := prometheus.Gatherers{reg}
// 给采集器提供一个http的访问方式
h := promhttp.HandlerFor(gatherers,
promhttp.HandlerOpts{
ErrorLog: log.NewErrorLogger(),
ErrorHandling: promhttp.ContinueOnError,
})
// 访问路径也可以是其他的
http.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
h.ServeHTTP(w, r)
})
log.Infoln("Start server at :8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Errorf("Error occur when start server %v", err)
os.Exit(1)
}
}
最后在Prometheus服务端的prometheus.yml文件中添加如下几行代码在重启服务就Ok了
- job_name: 'api_order'
metrics_path: '/metrics'
static_configs:
- targets: ['192.168.1.4:8080']
在用vi编辑文件的时候一定要注意空格不然就会出现如下的问题:
[root@10 prometheus]# ./prometheus
level=error ts=2020-08-30T06:43:12.630Z caller=main.go:283 msg="Error loading config (--config.file=prometheus.yml)" err="parsing YAML file prometheus.yml: yaml: line 29: did not find expected '-' indicator"
yaml文件注释中的path是没有冒号(:)的,但是自己在写路径是就要加上,不然就会出现如下问题:
[root@10 prometheus]# ./prometheus
level=error ts=2020-08-30T06:43:24.132Z caller=main.go:283 msg="Error loading config (--config.file=prometheus.yml)" err="parsing YAML file prometheus.yml: yaml: line 32: could not find expected ':'"