Go语言简单开发一个exporter

Go语言简单开发一个exporter

很多场景下需要自己定义监控指标,那么我们就需要自己开发 exporter 。

使用 go 语言开发 exporter 可以参考:

https://prometheus.io/docs

api 手册:

https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#section-readme

GitHub地址:

https://github.com/prometheus/client_golang

下面将使用 client_golang 语言编写一个极简的 exporter。

1、Prometheus的基本指标类型

1.1 Counter(只增不减的累加指标)

Counter 就是一个计数器,表示一种累积型指标,该指标只能单调递增或在重新启动时重置为零,例如可以使用

计数器来表示所服务的请求数。

1.2 Gauge(可增可减的测量指标)

Gauge 是最简单的度量类型,只有一个简单的返回值,可增可减,也可以设置为指定的值。所以 Gauge 通常用于

反映当前状态,比如当前温度或当前内存使用情况,当然也可以用于可增加可减少的计数指标。

1.3 Histogram(自带buckets区间用于统计分布的直方图)

Histogram 主要用于在设定的分布范围内记录的大小或者次数。

例如 http 请求响应时间:0-100ms、100-200ms、200-300ms、>300ms 的分布情况,Histogram 会自动创建 3

个指标,分别为:

事件发送的总次数:比如当前一共发生了2次http请求。

所有事件产生值的大小的总和:比如发生的2次http请求总的响应时间为150ms。

事件产生的值分布在bucket中的次数:比如响应时间0-100ms的请求1次,100-200ms的请求1次,其它的0次。

1.4 Summary(数据分布统计图)

Summary 和 Histogram 类似,都可以统计事件发生的次数或者大小,以及其分布情况。

Summary 和 Histogram 都提供了对于事件的计数 _count 以及值的汇总 _sum,因此使用 _count_sum

间序列可以计算出相同的内容。

同时 Summary 和 Histogram 都可以计算和统计样本的分布情况,比如中位数,n分位数等等。不同在于

Histogram 可以通过 histogram_quantile 函数在服务器端计算分位数。 而 Sumamry 的分位数则是直接在客户端

进行定义。因此对于分位数的计算。 Summary 在通过 PromQL 进行查询时有更好的性能表现,而 Histogram 则

会消耗更多的资源,相对的对于客户端而言 Histogram 消耗的资源更少。

2、编写exporter

2.1 Guage仪表盘类型

Gauge的特点:

1、可以任意上升或下降,没有固定的范围限制。

2、可以被设置为任何值,不像Counter只能递增。

3、可以被用来表示瞬时值或累计值。

4、可以被用来表示单个实体的状态,例如单个服务器的CPU使用率。

5、可以被用来表示多个实体的总体状态,例如整个集群的CPU使用率。

Gauge的使用:

1、Gauge的值可以通过set()方法进行设置。

2、Gauge的值可以通过inc()和dec()方法进行增加或减少。

3、Gauge的值可以通过add()方法进行增加或减少指定的值。

4、Gauge的值可以通过set_to_current_time()方法设置为当前时间戳。

5、Gauge的值可以通过observe()方法进行设置,这个方法可以用来记录样本值和时间戳。

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"log"
	"net/http"
	"proj/exporter3/util"
	"time"
)

var (
	// Gauge仪表盘类型
	// # HELP our_company_blob_storage_ops_queued Number of blob storage operations waiting to be processed
	// # TYPE our_company_blob_storage_ops_queued gauge
	// our_company_blob_storage_ops_queued 112
	opsQueued = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: "our_company",
		Subsystem: "blob_storage",
		Name:      "ops_queued",
		Help:      "Number of blob storage operations waiting to be processed",
	})
	// # HELP job_in_queue Current number of jobs in the queue
	// # TYPE job_in_queue gauge
	// job_in_queue{job_type="testjob"} 3
	jobsInQueue = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: "job_in_queue",
		Help: "Current number of jobs in the queue",
	}, []string{"job_type"})
)

func init() {
	prometheus.MustRegister(opsQueued, jobsInQueue)
}

func main() {
	jobsInQueue.WithLabelValues("testjob").Add(3)
	// 也可以使用With添加标签
	// jobsInQueue.With(map).Inc()
	// 或者是使用prometheus.Labels
	// jobsInQueue.With(prometheus.Labels{"device":"/dev/sda"}).Inc()
	go func() {
		for true {
			//每隔一秒加 4
			opsQueued.Add(4)
			// 如果设置固定值可以使用
			// opsQueued.Set(4)
			time.Sleep(time.Second)
		}
	}()
	http.Handle("/metrics", promhttp.Handler())
	log.Fatal(http.ListenAndServe(":9090", nil))
}

