為 Go 應(yīng)用添加 Prometheus 監(jiān)控指標(biāo)
前面我們了解了如何儀表化應(yīng)用,接下來(lái)我們將學(xué)習(xí)使用 Prometheus 的 Go 客戶端庫(kù)來(lái)為一個(gè) Go 應(yīng)用程序添加和暴露監(jiān)控指標(biāo)。
創(chuàng)建應(yīng)用
我們首先從一個(gè)最簡(jiǎn)單的 Go 應(yīng)用程序開(kāi)始,在端口 8080 的 /metrics 端點(diǎn)上暴露客戶端庫(kù)的默認(rèn)注冊(cè)表,暫時(shí)還沒(méi)有跟蹤任何其他自定義的監(jiān)控指標(biāo)。
先創(chuàng)建一個(gè)名為 instrument-demo 的目錄,在該目錄下面初始化項(xiàng)目:
- ☸ ➜ mkdir instrument-demo && cd instrument-demo
- ☸ ➜ go mod init github.com/cnych/instrument-demo
上面的命令會(huì)在 instrument-demo 目錄下面生成一個(gè) go.mod 文件,在同目錄下面新建一個(gè) main.go 的入口文件,內(nèi)容如下所示:
- package main
- import (
- "net/http"
- "github.com/prometheus/client_golang/prometheus/promhttp"
- )
- func main() {
- // Serve the default Prometheus metrics registry over HTTP on /metrics.
- http.Handle("/metrics", promhttp.Handler())
- http.ListenAndServe(":8080", nil)
- }
然后執(zhí)行下面的命令下載 Prometheus 客戶端庫(kù)依賴(lài):
- ☸ ➜ export GOPROXY="https://goproxy.cn"
- ☸ ➜ go mod tidy
- go: finding module for package github.com/prometheus/client_golang/prometheus/promhttp
- go: found github.com/prometheus/client_golang/prometheus/promhttp in github.com/prometheus/client_golang v1.11.0
- go: downloading google.golang.org/protobuf v1.26.0-rc.1
然后直接執(zhí)行 go run 命令啟動(dòng)服務(wù):
- ☸ ➜ go run main.go
然后我們可以在瀏覽器中訪問(wèn) http://localhost:8080/metrics 來(lái)獲得默認(rèn)的監(jiān)控指標(biāo)數(shù)據(jù):
- # 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_threads Number of OS threads created.
- # TYPE go_threads gauge
- go_threads 8
- # 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"} 1
- promhttp_metric_handler_requests_total{code="500"} 0
- promhttp_metric_handler_requests_total{code="503"} 0
我們并沒(méi)有在代碼中添加什么業(yè)務(wù)邏輯,但是可以看到依然有一些指標(biāo)數(shù)據(jù)輸出,這是因?yàn)?Go 客戶端庫(kù)默認(rèn)在我們暴露的全局默認(rèn)指標(biāo)注冊(cè)表中注冊(cè)了一些關(guān)于 promhttp 處理器和運(yùn)行時(shí)間相關(guān)的默認(rèn)指標(biāo),根據(jù)不同指標(biāo)名稱(chēng)的前綴可以看出:
- go_*:以 go_ 為前綴的指標(biāo)是關(guān)于 Go 運(yùn)行時(shí)相關(guān)的指標(biāo),比如垃圾回收時(shí)間、goroutine 數(shù)量等,這些都是 Go 客戶端庫(kù)特有的,其他語(yǔ)言的客戶端庫(kù)可能會(huì)暴露各自語(yǔ)言的其他運(yùn)行時(shí)指標(biāo)。
- promhttp_*:來(lái)自 promhttp 工具包的相關(guān)指標(biāo),用于跟蹤對(duì)指標(biāo)請(qǐng)求的處理。
這些默認(rèn)的指標(biāo)是非常有用,但是更多的時(shí)候我們需要自己控制,來(lái)暴露一些自定義指標(biāo)。這就需要我們?nèi)?shí)現(xiàn)自定義的指標(biāo)了。
添加自定義指標(biāo)
接下來(lái)我們來(lái)自定義一個(gè)的 gauge 指標(biāo)來(lái)暴露當(dāng)前的溫度。創(chuàng)建一個(gè)新的文件 custom-metric/main.go,內(nèi)容如下所示:
- package main
- import (
- "net/http"
- "github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/promhttp"
- )
- func main() {
- // 創(chuàng)建一個(gè)沒(méi)有任何 label 標(biāo)簽的 gauge 指標(biāo)
- temp := prometheus.NewGauge(prometheus.GaugeOpts{
- Name: "home_temperature_celsius",
- Help: "The current temperature in degrees Celsius.",
- })
- // 在默認(rèn)的注冊(cè)表中注冊(cè)該指標(biāo)
- prometheus.MustRegister(temp)
- // 設(shè)置 gauge 的值為 39
- temp.Set(39)
- // 暴露指標(biāo)
- http.Handle("/metrics", promhttp.Handler())
- http.ListenAndServe(":8080", nil)
- }
上面文件中和最初的文件就有一些變化了:
- 我們使用 prometheus.NewGauge() 函數(shù)創(chuàng)建了一個(gè)自定義的 gauge 指標(biāo)對(duì)象,指標(biāo)名稱(chēng)為 home_temperature_celsius,并添加了一個(gè)注釋信息。
- 然后使用 prometheus.MustRegister() 函數(shù)在默認(rèn)的注冊(cè)表中注冊(cè)了這個(gè) gauge 指標(biāo)對(duì)象。
- 通過(guò)調(diào)用 Set() 方法將 gauge 指標(biāo)的值設(shè)置為 39。
- 然后像之前一樣通過(guò) HTTP 暴露默認(rèn)的注冊(cè)表。
需要注意的是除了 prometheus.MustRegister() 函數(shù)之外還有一個(gè) prometheus.Register() 函數(shù),一般在 golang 中我們會(huì)將 Mustxxx 開(kāi)頭的函數(shù)定義為必須滿足條件的函數(shù),如果不滿足會(huì)返回一個(gè) panic 而不是一個(gè) error 操作,所以如果這里不能正常注冊(cè)的話會(huì)拋出一個(gè) panic。
現(xiàn)在我們來(lái)運(yùn)行這個(gè)程序:
- ☸ ➜ go run ./custom-metric
啟動(dòng)后重新訪問(wèn)指標(biāo)接口 http://localhost:8080/metrics,仔細(xì)對(duì)比我們會(huì)發(fā)現(xiàn)多了一個(gè)名為 home_temperature_celsius 的指標(biāo):
- ...
- # HELP home_temperature_celsius The current temperature in degrees Celsius.
- # TYPE home_temperature_celsius gauge
- home_temperature_celsius 42
- ...
這樣我們就實(shí)現(xiàn)了添加一個(gè)自定義的指標(biāo)的操作,整體比較簡(jiǎn)單,當(dāng)然在實(shí)際的項(xiàng)目中需要結(jié)合業(yè)務(wù)來(lái)確定添加哪些自定義指標(biāo)。
自定義注冊(cè)表
前面我們是使用 prometheus.MustRegister() 函數(shù)來(lái)將指標(biāo)注冊(cè)到全局默認(rèn)注冊(cè)中,此外我們還可以使用 prometheus.NewRegistry() 函數(shù)來(lái)創(chuàng)建和使用自己的非全局的注冊(cè)表。
既然有全局的默認(rèn)注冊(cè)表,為什么我們還需要自定義注冊(cè)表呢?這主要是因?yàn)椋?/p>
- 全局變量通常不利于維護(hù)和測(cè)試,創(chuàng)建一個(gè)非全局的注冊(cè)表,并明確地將其傳遞給程序中需要注冊(cè)指標(biāo)的地方,這也一種更加推薦的做法。
- 全局默認(rèn)注冊(cè)表包括一組默認(rèn)的指標(biāo),我們有時(shí)候可能希望除了自定義的指標(biāo)之外,不希望暴露其他的指標(biāo)。
下面的示例程序演示了如何創(chuàng)建、使用和暴露一個(gè)非全局注冊(cè)表對(duì)象,創(chuàng)建一個(gè)文件 custom-registry/main.go,內(nèi)容如下所示:
- package main
- import (
- "net/http"
- "github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/promhttp"
- )
- func main() {
- // 創(chuàng)建一個(gè)自定義的注冊(cè)表
- registry := prometheus.NewRegistry()
- // 可選: 添加 process 和 Go 運(yùn)行時(shí)指標(biāo)到我們自定義的注冊(cè)表中
- registry.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
- registry.MustRegister(prometheus.NewGoCollector())
- // 創(chuàng)建一個(gè)簡(jiǎn)單呃 gauge 指標(biāo)。
- temp := prometheus.NewGauge(prometheus.GaugeOpts{
- Name: "home_temperature_celsius",
- Help: "The current temperature in degrees Celsius.",
- })
- // 使用我們自定義的注冊(cè)表注冊(cè) gauge
- registry.MustRegister(temp)
- // 設(shè)置 gague 的值為 39
- temp.Set(39)
- // 暴露自定義指標(biāo)
- http.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{Registry: registry}))
- http.ListenAndServe(":8080", nil)
- }
上面我們沒(méi)有使用全局默認(rèn)的注冊(cè)表了,而是創(chuàng)建的一個(gè)自定義的注冊(cè)表:
- 首先使用 prometheus.NewRegistry() 函數(shù)創(chuàng)建我們自己的注冊(cè)表對(duì)象。
- 然后使用自定義注冊(cè)表對(duì)象上面的 MustRegister() 哈是來(lái)注冊(cè) guage 指標(biāo),而不是調(diào)用 prometheus.MustRegister() 函數(shù)(這會(huì)使用全局默認(rèn)的注冊(cè)表)。
- 如果我們希望在自定義注冊(cè)表中也有進(jìn)程和 Go 運(yùn)行時(shí)相關(guān)的指標(biāo),我們可以通過(guò)實(shí)例化 Collector 收集器來(lái)添加他們。
- 最后在暴露指標(biāo)的時(shí)候必須通過(guò)調(diào)用 promhttp.HandleFor() 函數(shù)來(lái)創(chuàng)建一個(gè)專(zhuān)門(mén)針對(duì)我們自定義注冊(cè)表的 HTTP 處理器,為了同時(shí)暴露前面示例中的 promhttp_* 相關(guān)的指標(biāo),我們還需要在 promhttp.HandlerOpts 配置對(duì)象的 Registry 字段中傳遞我們的注冊(cè)表對(duì)象。
同樣我們重新運(yùn)行上面的自定義注冊(cè)表程序:
- ☸ ➜ go run ./custom-metric
啟動(dòng)后再次訪問(wèn)指標(biāo)接口 http://localhost:8080/metrics,可以發(fā)現(xiàn)和上面示例中的指標(biāo)數(shù)據(jù)是相同的。
指標(biāo)定制
Gauges
前面的示例我們已經(jīng)了解了如何添加 gauge 類(lèi)型的指標(biāo),創(chuàng)建了一個(gè)沒(méi)有任何標(biāo)簽的指標(biāo),直接使用 prometheus.NewGauge() 函數(shù)即可實(shí)例化一個(gè) gauge 類(lèi)型的指標(biāo)對(duì)象,通過(guò) prometheus.GaugeOpts 對(duì)象可以指定指標(biāo)的名稱(chēng)和注釋信息:
- queueLength := prometheus.NewGauge(prometheus.GaugeOpts{
- Name: "queue_length",
- Help: "The number of items in the queue.",
- })
我們知道 gauge 類(lèi)型的指標(biāo)值是可以上升或下降的,所以我們可以為 gauge 指標(biāo)設(shè)置一個(gè)指定的值,所以 gauge 指標(biāo)對(duì)象暴露了 Set()、Inc()、Dec()、Add() 和 Sub() 這些函數(shù)來(lái)更改指標(biāo)值:
- // 使用 Set() 設(shè)置指定的值
- queueLength.Set(0)
- // 增加或減少
- queueLength.Inc() // +1:Increment the gauge by 1.
- queueLength.Dec() // -1:Decrement the gauge by 1.
- queueLength.Add(23) // Increment by 23.
- queueLength.Sub(42) // Decrement by 42.
另外 gauge 儀表盤(pán)經(jīng)常被用來(lái)暴露 Unix 的時(shí)間戳樣本值,所以也有一個(gè)方便的方法來(lái)將 gauge 設(shè)置為當(dāng)前的時(shí)間戳:
- demoTimestamp.SetToCurrentTime()
最終 gauge 指標(biāo)會(huì)被渲染成如下所示的數(shù)據(jù):
- # HELP queue_length The number of items in the queue.
- # TYPE queue_length gauge
- queue_length 42
Counters
要?jiǎng)?chuàng)建一個(gè) counter 類(lèi)型的指標(biāo)和 gauge 比較類(lèi)似,只是用 prometheus.NewCounter() 函數(shù)來(lái)初始化指標(biāo)對(duì)象:
- totalRequests := prometheus.NewCounter(prometheus.CounterOpts{
- Name: "http_requests_total",
- Help: "The total number of handled HTTP requests.",
- })
我們知道 counter 指標(biāo)只能隨著時(shí)間的推移而不斷增加,所以我們不能為其設(shè)置一個(gè)指定的值或者減少指標(biāo)值,所以該對(duì)象下面只有 Inc() 和 Add() 兩個(gè)函數(shù):
- totalRequests.Inc() // +1:Increment the counter by 1.
- totalRequests.Add(23) // +n:Increment the counter by 23.
當(dāng)服務(wù)進(jìn)程重新啟動(dòng)的時(shí)候,counter 指標(biāo)值會(huì)被重置為 0,不過(guò)不用擔(dān)心數(shù)據(jù)錯(cuò)亂,我們一般會(huì)使用的 rate() 函數(shù)會(huì)自動(dòng)處理。
最終 counter 指標(biāo)會(huì)被渲染成如下所示的數(shù)據(jù):
- # HELP http_requests_total The total number of handled HTTP requests.
- # TYPE http_requests_total counter
- http_requests_total 7734
Histograms
創(chuàng)建直方圖指標(biāo)比 counter 和 gauge 都要復(fù)雜,因?yàn)樾枰渲冒延^測(cè)值歸入的 bucket 的數(shù)量,以及每個(gè) bucket 的上邊界。Prometheus 中的直方圖是累積的,所以每一個(gè)后續(xù)的 bucket 都包含前一個(gè) bucket 的觀察計(jì)數(shù),所有 bucket 的下限都從 0 開(kāi)始的,所以我們不需要明確配置每個(gè) bucket 的下限,只需要配置上限即可。
同樣要?jiǎng)?chuàng)建直方圖指標(biāo)對(duì)象,我們使用 prometheus.NewHistogram() 函數(shù)來(lái)進(jìn)行初始化:
- requestDurations := prometheus.NewHistogram(prometheus.HistogramOpts{
- Name: "http_request_duration_seconds",
- Help: "A histogram of the HTTP request durations in seconds.",
- // Bucket 配置:第一個(gè) bucket 包括所有在 0.05s 內(nèi)完成的請(qǐng)求,最后一個(gè)包括所有在10s內(nèi)完成的請(qǐng)求。
- Buckets: []float64{0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10},
- })
這里和前面不一樣的地方在于除了指定指標(biāo)名稱(chēng)和幫助信息之外,還需要配置 Buckets。如果我們手動(dòng)去枚舉所有的 bucket 可能很繁瑣,所以 Go 客戶端庫(kù)為為我們提供了一些輔助函數(shù)可以幫助我們生成線性或者指數(shù)增長(zhǎng)的 bucket,比如 prometheus.LinearBuckets() 和 prometheus.ExponentialBuckets() 函數(shù)。
直方圖會(huì)自動(dòng)對(duì)數(shù)值的分布進(jìn)行分類(lèi)和計(jì)數(shù),所以它只有一個(gè) Observe() 方法,每當(dāng)你在代碼中處理要跟蹤的數(shù)據(jù)時(shí),就會(huì)調(diào)用這個(gè)方法。例如,如果你剛剛處理了一個(gè) HTTP 請(qǐng)求,花了 0.42 秒,則可以使用下面的代碼來(lái)跟蹤。
- requestDurations.Observe(0.42)
由于跟蹤持續(xù)時(shí)間是直方圖的一個(gè)常見(jiàn)用例,Go 客戶端庫(kù)就提供了輔助函數(shù),用于對(duì)代碼的某些部分進(jìn)行計(jì)時(shí),然后自動(dòng)觀察所產(chǎn)生的持續(xù)時(shí)間,將其轉(zhuǎn)化為直方圖,如下代碼所示:
- // 啟動(dòng)一個(gè)計(jì)時(shí)器
- timer := prometheus.NewTimer(requestDurations)
- // [...在應(yīng)用中處理請(qǐng)求...]
- // 停止計(jì)時(shí)器并觀察其持續(xù)時(shí)間,將其放進(jìn) requestDurations 的直方圖指標(biāo)中去
- timer.ObserveDuration()
直方圖指標(biāo)最終會(huì)生成如下所示的數(shù)據(jù):
- # HELP http_request_duration_seconds A histogram of the HTTP request durations in seconds.
- # TYPE http_request_duration_seconds histogram
- http_request_duration_seconds_bucket{le="0.05"} 4599
- http_request_duration_seconds_bucket{le="0.1"} 24128
- http_request_duration_seconds_bucket{le="0.25"} 45311
- http_request_duration_seconds_bucket{le="0.5"} 59983
- http_request_duration_seconds_bucket{le="1"} 60345
- http_request_duration_seconds_bucket{le="2.5"} 114003
- http_request_duration_seconds_bucket{le="5"} 201325
- http_request_duration_seconds_bucket{le="+Inf"} 227420
- http_request_duration_seconds_sum 88364.234
- http_request_duration_seconds_count 227420
每個(gè)配置的存儲(chǔ)桶最終作為一個(gè)帶有 _bucket 后綴的計(jì)數(shù)器時(shí)間序列,使用 le(小于或等于) 標(biāo)簽指示該存儲(chǔ)桶的上限,具有上限的隱式存儲(chǔ)桶 +Inf 也暴露于比最大配置的存儲(chǔ)桶邊界花費(fèi)更長(zhǎng)的時(shí)間的請(qǐng)求,還包括使用后綴 _sum 累積總和和計(jì)數(shù) _count 的指標(biāo),這些時(shí)間序列中的每一個(gè)在概念上都是一個(gè) counter 計(jì)數(shù)器(只能上升的單個(gè)值),只是它們是作為直方圖的一部分創(chuàng)建的。
Summaries
創(chuàng)建和使用摘要與直方圖非常類(lèi)似,只是我們需要指定要跟蹤的 quantiles 分位數(shù)值,而不需要處理 bucket 桶,比如我們想要跟蹤 HTTP 請(qǐng)求延遲的第 50、90 和 99 個(gè)百分位數(shù),那么我們可以創(chuàng)建這樣的一個(gè)摘要對(duì)象:
- requestDurations := prometheus.NewSummary(prometheus.SummaryOpts{
- Name: "http_request_duration_seconds",
- Help: "A summary of the HTTP request durations in seconds.",
- Objectives: map[float64]float64{
- 0.5: 0.05, // 第50個(gè)百分位數(shù),最大絕對(duì)誤差為0.05。
- 0.9: 0.01, // 第90個(gè)百分位數(shù),最大絕對(duì)誤差為0.01。
- 0.99: 0.001, // 第90個(gè)百分位數(shù),最大絕對(duì)誤差為0.001。
- },
- },
- )
這里和前面不一樣的地方在于使用 prometheus.NewSummary() 函數(shù)初始化摘要指標(biāo)對(duì)象的時(shí)候,需要通過(guò) prometheus.SummaryOpts{} 對(duì)象的 Objectives 屬性指定想要跟蹤的分位數(shù)值。
同樣摘要指標(biāo)對(duì)象創(chuàng)建后,跟蹤持續(xù)時(shí)間的方式和直方圖是完全一樣的,使用一個(gè) Observe() 函數(shù)即可:
- requestDurations.Observe(0.42)
雖然直方圖桶可以跨維度匯總(如端點(diǎn)、HTTP 方法等),但這對(duì)于匯總 quantiles 分位數(shù)值來(lái)說(shuō)在統(tǒng)計(jì)學(xué)上是無(wú)效的。例如,你不能對(duì)兩個(gè)單獨(dú)的服務(wù)實(shí)例的第 90 百分位延遲進(jìn)行平均,并期望得到一個(gè)有效的整體第 90 百分位延遲。如果需要按維度進(jìn)行匯總,那么我們需要使用直方圖而不是摘要指標(biāo)。
摘要指標(biāo)最終生成的指標(biāo)數(shù)據(jù)與直方圖非常類(lèi)似,不同之處在于使用 quantile 標(biāo)簽來(lái)表示分位數(shù)序列,并且這些序列沒(méi)有擴(kuò)展指標(biāo)名稱(chēng)的后綴:
- # HELP http_request_duration_seconds A summary of the HTTP request durations in seconds.
- # TYPE http_request_duration_seconds summary
- http_request_duration_seconds{quantile="0.5"} 0.052
- http_request_duration_seconds{quantile="0.90"} 0.564
- http_request_duration_seconds{quantile="0.99"} 2.372
- http_request_duration_seconds_sum 88364.234
- http_request_duration_seconds_count 227420
標(biāo)簽
到目前為止,我們還沒(méi)有為指標(biāo)對(duì)象添加任何的標(biāo)簽,要?jiǎng)?chuàng)建具有標(biāo)簽維度的指標(biāo),我們可以調(diào)用類(lèi)似于 NewXXXVec() 的構(gòu)造函數(shù)來(lái)初始化指標(biāo)對(duì)象:
- NewGauge() 變成 NewGaugeVec()
- NewCounter() 變成 NewCounterVec()
- NewSummary() 變成 NewSummaryVec()
- NewHistogram() 變成 NewHistogramVec()
這些函數(shù)允許我們指定一個(gè)額外的字符串切片參數(shù),提供標(biāo)簽名稱(chēng)的列表,通過(guò)它來(lái)拆分指標(biāo)。
例如,為了按照房子以及測(cè)量溫度的房間來(lái)劃分我們?cè)缙诘臏囟缺碇笜?biāo),可以這樣創(chuàng)建指標(biāo)。
- temp := prometheus.NewGaugeVec(
- prometheus.GaugeOpts{
- Name: "home_temperature_celsius",
- Help: "The current temperature in degrees Celsius.",
- },
- // 兩個(gè)標(biāo)簽名稱(chēng),通過(guò)它們來(lái)分割指標(biāo)。
- []string{"house", "room"},
- )
然后要訪問(wèn)一個(gè)特有標(biāo)簽的子指標(biāo),需要在設(shè)置其值之前,用 house 和 room 標(biāo)簽的各自數(shù)值,對(duì)產(chǎn)生的 gauge 向量調(diào)用 WithLabelValues() 方法來(lái)處理下:
- // 為 home=ydzs 和 room=living-room 設(shè)置指標(biāo)值
- temp.WithLabelValues("ydzs", "living-room").Set(27)
如果你喜歡在選擇的子指標(biāo)中明確提供標(biāo)簽名稱(chēng),可以使用效率稍低的 With() 方法來(lái)代替:
- temp.With(prometheus.Labels{"house": "ydzs", "room": "living-room"}).Set(66)
不過(guò)需要注意如果向這兩個(gè)方法傳遞不正確的標(biāo)簽數(shù)量或不正確的標(biāo)簽名稱(chēng),這兩個(gè)方法都會(huì)觸發(fā) panic。
下面是我們按照 house 和 room 標(biāo)簽維度區(qū)分指標(biāo)的完整示例,創(chuàng)建一個(gè)名為 label-metric/main.go 的新文件,內(nèi)容如下所示:
- package main
- import (
- "net/http"
- "github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/promhttp"
- )
- func main() {
- // 創(chuàng)建帶 house 和 room 標(biāo)簽的 gauge 指標(biāo)對(duì)象
- temp := prometheus.NewGaugeVec(
- prometheus.GaugeOpts{
- Name: "home_temperature_celsius",
- Help: "The current temperature in degrees Celsius.",
- },
- // 指定標(biāo)簽名稱(chēng)
- []string{"house", "room"},
- )
- // 注冊(cè)到全局默認(rèn)注冊(cè)表中
- prometheus.MustRegister(temp)
- // 針對(duì)不同標(biāo)簽值設(shè)置不同的指標(biāo)值
- temp.WithLabelValues("cnych", "living-room").Set(27)
- temp.WithLabelValues("cnych", "bedroom").Set(25.3)
- temp.WithLabelValues("ydzs", "living-room").Set(24.5)
- temp.WithLabelValues("ydzs", "bedroom").Set(27.7)
- // 暴露自定義的指標(biāo)
- http.Handle("/metrics", promhttp.Handler())
- http.ListenAndServe(":8080", nil)
- }
上面代碼非常清晰了,運(yùn)行下面的程序:
- ☸ ➜ go run ./label-metric
啟動(dòng)完成后重新訪問(wèn)指標(biāo)端點(diǎn) http://localhost:8080/metrics,可以找到 home_temperature_celsius 指標(biāo)不同標(biāo)簽維度下面的指標(biāo)值:
- ...
- # HELP home_temperature_celsius The current temperature in degrees Celsius.
- # TYPE home_temperature_celsius gauge
- home_temperature_celsius{house="cnych",room="bedroom"} 25.3
- home_temperature_celsius{house="cnych",room="living-room"} 27
- home_temperature_celsius{house="ydzs",room="bedroom"} 27.7
- home_temperature_celsius{house="ydzs",room="living-room"} 24.5
- ...
注意:當(dāng)使用帶有標(biāo)簽維度的指標(biāo)時(shí),任何標(biāo)簽組合的時(shí)間序列只有在該標(biāo)簽組合被訪問(wèn)過(guò)至少一次后才會(huì)出現(xiàn)在 /metrics 輸出中,這對(duì)我們?cè)?PromQL 查詢(xún)的時(shí)候會(huì)產(chǎn)生一些問(wèn)題,因?yàn)樗M承r(shí)間序列一直存在,我們可以在程序第一次啟動(dòng)時(shí),將所有重要的標(biāo)簽組合預(yù)先初始化為默認(rèn)值。
同樣的方式在其他幾個(gè)指標(biāo)類(lèi)型中使用標(biāo)簽的方法與上面的方式一致。