構建應用程式
先決條件
- 您有一個 Git 客戶端。本節中的示例使用基於命令列的 Git 客戶端,但您可以使用任何客戶端。
您將建立一個帶有某些端點的 Golang 伺服器,以模擬真實世界的應用程式。然後,您將使用 Prometheus 從伺服器公開指標。
獲取示例應用程式
克隆示例應用程式以配合本指南使用。開啟終端,將目錄更改到您要工作的目錄,然後執行以下命令克隆儲存庫:
$ git clone https://github.com/dockersamples/go-prometheus-monitoring.git
克隆後,您將在 go-prometheus-monitoring
目錄中看到以下內容結構:
go-prometheus-monitoring
├── CONTRIBUTING.md
├── Docker
│ ├── grafana.yml
│ └── prometheus.yml
├── dashboard.json
├── Dockerfile
├── LICENSE
├── README.md
├── compose.yaml
├── go.mod
├── go.sum
└── main.go
- main.go - 應用程式的入口點。
- go.mod 和 go.sum - Go 模組檔案。
- Dockerfile - 用於構建應用程式的 Dockerfile。
- Docker/ - 包含 Grafana 和 Prometheus 的 Docker Compose 配置檔案。
- compose.yaml - 用於啟動所有內容(Golang 應用程式、Prometheus 和 Grafana)的 Compose 檔案。
- dashboard.json - Grafana 儀表板配置檔案。
- Dockerfile - 用於構建 Golang 應用程式的 Dockerfile。
- compose.yaml - 用於啟動所有內容(Golang 應用程式、Prometheus 和 Grafana)的 Docker Compose 檔案。
- 其他檔案用於許可和文件目的。
瞭解應用程式
以下是您將在 main.go
中找到的應用程式的完整邏輯。
package main
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Define metrics
var (
HttpRequestTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_total",
Help: "Total number of requests processed by the API",
}, []string{"path", "status"})
HttpRequestErrorTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_error_total",
Help: "Total number of errors returned by the API",
}, []string{"path", "status"})
)
// Custom registry (without default Go metrics)
var customRegistry = prometheus.NewRegistry()
// Register metrics with custom registry
func init() {
customRegistry.MustRegister(HttpRequestTotal, HttpRequestErrorTotal)
}
func main() {
router := gin.Default()
// Register /metrics before middleware
router.GET("/metrics", PrometheusHandler())
router.Use(RequestMetricsMiddleware())
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Up and running!",
})
})
router.GET("/v1/users", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello from /v1/users",
})
})
router.Run(":8000")
}
// Custom metrics handler with custom registry
func PrometheusHandler() gin.HandlerFunc {
h := promhttp.HandlerFor(customRegistry, promhttp.HandlerOpts{})
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
// Middleware to record incoming requests metrics
func RequestMetricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Request.URL.Path
c.Next()
status := c.Writer.Status()
if status < 400 {
HttpRequestTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
} else {
HttpRequestErrorTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
}
}
}
在這段程式碼中,您匯入了所需的包 gin
、prometheus
和 promhttp
。然後您定義了幾個變數,HttpRequestTotal
和 HttpRequestErrorTotal
是 Prometheus 計數器指標,customRegistry
是一個自定義登錄檔,將用於註冊這些指標。指標名稱是一個字串,您可以使用它來識別指標。幫助字串是當您查詢 /metrics
端點以瞭解指標時將顯示的字串。您使用自定義登錄檔的原因是為了避免 Prometheus 客戶端預設註冊的預設 Go 指標。然後,使用 init
函式,您將指標註冊到自定義登錄檔。
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Define metrics
var (
HttpRequestTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_total",
Help: "Total number of requests processed by the API",
}, []string{"path", "status"})
HttpRequestErrorTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_error_total",
Help: "Total number of errors returned by the API",
}, []string{"path", "status"})
)
// Custom registry (without default Go metrics)
var customRegistry = prometheus.NewRegistry()
// Register metrics with custom registry
func init() {
customRegistry.MustRegister(HttpRequestTotal, HttpRequestErrorTotal)
}
在 main
函式中,您建立了一個新的 gin
框架例項並建立了三個路由。您可以看到路徑為 /health
的健康端點,它將返回一個帶有 {"message": "Up and running!"}
的 JSON,以及路徑為 /v1/users
的端點,它將返回一個帶有 {"message": "Hello from /v1/users"}
的 JSON。第三個路由是用於 /metrics
端點,它將以 Prometheus 格式返回指標。然後您有 RequestMetricsMiddleware
中介軟體,它將針對對 API 的每個請求呼叫。它將記錄傳入請求的指標,例如狀態碼和路徑。最後,您在埠 8000 上執行 gin 應用程式。
func main() {
router := gin.Default()
// Register /metrics before middleware
router.GET("/metrics", PrometheusHandler())
router.Use(RequestMetricsMiddleware())
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Up and running!",
})
})
router.GET("/v1/users", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello from /v1/users",
})
})
router.Run(":8000")
}
現在是中介軟體函式 RequestMetricsMiddleware
。此函式針對對 API 的每個請求呼叫。如果狀態碼小於或等於 400,它會增加 HttpRequestTotal
計數器(不同路徑和狀態碼有不同的計數器)。如果狀態碼大於 400,它會增加 HttpRequestErrorTotal
計數器(不同路徑和狀態碼有不同的計數器)。PrometheusHandler
函式是自定義處理程式,將針對 /metrics
端點呼叫。它將以 Prometheus 格式返回指標。
// Custom metrics handler with custom registry
func PrometheusHandler() gin.HandlerFunc {
h := promhttp.HandlerFor(customRegistry, promhttp.HandlerOpts{})
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
// Middleware to record incoming requests metrics
func RequestMetricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Request.URL.Path
c.Next()
status := c.Writer.Status()
if status < 400 {
HttpRequestTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
} else {
HttpRequestErrorTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
}
}
}
就是這樣,這是應用程式的完整要點。現在是時候執行並測試應用程式是否正確註冊指標了。
執行應用程式
確保您仍在終端的 go-prometheus-monitoring
目錄中,並執行以下命令。透過執行 go mod tidy
安裝依賴項,然後透過執行 go run main.go
構建並執行應用程式。然後訪問 https://:8000/health
或 https://:8000/v1/users
。您應該看到輸出 {"message": "Up and running!"}
或 {"message": "Hello from /v1/users"}
。如果您能看到這些,那麼您的應用程式已成功啟動並執行。
現在,透過訪問 /metrics
端點檢查應用程式的指標。在瀏覽器中開啟 https://:8000/metrics
。您應該看到類似以下的輸出。
# HELP api_http_request_error_total Total number of errors returned by the API
# TYPE api_http_request_error_total counter
api_http_request_error_total{path="/",status="404"} 1
api_http_request_error_total{path="//v1/users",status="404"} 1
api_http_request_error_total{path="/favicon.ico",status="404"} 1
# HELP api_http_request_total Total number of requests processed by the API
# TYPE api_http_request_total counter
api_http_request_total{path="/health",status="200"} 2
api_http_request_total{path="/v1/users",status="200"} 1
在終端中,按 ctrl
+ c
停止應用程式。
注意如果您不想在本地執行應用程式,並希望在 Docker 容器中執行它,請跳到下一頁,其中您將建立一個 Dockerfile 並容器化應用程式。
摘要
在本節中,您學習瞭如何建立 Golang 應用程式以使用 Prometheus 註冊指標。透過實現中介軟體函式,您可以根據請求路徑和狀態碼增加計數器。
後續步驟
在下一節中,您將學習如何容器化您的應用程式。