2.2 Count计数器类型

Counter的特点:

1、Counter只能增加,不能减少或重置。

2、Counter的值是一个非负整数。

3、Counter的值可以随时间增加,但不会减少。

4、Counter的值在重启Prometheus时会重置为0。

5、Counter的值可以被多个Goroutine同时增加,不需要加锁。

6、Counter的值可以被推送到Pushgateway中,用于监控非Prometheus监控的数据。

Counter的使用方法:

1、在程序中定义一个Counter对象,并初始化为0。

2、当需要记录计数时,调用Counter的Inc()方法增加计数器的值。

3、将Counter对象暴露给Prometheus,使其能够收集数据。

4、在Prometheus中定义一个相应的指标,并将Counter对象与该指标关联。

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"log"
	"net/http"
	"time"
)

var (
	// Count计数器类型
	// # HELP worker_pool_completed_tasks_total Total number of tasks completed.
	// # TYPE worker_pool_completed_tasks_total counter
	// worker_pool_completed_tasks_total 17
	taskCounter = prometheus.NewCounter(prometheus.CounterOpts{
		Subsystem: "worker_pool",
		Name:      "completed_tasks_total",
		Help:      "Total number of tasks completed.",
	})
)

func init() {
	prometheus.MustRegister(taskCounter)
}

func main() {
	go func() {
		for true {
			//每隔一秒加 4
			taskCounter.Inc()
			time.Sleep(time.Second)
		}
	}()
	http.Handle("/metrics", promhttp.Handler())
	log.Fatal(http.ListenAndServe(":9090", nil))
}

2.3 Summary类型

Summary是Prometheus中的一种指标类型,用于记录一组样本的总和、计数和分位数。它适用于记录耗时、请

求大小等具有较大变化范围的指标。

Summary指标类型包含以下几个指标:

1、sum:样本值的总和。

2、count:样本值的计数。

3、quantile:分位数。

其中,sum和count是必须的,而quantile是可选的。

在使用Summary指标类型时,需要注意以下几点:

1、每个Summary指标类型都会记录所有样本的总和和计数,因此它们的值会随时间变化而变化。

2、每个Summary指标类型都可以记录多个分位数,例如50%、90%、95%、99%等。

3、每个Summary指标类型都可以设置一个时间窗口,用于计算分位数。

4、每个Summary指标类型都可以设置一个最大样本数,用于限制内存使用。

5、每个Summary指标类型都可以设置一个标签集,用于区分不同的实例。

总之,Summary指标类型是一种非常有用的指标类型,可以帮助我们更好地了解系统的性能和健康状况。

Summary 类型的指标,需要提供分位点,如下:

package main

import (
	"fmt"
	"github.com/golang/protobuf/proto"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	dto "github.com/prometheus/client_model/go"
	"log"
	"math"
	"net/http"
)

var (
	// Summary类型,需要提供分位点
	// # HELP pond_temperature_celsius The temperature of the frog pond.
	// # TYPE pond_temperature_celsius summary
	// pond_temperature_celsius{quantile="0.5"} 31.1
	// pond_temperature_celsius{quantile="0.9"} 41.3
	// pond_temperature_celsius{quantile="0.99"} 41.9
	// pond_temperature_celsius_sum 29969.50000000001
	// pond_temperature_celsius_count 1000
	tempSummary = prometheus.NewSummary(prometheus.SummaryOpts{
		Name:       "pond_temperature_celsius",
		Help:       "The temperature of the frog pond.",
		Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
	})

	// # HELP rpc_durations_seconds RPC latency distributions.
	// # TYPE rpc_durations_seconds summary
	// rpc_durations_seconds{error_code="400",service="normal",quantile="0.5"} 31.1
	// rpc_durations_seconds{error_code="400",service="normal",quantile="0.9"} 41.3
	// rpc_durations_seconds{error_code="400",service="normal",quantile="0.99"} 41.9
	// rpc_durations_seconds_sum{error_code="400",service="normal"} 29969.50000000001
	// rpc_durations_seconds_count{error_code="400",service="normal"} 1000
	rpcDurations = prometheus.NewSummaryVec(
		prometheus.SummaryOpts{
			Name:       "rpc_durations_seconds",
			Help:       "RPC latency distributions.",
			Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}},
		[]string{"service", "error_code"},
	)
)

