| 35 | ) |
| 36 | |
| 37 | func recordRPCCost(startTime time.Time, method string, err error) { |
| 38 | var ( |
| 39 | name, nameC string |
| 40 | val, valC expvar.Var |
| 41 | ) |
| 42 | costTime := time.Since(startTime) |
| 43 | if err == nil { |
| 44 | name = "t_succ:" + method |
| 45 | nameC = "c_succ:" + method |
| 46 | } else { |
| 47 | name = "t_fail:" + method |
| 48 | nameC = "c_fail:" + method |
| 49 | } |
| 50 | // Optimistically, val will not be nil except the first Call of method |
| 51 | // expvar uses sync.Map |
| 52 | // So, we try it first without lock |
| 53 | val = expvar.Get(name) |
| 54 | valC = expvar.Get(nameC) |
| 55 | if val == nil || valC == nil { |
| 56 | callRPCExpvarLock.Lock() |
| 57 | val = expvar.Get(name) |
| 58 | if val == nil { |
| 59 | expvar.Publish(name, mw.NewHistogram("10s1s", "1m5s", "1h1m")) |
| 60 | expvar.Publish(nameC, mw.NewCounter("10s1s", "1h1m")) |
| 61 | } |
| 62 | callRPCExpvarLock.Unlock() |
| 63 | val = expvar.Get(name) |
| 64 | valC = expvar.Get(nameC) |
| 65 | } |
| 66 | val.(mw.Metric).Add(costTime.Seconds()) |
| 67 | valC.(mw.Metric).Add(1) |
| 68 | return |
| 69 | } |
| 70 | |
| 71 | // Caller is a wrapper for session pooling and RPC calling. |
| 72 | type Caller struct { |