1 minute read

Prometheus Exporter 交互架構圖

flowchart TD
    A[Prometheus] --HTTP Request--> MyExporter[MyTarget Exporter]
    MyExporter --Extract--> C[MyTargetSource]
    
    subgraph MyExporter
        a1[Colllector 1]
        a2[Colllector 2]
        aN[Colllector N...]
    end


  • Prometheus 實際上可以理解成一個資料庫, 並可以使用一些PromQL進行查詢
  • Prometheus 獲取資料的方式是藉由發起 HTTP Request 與想監測的資源互動,但需監測的資源並不一定會提供 Prometheus 的資料格式接口,這邊會需要利用Exporter作為中間人使 prometheus 可以獲取監控目標的資料
  • 可以理解Exporter 就是一個 HTTP 的API Server, 只是response的格式是符合Prometheus的格式
  • Collector 是 Prometheus 官方定義的一種物件資源, 主要用來將資料源抽象化, 並提供一個統一的介面給Exporter使用
  • 假設某Exporter 可能需要監控某元件 A,B,C種類型的資料, 這時候就可以使用Collector來將A,B,C的資料抽象化, 若某些情況只需要A類型資料, 就可以很只調用A的Collector即可,

Exporter 範例

Go有提供SDK可以快速的開發Exporter,
流程 簡單來說就是 定義一個collector,
然後將collector註冊到Exporter Register,
再藉由HTTP Server將監控資料暴露出去

Exporter 主要邏輯範例

func main() {

	c := &MyCollector{}
	// 定義一個collector

	reg := prometheus.NewRegistry()
	// 創建一個prometheus的註冊器

	reg.MustRegister(c)
	// 註冊自定義的collector

	http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
	http.ListenAndServe(":18081", nil)
	// 啟動一個http server, 並且將監控資料暴露出去  

}
  • Collector: 接口只須滿足Describe, Collect兩個方法即可
  • Describe: 用來定義監控資料的meta data, 當監控資料被註冊到Exporter時, 會被調用一次
  • Collect: 用來定義監控資料的數值, 每當該Http Server被請求時, 會被調用一次

    啟動後, Prometheus 就會每過一小段間隔, 對該Http Server發起一次請求, 並將資料存入prometheus的資料庫

Collector 自定義範例

type MyCollector struct {
	queue_set map[string]*prometheus.Desc 
	// 創建一個map 存放監控資料的meta data 
    // 這邊的key 是監控資料的名稱, value 是該監控資料的meta data
    // promtheus.Desc 是SDK提供的一個結構, 用來定義監控資料的meta data
}

// 將 定義監控的資料類型的 prometheus.Desc 傳入ch
// 這邊是監控兩組資料 名為 my_gauge, my_counter
func (self *MyCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- self.queue_set["my_gauge"]
	ch <- self.queue_set["my_counter"]
}

// 將數值更新至 instance, 傳入
func (self *MyCollector) Collect(ch chan<- prometheus.Metric) {
	val := rand.Intn(999999)
	sessionid1 := []string{strconv.Itoa(rand.Intn(1111)), strconv.Itoa(rand.Intn(2222))}
	sessionid2 := []string{strconv.Itoa(rand.Intn(2222)), strconv.Itoa(rand.Intn(3222))}
	// 這邊是模擬一組數值   
	
	
	ch <- prometheus.MustNewConstMetric(self.queue_set["my_gauge"], prometheus.GaugeValue, float64(val), sessionid1...)
	// 將當下的數值更新至 my_gauge,    
	// MustNewConstMetric 是SDK提供的一個方法, 用來創建一個監控資料的數值
	// 參數依序是 1. 該metric的meta data 是哪一組,  2. 該metric的數值類型, 3. 該metric的數值, 4. 這組metric有設定動態的label, 這邊是設定該次的labe數值  
	
	ch <- prometheus.MustNewConstMetric(self.queue_set["my_counter"], prometheus.CounterValue, float64(time.Now().Unix()), sessionid2...)
    // 同上 只是是更新 my_counter 的數值
}

完整範例

將上面collect結合main的範例, 就可以啟動一個Exporter, 並且將監控資料暴露出去

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"math/rand"
	"net/http"
	"strconv"
	"time"
)

type MyCollector struct {
	queue_set map[string]*prometheus.Desc // define data queue instance
}

func (self *MyCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- self.queue_set["my_gauge"]
	ch <- self.queue_set["my_counter"]
}

func (self *MyCollector) Collect(ch chan<- prometheus.Metric) {
	val := rand.Intn(999999)
	sessionid1 := []string{strconv.Itoa(rand.Intn(1111)), strconv.Itoa(rand.Intn(2222))}
	sessionid2 := []string{strconv.Itoa(rand.Intn(2222)), strconv.Itoa(rand.Intn(3222))}
	ch <- prometheus.MustNewConstMetric(self.queue_set["my_gauge"], prometheus.GaugeValue, float64(val), sessionid1...)
	ch <- prometheus.MustNewConstMetric(self.queue_set["my_counter"], prometheus.CounterValue, float64(time.Now().Unix()), sessionid2...)
}

func main() {

	c := &MyCollector{queue_set: map[string]*prometheus.Desc{
		"my_gauge": prometheus.NewDesc("my_gauge", "gauge_help_tag", []string{"l1", "l2"}, map[string]string{ // 靜態label
			"static_example": "I am static value",
		}),
		"my_counter": prometheus.NewDesc("my_counter", "counter_help_tag", []string{"l3", "l4"}, nil),
	}}
	// 創建一個collector instance

	reg := prometheus.NewRegistry() 
	// 創建一個prometheus的註冊器

	reg.MustRegister(c)
	// 將collector 註冊到 prometheus 的註冊器 


	http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
	http.ListenAndServe(":18081", nil)  // 自定義 port 18081

}

執行後 透過 http://localhost:18081/metrics 就可以看到監控資料