func init() {
	prometheus.MustRegister(tempSummary, rpcDurations)
}

func main() {
	go func() {
		// 模拟观察温度
		for i := 0; i < 1000; i++ {
			tempSummary.Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10)
		}
		// 仅供示范,让我们通过使用它的Write方法检查摘要的状态(通常只在Prometheus内部使用)
		metric := &dto.Metric{}
		tempSummary.Write(metric)
		/*
			summary: <
			  sample_count: 1000
			  sample_sum: 29969.50000000001
			  quantile: <
			    quantile: 0.5
			    value: 31.1
			  >
			  quantile: <
			    quantile: 0.9
			    value: 41.3
			  >
			  quantile: <
			    quantile: 0.99
			    value: 41.9
			  >
			>
		*/
		fmt.Println(proto.MarshalTextString(metric))
	}()
	go func() {
		// 模拟观察温度
		for i := 0; i < 1000; i++ {
			rpcDurations.WithLabelValues("normal", "400").Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10)
		}
	}()
	http.Handle("/metrics", promhttp.Handler())
	log.Fatal(http.ListenAndServe(":9090", nil))
}

2.4 Histogram类型

Histogram是一种Prometheus指标类型,用于度量数据的分布情况。它将数据分成一系列桶(bucket),每个桶代

表一段范围内的数据。每个桶都有一个计数器(counter),用于记录该范围内的数据数量。在Prometheus中,

Histogram指标类型的名称以_bucket结尾。

Histogram指标类型通常用于度量请求延迟、响应大小等连续型数据。例如,我们可以使用Histogram指标类型来

度量Web应用程序的请求延迟。我们可以将请求延迟分成几个桶,例如0.1秒、0.5秒、1秒、5秒、10秒、30秒

等。每个桶都记录了在该范围内的请求延迟的数量。

Histogram指标类型还有两个重要的计数器:sum和count。sum用于记录所有数据的总和,count用于记录数据

的数量。通过这两个计数器,我们可以计算出平均值和其他统计信息。

在Prometheus中,我们可以使用histogram_quantile函数来计算某个百分位数的值。例如,我们可以使用

histogram_quantile(0.9, my_histogram)来计算my_histogram指标类型中90%的请求延迟的值。

总之,Histogram指标类型是一种非常有用的指标类型,可以帮助我们了解数据的分布情况,从而更好地监控和优

化应用程序的性能。

Histogram 类型的指标,需要提供 Bucket 大小,如下:

package main

import (
	"fmt"
	"github.com/golang/protobuf/proto"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	dto "github.com/prometheus/client_model/go"
	"log"
	"math"
	"net/http"
)

var (
	//Histogram类型,需要提供Bucket大小
	// # HELP pond_temperature_histogram_celsius The temperature of the frog pond.
	// # TYPE pond_temperature_histogram_celsius histogram
	// pond_temperature_histogram_celsius_bucket{le="20"} 192
	// pond_temperature_histogram_celsius_bucket{le="25"} 366
	// pond_temperature_histogram_celsius_bucket{le="30"} 501
	// pond_temperature_histogram_celsius_bucket{le="35"} 638
	// pond_temperature_histogram_celsius_bucket{le="40"} 816
	// pond_temperature_histogram_celsius_bucket{le="+Inf"} 1000
	// pond_temperature_histogram_celsius_sum 29969.50000000001
	// pond_temperature_histogram_celsius_count 1000
	tempsHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
		Name:        "pond_temperature_histogram_celsius",
		Help:        "The temperature of the frog pond.",
		ConstLabels: nil,
		// 5个buckets,跨度为5摄氏度
		Buckets: prometheus.LinearBuckets(20, 5, 5),
		// 等价于这个
		// Buckets:     []float64{20, 25, 30, 35, 40},
		// 由于填写一串Bucket过于繁琐,所以Prometheus还提供了便捷的生成方法:
		// LinearBuckets用于创建等差数列
		// ExponentialBucket用于创建等比数列
	})
)

func init() {
	prometheus.MustRegister(tempsHistogram)
}

