1. 程式人生 > 實用技巧 >開發一個簡單的golang prometheus exporter.

開發一個簡單的golang prometheus exporter.

以下是一個簡單的學習關於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 實現,而且好多語言的框架已經提供了類似的中介軟體擴充套件我們可以直接使用

參考資料

https://github.com/prometheus/client_golang