Golang开发Prometheus的Exporter

**

简介:

**
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 ':'"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值