func main() {
	go func() {
		// 模拟观察温度
		for i := 0; i < 1000; i++ {
			tempsHistogram.Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10)
		}
		// 仅供示范,让我们通过使用它的Write方法检查摘要的状态(通常只在Prometheus内部使用)
		metric := &dto.Metric{}
		tempsHistogram.Write(metric)
		/*
		histogram: <
		  sample_count: 1000
		  sample_sum: 29969.50000000001
		  bucket: <
		    cumulative_count: 192
		    upper_bound: 20
		  >
		  bucket: <
		    cumulative_count: 366
		    upper_bound: 25
		  >
		  bucket: <
		    cumulative_count: 501
		    upper_bound: 30
		  >
		  bucket: <
		    cumulative_count: 638
		    upper_bound: 35
		  >
		  bucket: <
		    cumulative_count: 816
		    upper_bound: 40
		  >
		>
		*/
		fmt.Println(proto.MarshalTextString(metric))
	}()
	http.Handle("/metrics", promhttp.Handler())
	log.Fatal(http.ListenAndServe(":9090", nil))
}

3、自定义类型

如果上面 Counter,Gauge,Histogram,Summary 四种内置指标都不能满足我们要求时,我们还可以自定义类

型。只要实现了 Collect 接口的方法,然后调用 MustRegister 即可。

func MustRegister(cs ...Collector) {
    DefaultRegisterer.MustRegister(cs...)
}

type Collector interface {
    // 用于传递所有可能的指标的定义描述符
    // 可以在程序运行期间添加新的描述,收集新的指标信息
    // 重复的描述符将被忽略,两个不同的Collector不要设置相同的描述符
    Describe(chan<- *Desc)

    // Prometheus的注册器调用Collect执行实际的抓取参数的工作,
    // 并将收集的数据传递到Channel中返回
    // 收集的指标信息来自于Describe中传递,可以并发的执行抓取工作,但是必须要保证线程的安全。
    Collect(chan<- Metric)
}

3.1 示例1

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	log "github.com/sirupsen/logrus"
	"net/http"
)

type fooCollector struct {
	fooMetric *prometheus.Desc
	barMetric *prometheus.Desc
}

func newFooCollector() *fooCollector {
	return &fooCollector{
		// # HELP foo_metric Shows whether a foo has occurred in our cluster
		// # TYPE foo_metric counter
		// foo_metric 1
		fooMetric: prometheus.NewDesc("foo_metric",
			"Shows whether a foo has occurred in our cluster",
			nil, nil,
		),
		// # HELP bar_metric Shows whether a bar has occurred in our cluster
		// # TYPE bar_metric counter
		// bar_metric 1
		barMetric: prometheus.NewDesc("bar_metric",
			"Shows whether a bar has occurred in our cluster",
			nil, nil,
		),
	}
}

func (collector *fooCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- collector.fooMetric
	ch <- collector.barMetric
}

func (collector *fooCollector) Collect(ch chan<- prometheus.Metric) {
	var metricValue float64
	if 1 == 1 {
		metricValue = 1
	}
	ch <- prometheus.MustNewConstMetric(collector.fooMetric, prometheus.CounterValue, metricValue)
	ch <- prometheus.MustNewConstMetric(collector.barMetric, prometheus.CounterValue, metricValue)
}

func main() {

	foo := newFooCollector()
	prometheus.MustRegister(foo)

	http.Handle("/metrics", promhttp.Handler())
	log.Info("Beginning to serve on port :9090")
	log.Fatal(http.ListenAndServe(":9090", nil))
}

启动访问 http://127.0.0.1:9090/metrics

