内容简介:最近看到同事用一个库,叫做意思是这个库用来暴露一些公共的变量,他会自动注册到请求一下就可以看到输出:
最近看到同事用一个库,叫做 expvar
,这个库的作用官网描述如下:
Package expvar provides a standardized interface to public variables, such as operation counters in servers. It exposes these variables via HTTP at /debug/vars in JSON format.
意思是这个库用来暴露一些公共的变量,他会自动注册到 /debug/vars
这个路径下。我们来看看基本用法:
package main import ( "expvar" "net/http" ) func main() { http.ListenAndServe(":8080", expvar.Handler()) } // 或者如下 package main import ( _ "expvar" "net/http" ) func main() { http.ListenAndServe(":8080", nil) }
请求一下就可以看到输出:
$ http :8080 # 如果是第二种代码,这里的命令应该改成 `http :8080/debug/vars` HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Date: Sun, 12 Apr 2020 01:22:14 GMT Transfer-Encoding: chunked { "cmdline": [ "/tmp/go-build998114494/b001/exe/main" ], "memstats": { "Alloc": 246696, "BuckHashSys": 3565, "BySize": [ { "Frees": 0, "Mallocs": 0, "Size": 0 }, { "Frees": 0, "Mallocs": 15, "Size": 8 }, ...
这是因为expvar实现的时候,它会自动带上 cmdline
和 memstats
这两节:
func cmdline() interface{} { return os.Args } func memstats() interface{} { stats := new(runtime.MemStats) runtime.ReadMemStats(stats) return *stats } func init() { http.HandleFunc("/debug/vars", expvarHandler) Publish("cmdline", Func(cmdline)) Publish("memstats", Func(memstats)) }
我们可以加上自己想要展示的公共变量:
package main import ( "expvar" "net/http" "time" ) func main() { lastAccess := expvar.NewString("lastAccess") http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) lastAccess.Set(time.Now().String()) }) http.ListenAndServe(":8080", nil) }
测试效果:
$ http :8080/debug/vars | grep lastAccess "lastAccess": "2020-04-12 09:52:14.127334409 +0800 CST m=+15.783055827", $ http :8080/ HTTP/1.1 200 OK Content-Length: 5 Content-Type: text/plain; charset=utf-8 Date: Sun, 12 Apr 2020 01:52:27 GMT hello $ http :8080/debug/vars | grep lastAccess "lastAccess": "2020-04-12 09:52:27.533390067 +0800 CST m=+29.189111480",
可以看到,每次我们都能看到最近访问时间。
源码阅读
我们要知其然知其所以然,来看看expvar是怎么实现的吧!为了方便,我把阅读思路也写在了注释里面。
// 从 NewString 入手 lastAccess := expvar.NewString("lastAccess") func NewString(name string) *String { v := new(String) Publish(name, v) return v } // 看看String的定义 type String struct { s atomic.Value // string } // 看看Publish的定义 // Publish declares a named exported variable. This should be called from a // package's init function when it creates its Vars. If the name is already // registered then this will log.Panic. func Publish(name string, v Var) { if _, dup := vars.LoadOrStore(name, v); dup { log.Panicln("Reuse of exported var name:", name) } varKeysMu.Lock() defer varKeysMu.Unlock() varKeys = append(varKeys, name) sort.Strings(varKeys) } // 可以看到 Var 是一个接口 // Var is an abstract type for all exported variables. type Var interface { // String returns a valid JSON value for the variable. // Types with String methods that do not return valid JSON // (such as time.Time) must not be used as a Var. String() string } // vars 和 varKeys 的定义是这样的 // All published variables. var ( vars sync.Map // map[string]Var varKeysMu sync.RWMutex varKeys []string // sorted ) // 所以可以看到,逻辑就是每次把数值存储到 `vars`,`vars` 是一个map[string]Var类型的map。因为map迭代时是无序的, // 所以有 `varKeys` 用来排序,这样输出的时候,就可以每次都有序输出 // 来看看如何暴露这些变量 func expvarHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") fmt.Fprintf(w, "{\n") first := true Do(func(kv KeyValue) { if !first { fmt.Fprintf(w, ",\n") } first = false fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value) }) fmt.Fprintf(w, "\n}\n") } // 可以看到,很粗暴,先输出 `{\n`,然后输出key value的字符串,最后输出 `\n}\n`,相当于代码拼接JSON // Do这个函数用来迭代 // Do calls f for each exported variable. // The global variable map is locked during the iteration, // but existing entries may be concurrently updated. func Do(f func(KeyValue)) { varKeysMu.RLock() defer varKeysMu.RUnlock() for _, k := range varKeys { val, _ := vars.Load(k) f(KeyValue{k, val.(Var)}) } } // 就如我们前面所说,按 varKeys 的顺序来迭代,然后依次执行传入的函数
至此我们了解了expvar的作用和实现,用起来吧!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 【源码阅读】AndPermission源码阅读
- 【源码阅读】Gson源码阅读
- 如何阅读Java源码 ,阅读java的真实体会
- 我的源码阅读之路:redux源码剖析
- JDK源码阅读(六):HashMap源码分析
- 如何阅读源码?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
500 Lines or Less
Amy Brown、Michael DiBernardo / 2016-6-28 / USD 35.00
This book provides you with the chance to study how 26 experienced programmers think when they are building something new. The programs you will read about in this book were all written from scratch t......一起来看看 《500 Lines or Less》 这本书的介绍吧!