以下是一个简单的学习关于golang 开发prometheus exporter 的说明
环境准备
- go mod
module ladap-exporter
go 1.14
require (
github.com/go-ldap/ldap/v3 v3.2.3 // indirect
github.com/prometheus/client_golang v1.7.1
)
- main.go
package main
import (
"flag"
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var addr = flag.String("listen-address", ":9001", "The address to listen on for HTTP requests.")
var 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"},
)
var up = prometheus.NewDesc(
"ldap_up",
"watch ladap info",
[]string{"name", "class"},
nil,
)
var rpc = prometheus.NewDesc(
"rpc_request_total",
"rpc request total",
[]string{"rpc_func", "rpc_source"},
nil,
)
var version = prometheus.MustNewConstMetric(
prometheus.NewDesc("ldap_exporter_version", "ldap exporter version", []string{"type", "build"}, nil),
prometheus.GaugeValue,
1.0,
"cust", "2020-09-08",
)
// MyLDAPCollector myLDAPCollector
type MyLDAPCollector struct {
up *prometheus.Desc
rpc *prometheus.Desc
version *prometheus.Desc
}
//Describe describe
func (c MyLDAPCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.up
ch <- c.rpc
ch <- c.version
}
//Collect collect
func (c MyLDAPCollector) Collect(ch chan<- prometheus.Metric) {
upMetrics := prometheus.MustNewConstMetric(up, prometheus.GaugeValue, 1, "dalong", "demo")
rpcRequest := prometheus.MustNewConstMetric(rpc, prometheus.CounterValue, 1000, "login", "a")
ch <- version
ch <- upMetrics
ch <- rpcRequest
}
func init() {
myLDAPCollector := MyLDAPCollector{
up: up,
rpc: rpc,
version: version.Desc(),
}
// Add MyCus Collector
prometheus.MustRegister(myLDAPCollector)
// Add rpc summary collector
prometheus.MustRegister(rpcDurations)
// Add Go module build info.
prometheus.MustRegister(prometheus.NewBuildInfoCollector())
}
func main() {
flag.Parse()
server := http.NewServeMux()
server.HandleFunc("/", func(response http.ResponseWriter, Request *http.Request) {
indexpage := `<html>
<body>
<h1>ldap exporter</h1>
<p><a href="/metrics">metrics</a></p>
</body>
</html>`
response.Write([]byte(indexpage))
})
server.HandleFunc("/api", func(response http.ResponseWriter, Request *http.Request) {
rpcDurations.WithLabelValues("mydemo").Observe(22)
response.Write([]byte("dalongdemo"))
})
server.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(*addr, server)
}
- 代码说明
以上代码同时包含了基于自定义collector 以及内置默认的处理,对于自定义的collector 我们需要实现
参考接口定义
type Collector interface {
// Describe sends the super-set of all possible descriptors of metrics
// collected by this Collector to the provided channel and returns once
// the last descriptor has been sent. The sent descriptors fulfill the
// consistency and uniqueness requirements described in the Desc
// documentation.
//
// It is valid if one and the same Collector sends duplicate
// descriptors. Those duplicates are simply ignored. However, two
// different Collectors must not send duplicate descriptors.
//
// Sending no descriptor at all marks the Collector as “unchecked”,
// i.e. no checks will be performed at registration time, and the
// Collector may yield any Metric it sees fit in its Collect method.
//
// This method idempotently sends the same descriptors throughout the
// lifetime of the Collector. It may be called concurrently and
// therefore must be implemented in a concurrency safe way.
//
// If a Collector encounters an error while executing this method, it
// must send an invalid descriptor (created with NewInvalidDesc) to
// signal the error to the registry.
Describe(chan<- *Desc)
// Collect is called by the Prometheus registry when collecting
// metrics. The implementation sends each collected metric via the
// provided channel and returns once the last metric has been sent. The
// descriptor of each sent metric is one of those returned by Describe
// (unless the Collector is unchecked, see above). Returned metrics that
// share the same descriptor must differ in their variable label
// values.
//
// This method may be called concurrently and must therefore be
// implemented in a concurrency safe way. Blocking occurs at the expense
// of total performance of rendering all registered metrics. Ideally,
// Collector implementations support concurrent readers.
Collect(chan<- Metric)
}
type MyLDAPCollector struct 说明
为了方便统计添加了up version 以及rpc 的定义,up 是标记exporter 运行准备的,version 记录exporter 版本的
rpc 是一个简单的total 模式的metrics 定义
对于golang prometheus metrics 的定义,一般我们需要的是desc(表明metrics 的名称,帮助信息,以及可能包含的label)
自定义collector 的Describe主要是进行metrics desc 信息的暴露,Collect 是实际的metrics 处理(拉取数据库,其他中间件的信息拉取。。。。)
定义完collector之后我们需要进行注册才能使用,具体的注册比较简单prometheus.MustRegister 就可以了,同时golang 版本的sdk
已经提供了好多便捷的metrics 帮助没(count,gauge.summary,histogram)都是比较方便的,同时也内置了一些golang runtime 的metrics
都是可以注册使用的
prometheus exporter http server 的暴露也比较简单,默认以及提供了http handler 的实现,我们注册就可以了
server.Handle("/metrics", promhttp.Handler())
- 运行效果
go run main.go
说明
以上是一个简单的metrics 实现,而且好多语言的框架已经提供了类似的中间件扩展我们可以直接使用