- Go語言精進之路:從新手到高手的編程思想、方法和技巧(2)
- 白明
- 806字
- 2022-01-04 17:42:28
48.1 expvar包的工作原理
Go標準庫中的expvar包提供了一種輸出應用內部狀態信息的標準化方案,這個方案標準化了以下三方面內容:
- 數據輸出接口形式;
- 輸出數據的編碼格式;
- 用戶自定義性能指標的方法。
Go應用通過expvar包輸出內部狀態信息的工作原理如圖48-1所示。

圖48-1 expvar包工作原理
從圖48-1中我們看到,Go應用如果需要輸出自身狀態數據,需要以下面的形式導入expvar:
import _ "expvar"
和net/http/pprof類似,expvar包也在自己的init函數中向http包的默認請求“路由器”DefaultServeMux注冊一個服務端點/debug/vars:
// $GOROOT/src/expvar/expvar.go func init() { http.HandleFunc("/debug/vars", expvarHandler) ... }
這個服務端點就是expvar提供給外部的獲取應用內部狀態的唯一標準接口,外部工具(無論是命令行還是基于Web的圖形化程序)都可以通過標準的http get請求從該服務端點獲取應用內部狀態數據。下面是一個簡單的例子:
// chapter8/sources/expvar_demo1.go package main import ( _ "expvar" "fmt" "net/http" ) func main() { http.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hi")) })) fmt.Println(http.ListenAndServe("localhost:8080", nil)) }
運行上述示例后,通過瀏覽器訪問http://localhost:8080/debug/vars將得到如圖48-2所示的結果。

圖48-2 通過瀏覽器訪問expvar包注冊的服務端點
如果應用程序本身并沒有使用默認“路由器”DefaultServeMux,那么我們需要手動將expvar包的服務端點注冊到應用程序所使用的“路由器”上。expvar包提供了Handler函數,該函數可用于其內部expvarHandler的注冊。
// expvar_demo2.go package main import ( "expvar" "fmt" "net/http" ) func main() { mux := http.NewServeMux() mux.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hi")) })) mux.Handle("/debug/vars", expvar.Handler()) fmt.Println(http.ListenAndServe("localhost:8080", mux)) }
如果應用程序本身并沒有啟動HTTP服務,那么還需在一個單獨的goroutine中啟動一個HTTP服務,這樣expvar提供的服務才能有效。
從圖48-2中我們還可以看到,expvar包提供的內部狀態服務端點返回的是標準的JSON格式數據。樣例如下:
{ "cmdline": ["/var/folders/cz/sbj5kg2d3m3c6j650z0qfm800000gn/T/go-build507091832/ b001/exe/expvar_demo2"], "memstats": { "Alloc": 223808, "TotalAlloc": 223808, "Sys": 71387144, "Lookups": 0, "Mallocs": 743, "Frees": 11, ... } }
在默認返回的狀態數據中包含了兩個字段:cmdline和memstats。這兩個輸出數據是expvar包在init函數中就已經發布(Publish)了的變量:
//$GOROOT/src/expvar/expvar.go func init() { http.HandleFunc("/debug/vars", expvarHandler) Publish("cmdline", Func(cmdline)) Publish("memstats", Func(memstats)) }
cmdline字段的含義是輸出數據的應用名,這里因為是通過go run運行的應用,所以cmdline的值是一個臨時路徑下的應用。
而memstats輸出的數據對應的是runtime.Memstats結構體,反映的是應用在運行期間堆內存分配、棧內存分配及GC的狀態。runtime.Memstats結構體的字段可能會隨著Go版本的演進而發生變化,其字段具體含義可以參考Memstats結構體中的注釋。
//$GOROOT/src/expvar/expvar.go func memstats() interface{} { stats := new(runtime.MemStats) runtime.ReadMemStats(stats) return *stats }
- The Complete Rust Programming Reference Guide
- Learning Cython Programming
- Mastering Adobe Captivate 2017(Fourth Edition)
- PostgreSQL for Data Architects
- PaaS程序設計
- Python數據挖掘與機器學習實戰
- Kali Linux Wireless Penetration Testing Beginner's Guide(Third Edition)
- Getting Started with Laravel 4
- PyQt編程快速上手
- 實戰Python網絡爬蟲
- Node.js 6.x Blueprints
- 少兒編程輕松學(全2冊)
- Learning Ionic(Second Edition)
- Microsoft Azure Security
- Scratch 3.0少兒積木式編程(6~10歲)