【Go Web 開發】創建自定義性能參數
expvar 處理程序提供的默認信息是一個好的開始。但我們可以通過在 JSON 響應中開放一些額外的定製指標來讓它變得更有用。
爲了說明自定義性能參數,我們先開始一個簡單的,將應用程序的版本號添加到 JSON 響應中。如果你忘記了,版本號是定義在 main.go 文件中的字符串常量值爲:"1.0.0"。
實現的代碼分爲兩個基本步驟:1、使用 expvar 包註冊一個自定義變量。2、需要爲變量賦值。代碼大致爲:
expvar.NewString("version").Set(version)
代碼的第一部分:expvar.NewString("version") 創建一個新的 expvar.String 類型,然後分佈到 expvar 處理程序的 JSON 響應中,名稱爲 "version" 並返回一個指向它的指針。然後我們使用 Set() 方法來爲指針賦值。
需要注意的兩個事情:
-
expvar.String 類型是併發安全的。因此,如果有需要,可以在你的處理程序中對其值進行處理。
-
如果你試圖註冊兩個相同名稱的 expvar 變量,當註冊重複的變量,會導致運行時 panic。
下面,我們將前面的代碼集成到 main() 函數中,如下所示:
File: cmd/api/main.go
package main
...
expvar.NewString("version").Set(version)
// 添加models字段,引入數據庫模型爲接口處理程序所用
app := &application{
config: cfg,
logger: logger,
models: data.NewModels(db),
mailer: mailer.New(cfg.smtp.host, cfg.smtp.port, cfg.smtp.username, cfg.smtp.password, cfg.smtp.sender),
}
// 啓動HTTP服務
err = app.server()
if err != nil {
logger.Fatal(err, nil)
}
}
...
如果你重啓 API 服務並再次訪問 http://localhost:4000/debug/vars,你將在 JSON 中 "version": "1.0.0"。如下所示:
$ curl http://localhost:4000/debug/vars -s | python -m json.tool
{
"cmdline": [
"/var/folders/x6/8wtj7zfd7r59wpk5fmjln2p40000gn/T/go-build3315447716/b001/exe/api",
"-limiter-enable=false",
"-port=4000"
],
"memstats": {
"Alloc": 545376,
...
"PauseTotalNs": 0,
"StackInuse": 458752,
"StackSys": 458752,
"Sys": 71961616,
"TotalAlloc": 334776
},
"version": "1.0.0"
}
注意:在上面的代碼中我們使用 expvar.NewString() 函數註冊和發佈字符串到 expvar 處理程序。但是 Go 也爲其他一些常見的數據類型提供了函數: NewFloat(), newint() 和 NewMap()。所有這些都以非常相似的方式工作,我們將在下一節中使用它們。
動態性能參數
有時候返回的參數需要調用其他代碼或做一些預處理生成必要信息。expvar.Puhlish() 函數能實現這個功能,將函數的運行結果發佈到 JSON 響應中。
例如,你想將 Go 的 runtime.NumGoroutine() 函數返回的當前活躍的 goroutine 數量添加到 JSON 響應中,可以像下面這樣寫代碼:
expvar.Publish("goroutine", expvar.Func(func() interface{} {
return runtime.NumGoroutine()
}))
需要指出的是這裏函數返回的 interface{} 值必須能被正確序列化爲 JSON。如果無法序列化成 JSON,expvar 的結果中會忽略該值,GET /debug/var 響應內容將不完整。任何錯誤都將被安靜地丟棄。
在上面的代碼中,runtime.NumGoroutine() 返回的是一個普通 int 類型,將被編碼爲 JSON 數字。因此不會出現問題。
下面我們將這些代碼添加到 main() 函數中,以及其他兩個函數:
-
發佈關於數據庫連接池狀態的信息 (例如空閒和正在使用的連接數) 通過 db.Stats()方法。
-
以秒爲單位發佈當前 Unix 時間戳。
File:cmd/api/main.go
package main
...
expvar.NewString("version").Set(version)
//發佈goroutines數量
expvar.Publish("goroutines", expvar.Func(func() interface{} {
return runtime.NumGoroutine()
}))
//發佈數據庫連接池數據統計
expvar.Publish("database", expvar.Func(func() interface{} {
return db.Stats()
}))
//發佈當前時間戳
expvar.Publish("timestamp", expvar.Func(func() interface{} {
return time.Now().Unix()
}))
app := &application{
config: cfg,
logger: logger,
models: data.NewModels(db),
mailer: mailer.New(cfg.smtp.host, cfg.smtp.port, cfg.smtp.username, cfg.smtp.password, cfg.smtp.sender),
}
// 啓動HTTP服務
err = app.server()
if err != nil {
logger.Fatal(err, nil)
}
}
...
如果你重啓 API 服務,在瀏覽器中打開 GET /debug/vars 接口,你將看到響應的 JSON 值新增的 "database","goroutines" 和 "timestamp" 鍵值。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/dWE7ZEQ2o2oIbsexBVvrDA