# HELP bar_metric Shows whether a bar has occurred in our cluster
# TYPE bar_metric counter
bar_metric 1
# HELP foo_metric Shows whether a foo has occurred in our cluster
# TYPE foo_metric counter
foo_metric 1
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
go_gc_duration_seconds{quantile="0.5"} 0
go_gc_duration_seconds{quantile="0.75"} 0
go_gc_duration_seconds{quantile="1"} 0
go_gc_duration_seconds_sum 0
go_gc_duration_seconds_count 0
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 6
# HELP go_info Information about the Go environment.
# TYPE go_info gauge
go_info{version="go1.18.4"} 1
# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes 1.614816e+06
# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed.
# TYPE go_memstats_alloc_bytes_total counter
go_memstats_alloc_bytes_total 1.614816e+06
# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table.
# TYPE go_memstats_buck_hash_sys_bytes gauge
go_memstats_buck_hash_sys_bytes 6668
# HELP go_memstats_frees_total Total number of frees.
# TYPE go_memstats_frees_total counter
go_memstats_frees_total 0
# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata.
# TYPE go_memstats_gc_sys_bytes gauge
go_memstats_gc_sys_bytes 1.444472e+06
# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use.
# TYPE go_memstats_heap_alloc_bytes gauge
go_memstats_heap_alloc_bytes 1.614816e+06
# HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used.
# TYPE go_memstats_heap_idle_bytes gauge
go_memstats_heap_idle_bytes 2.400256e+06
# HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use.
# TYPE go_memstats_heap_inuse_bytes gauge
go_memstats_heap_inuse_bytes 1.630208e+06
# HELP go_memstats_heap_objects Number of allocated objects.
# TYPE go_memstats_heap_objects gauge
go_memstats_heap_objects 16185
# HELP go_memstats_heap_released_bytes Number of heap bytes released to OS.
# TYPE go_memstats_heap_released_bytes gauge
go_memstats_heap_released_bytes 2.400256e+06
# HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system.
# TYPE go_memstats_heap_sys_bytes gauge
go_memstats_heap_sys_bytes 4.030464e+06
# HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection.
# TYPE go_memstats_last_gc_time_seconds gauge
go_memstats_last_gc_time_seconds 0
# HELP go_memstats_lookups_total Total number of pointer lookups.
# TYPE go_memstats_lookups_total counter
go_memstats_lookups_total 0
# HELP go_memstats_mallocs_total Total number of mallocs.
# TYPE go_memstats_mallocs_total counter
go_memstats_mallocs_total 16185
# HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures.
# TYPE go_memstats_mcache_inuse_bytes gauge
go_memstats_mcache_inuse_bytes 9344
# HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system.
# TYPE go_memstats_mcache_sys_bytes gauge
go_memstats_mcache_sys_bytes 16352
# HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures.
# TYPE go_memstats_mspan_inuse_bytes gauge
go_memstats_mspan_inuse_bytes 28968
# HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system.
# TYPE go_memstats_mspan_sys_bytes gauge
go_memstats_mspan_sys_bytes 32640
# HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place.
# TYPE go_memstats_next_gc_bytes gauge
go_memstats_next_gc_bytes 4.194304e+06
# HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations.
# TYPE go_memstats_other_sys_bytes gauge
go_memstats_other_sys_bytes 1.010924e+06
# HELP go_memstats_stack_inuse_bytes Number of bytes in use by the stack allocator.
# TYPE go_memstats_stack_inuse_bytes gauge
go_memstats_stack_inuse_bytes 163840
# HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator.
# TYPE go_memstats_stack_sys_bytes gauge
go_memstats_stack_sys_bytes 163840
# HELP go_memstats_sys_bytes Number of bytes obtained from system.
# TYPE go_memstats_sys_bytes gauge
go_memstats_sys_bytes 6.70536e+06
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
go_threads 8
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.03125
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1.6777216e+07
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 99
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 8.47872e+06
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.684024205e+09
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 1.4680064e+07
# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served.
# TYPE promhttp_metric_handler_requests_in_flight gauge
promhttp_metric_handler_requests_in_flight 1
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 0
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0

3.2 示例2

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	log "github.com/sirupsen/logrus"
	"math/rand"
	"net/http"
	"os"
)

// 先定义结构体,这是一个集群的指标采集器
// 每个集群都有自己的Zone,代表集群的名称,另外两个是保存的采集的指标
type ClusterManager struct {
	Zone         string
	OOMCountDesc *prometheus.Desc
	RAMUsageDesc *prometheus.Desc
}

// 返回一个按照主机名作为键采集到的数据,两个返回值分别代表了OOM错误计数和RAM使用指标信息
func (c *ClusterManager) ReallyExpensiveAssessmentOfTheSystemState() (
	oomCountByHost map[string]int, ramUsageByHost map[string]float64,
) {
	oomCountByHost = map[string]int{
		"foo.example.org": int(rand.Int31n(1000)),
		"bar.example.org": int(rand.Int31n(1000)),
	}
	ramUsageByHost = map[string]float64{
		"foo.example.org": rand.Float64() * 100,
		"bar.example.org": rand.Float64() * 100,
	}
	return
}

// 实现Describe接口,传递指标描述符到channel
func (c *ClusterManager) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.OOMCountDesc
	ch <- c.RAMUsageDesc
}

// Collect函数将执行抓取函数并返回数据,返回的数据传递到channel中,并且传递的同时绑定原先的指标描述符
// 以及指标的类型(一个Counter和一个Gauge)
func (c *ClusterManager) Collect(ch chan<- prometheus.Metric) {
	oomCountByHost, ramUsageByHost := c.ReallyExpensiveAssessmentOfTheSystemState()
	for host, oomCount := range oomCountByHost {
		ch <- prometheus.MustNewConstMetric(
			c.OOMCountDesc,
			prometheus.CounterValue,
			float64(oomCount),
			host,
		)
	}
	for host, ramUsage := range ramUsageByHost {
		ch <- prometheus.MustNewConstMetric(
			c.RAMUsageDesc,
			prometheus.GaugeValue,
			ramUsage,
			host,
		)
	}
}

// 创建结构体及对应的指标信息,NewDesc参数第一个为指标的名称,第二个为帮助信息,显示在指标的上面作为注释
// 第三个是定义的label名称数组,第四个是定义的Labels
func NewClusterManager(zone string) *ClusterManager {
	return &ClusterManager{
		Zone: zone,
		OOMCountDesc: prometheus.NewDesc(
			"clustermanager_oom_crashes_total",
			"Number of OOM crashes.",
			[]string{"host"},
			prometheus.Labels{"zone": zone},
		),
		RAMUsageDesc: prometheus.NewDesc(
			"clustermanager_ram_usage_bytes",
			"RAM usage as reported to the cluster manager.",
			[]string{"host"},
			prometheus.Labels{"zone": zone},
		),
	}
}

func main() {
	workerDB := NewClusterManager("db")
	workerCA := NewClusterManager("ca")
	reg := prometheus.NewPedanticRegistry()
	reg.MustRegister(workerDB)
	reg.MustRegister(workerCA)
	// prometheus.Gatherers用来定义一个采集数据的收集器集合,可以merge多个不同的采集数据到一个结果集合
	// 这里我们传递了缺省的DefaultGatherer,所以他在输出中也会包含go运行时指标信息
	// 同时包含reg是我们之前生成的一个注册对象,用来自定义采集数据
	// 如果注释掉了prometheus.DefaultGatherername只会采集我们自己定义的指标
	gatherers := prometheus.Gatherers{
		//prometheus.DefaultGatherer,
		reg,
	}
	// promhttp.HandlerFor()函数传递之前的Gatherers对象,并返回一个httpHandler对象
	// 这个httpHandler对象可以调用其自身的ServHTTP函数来接手http请求并返回响应
	// 其中promhttp.HandlerOpts定义了采集过程中如果发生错误时,继续采集其他的数据。
	h := promhttp.HandlerFor(gatherers,
		promhttp.HandlerOpts{
			ErrorLog:      &log.Logger{Level: log.ErrorLevel},
			ErrorHandling: promhttp.ContinueOnError,
		})
	http.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
		h.ServeHTTP(w, r)
	})
	log.Infoln("Start server at :9090")
	if err := http.ListenAndServe(":9090", nil); err != nil {
		log.Errorf("Error occur when start server %v", err)
		os.Exit(1)
	}
}

启动访问 http://127.0.0.1:9090/metrics

# HELP clustermanager_oom_crashes_total Number of OOM crashes.
# TYPE clustermanager_oom_crashes_total counter
clustermanager_oom_crashes_total{host="bar.example.org",zone="ca"} 318
clustermanager_oom_crashes_total{host="bar.example.org",zone="db"} 887
clustermanager_oom_crashes_total{host="foo.example.org",zone="ca"} 81
clustermanager_oom_crashes_total{host="foo.example.org",zone="db"} 81
# HELP clustermanager_ram_usage_bytes RAM usage as reported to the cluster manager.
# TYPE clustermanager_ram_usage_bytes gauge
clustermanager_ram_usage_bytes{host="bar.example.org",zone="ca"} 15.651925473279125
clustermanager_ram_usage_bytes{host="bar.example.org",zone="db"} 43.771418718698015
clustermanager_ram_usage_bytes{host="foo.example.org",zone="ca"} 6.563701921747622
clustermanager_ram_usage_bytes{host="foo.example.org",zone="db"} 66.45600532184905
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值