├── config ├── const.go └── config.go ├── .gitignore ├── sys ├── funcs │ ├── collector.go │ ├── meminfo.go │ ├── funcs.go │ ├── common.go │ ├── clients.go │ ├── cron.go │ ├── funcs_test.go │ ├── ntp.go │ ├── dfstat.go │ ├── diskIOCounters.go │ ├── tcpip.go │ ├── diskstat.go │ ├── ntpCalc.go │ ├── push.go │ ├── cpustat.go │ └── ifstat.go ├── plugins │ ├── cron.go │ ├── plugin.go │ ├── reader.go │ └── scheduler.go ├── identity │ ├── identity_test.go │ └── identity.go ├── ports │ ├── cron.go │ ├── port.go │ └── scheduler.go ├── procs │ ├── cron.go │ ├── proc.go │ └── scheduler.go └── config.go ├── etc ├── address.yml └── win-collector.yml ├── http └── routes │ ├── routes.go │ └── api_router.go ├── go.mod ├── stra ├── init.go ├── cron.go ├── proc.go └── port.go ├── plugin └── 60_uptime.ps1 ├── cache └── cache.go ├── README.md ├── report └── report.go ├── collector.go └── go.sum /config/const.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | const Version = "0.3.3" 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | logs 3 | *.local.yml 4 | etc/*.local.yml 5 | *.zip 6 | nssm/ 7 | .idea 8 | -------------------------------------------------------------------------------- /sys/funcs/collector.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "github.com/didi/nightingale/src/common/dataobj" 5 | ) 6 | 7 | func CollectorMetrics() []*dataobj.MetricValue { 8 | return []*dataobj.MetricValue{ 9 | GaugeValue("proc.agent.alive", 1), 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /etc/address.yml: -------------------------------------------------------------------------------- 1 | --- 2 | monapi: 3 | http: 0.0.0.0:8006 4 | addresses: 5 | - 192.168.0.100 6 | 7 | transfer: 8 | http: 0.0.0.0:8008 9 | rpc: 0.0.0.0:8009 10 | addresses: 11 | - 192.168.0.100 12 | 13 | ams: 14 | http: 0.0.0.0:8002 15 | addresses: 16 | - 192.168.0.100 17 | 18 | collector: 19 | http: 0.0.0.0:2058 20 | 21 | -------------------------------------------------------------------------------- /sys/plugins/cron.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | func Detect() { 8 | detect() 9 | go loopDetect() 10 | } 11 | 12 | func loopDetect() { 13 | for { 14 | time.Sleep(time.Second * 10) 15 | detect() 16 | } 17 | } 18 | 19 | func detect() { 20 | ps := ListPlugins() 21 | DelNoUsePlugins(ps) 22 | AddNewPlugins(ps) 23 | } 24 | -------------------------------------------------------------------------------- /sys/identity/identity_test.go: -------------------------------------------------------------------------------- 1 | package identity 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test_myip(t *testing.T) { 8 | ips, err := MyIp4List() 9 | if err != nil { 10 | t.Error(err) 11 | return 12 | } 13 | t.Log(ips) 14 | 15 | } 16 | 17 | func Benchmark_myip(b *testing.B) { 18 | for i := 0; i < b.N; i++ { 19 | MyIp4List() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sys/ports/cron.go: -------------------------------------------------------------------------------- 1 | package ports 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/n9e/win-collector/stra" 7 | ) 8 | 9 | func Detect() { 10 | detect() 11 | go loopDetect() 12 | } 13 | 14 | func loopDetect() { 15 | for { 16 | time.Sleep(time.Second * 10) 17 | detect() 18 | } 19 | } 20 | 21 | func detect() { 22 | ps := stra.GetPortCollects() 23 | DelNoPortCollect(ps) 24 | AddNewPortCollect(ps) 25 | } 26 | -------------------------------------------------------------------------------- /sys/procs/cron.go: -------------------------------------------------------------------------------- 1 | package procs 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/n9e/win-collector/stra" 7 | ) 8 | 9 | func Detect() { 10 | detect() 11 | go loopDetect() 12 | } 13 | 14 | func loopDetect() { 15 | for { 16 | time.Sleep(time.Second * 10) 17 | detect() 18 | } 19 | } 20 | 21 | func detect() { 22 | ps := stra.GetProcCollects() 23 | DelNoPorcCollect(ps) 24 | AddNewPorcCollect(ps) 25 | } 26 | -------------------------------------------------------------------------------- /http/routes/routes.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/gin-contrib/pprof" 5 | "github.com/gin-gonic/gin" 6 | ) 7 | 8 | // Config routes 9 | func Config(r *gin.Engine) { 10 | sys := r.Group("/api/collector") 11 | { 12 | sys.GET("/ping", ping) 13 | sys.GET("/pid", pid) 14 | sys.GET("/addr", addr) 15 | 16 | sys.GET("/stra", getStrategy) 17 | sys.POST("/push", pushData) 18 | } 19 | 20 | pprof.Register(r, "/api/collector/debug/pprof") 21 | } 22 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/n9e/win-collector 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d 7 | github.com/didi/nightingale v0.0.0-20201018021739-93c35fd0ec44 8 | github.com/gin-contrib/pprof v1.3.0 9 | github.com/gin-gonic/gin v1.6.3 10 | github.com/json-iterator/go v1.1.10 // indirect 11 | github.com/shirou/gopsutil v2.20.7+incompatible 12 | github.com/spf13/viper v1.7.1 13 | github.com/toolkits/pkg v1.1.3 14 | github.com/ugorji/go/codec v1.1.7 15 | ) 16 | -------------------------------------------------------------------------------- /stra/init.go: -------------------------------------------------------------------------------- 1 | package stra 2 | 3 | import model "github.com/didi/nightingale/src/models" 4 | 5 | var StraConfig StraSection 6 | var Collect model.Collect 7 | 8 | type StraSection struct { 9 | Enable bool `yaml:"enable"` 10 | Interval int `yaml:"interval"` 11 | Api string `yaml:"api"` 12 | Timeout int `yaml:"timeout"` 13 | PortPath string `yaml:"portPath"` 14 | ProcPath string `yaml:"procPath"` 15 | LogPath string `yaml:"logPath"` 16 | } 17 | 18 | ///api/portal/collects/%s 19 | 20 | func Init(stra StraSection) { 21 | StraConfig = stra 22 | 23 | GetCollects() 24 | } 25 | -------------------------------------------------------------------------------- /plugin/60_uptime.ps1: -------------------------------------------------------------------------------- 1 | # get localIP 2 | $ips = foreach($ipv4 in (ipconfig) -like '*IPv4*') { ($ipv4 -split ' : ')[-1]} 3 | if ($ips -is [array]){ 4 | $localIP = $ips[0] 5 | }else{ 6 | $localIP = $ips 7 | } 8 | 9 | 10 | # get timestamp 11 | $ts = [int64](Get-Date(Get-Date).ToUniversalTime() -UFormat "%s") 12 | 13 | # get uptime 14 | $millisec = [Environment]::TickCount 15 | $uptime = [Timespan]::FromMilliseconds($millisec).TotalSeconds 16 | 17 | # get step 18 | $step = ($MyInvocation.MyCommand.Name -split '_')[0] 19 | 20 | Write-Host " 21 | [ 22 | { 23 | `"endpoint`": `"$localIP`", 24 | `"tags`": `"`", 25 | `"timestamp`": $ts, 26 | `"metric`": `"sys.uptime.duration`", 27 | `"value`": $uptime, 28 | `"step`": $step 29 | } 30 | ]" -------------------------------------------------------------------------------- /sys/funcs/meminfo.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "github.com/didi/nightingale/src/common/dataobj" 5 | "github.com/shirou/gopsutil/mem" 6 | "github.com/toolkits/pkg/logger" 7 | ) 8 | 9 | func memInfo() (*mem.VirtualMemoryStat, error) { 10 | meminfo, err := mem.VirtualMemory() 11 | return meminfo, err 12 | } 13 | 14 | func MemMetrics() []*dataobj.MetricValue { 15 | meminfo, err := memInfo() 16 | if err != nil { 17 | logger.Error("get mem info failed: ", err) 18 | return nil 19 | } 20 | 21 | return []*dataobj.MetricValue{ 22 | GaugeValue("mem.bytes.total", meminfo.Total), 23 | GaugeValue("mem.bytes.used", meminfo.Used), 24 | GaugeValue("mem.bytes.free", meminfo.Available), 25 | GaugeValue("mem.bytes.used.percent", meminfo.UsedPercent), 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /sys/funcs/funcs.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "github.com/n9e/win-collector/sys" 5 | 6 | "github.com/didi/nightingale/src/common/dataobj" 7 | ) 8 | 9 | type FuncsAndInterval struct { 10 | Fs []func() []*dataobj.MetricValue 11 | Interval int 12 | } 13 | 14 | var Mappers []FuncsAndInterval 15 | 16 | func BuildMappers() { 17 | interval := sys.Config.Interval 18 | Mappers = []FuncsAndInterval{ 19 | { 20 | Fs: []func() []*dataobj.MetricValue{ 21 | CollectorMetrics, 22 | CpuMetrics, 23 | MemMetrics, 24 | NetMetrics, 25 | IOStatsMetrics, 26 | NtpOffsetMetrics, 27 | TcpipMetrics, 28 | }, 29 | Interval: interval, 30 | }, 31 | { 32 | Fs: []func() []*dataobj.MetricValue{ 33 | DeviceMetrics, 34 | }, 35 | Interval: interval, 36 | }, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sys/funcs/common.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/didi/nightingale/src/common/dataobj" 7 | ) 8 | 9 | func NewMetricValue(metric string, val interface{}, dataType string, tags ...string) *dataobj.MetricValue { 10 | mv := dataobj.MetricValue{ 11 | Metric: metric, 12 | ValueUntyped: val, 13 | CounterType: dataType, 14 | } 15 | 16 | size := len(tags) 17 | 18 | if size > 0 { 19 | mv.Tags = strings.Join(tags, ",") 20 | } 21 | 22 | return &mv 23 | } 24 | 25 | func GaugeValue(metric string, val interface{}, tags ...string) *dataobj.MetricValue { 26 | return NewMetricValue(metric, val, "GAUGE", tags...) 27 | } 28 | 29 | func CounterValue(metric string, val interface{}, tags ...string) *dataobj.MetricValue { 30 | return NewMetricValue(metric, val, "COUNTER", tags...) 31 | } 32 | -------------------------------------------------------------------------------- /sys/config.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | type SysSection struct { 4 | IfacePrefix []string `yaml:"ifacePrefix"` 5 | MountPoint []string `yaml:"mountPoint"` 6 | MountIgnorePrefix []string `yaml:"mountIgnorePrefix"` 7 | IgnoreMetrics []string `yaml:"ignoreMetrics"` 8 | IgnoreMetricsMap map[string]struct{} `yaml:"-"` 9 | NtpServers []string `yaml:"ntpServers"` 10 | Plugin string `yaml:"plugin"` 11 | PluginRemote bool `yaml:"pluginRemote"` 12 | Interval int `yaml:"interval"` 13 | Timeout int `yaml:"timeout"` 14 | } 15 | 16 | var Config SysSection 17 | 18 | func Init(s SysSection) { 19 | Config = s 20 | 21 | l := len(Config.IgnoreMetrics) 22 | m := make(map[string]struct{}, l) 23 | for i := 0; i < l; i++ { 24 | m[Config.IgnoreMetrics[i]] = struct{}{} 25 | } 26 | 27 | Config.IgnoreMetricsMap = m 28 | } 29 | -------------------------------------------------------------------------------- /sys/funcs/clients.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "net/rpc" 5 | "sync" 6 | ) 7 | 8 | type RpcClientContainer struct { 9 | M map[string]*rpc.Client 10 | sync.RWMutex 11 | } 12 | 13 | var rpcClients *RpcClientContainer 14 | 15 | func InitRpcClients() { 16 | rpcClients = &RpcClientContainer{ 17 | M: make(map[string]*rpc.Client), 18 | } 19 | } 20 | 21 | func (rcc *RpcClientContainer) Get(addr string) *rpc.Client { 22 | rcc.RLock() 23 | defer rcc.RUnlock() 24 | 25 | client, has := rcc.M[addr] 26 | if !has { 27 | return nil 28 | } 29 | 30 | return client 31 | } 32 | 33 | // Put 返回的bool表示affected,确实把自己塞进去了 34 | func (rcc *RpcClientContainer) Put(addr string, client *rpc.Client) bool { 35 | rcc.Lock() 36 | defer rcc.Unlock() 37 | 38 | oc, has := rcc.M[addr] 39 | if has && oc != nil { 40 | return false 41 | } 42 | 43 | rcc.M[addr] = client 44 | return true 45 | } 46 | 47 | func (rcc *RpcClientContainer) Del(addr string) { 48 | rcc.Lock() 49 | defer rcc.Unlock() 50 | delete(rcc.M, addr) 51 | } 52 | -------------------------------------------------------------------------------- /sys/procs/proc.go: -------------------------------------------------------------------------------- 1 | package procs 2 | 3 | import ( 4 | model "github.com/didi/nightingale/src/models" 5 | ) 6 | 7 | var ( 8 | Procs = make(map[string]*model.ProcCollect) 9 | ProcsWithScheduler = make(map[string]*ProcScheduler) 10 | ) 11 | 12 | func DelNoPorcCollect(newCollect map[string]*model.ProcCollect) { 13 | for currKey, currProc := range Procs { 14 | newProc, ok := newCollect[currKey] 15 | if !ok || currProc.LastUpdated != newProc.LastUpdated { 16 | deleteProc(currKey) 17 | } 18 | } 19 | } 20 | 21 | func AddNewPorcCollect(newCollect map[string]*model.ProcCollect) { 22 | for target, newProc := range newCollect { 23 | if _, ok := Procs[target]; ok && newProc.LastUpdated == Procs[target].LastUpdated { 24 | continue 25 | } 26 | 27 | Procs[target] = newProc 28 | sch := NewProcScheduler(newProc) 29 | ProcsWithScheduler[target] = sch 30 | sch.Schedule() 31 | } 32 | } 33 | 34 | func deleteProc(key string) { 35 | v, ok := ProcsWithScheduler[key] 36 | if ok { 37 | v.Stop() 38 | delete(ProcsWithScheduler, key) 39 | } 40 | delete(Procs, key) 41 | } 42 | -------------------------------------------------------------------------------- /sys/funcs/cron.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/n9e/win-collector/sys/identity" 7 | 8 | "github.com/n9e/win-collector/sys" 9 | 10 | "github.com/didi/nightingale/src/common/dataobj" 11 | ) 12 | 13 | func Collect() { 14 | go PrepareCpuStat() 15 | go PrepareDiskStats() 16 | for _, v := range Mappers { 17 | for _, f := range v.Fs { 18 | go collect(int64(v.Interval), f) 19 | } 20 | } 21 | } 22 | 23 | func collect(sec int64, fn func() []*dataobj.MetricValue) { 24 | t := time.NewTicker(time.Second * time.Duration(sec)) 25 | defer t.Stop() 26 | 27 | ignoreMetrics := sys.Config.IgnoreMetricsMap 28 | 29 | for { 30 | <-t.C 31 | 32 | metricValues := []*dataobj.MetricValue{} 33 | now := time.Now().Unix() 34 | 35 | items := fn() 36 | if items == nil || len(items) == 0 { 37 | continue 38 | } 39 | 40 | for _, item := range items { 41 | if _, exists := ignoreMetrics[item.Metric]; exists { 42 | continue 43 | } 44 | 45 | item.Step = sec 46 | item.Endpoint = identity.GetIdent() 47 | item.Timestamp = now 48 | metricValues = append(metricValues, item) 49 | } 50 | Push(metricValues) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /sys/plugins/plugin.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | type Plugin struct { 4 | FilePath string 5 | Params string 6 | MTime int64 7 | Cycle int 8 | } 9 | 10 | var ( 11 | Plugins = make(map[string]*Plugin) 12 | PluginsWithScheduler = make(map[string]*PluginScheduler) 13 | ) 14 | 15 | func DelNoUsePlugins(newPlugins map[string]*Plugin) { 16 | for currKey, currPlugin := range Plugins { 17 | newPlugin, ok := newPlugins[currKey] 18 | if !ok || currPlugin.MTime != newPlugin.MTime { 19 | deletePlugin(currKey) 20 | } 21 | } 22 | } 23 | 24 | func AddNewPlugins(newPlugins map[string]*Plugin) { 25 | for fpath, newPlugin := range newPlugins { 26 | if _, ok := Plugins[fpath]; ok && newPlugin.MTime == Plugins[fpath].MTime { 27 | continue 28 | } 29 | 30 | Plugins[fpath] = newPlugin 31 | sch := NewPluginScheduler(newPlugin) 32 | PluginsWithScheduler[fpath] = sch 33 | sch.Schedule() 34 | } 35 | } 36 | 37 | func ClearAllPlugins() { 38 | for k := range Plugins { 39 | deletePlugin(k) 40 | } 41 | } 42 | 43 | func deletePlugin(key string) { 44 | v, ok := PluginsWithScheduler[key] 45 | if ok { 46 | v.Stop() 47 | delete(PluginsWithScheduler, key) 48 | } 49 | delete(Plugins, key) 50 | } 51 | -------------------------------------------------------------------------------- /cache/cache.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | 7 | "github.com/didi/nightingale/src/common/dataobj" 8 | ) 9 | 10 | var MetricHistory *History 11 | 12 | func Init() { 13 | MetricHistory = NewHistory() 14 | } 15 | 16 | func NewHistory() *History { 17 | h := History{ 18 | Data: make(map[string]dataobj.MetricValue), 19 | } 20 | 21 | go h.Clean() 22 | return &h 23 | } 24 | 25 | type History struct { 26 | sync.RWMutex 27 | Data map[string]dataobj.MetricValue 28 | } 29 | 30 | func (h *History) Set(key string, item dataobj.MetricValue) { 31 | h.Lock() 32 | defer h.Unlock() 33 | h.Data[key] = item 34 | } 35 | 36 | func (h *History) Get(key string) (dataobj.MetricValue, bool) { 37 | h.RLock() 38 | defer h.RUnlock() 39 | 40 | item, exists := h.Data[key] 41 | return item, exists 42 | } 43 | 44 | func (h *History) Clean() { 45 | ticker := time.NewTicker(10 * time.Minute) 46 | for { 47 | select { 48 | case <-ticker.C: 49 | h.clean() 50 | } 51 | } 52 | } 53 | 54 | func (h *History) clean() { 55 | h.Lock() 56 | defer h.Unlock() 57 | now := time.Now().Unix() 58 | for key, item := range h.Data { 59 | if now-item.Timestamp > 10*item.Step { 60 | delete(h.Data, key) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /sys/ports/port.go: -------------------------------------------------------------------------------- 1 | package ports 2 | 3 | import ( 4 | model "github.com/didi/nightingale/src/models" 5 | ) 6 | 7 | var ( 8 | Ports = make(map[int]*model.PortCollect) 9 | PortsWithScheduler = make(map[int]*PortScheduler) 10 | ) 11 | 12 | func DelNoPortCollect(newCollect map[int]*model.PortCollect) { 13 | for currKey, currPort := range Ports { 14 | newPort, ok := newCollect[currKey] 15 | if !ok || currPort.LastUpdated != newPort.LastUpdated { 16 | deletePort(currKey) 17 | } 18 | } 19 | } 20 | 21 | func AddNewPortCollect(newCollect map[int]*model.PortCollect) { 22 | for target, newPort := range newCollect { 23 | if _, ok := Ports[target]; ok && newPort.LastUpdated == Ports[target].LastUpdated { 24 | continue 25 | } 26 | 27 | Ports[target] = newPort 28 | sch := NewPortScheduler(newPort) 29 | PortsWithScheduler[target] = sch 30 | sch.Schedule() 31 | } 32 | } 33 | 34 | func deletePort(key int) { 35 | v, ok := PortsWithScheduler[key] 36 | if ok { 37 | v.Stop() 38 | delete(PortsWithScheduler, key) 39 | } 40 | delete(Ports, key) 41 | } 42 | 43 | func NewPortCollect(port, step int, tags string) *model.PortCollect { 44 | return &model.PortCollect{ 45 | CollectType: "port", 46 | Port: port, 47 | Step: step, 48 | Tags: tags, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /http/routes/api_router.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/n9e/win-collector/stra" 8 | "github.com/n9e/win-collector/sys/funcs" 9 | 10 | "github.com/didi/nightingale/src/common/dataobj" 11 | "github.com/didi/nightingale/src/toolkits/http/render" 12 | 13 | "github.com/gin-gonic/gin" 14 | "github.com/toolkits/pkg/errors" 15 | ) 16 | 17 | func ping(c *gin.Context) { 18 | c.String(200, "pong") 19 | } 20 | 21 | func addr(c *gin.Context) { 22 | c.String(200, c.Request.RemoteAddr) 23 | } 24 | 25 | func pid(c *gin.Context) { 26 | c.String(200, fmt.Sprintf("%d", os.Getpid())) 27 | } 28 | 29 | func pushData(c *gin.Context) { 30 | if c.Request.ContentLength == 0 { 31 | render.Message(c, "blank body") 32 | return 33 | } 34 | 35 | recvMetricValues := []*dataobj.MetricValue{} 36 | errors.Dangerous(c.ShouldBindJSON(&recvMetricValues)) 37 | 38 | err := funcs.Push(recvMetricValues) 39 | render.Message(c, err) 40 | return 41 | } 42 | 43 | func getStrategy(c *gin.Context) { 44 | var resp []interface{} 45 | 46 | port := stra.GetPortCollects() 47 | for _, stra := range port { 48 | resp = append(resp, stra) 49 | } 50 | 51 | proc := stra.GetProcCollects() 52 | for _, stra := range proc { 53 | resp = append(resp, stra) 54 | } 55 | 56 | render.Data(c, resp, nil) 57 | } 58 | -------------------------------------------------------------------------------- /etc/win-collector.yml: -------------------------------------------------------------------------------- 1 | logger: 2 | dir: logs/collector 3 | level: WARNING 4 | keepHours: 2 5 | 6 | identity: 7 | specify: "" 8 | 9 | ip: 10 | specify: "" 11 | 12 | enable: 13 | report: true 14 | 15 | # 在 n9e v4 中,这里要修改为 Server.Push 16 | # server: 17 | # rpcMethod: "Transfer.Push" 18 | 19 | stra: 20 | api: /api/mon/collects/ # n9e v3 使用这个地址,n9e v2 可以不配 stra 部分,或者配 /api/portal/collects/ 21 | 22 | report: 23 | # 调用ams的接口上报数据,需要ams的token 24 | token: ams-builtin-token 25 | 26 | # 上报周期,单位是秒 27 | interval: 10 28 | 29 | # physical:物理机,virtual:虚拟机,container:容器,switch:交换机 30 | cate: physical 31 | 32 | # 使用哪个字段作为唯一KEY,即作为where条件更新对应记录,一般使用sn或ip 33 | uniqkey: ip 34 | 35 | # 如果是虚拟机,应该是获取uuid 36 | # curl -s http://169.254.169.254/a/meta-data/instance-id 37 | sn: (Get-WmiObject -ComputerName $env:ComputerName -Class Win32_BIOS).SerialNumber 38 | 39 | fields: 40 | cpu: (Get-WmiObject -class Win32_ComputerSystem).numberoflogicalprocessors 41 | mem: Write-Host $('{0:f2}' -f ((Get-WmiObject -class "cim_physicalmemory" | Measure-Object -Property Capacity -Sum).Sum/(1024*1024*1024)))Gi 42 | disk: Write-Host $('{0:f2}' -f ((Get-WmiObject Win32_LogicalDisk -ComputerName $env:ComputerName -Filter "DeviceID='C:'" | Select-Object Size).Size/(1024*1024*1024)))Gi 43 | 44 | sys: 45 | # timeout in ms 46 | # interval in second 47 | timeout: 1000 48 | interval: 20 49 | ifacePrefix: 50 | - 以太网 51 | - 本地连接 52 | mountPoint: [] 53 | mountIgnorePrefix: 54 | - /var/lib 55 | ntpServers: 56 | - ntp.aliyun.com 57 | plugin: plugin/ 58 | ignoreMetrics: 59 | - cpu.core.idle 60 | - cpu.core.util 61 | - cpu.core.sys 62 | - cpu.core.user 63 | - cpu.core.irq 64 | -------------------------------------------------------------------------------- /sys/funcs/funcs_test.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func Test_cpu(t *testing.T) { 10 | d := time.Duration(3) * time.Second 11 | if err := UpdateCpuStat(); err != nil { 12 | t.Error(err) 13 | return 14 | } 15 | time.Sleep(d) 16 | if err := UpdateCpuStat(); err != nil { 17 | t.Error(err) 18 | return 19 | } 20 | for _, m := range CpuMetrics() { 21 | bs, _ := json.Marshal(m) 22 | t.Log(string(bs)) 23 | } 24 | } 25 | 26 | func Test_dfstat(t *testing.T) { 27 | ignore := []string{"C"} 28 | for _, m := range deviceMetrics(ignore) { 29 | bs, _ := json.Marshal(m) 30 | t.Log(string(bs)) 31 | } 32 | } 33 | 34 | func Test_DiskIOStat(t *testing.T) { 35 | d := time.Duration(3) * time.Second 36 | if err := UpdateDiskStats(); err != nil { 37 | t.Error(err) 38 | return 39 | } 40 | time.Sleep(d) 41 | if err := UpdateDiskStats(); err != nil { 42 | t.Error(err) 43 | return 44 | } 45 | for _, m := range IOStatsMetrics() { 46 | bs, _ := json.Marshal(m) 47 | t.Log(string(bs)) 48 | } 49 | } 50 | 51 | func Test_IfStat(t *testing.T) { 52 | ifacePrefix := []string{"以太网"} 53 | d := time.Duration(3) * time.Second 54 | time.Sleep(d) 55 | netMetrics(ifacePrefix) 56 | for _, m := range netMetrics(ifacePrefix) { 57 | bs, _ := json.Marshal(m) 58 | t.Log(string(bs)) 59 | } 60 | } 61 | 62 | func Test_MemInfo(t *testing.T) { 63 | for _, m := range MemMetrics() { 64 | bs, _ := json.Marshal(m) 65 | t.Log(string(bs)) 66 | } 67 | } 68 | 69 | func Test_Ntp(t *testing.T) { 70 | ntpServers := []string{"ntp.aliyun.com"} 71 | for _, m := range ntpOffsetMetrics(ntpServers) { 72 | bs, _ := json.Marshal(m) 73 | t.Log(string(bs)) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /sys/funcs/ntp.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/n9e/win-collector/sys" 7 | 8 | "github.com/didi/nightingale/src/common/dataobj" 9 | 10 | "github.com/toolkits/pkg/logger" 11 | ) 12 | 13 | var ntpServer string 14 | 15 | func NtpOffsetMetrics() []*dataobj.MetricValue { 16 | return ntpOffsetMetrics(sys.Config.NtpServers) 17 | } 18 | 19 | func ntpOffsetMetrics(ntpServers []string) (L []*dataobj.MetricValue) { 20 | if len(ntpServers) <= 0 { 21 | return 22 | } 23 | 24 | for idx, server := range ntpServers { 25 | if ntpServer == "" { 26 | ntpServer = server 27 | } 28 | orgTime := time.Now() 29 | logger.Debug("ntp: use server, ", ntpServer) 30 | logger.Debug("ntp: client send time, ", orgTime) 31 | serverReciveTime, serverTransmitTime, err := NtpTwoTime(ntpServer) 32 | if err != nil { 33 | logger.Warning("ntp: get err", ntpServer, err) 34 | ntpServer = "" 35 | time.Sleep(time.Second * time.Duration(idx+1)) 36 | continue 37 | } else { 38 | ntpServer = server //找一台正常的ntp一直使用 39 | } 40 | dstTime := time.Now() 41 | // 算法见https://en.wikipedia.org/wiki/Network_Time_Protocol 42 | duration := ((serverReciveTime.UnixNano() - orgTime.UnixNano()) + (serverTransmitTime.UnixNano() - dstTime.UnixNano())) / 2 43 | logger.Debug("ntp: server receive time, ", serverReciveTime) 44 | logger.Debug("ntp: server reply time, ", serverTransmitTime) 45 | logger.Debug("ntp: client receive time, ", dstTime) 46 | 47 | delta := duration / 1e6 // 转换成 ms 48 | L = append(L, GaugeValue("sys.ntp.offset.ms", delta)) 49 | //one ntp server's response is enough 50 | 51 | return 52 | } 53 | 54 | //keep silence when no config ntp server 55 | if len(ntpServers) > 0 { 56 | logger.Error("sys.ntp.offset error. all ntp servers response failed.") 57 | } 58 | return 59 | } 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # windows 服务器基础资源采集 agent 2 | 3 | ## 功能 4 | 系统指标采集 5 | 6 | ### 指标 7 | 指标与 linux 版本基本保持一致,部分指标上有差异。 8 | 9 | 以下仅列出差异部分 10 | 11 | #### cpu 12 | |metric|linux|windows| 13 | |--|--|--| 14 | |cpu.softirq|支持|不支持| 15 | |cpu.steal|支持|不支持| 16 | |cpu.iowait|支持|不支持| 17 | |cpu.nice|支持|不支持| 18 | |cpu.guest|支持|不支持| 19 | |cpu.core.softirq|支持|不支持| 20 | |cpu.core.steal|支持|不支持| 21 | |cpu.core.iowait|支持|不支持| 22 | |cpu.core.nice|支持|不支持| 23 | |cpu.core.guest|支持|不支持| 24 | |cpu.loadavg.1|支持|不支持| 25 | |cpu.loadavg.5|支持|不支持| 26 | |cpu.loadavg.15|支持|不支持| 27 | 28 | #### mem 29 | |metric|linux|windows| 30 | |--|--|--| 31 | |mem.bytes.buffers|支持|不支持| 32 | |mem.bytes.cached|支持|不支持| 33 | |mem.swap.*|支持|不支持| 34 | 35 | 36 | #### disk 37 | |metric|linux|windows| 38 | |--|--|--| 39 | |disk.inodes.*|支持|不支持| 40 | |disk.io.avgrq_sz|支持|不支持| 41 | |disk.io.avgqu_sz|支持|不支持| 42 | |disk.io.svctm|支持|不支持| 43 | |disk.io.read.msec|不支持|支持| 44 | |disk.io.write.msec|不支持|支持| 45 | |disk.rw.error|支持|不支持| 46 | 47 | 48 | #### net 49 | |metric|linux|windows| 50 | |--|--|--| 51 | |net.sockets.*|支持|不支持| 52 | 53 | #### sys 54 | |metric|linux|windows| 55 | |--|--|--| 56 | |sys.net.netfilter.*|支持|不支持| 57 | |sys.net.tcp.ip4.confailures|不支持|支持| 58 | |sys.net.tcp.ip4.confailures|不支持|支持| 59 | |sys.net.tcp.ip4.conpassive|不支持|支持| 60 | |sys.net.tcp.ip4.conestablished|不支持|支持| 61 | |sys.net.tcp.ip4.conreset|不支持|支持| 62 | |sys.ps.entity.total|支持|不支持| 63 | 64 | #### log 65 | 暂不支持,Todo 66 | 67 | #### port 68 | 无差异 69 | 70 | #### proc 71 | 无差异 72 | 73 | 注意由于 windows 获取 process 列表性能较差,启用进程监控时记得把采集周期调大一点。 74 | 75 | 可以开启 debug 来查看获取 process 的开销耗时,务必将采集周期调到采集开销的2倍以上。否则长时间会导致 oom 76 | 77 | 78 | ## 运行 79 | 管理员权限直接运行 `win-collector.exe` ([下载win-collector](https://github.com/n9e/win-collector/releases)) 即可。配置文件在 `etc/address.yml` 和 `etc/win-collector.yml` 内 80 | 81 | ## 注册为服务 82 | 可以使用 [nssm](https://nssm.cc/) 将其注册为服务 83 | -------------------------------------------------------------------------------- /stra/cron.go: -------------------------------------------------------------------------------- 1 | package stra 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | 8 | "github.com/toolkits/pkg/logger" 9 | "github.com/toolkits/pkg/net/httplib" 10 | 11 | "github.com/n9e/win-collector/sys/identity" 12 | 13 | "github.com/didi/nightingale/src/common/address" 14 | model "github.com/didi/nightingale/src/models" 15 | ) 16 | 17 | func GetCollects() { 18 | if !StraConfig.Enable { 19 | return 20 | } 21 | 22 | detect() 23 | go loopDetect() 24 | } 25 | 26 | func loopDetect() { 27 | t1 := time.NewTicker(time.Duration(StraConfig.Interval) * time.Second) 28 | for { 29 | <-t1.C 30 | detect() 31 | } 32 | } 33 | 34 | func detect() { 35 | c, err := GetCollectsRetry() 36 | if err != nil { 37 | logger.Errorf("get collect err:%v", err) 38 | return 39 | } 40 | 41 | Collect.Update(&c) 42 | } 43 | 44 | type CollectResp struct { 45 | Dat model.Collect `json:"dat"` 46 | Err string `json:"err"` 47 | } 48 | 49 | func GetCollectsRetry() (model.Collect, error) { 50 | count := len(address.GetHTTPAddresses("monapi")) 51 | var resp CollectResp 52 | var err error 53 | for i := 0; i < count; i++ { 54 | resp, err = getCollects() 55 | if err == nil { 56 | if resp.Err != "" { 57 | err = fmt.Errorf(resp.Err) 58 | continue 59 | } 60 | return resp.Dat, err 61 | } 62 | } 63 | 64 | return resp.Dat, err 65 | } 66 | 67 | func getCollects() (CollectResp, error) { 68 | addrs := address.GetHTTPAddresses("monapi") 69 | i := rand.Intn(len(addrs)) 70 | addr := addrs[i] 71 | 72 | var res CollectResp 73 | var err error 74 | 75 | url := fmt.Sprintf("http://%s%s%s", addr, StraConfig.Api, identity.GetIdent()) 76 | err = httplib.Get(url).SetTimeout(time.Duration(StraConfig.Timeout) * time.Millisecond).ToJSON(&res) 77 | if err != nil { 78 | err = fmt.Errorf("get collects from remote:%s failed, error:%v", url, err) 79 | } 80 | 81 | return res, err 82 | } 83 | -------------------------------------------------------------------------------- /sys/identity/identity.go: -------------------------------------------------------------------------------- 1 | package identity 2 | 3 | import ( 4 | "errors" 5 | "log" 6 | 7 | "net" 8 | ) 9 | 10 | type Identity struct { 11 | IP string `yaml:"ip"` 12 | Ident string `yaml:"ident"` 13 | } 14 | 15 | var config Identity 16 | 17 | type IdentitySection struct { 18 | Specify string `yaml:"specify"` 19 | } 20 | 21 | type IPSection struct { 22 | Specify string `yaml:"specify"` 23 | } 24 | 25 | func MyIp4List() ([]string, error) { 26 | ips := []string{} 27 | addrs, err := net.InterfaceAddrs() 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | for _, a := range addrs { 33 | if ipnet, ok := a.(*net.IPNet); ok && ipnet.IP.IsGlobalUnicast() { 34 | if ipnet.IP.To4() != nil { 35 | ips = append(ips, ipnet.IP.String()) 36 | } 37 | } 38 | } 39 | return ips, nil 40 | } 41 | 42 | func getMyIP() (ip string, err error) { 43 | ips, err := MyIp4List() 44 | if err != nil { 45 | return 46 | } 47 | if len(ips) == 0 { 48 | err = errors.New("cannot get identity, no global unicast ip can found") 49 | return 50 | } 51 | ip = ips[0] 52 | return 53 | } 54 | 55 | func getIdent(identity IdentitySection) (string, error) { 56 | if identity.Specify != "" { 57 | return identity.Specify, nil 58 | } 59 | myip, err := getMyIP() 60 | if err != nil { 61 | return "", nil 62 | } 63 | return myip, nil 64 | } 65 | 66 | func getIP(ip IPSection) (string, error) { 67 | if ip.Specify != "" { 68 | return ip.Specify, nil 69 | } 70 | myip, err := getMyIP() 71 | if err != nil { 72 | return "", nil 73 | } 74 | return myip, nil 75 | } 76 | 77 | func Init(identity IdentitySection, ip IPSection) { 78 | ident, err := getIdent(identity) 79 | if err != nil { 80 | log.Fatalf("init identity failed, %v", err) 81 | } 82 | myip, err := getIP(ip) 83 | if err != nil { 84 | log.Fatalf("init ip failed, %v", err) 85 | } 86 | config.Ident = ident 87 | config.IP = myip 88 | return 89 | } 90 | 91 | func GetIP() string { 92 | return config.IP 93 | } 94 | func GetIdent() string { 95 | return config.Ident 96 | } 97 | -------------------------------------------------------------------------------- /stra/proc.go: -------------------------------------------------------------------------------- 1 | package stra 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | 8 | model "github.com/didi/nightingale/src/models" 9 | "github.com/didi/nightingale/src/toolkits/str" 10 | 11 | "github.com/toolkits/pkg/file" 12 | "github.com/toolkits/pkg/logger" 13 | ) 14 | 15 | func NewProcCollect(method, name, tags string, step int) *model.ProcCollect { 16 | return &model.ProcCollect{ 17 | CollectType: "proc", 18 | CollectMethod: method, 19 | Target: name, 20 | Step: step, 21 | Tags: tags, 22 | } 23 | } 24 | 25 | func GetProcCollects() map[string]*model.ProcCollect { 26 | procs := make(map[string]*model.ProcCollect) 27 | 28 | if StraConfig.Enable { 29 | procs = Collect.GetProcs() 30 | for _, p := range procs { 31 | tagsMap := str.DictedTagstring(p.Tags) 32 | tagsMap["target"] = p.Target 33 | p.Tags = str.SortedTags(tagsMap) 34 | } 35 | } 36 | 37 | files, err := file.FilesUnder(StraConfig.ProcPath) 38 | if err != nil { 39 | logger.Error(err) 40 | return procs 41 | } 42 | 43 | //扫描文件采集配置 44 | for _, f := range files { 45 | method, name, step, err := parseProcName(f) 46 | if err != nil { 47 | logger.Warning(err) 48 | continue 49 | } 50 | 51 | service, err := file.ToTrimString(StraConfig.ProcPath + "/" + f) 52 | if err != nil { 53 | logger.Warning(err) 54 | continue 55 | } 56 | 57 | tags := fmt.Sprintf("target=%s,service=%s", name, service) 58 | p := NewProcCollect(method, name, tags, step) 59 | procs[p.Name] = p 60 | } 61 | 62 | return procs 63 | } 64 | 65 | func parseProcName(fname string) (method string, name string, step int, err error) { 66 | arr := strings.Split(fname, "_") 67 | if len(arr) < 3 { 68 | err = fmt.Errorf("name is illegal %s, split _ < 3", fname) 69 | return 70 | } 71 | 72 | step, err = strconv.Atoi(arr[0]) 73 | if err != nil { 74 | err = fmt.Errorf("name is illegal %s %v", fname, err) 75 | return 76 | } 77 | 78 | method = arr[1] 79 | 80 | name = strings.Join(arr[2:len(arr)], "_") 81 | return 82 | } 83 | -------------------------------------------------------------------------------- /stra/port.go: -------------------------------------------------------------------------------- 1 | package stra 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | 8 | model "github.com/didi/nightingale/src/models" 9 | "github.com/didi/nightingale/src/toolkits/str" 10 | 11 | "github.com/toolkits/pkg/file" 12 | "github.com/toolkits/pkg/logger" 13 | ) 14 | 15 | func NewPortCollect(port, step int, tags string) *model.PortCollect { 16 | return &model.PortCollect{ 17 | CollectType: "port", 18 | Port: port, 19 | Step: step, 20 | Tags: tags, 21 | } 22 | } 23 | 24 | func GetPortCollects() map[int]*model.PortCollect { 25 | portPath := StraConfig.PortPath 26 | ports := make(map[int]*model.PortCollect) 27 | 28 | if StraConfig.Enable { 29 | ports = Collect.GetPorts() 30 | for _, p := range ports { 31 | tagsMap := str.DictedTagstring(p.Tags) 32 | tagsMap["port"] = strconv.Itoa(p.Port) 33 | 34 | p.Tags = str.SortedTags(tagsMap) 35 | } 36 | } 37 | 38 | files, err := file.FilesUnder(portPath) 39 | if err != nil { 40 | logger.Error(err) 41 | return ports 42 | } 43 | //扫描文件采集配置 44 | for _, f := range files { 45 | port, step, err := parseName(f) 46 | if err != nil { 47 | logger.Warning(err) 48 | continue 49 | } 50 | 51 | service, err := file.ToTrimString(StraConfig.PortPath + "/" + f) 52 | if err != nil { 53 | logger.Warning(err) 54 | continue 55 | } 56 | 57 | tags := fmt.Sprintf("port=%s,service=%s", strconv.Itoa(port), service) 58 | p := NewPortCollect(port, step, tags) 59 | ports[p.Port] = p 60 | } 61 | 62 | return ports 63 | } 64 | 65 | func parseName(name string) (port, step int, err error) { 66 | arr := strings.Split(name, "_") 67 | if len(arr) < 2 { 68 | err = fmt.Errorf("name is illegal %s, split _ < 2", name) 69 | 70 | return 71 | } 72 | 73 | step, err = strconv.Atoi(arr[0]) 74 | if err != nil { 75 | err = fmt.Errorf("name is illegal %s %v", name, err) 76 | return 77 | } 78 | 79 | port, err = strconv.Atoi(arr[1]) 80 | if err != nil { 81 | err = fmt.Errorf("name is illegal %s %v", name, err) 82 | return 83 | } 84 | return 85 | } 86 | -------------------------------------------------------------------------------- /sys/ports/scheduler.go: -------------------------------------------------------------------------------- 1 | package ports 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "time" 7 | 8 | "github.com/didi/nightingale/src/common/dataobj" 9 | model "github.com/didi/nightingale/src/models" 10 | "github.com/n9e/win-collector/sys/funcs" 11 | "github.com/n9e/win-collector/sys/identity" 12 | "github.com/toolkits/pkg/logger" 13 | ) 14 | 15 | type PortScheduler struct { 16 | Ticker *time.Ticker 17 | Port *model.PortCollect 18 | Quit chan struct{} 19 | } 20 | 21 | func NewPortScheduler(p *model.PortCollect) *PortScheduler { 22 | scheduler := PortScheduler{Port: p} 23 | scheduler.Ticker = time.NewTicker(time.Duration(p.Step) * time.Second) 24 | scheduler.Quit = make(chan struct{}) 25 | return &scheduler 26 | } 27 | 28 | func (this *PortScheduler) Schedule() { 29 | go func() { 30 | for { 31 | select { 32 | case <-this.Ticker.C: 33 | PortCollect(this.Port) 34 | case <-this.Quit: 35 | this.Ticker.Stop() 36 | return 37 | } 38 | } 39 | }() 40 | } 41 | 42 | func (this *PortScheduler) Stop() { 43 | close(this.Quit) 44 | } 45 | 46 | func PortCollect(p *model.PortCollect) { 47 | value := 0 48 | if isListening(p.Port, p.Timeout) { 49 | value = 1 50 | } 51 | 52 | item := funcs.GaugeValue("proc.port.listen", value, p.Tags) 53 | item.Step = int64(p.Step) 54 | item.Timestamp = time.Now().Unix() 55 | item.Endpoint = identity.GetIdent() 56 | funcs.Push([]*dataobj.MetricValue{item}) 57 | } 58 | 59 | func isListening(port int, timeout int) bool { 60 | if isListen(port, timeout, "127.0.0.1") { 61 | return true 62 | } 63 | ips, err := identity.MyIp4List() 64 | if err != nil { 65 | logger.Error(err) 66 | return false 67 | } 68 | for _, ip := range ips { 69 | if isListen(port, timeout, ip) { 70 | return true 71 | } 72 | } 73 | 74 | return false 75 | } 76 | 77 | func isListen(port, timeout int, ip string) bool { 78 | var conn net.Conn 79 | var err error 80 | addr := fmt.Sprintf("%s:%d", ip, port) 81 | if timeout <= 0 { 82 | // default timeout 3 second 83 | timeout = 3 84 | } 85 | conn, err = net.DialTimeout("tcp", addr, time.Duration(timeout)*time.Second) 86 | if err != nil { 87 | return false 88 | } 89 | conn.Close() 90 | return true 91 | } 92 | -------------------------------------------------------------------------------- /sys/plugins/reader.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "path/filepath" 7 | "strconv" 8 | "strings" 9 | 10 | "github.com/n9e/win-collector/stra" 11 | "github.com/n9e/win-collector/sys" 12 | 13 | "github.com/toolkits/pkg/file" 14 | "github.com/toolkits/pkg/logger" 15 | ) 16 | 17 | // key: 60_ntp.py 18 | func ListPlugins() map[string]*Plugin { 19 | plugins := make(map[string]*Plugin) 20 | if sys.Config.PluginRemote { 21 | plugins = ListPluginsFromMonapi() 22 | } else { 23 | plugins = ListPluginsFromLocal() 24 | } 25 | return plugins 26 | } 27 | 28 | func ListPluginsFromMonapi() map[string]*Plugin { 29 | ret := make(map[string]*Plugin) 30 | 31 | plugins := stra.Collect.GetPlugin() 32 | 33 | for _, p := range plugins { 34 | fpath := p.FilePath 35 | fileInfo, err := os.Stat(fpath) 36 | if err != nil { 37 | logger.Warningf("plugin:%s get info err:%v", p.FilePath, err) 38 | continue 39 | } 40 | 41 | plugin := &Plugin{ 42 | FilePath: fpath, 43 | MTime: fileInfo.ModTime().Unix(), 44 | Cycle: p.Step, 45 | Params: p.Params, 46 | } 47 | 48 | ret[fpath] = plugin 49 | } 50 | 51 | return ret 52 | } 53 | 54 | func ListPluginsFromLocal() map[string]*Plugin { 55 | dir := sys.Config.Plugin 56 | ret := make(map[string]*Plugin) 57 | 58 | if dir == "" || !file.IsExist(dir) || file.IsFile(dir) { 59 | return ret 60 | } 61 | 62 | fs, err := ioutil.ReadDir(dir) 63 | if err != nil { 64 | logger.Error("[E] can not list files under", dir) 65 | return ret 66 | } 67 | 68 | for _, f := range fs { 69 | if f.IsDir() { 70 | continue 71 | } 72 | 73 | filename := f.Name() 74 | arr := strings.Split(filename, "_") 75 | if len(arr) < 2 { 76 | logger.Warningf("plugin:%s name illegal, should be: $cycle_$xx", filename) 77 | continue 78 | } 79 | 80 | // filename should be: $cycle_$xx 81 | var cycle int 82 | cycle, err = strconv.Atoi(arr[0]) 83 | if err != nil { 84 | logger.Warningf("plugin:%s name illegal, should be: $cycle_$xx %v", filename, err) 85 | continue 86 | } 87 | 88 | fpath, err := filepath.Abs(filepath.Join(dir, filename)) 89 | if err != nil { 90 | logger.Warningf("plugin:%s absolute path get err:%v", filename, err) 91 | continue 92 | } 93 | 94 | plugin := &Plugin{FilePath: fpath, MTime: f.ModTime().Unix(), Cycle: cycle} 95 | ret[fpath] = plugin 96 | } 97 | 98 | return ret 99 | } 100 | -------------------------------------------------------------------------------- /sys/funcs/dfstat.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/n9e/win-collector/sys" 8 | 9 | "github.com/didi/nightingale/src/common/dataobj" 10 | "github.com/shirou/gopsutil/disk" 11 | "github.com/toolkits/pkg/logger" 12 | ) 13 | 14 | func diskUsage(path string) (*disk.UsageStat, error) { 15 | diskUsage, err := disk.Usage(path) 16 | return diskUsage, err 17 | } 18 | 19 | func diskPartitions() ([]disk.PartitionStat, error) { 20 | diskPartitions, err := disk.Partitions(true) 21 | return diskPartitions, err 22 | } 23 | 24 | func deviceMetrics(ignoreMountPointsPrefix []string) (L []*dataobj.MetricValue) { 25 | diskPartitions, err := diskPartitions() 26 | 27 | if err != nil { 28 | logger.Error("get disk stat failed", err) 29 | return 30 | } 31 | 32 | var diskTotal uint64 = 0 33 | var diskUsed uint64 = 0 34 | for _, device := range diskPartitions { 35 | if hasIgnorePrefix(device.Mountpoint, ignoreMountPointsPrefix) { 36 | continue 37 | } 38 | du, err := diskUsage(device.Mountpoint) 39 | if err != nil { 40 | logger.Error("get disk stat fail", err) 41 | continue 42 | } 43 | 44 | diskTotal += du.Total 45 | diskUsed += du.Used 46 | tags := fmt.Sprintf("mount=%s,fstype=%s", device.Mountpoint, device.Fstype) 47 | L = append(L, GaugeValue("disk.bytes.total", du.Total, tags)) 48 | L = append(L, GaugeValue("disk.bytes.used", du.Used, tags)) 49 | L = append(L, GaugeValue("disk.bytes.free", du.Free, tags)) 50 | L = append(L, GaugeValue("disk.bytes.used.percent", du.UsedPercent, tags)) 51 | } 52 | 53 | if len(L) > 0 && diskTotal > 0 { 54 | L = append(L, GaugeValue("disk.cap.bytes.total", float64(diskTotal))) 55 | L = append(L, GaugeValue("disk.cap.bytes.used", float64(diskUsed))) 56 | L = append(L, GaugeValue("disk.cap.bytes.free", float64(diskTotal-diskUsed))) 57 | L = append(L, GaugeValue("disk.cap.bytes.used.percent", float64(diskUsed)*100.0/float64(diskTotal))) 58 | } 59 | return 60 | } 61 | 62 | func DeviceMetrics() (L []*dataobj.MetricValue) { 63 | return deviceMetrics(sys.Config.MountIgnorePrefix) 64 | } 65 | 66 | func hasIgnorePrefix(fsFile string, ignoreMountPointsPrefix []string) bool { 67 | hasPrefix := false 68 | if len(ignoreMountPointsPrefix) > 0 { 69 | for _, ignorePrefix := range ignoreMountPointsPrefix { 70 | if strings.HasPrefix(fsFile, ignorePrefix) { 71 | hasPrefix = true 72 | logger.Debugf("mount point %s has ignored prefix %s", fsFile, ignorePrefix) 73 | break 74 | } 75 | } 76 | } 77 | return hasPrefix 78 | } 79 | -------------------------------------------------------------------------------- /sys/funcs/diskIOCounters.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "github.com/StackExchange/wmi" 5 | "github.com/toolkits/pkg/logger" 6 | ) 7 | 8 | type Win32_PerfFormattedData struct { 9 | AvgDiskSecPerRead_Base uint32 10 | AvgDiskSecPerWrite_Base uint32 11 | DiskReadBytesPerSec uint64 12 | DiskReadsPerSec uint32 13 | DiskWriteBytesPerSec uint64 14 | DiskWritesPerSec uint32 15 | Name string 16 | } 17 | 18 | type Win32_PerfFormattedData_IDLE struct { 19 | Name string 20 | PercentIdleTime uint64 21 | } 22 | 23 | type diskIOCounter struct { 24 | Device string 25 | MsecRead uint64 26 | MsecWrite uint64 27 | ReadBytes uint64 28 | ReadRequests uint64 29 | WriteBytes uint64 30 | WriteRequests uint64 31 | Util uint64 32 | } 33 | 34 | func PerfFormattedData() ([]Win32_PerfFormattedData, error) { 35 | 36 | var dst []Win32_PerfFormattedData 37 | Query := `SELECT 38 | AvgDiskSecPerRead_Base, 39 | AvgDiskSecPerWrite_Base, 40 | DiskReadBytesPerSec, 41 | DiskReadsPerSec, 42 | DiskWriteBytesPerSec, 43 | DiskWritesPerSec, 44 | Name 45 | FROM Win32_PerfRawData_PerfDisk_PhysicalDisk` 46 | err := wmi.Query(Query, &dst) 47 | 48 | return dst, err 49 | } 50 | 51 | func PerfFormattedDataIDLE(name string) ([]Win32_PerfFormattedData_IDLE, error) { 52 | 53 | var dst []Win32_PerfFormattedData_IDLE 54 | query := `SELECT PercentIdleTime FROM Win32_PerfFormattedData_PerfDisk_PhysicalDisk WHERE Name = '` + name + `'` 55 | err := wmi.Query(query, &dst) 56 | 57 | return dst, err 58 | } 59 | 60 | func IOCounters() ([]diskIOCounter, error) { 61 | ret := []diskIOCounter{} 62 | dst, err := PerfFormattedData() 63 | if err != nil { 64 | return nil, err 65 | } 66 | for _, d := range dst { 67 | 68 | if d.Name == "_Total" { // not get _Total 69 | continue 70 | } 71 | 72 | dstat := diskIOCounter{ 73 | Device: d.Name, 74 | MsecRead: uint64(d.AvgDiskSecPerRead_Base), 75 | MsecWrite: uint64(d.AvgDiskSecPerWrite_Base), 76 | ReadBytes: d.DiskReadBytesPerSec, 77 | ReadRequests: uint64(d.DiskReadsPerSec), 78 | WriteBytes: d.DiskWriteBytesPerSec, 79 | WriteRequests: uint64(d.DiskWritesPerSec), 80 | } 81 | idle, err := PerfFormattedDataIDLE(d.Name) 82 | if err != nil || len(idle) == 0 { 83 | logger.Error("get disk idle failed: ", err) 84 | } else { 85 | dstat.Util = uint64(100) - idle[0].PercentIdleTime 86 | } 87 | ret = append(ret, dstat) 88 | } 89 | 90 | return ret, nil 91 | } 92 | -------------------------------------------------------------------------------- /sys/funcs/tcpip.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/StackExchange/wmi" 7 | "github.com/didi/nightingale/src/common/dataobj" 8 | "github.com/toolkits/pkg/logger" 9 | ) 10 | 11 | var ( 12 | historyTcpipStat *Win32_TCPPerfFormattedData 13 | lasttcpipTime time.Time 14 | ) 15 | 16 | func TcpipMetrics() (L []*dataobj.MetricValue) { 17 | tcpipStat, err := TcpipCounters() 18 | if err != nil || len(tcpipStat) == 0 { 19 | logger.Error("Get tcpip data fail: ", err) 20 | return 21 | } 22 | newTcpipStat := &tcpipStat[0] 23 | now := time.Now() 24 | interval := now.Unix() - lasttcpipTime.Unix() 25 | lasttcpipTime = now 26 | 27 | if historyTcpipStat == nil { 28 | historyTcpipStat = newTcpipStat 29 | return []*dataobj.MetricValue{} 30 | } 31 | v := float64(newTcpipStat.ConnectionFailures-historyTcpipStat.ConnectionFailures) / float64(interval) 32 | if v < 0 { 33 | v = 0 34 | } 35 | L = append(L, GaugeValue("sys.net.tcp.ip4.con.failures", v)) 36 | 37 | v = float64(newTcpipStat.ConnectionsPassive-historyTcpipStat.ConnectionsPassive) / float64(interval) 38 | if v < 0 { 39 | v = 0 40 | } 41 | L = append(L, GaugeValue("sys.net.tcp.ip4.con.passive", v)) 42 | 43 | v = float64(newTcpipStat.ConnectionsReset-historyTcpipStat.ConnectionsReset) / float64(interval) 44 | if v < 0 { 45 | v = 0 46 | } 47 | L = append(L, GaugeValue("sys.net.tcp.ip4.con.reset", v)) 48 | 49 | v = float64(newTcpipStat.ConnectionsActive-historyTcpipStat.ConnectionsActive) / float64(interval) 50 | logger.Debugf("row connection active,new value is %v, history value is %v,interval is %v", newTcpipStat.ConnectionsActive, historyTcpipStat.ConnectionsActive, interval) 51 | if v < 0 { 52 | v = 0 53 | } 54 | L = append(L, GaugeValue("sys.net.tcp.ip4.con.active", v)) 55 | 56 | v = float64(newTcpipStat.ConnectionsEstablished+historyTcpipStat.ConnectionsEstablished) / 2 57 | L = append(L, GaugeValue("sys.net.tcp.ip4.con.established", v)) 58 | 59 | historyTcpipStat = newTcpipStat 60 | return 61 | } 62 | 63 | type Win32_TCPPerfFormattedData struct { 64 | ConnectionFailures uint64 65 | ConnectionsActive uint64 66 | ConnectionsPassive uint64 67 | ConnectionsEstablished uint64 68 | ConnectionsReset uint64 69 | } 70 | 71 | func TcpipCounters() ([]Win32_TCPPerfFormattedData, error) { 72 | var dst []Win32_TCPPerfFormattedData 73 | err := wmi.Query("SELECT ConnectionFailures,ConnectionsActive,ConnectionsPassive,ConnectionsEstablished,ConnectionsReset FROM Win32_PerfRawData_Tcpip_TCPv4", &dst) 74 | return dst, err 75 | } 76 | -------------------------------------------------------------------------------- /sys/procs/scheduler.go: -------------------------------------------------------------------------------- 1 | package procs 2 | 3 | import ( 4 | "strings" 5 | "time" 6 | 7 | "github.com/shirou/gopsutil/process" 8 | "github.com/toolkits/pkg/logger" 9 | 10 | "github.com/n9e/win-collector/sys/funcs" 11 | "github.com/n9e/win-collector/sys/identity" 12 | 13 | "github.com/didi/nightingale/src/common/dataobj" 14 | model "github.com/didi/nightingale/src/models" 15 | ) 16 | 17 | type ProcScheduler struct { 18 | Ticker *time.Ticker 19 | Proc *model.ProcCollect 20 | Quit chan struct{} 21 | } 22 | 23 | func NewProcScheduler(p *model.ProcCollect) *ProcScheduler { 24 | scheduler := ProcScheduler{Proc: p} 25 | scheduler.Ticker = time.NewTicker(time.Duration(p.Step) * time.Second) 26 | scheduler.Quit = make(chan struct{}) 27 | return &scheduler 28 | } 29 | 30 | func (this *ProcScheduler) Schedule() { 31 | go func() { 32 | for { 33 | select { 34 | case <-this.Ticker.C: 35 | ProcCollect(this.Proc) 36 | case <-this.Quit: 37 | this.Ticker.Stop() 38 | return 39 | } 40 | } 41 | }() 42 | } 43 | 44 | func (this *ProcScheduler) Stop() { 45 | close(this.Quit) 46 | } 47 | 48 | type P struct { 49 | Pid int32 50 | Name string 51 | Cmdline string 52 | } 53 | 54 | func ProcCollect(p *model.ProcCollect) { 55 | startTime := time.Now() 56 | ps, err := procs() 57 | if err != nil { 58 | logger.Error(err) 59 | return 60 | } 61 | endTime := time.Now() 62 | logger.Debugf("collect procs complete. Process time %s. Number of procs is %d", endTime.Sub(startTime), len(ps)) 63 | 64 | pslen := len(ps) 65 | cnt := 0 66 | for i := 0; i < pslen; i++ { 67 | if isProc(ps[i], p.CollectMethod, p.Target) { 68 | cnt++ 69 | } 70 | } 71 | 72 | item := funcs.GaugeValue("proc.num", cnt, p.Tags) 73 | item.Step = int64(p.Step) 74 | item.Timestamp = time.Now().Unix() 75 | item.Endpoint = identity.GetIdent() 76 | 77 | funcs.Push([]*dataobj.MetricValue{item}) 78 | } 79 | 80 | func isProc(p P, method, target string) bool { 81 | if method == "name" && target == p.Name { 82 | return true 83 | } else if (method == "cmdline" || method == "cmd") && strings.Contains(p.Cmdline, target) { 84 | return true 85 | } 86 | return false 87 | } 88 | 89 | func procs() ([]P, error) { 90 | var processes = []P{} 91 | var PROCESS P 92 | pids, err := process.Pids() 93 | if err != nil { 94 | return processes, err 95 | } 96 | for _, pid := range pids { 97 | p, err := process.NewProcess(pid) 98 | if err == nil { 99 | pname, err := p.Name() 100 | pcmdline, err := p.Cmdline() 101 | if err == nil { 102 | PROCESS.Name = pname 103 | PROCESS.Cmdline = pcmdline 104 | PROCESS.Pid = pid 105 | processes = append(processes, PROCESS) 106 | } 107 | } 108 | } 109 | return processes, err 110 | } 111 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "sync" 7 | 8 | "github.com/n9e/win-collector/stra" 9 | "github.com/n9e/win-collector/sys" 10 | "github.com/n9e/win-collector/sys/identity" 11 | 12 | logger "github.com/didi/nightingale/src/common/loggeri" 13 | "github.com/spf13/viper" 14 | "github.com/toolkits/pkg/file" 15 | ) 16 | 17 | type ConfYaml struct { 18 | Logger logger.Config `yaml:"logger"` 19 | Identity identity.IdentitySection `yaml:"identity"` 20 | IP identity.IPSection `yaml:"ip"` 21 | Stra stra.StraSection `yaml:"stra"` 22 | Enable enableSection `yaml:"enable"` 23 | Report reportSection `yaml:"report"` 24 | Sys sys.SysSection `yaml:"sys"` 25 | Server serverSection `yaml:"server"` 26 | } 27 | 28 | type enableSection struct { 29 | Report bool `yaml:"report"` 30 | } 31 | 32 | type reportSection struct { 33 | Token string `yaml:"token"` 34 | Interval int `yaml:"interval"` 35 | Cate string `yaml:"cate"` 36 | UniqKey string `yaml:"uniqkey"` 37 | SN string `yaml:"sn"` 38 | Fields map[string]string `yaml:"fields"` 39 | } 40 | 41 | type serverSection struct { 42 | RpcMethod string `yaml:"rpcMethod"` 43 | } 44 | 45 | var ( 46 | Config *ConfYaml 47 | lock = new(sync.RWMutex) 48 | Endpoint string 49 | Cwd string 50 | ) 51 | 52 | // Get configuration file 53 | func Get() *ConfYaml { 54 | lock.RLock() 55 | defer lock.RUnlock() 56 | return Config 57 | } 58 | 59 | func Parse(conf string) error { 60 | bs, err := file.ReadBytes(conf) 61 | if err != nil { 62 | return fmt.Errorf("cannot read yml[%s]: %v", conf, err) 63 | } 64 | 65 | lock.Lock() 66 | defer lock.Unlock() 67 | 68 | viper.SetConfigType("yaml") 69 | err = viper.ReadConfig(bytes.NewBuffer(bs)) 70 | if err != nil { 71 | return fmt.Errorf("cannot read yml[%s]: %v", conf, err) 72 | } 73 | 74 | viper.SetDefault("worker", map[string]interface{}{ 75 | "workerNum": 10, 76 | "queueSize": 1024000, 77 | "pushInterval": 5, 78 | "waitPush": 0, 79 | }) 80 | 81 | viper.SetDefault("stra", map[string]interface{}{ 82 | "enable": true, 83 | "timeout": 1000, 84 | "interval": 10, //采集策略更新时间 85 | "portPath": "/home/n9e/etc/port", 86 | "procPath": "/home/n9e/etc/proc", 87 | "logPath": "/home/n9e/etc/log", 88 | "api": "/api/portal/collects/", 89 | }) 90 | 91 | viper.SetDefault("sys", map[string]interface{}{ 92 | "timeout": 1000, //请求超时时间 93 | "interval": 10, //基础指标上报周期 94 | "plugin": "/home/n9e/plugin", 95 | }) 96 | 97 | viper.SetDefault("server.rpcMethod", "Transfer.Push") 98 | 99 | err = viper.Unmarshal(&Config) 100 | if err != nil { 101 | return fmt.Errorf("Unmarshal %v", err) 102 | } 103 | 104 | return nil 105 | } 106 | -------------------------------------------------------------------------------- /sys/funcs/diskstat.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "strings" 5 | "sync" 6 | "time" 7 | 8 | "github.com/didi/nightingale/src/common/dataobj" 9 | "github.com/toolkits/pkg/logger" 10 | ) 11 | 12 | var ( 13 | diskStatsMap = make(map[string][2]*diskIOCounter) 14 | dsLock = new(sync.RWMutex) 15 | ) 16 | 17 | func PrepareDiskStats() { 18 | d := time.Duration(3) * time.Second 19 | for { 20 | err := UpdateDiskStats() 21 | if err != nil { 22 | logger.Error("update disk stats fail", err) 23 | } 24 | time.Sleep(d) 25 | } 26 | } 27 | 28 | func UpdateDiskStats() error { 29 | dsList, err := IOCounters() 30 | if err != nil { 31 | return err 32 | } 33 | 34 | dsLock.Lock() 35 | defer dsLock.Unlock() 36 | for i := 0; i < len(dsList); i++ { 37 | device := dsList[i].Device 38 | diskStatsMap[device] = [2]*diskIOCounter{&dsList[i], diskStatsMap[device][0]} 39 | } 40 | return nil 41 | } 42 | 43 | func IOReadRequests(arr [2]*diskIOCounter) uint64 { 44 | return arr[0].ReadRequests - arr[1].ReadRequests 45 | } 46 | 47 | func IOWriteRequests(arr [2]*diskIOCounter) uint64 { 48 | return arr[0].WriteRequests - arr[1].WriteRequests 49 | } 50 | 51 | func IOMsecRead(arr [2]*diskIOCounter) uint64 { 52 | return arr[0].MsecRead - arr[1].MsecRead 53 | } 54 | 55 | func IOMsecWrite(arr [2]*diskIOCounter) uint64 { 56 | return arr[0].MsecWrite - arr[1].MsecWrite 57 | } 58 | 59 | func IOReadBytes(arr [2]*diskIOCounter) uint64 { 60 | return arr[0].ReadBytes - arr[1].ReadBytes 61 | } 62 | 63 | func IOWriteBytes(arr [2]*diskIOCounter) uint64 { 64 | return arr[0].WriteBytes - arr[1].WriteBytes 65 | } 66 | 67 | func IOUtilTotal(arr [2]*diskIOCounter) uint64 { 68 | return arr[0].Util + arr[1].Util 69 | } 70 | 71 | func IODelta(device string, f func([2]*diskIOCounter) uint64) uint64 { 72 | val, ok := diskStatsMap[device] 73 | if !ok { 74 | return 0 75 | } 76 | 77 | if val[1] == nil { 78 | return 0 79 | } 80 | return f(val) 81 | } 82 | 83 | func IOStatsMetrics() (L []*dataobj.MetricValue) { 84 | dsLock.RLock() 85 | defer dsLock.RUnlock() 86 | 87 | for device := range diskStatsMap { 88 | tags := "device=" + strings.Replace(device, " ", "", -1) 89 | rio := IODelta(device, IOReadRequests) 90 | wio := IODelta(device, IOWriteRequests) 91 | rbytes := IODelta(device, IOReadBytes) 92 | wbytes := IODelta(device, IOWriteBytes) 93 | ruse := IODelta(device, IOMsecRead) 94 | wuse := IODelta(device, IOMsecWrite) 95 | utilTotal := IODelta(device, IOUtilTotal) 96 | n_io := rio + wio 97 | await := 0.0 98 | if n_io != 0 { 99 | await = float64(ruse+wuse) / float64(n_io) 100 | } 101 | 102 | L = append(L, GaugeValue("disk.io.read.request", float64(rio), tags)) 103 | L = append(L, GaugeValue("disk.io.write.request", float64(wio), tags)) 104 | L = append(L, GaugeValue("disk.io.read.bytes", float64(rbytes), tags)) 105 | L = append(L, GaugeValue("disk.io.write.bytes", float64(wbytes), tags)) 106 | L = append(L, GaugeValue("disk.io.read.msec", float64(ruse), tags)) 107 | L = append(L, GaugeValue("disk.io.write.msec", float64(wuse), tags)) 108 | L = append(L, GaugeValue("disk.io.await", await, tags)) 109 | L = append(L, GaugeValue("disk.io.util", float64(utilTotal)/2, tags)) 110 | } 111 | 112 | return 113 | } 114 | -------------------------------------------------------------------------------- /sys/plugins/scheduler.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "os/exec" 7 | "path/filepath" 8 | "strings" 9 | "time" 10 | 11 | "github.com/toolkits/pkg/file" 12 | "github.com/toolkits/pkg/logger" 13 | 14 | "github.com/didi/nightingale/src/common/dataobj" 15 | "github.com/n9e/win-collector/sys/funcs" 16 | ) 17 | 18 | type PluginScheduler struct { 19 | Ticker *time.Ticker 20 | Plugin *Plugin 21 | Quit chan struct{} 22 | } 23 | 24 | func NewPluginScheduler(p *Plugin) *PluginScheduler { 25 | scheduler := PluginScheduler{Plugin: p} 26 | scheduler.Ticker = time.NewTicker(time.Duration(p.Cycle) * time.Second) 27 | scheduler.Quit = make(chan struct{}) 28 | return &scheduler 29 | } 30 | 31 | func (p *PluginScheduler) Schedule() { 32 | go func() { 33 | for { 34 | select { 35 | case <-p.Ticker.C: 36 | PluginRun(p.Plugin) 37 | case <-p.Quit: 38 | p.Ticker.Stop() 39 | return 40 | } 41 | } 42 | }() 43 | } 44 | 45 | func (p *PluginScheduler) Stop() { 46 | close(p.Quit) 47 | } 48 | 49 | func PluginRun(plugin *Plugin) { 50 | 51 | timeout := plugin.Cycle*1000 - 500 //比运行周期少500毫秒 52 | 53 | fpath := plugin.FilePath 54 | if !file.IsExist(fpath) { 55 | logger.Error("no such plugin:", fpath) 56 | return 57 | } 58 | 59 | logger.Debug(fpath, " running") 60 | params := strings.Split(plugin.Params, " ") 61 | params = append([]string{fpath}, params...) 62 | cmd := exec.Command("powershell.exe", params...) 63 | cmd.Dir = filepath.Dir(fpath) 64 | var stdout bytes.Buffer 65 | cmd.Stdout = &stdout 66 | var stderr bytes.Buffer 67 | cmd.Stderr = &stderr 68 | err := cmd.Start() 69 | if err != nil { 70 | logger.Error(err) 71 | return 72 | } 73 | 74 | err, isTimeout := WrapTimeout(cmd, time.Duration(timeout)*time.Millisecond) 75 | 76 | errStr := stderr.String() 77 | if errStr != "" { 78 | logger.Errorf("exec %s fail: %s", fpath, errStr) 79 | return 80 | } 81 | 82 | if isTimeout { 83 | if err == nil { 84 | logger.Infof("timeout and kill process %s successfully", fpath) 85 | } 86 | 87 | if err != nil { 88 | logger.Errorf("kill process %s occur error %v", fpath, err) 89 | } 90 | 91 | return 92 | } 93 | 94 | if err != nil { 95 | logger.Errorf("exec plugin %s occur error: %v", fpath, err) 96 | return 97 | } 98 | 99 | // exec successfully 100 | data := stdout.Bytes() 101 | if len(data) == 0 { 102 | logger.Debug("stdout of", fpath, "is blank") 103 | return 104 | } 105 | 106 | var items []*dataobj.MetricValue 107 | err = json.Unmarshal(data, &items) 108 | if err != nil { 109 | logger.Errorf("json.Unmarshal stdout of %s fail. error:%s stdout: %s", fpath, err, stdout.String()) 110 | return 111 | } 112 | 113 | if len(items) == 0 { 114 | logger.Debugf("%s item result is empty", fpath) 115 | return 116 | } 117 | 118 | funcs.Push(items) 119 | } 120 | 121 | func WrapTimeout(cmd *exec.Cmd, timeout time.Duration) (error, bool) { 122 | var err error 123 | 124 | done := make(chan error) 125 | go func() { 126 | done <- cmd.Wait() 127 | }() 128 | 129 | select { 130 | case <-time.After(timeout): 131 | go func() { 132 | <-done // allow goroutine to exit 133 | }() 134 | 135 | err := cmd.Process.Kill() 136 | return err, true 137 | case err = <-done: 138 | return err, false 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /report/report.go: -------------------------------------------------------------------------------- 1 | package report 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "math/rand" 8 | "os" 9 | "os/exec" 10 | "sort" 11 | "strings" 12 | "time" 13 | 14 | "github.com/toolkits/pkg/file" 15 | "github.com/toolkits/pkg/logger" 16 | "github.com/toolkits/pkg/net/httplib" 17 | "github.com/toolkits/pkg/str" 18 | 19 | "github.com/didi/nightingale/src/common/address" 20 | "github.com/n9e/win-collector/config" 21 | "github.com/n9e/win-collector/sys/identity" 22 | ) 23 | 24 | var ( 25 | sn string 26 | ip string 27 | ident string 28 | ) 29 | 30 | func LoopReport() { 31 | duration := time.Duration(config.Config.Report.Interval) * time.Second 32 | for { 33 | time.Sleep(duration) 34 | if err := report(); err != nil { 35 | logger.Error("report occur error: ", err) 36 | } 37 | } 38 | } 39 | 40 | func GatherBase() error { 41 | var err error 42 | sn, err = execPowershell(config.Config.Report.SN) 43 | if err != nil { 44 | return fmt.Errorf("cannot get sn: %s", err) 45 | } 46 | 47 | ip = identity.GetIP() 48 | 49 | ident = identity.GetIdent() 50 | 51 | return nil 52 | } 53 | 54 | func gatherFields(m map[string]string) (map[string]string, error) { 55 | ret := make(map[string]string) 56 | for k, v := range m { 57 | output, err := execPowershell(v) 58 | if err != nil { 59 | return nil, err 60 | } 61 | ret[k] = output 62 | } 63 | return ret, nil 64 | } 65 | 66 | type hostRegisterForm struct { 67 | SN string `json:"sn"` 68 | IP string `json:"ip"` 69 | Ident string `json:"ident"` 70 | Name string `json:"name"` 71 | Cate string `json:"cate"` 72 | UniqKey string `json:"uniqkey"` 73 | Fields map[string]string `json:"fields"` 74 | Digest string `json:"digest"` 75 | } 76 | 77 | type errRes struct { 78 | Err string `json:"err"` 79 | } 80 | 81 | func report() error { 82 | name, err := os.Hostname() 83 | if err != nil { 84 | return fmt.Errorf("cannot get hostname: %s", err) 85 | } 86 | 87 | fields, err := gatherFields(config.Config.Report.Fields) 88 | if err != nil { 89 | return err 90 | } 91 | 92 | form := hostRegisterForm{ 93 | SN: sn, 94 | IP: ip, 95 | Ident: ident, 96 | Name: name, 97 | Cate: config.Config.Report.Cate, 98 | UniqKey: config.Config.Report.UniqKey, 99 | Fields: fields, 100 | } 101 | 102 | content := form.SN + form.IP + form.Ident + form.Name + form.Cate + form.UniqKey 103 | var keys []string 104 | for key := range fields { 105 | keys = append(keys, key) 106 | } 107 | sort.Strings(keys) 108 | 109 | for _, key := range keys { 110 | content += fields[key] 111 | } 112 | 113 | form.Digest = str.MD5(content) 114 | 115 | servers := address.GetHTTPAddresses("ams") 116 | for _, i := range rand.Perm(len(servers)) { 117 | url := fmt.Sprintf("http://%s/v1/ams-ce/hosts/register", servers[i]) 118 | 119 | var body errRes 120 | err := httplib.Post(url).JSONBodyQuiet(form).Header("X-Srv-Token", config.Config.Report.Token).SetTimeout(time.Second * 5).ToJSON(&body) 121 | if err != nil { 122 | return fmt.Errorf("curl %s fail: %v", url, err) 123 | } 124 | 125 | if body.Err != "" { 126 | return fmt.Errorf(body.Err) 127 | } 128 | 129 | return nil 130 | } 131 | 132 | return fmt.Errorf("all server instance is dead") 133 | } 134 | 135 | func execPowershell(shell string) (string, error) { 136 | //如果一个空格都没有,基本上不太可能是一个shell,原值直接返回 137 | //这样可以支持没有powershell的环境 138 | //Linux不可能没有shell,win还真有卸载掉powershell的。。。 139 | if !strings.Contains(shell, " ") { 140 | return shell, nil 141 | } 142 | cmd := exec.Command("powershell.exe", shell) 143 | out, err := cmd.Output() 144 | if err != nil { 145 | reader := bufio.NewReader(bytes.NewBuffer(out)) 146 | line, _ := file.ReadLine(reader) 147 | return string(line), err 148 | } 149 | 150 | reader := bufio.NewReader(bytes.NewBuffer(out)) 151 | line, err := file.ReadLine(reader) 152 | if err != nil { 153 | return "", err 154 | } 155 | return string(line), err 156 | } 157 | -------------------------------------------------------------------------------- /collector.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "os" 8 | "os/signal" 9 | "syscall" 10 | 11 | "github.com/n9e/win-collector/cache" 12 | "github.com/n9e/win-collector/config" 13 | "github.com/n9e/win-collector/sys/identity" 14 | 15 | "github.com/n9e/win-collector/http/routes" 16 | "github.com/n9e/win-collector/report" 17 | "github.com/n9e/win-collector/stra" 18 | "github.com/n9e/win-collector/sys" 19 | "github.com/n9e/win-collector/sys/funcs" 20 | "github.com/n9e/win-collector/sys/plugins" 21 | "github.com/n9e/win-collector/sys/ports" 22 | "github.com/n9e/win-collector/sys/procs" 23 | 24 | tlogger "github.com/didi/nightingale/src/common/loggeri" 25 | "github.com/didi/nightingale/src/toolkits/http" 26 | 27 | "github.com/StackExchange/wmi" 28 | "github.com/gin-gonic/gin" 29 | "github.com/toolkits/pkg/file" 30 | "github.com/toolkits/pkg/logger" 31 | "github.com/toolkits/pkg/runner" 32 | ) 33 | 34 | var ( 35 | vers *bool 36 | help *bool 37 | conf *string 38 | ) 39 | 40 | func init() { 41 | vers = flag.Bool("v", false, "display the version.") 42 | help = flag.Bool("h", false, "print this help.") 43 | conf = flag.String("f", "", "specify configuration file.") 44 | flag.Parse() 45 | 46 | if *vers { 47 | fmt.Println("version:", config.Version) 48 | os.Exit(0) 49 | } 50 | 51 | if *help { 52 | flag.Usage() 53 | os.Exit(0) 54 | } 55 | } 56 | 57 | func main() { 58 | aconf() 59 | pconf() 60 | start() 61 | 62 | initWbem() 63 | 64 | cfg := config.Get() 65 | 66 | tlogger.Init(cfg.Logger) 67 | 68 | identity.Init(cfg.Identity, cfg.IP) 69 | log.Println("endpoint & ip:", identity.GetIdent(), identity.GetIP()) 70 | 71 | sys.Init(cfg.Sys) 72 | stra.Init(cfg.Stra) 73 | 74 | funcs.InitRpcClients() 75 | funcs.BuildMappers() 76 | funcs.Collect() 77 | 78 | //插件采集 79 | plugins.Detect() 80 | 81 | //进程采集 82 | procs.Detect() 83 | 84 | //端口采集 85 | ports.Detect() 86 | 87 | //初始化缓存,用作保存COUNTER类型数据 88 | cache.Init() 89 | if cfg.Enable.Report { 90 | reportStart() 91 | } 92 | 93 | r := gin.New() 94 | routes.Config(r) 95 | http.Start(r, "collector", cfg.Logger.Level) 96 | ending() 97 | } 98 | 99 | // auto detect configuration file 100 | func aconf() { 101 | if *conf != "" && file.IsExist(*conf) { 102 | return 103 | } 104 | 105 | *conf = "etc/win-collector.local.yml" 106 | if file.IsExist(*conf) { 107 | return 108 | } 109 | 110 | *conf = "etc/win-collector.yml" 111 | if file.IsExist(*conf) { 112 | return 113 | } 114 | 115 | fmt.Println("no configuration file for collector") 116 | os.Exit(1) 117 | } 118 | 119 | // parse configuration file 120 | func pconf() { 121 | if err := config.Parse(*conf); err != nil { 122 | fmt.Println("cannot parse configuration file:", err) 123 | os.Exit(1) 124 | } 125 | } 126 | 127 | func ending() { 128 | c := make(chan os.Signal, 1) 129 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) 130 | select { 131 | case <-c: 132 | fmt.Printf("stop signal caught, stopping... pid=%d\n", os.Getpid()) 133 | } 134 | 135 | logger.Close() 136 | http.Shutdown() 137 | fmt.Println("sender stopped successfully") 138 | } 139 | 140 | func start() { 141 | runner.Init() 142 | fmt.Println("collector start, use configuration file:", *conf) 143 | fmt.Println("runner.cwd:", runner.Cwd) 144 | } 145 | 146 | func reportStart() { 147 | if err := report.GatherBase(); err != nil { 148 | fmt.Println("gatherBase fail: ", err) 149 | os.Exit(1) 150 | } 151 | 152 | go report.LoopReport() 153 | } 154 | 155 | func initWbem() { 156 | // This initialization prevents a memory leak on WMF 5+. See 157 | // https://github.com/prometheus-community/windows_exporter/issues/77 and 158 | // linked issues for details. 159 | // thanks prometheus windows exporter community for this issues. by yimeng 160 | logger.Debug("Initializing SWbemServices") 161 | 162 | s, err := wmi.InitializeSWbemServices(wmi.DefaultClient) 163 | if err != nil { 164 | log.Fatal(err) 165 | } 166 | wmi.DefaultClient.AllowMissingFields = true 167 | wmi.DefaultClient.SWbemServicesClient = s 168 | } 169 | -------------------------------------------------------------------------------- /sys/funcs/ntpCalc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Brett Vickers. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package ntp provides a simple mechanism for querying the current time 6 | // from a remote NTP server. This package only supports NTP client mode 7 | // behavior and version 4 of the NTP protocol. See RFC 5905. 8 | // Approach inspired by go-nuts post by Michael Hofmann: 9 | // https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/FlcdMU5fkLQ 10 | package funcs 11 | 12 | import ( 13 | "encoding/binary" 14 | "net" 15 | "time" 16 | ) 17 | 18 | type mode byte 19 | 20 | const ( 21 | reserved mode = 0 + iota 22 | symmetricActive 23 | symmetricPassive 24 | client 25 | server 26 | broadcast 27 | controlMessage 28 | reservedPrivate 29 | ) 30 | 31 | type ntpTime struct { 32 | Seconds uint32 33 | Fraction uint32 34 | } 35 | 36 | func (t ntpTime) UTC() time.Time { 37 | nsec := uint64(t.Seconds)*1e9 + (uint64(t.Fraction) * 1e9 >> 32) 38 | return time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(nsec)) 39 | } 40 | 41 | type msg struct { 42 | LiVnMode byte // Leap Indicator (2) + Version (3) + Mode (3) 43 | Stratum byte 44 | Poll byte 45 | Precision byte 46 | RootDelay uint32 47 | RootDispersion uint32 48 | ReferenceId uint32 49 | ReferenceTime ntpTime 50 | OriginTime ntpTime 51 | ReceiveTime ntpTime 52 | TransmitTime ntpTime 53 | } 54 | 55 | // SetVersion sets the NTP protocol version on the message. 56 | func (m *msg) SetVersion(v byte) { 57 | m.LiVnMode = (m.LiVnMode & 0xc7) | v<<3 58 | } 59 | 60 | // SetMode sets the NTP protocol mode on the message. 61 | func (m *msg) SetMode(md mode) { 62 | m.LiVnMode = (m.LiVnMode & 0xf8) | byte(md) 63 | } 64 | 65 | // Time returns the "receive time" from the remote NTP server 66 | // specifed as host. NTP client mode is used. 67 | func getTwoTime(host string, version byte) (time.Time, time.Time, error) { 68 | if version < 2 || version > 4 { 69 | panic("ntp: invalid version number") 70 | } 71 | 72 | raddr, err := net.ResolveUDPAddr("udp", host+":123") 73 | if err != nil { 74 | return time.Now(), time.Now(), err 75 | } 76 | 77 | con, err := net.DialUDP("udp", nil, raddr) 78 | if err != nil { 79 | return time.Now(), time.Now(), err 80 | } 81 | defer con.Close() 82 | con.SetDeadline(time.Now().Add(5 * time.Second)) 83 | 84 | m := new(msg) 85 | m.SetMode(client) 86 | m.SetVersion(version) 87 | 88 | err = binary.Write(con, binary.BigEndian, m) 89 | if err != nil { 90 | return time.Now(), time.Now(), err 91 | } 92 | 93 | err = binary.Read(con, binary.BigEndian, m) 94 | if err != nil { 95 | return time.Now(), time.Now(), err 96 | } 97 | 98 | t := m.ReceiveTime.UTC().Local() 99 | transmitTime := m.TransmitTime.UTC().Local() 100 | return t, transmitTime, nil 101 | } 102 | 103 | func getTime(host string, version byte) (time.Time, error) { 104 | if version < 2 || version > 4 { 105 | panic("ntp: invalid version number") 106 | } 107 | 108 | raddr, err := net.ResolveUDPAddr("udp", host+":123") 109 | if err != nil { 110 | return time.Now(), err 111 | } 112 | 113 | con, err := net.DialUDP("udp", nil, raddr) 114 | if err != nil { 115 | return time.Now(), err 116 | } 117 | defer con.Close() 118 | con.SetDeadline(time.Now().Add(5 * time.Second)) 119 | 120 | m := new(msg) 121 | m.SetMode(client) 122 | m.SetVersion(version) 123 | 124 | err = binary.Write(con, binary.BigEndian, m) 125 | if err != nil { 126 | return time.Now(), err 127 | } 128 | 129 | err = binary.Read(con, binary.BigEndian, m) 130 | if err != nil { 131 | return time.Now(), err 132 | } 133 | 134 | t := m.ReceiveTime.UTC().Local() 135 | return t, nil 136 | } 137 | 138 | // TimeV returns the "receive time" from the remote NTP server 139 | // specifed as host. Use the NTP client mode with the requested 140 | // version number (2, 3, or 4). 141 | func NtpTimeV(host string, version byte) (time.Time, error) { 142 | return getTime(host, version) 143 | } 144 | 145 | // Time returns the "receive time" from the remote NTP server 146 | // specifed as host. NTP client mode version 4 is used. 147 | func NtpTime(host string) (time.Time, error) { 148 | return getTime(host, 4) 149 | } 150 | 151 | // Time returns the "receive time" from the remote NTP server 152 | // specifed as host. NTP client mode version 4 is used. 153 | func NtpTwoTime(host string) (time.Time, time.Time, error) { 154 | return getTwoTime(host, 4) 155 | } 156 | -------------------------------------------------------------------------------- /sys/funcs/push.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "math/rand" 8 | "net" 9 | "net/rpc" 10 | "reflect" 11 | "time" 12 | 13 | "github.com/n9e/win-collector/cache" 14 | "github.com/n9e/win-collector/config" 15 | "github.com/toolkits/pkg/logger" 16 | "github.com/ugorji/go/codec" 17 | 18 | "github.com/didi/nightingale/src/common/address" 19 | "github.com/didi/nightingale/src/common/dataobj" 20 | "github.com/n9e/win-collector/sys/identity" 21 | ) 22 | 23 | func Push(metricItems []*dataobj.MetricValue) error { 24 | var err error 25 | var items []*dataobj.MetricValue 26 | now := time.Now().Unix() 27 | for _, item := range metricItems { 28 | logger.Debug("->recv: ", item) 29 | if item.Endpoint == "" { 30 | item.Endpoint = identity.GetIdent() 31 | } 32 | err = item.CheckValidity(now) 33 | if err != nil { 34 | msg := fmt.Errorf("metric:%v err:%v", item, err) 35 | logger.Warning(msg) 36 | return msg 37 | } 38 | if item.CounterType == dataobj.COUNTER { 39 | if err := CounterToGauge(item); err != nil { 40 | //旧值不存在则不推送 41 | logger.Warning(err) 42 | continue 43 | } 44 | } 45 | logger.Debug("push item: ", item) 46 | items = append(items, item) 47 | } 48 | 49 | addrs := address.GetRPCAddresses("transfer") 50 | count := len(addrs) 51 | retry := 0 52 | for { 53 | for _, i := range rand.Perm(count) { 54 | addr := addrs[i] 55 | reply, err := rpcCall(addr, items) 56 | if err != nil { 57 | logger.Error(err) 58 | continue 59 | } else { 60 | if reply.Msg != "ok" { 61 | err = fmt.Errorf("some item push err: %s", reply.Msg) 62 | logger.Error(err) 63 | } 64 | return err 65 | } 66 | } 67 | 68 | time.Sleep(time.Millisecond * 500) 69 | 70 | retry += 1 71 | if retry == 3 { 72 | retry = 0 73 | break 74 | } 75 | } 76 | return err 77 | } 78 | 79 | func rpcCall(addr string, items []*dataobj.MetricValue) (dataobj.TransferResp, error) { 80 | var reply dataobj.TransferResp 81 | var err error 82 | 83 | client := rpcClients.Get(addr) 84 | if client == nil { 85 | client, err = rpcClient(addr) 86 | if err != nil { 87 | return reply, err 88 | } else { 89 | affected := rpcClients.Put(addr, client) 90 | if !affected { 91 | defer func() { 92 | // 我尝试把自己这个client塞进map失败,说明已经有一个client塞进去了,那我自己用完了就关闭 93 | client.Close() 94 | }() 95 | } 96 | } 97 | } 98 | 99 | timeout := time.Duration(8) * time.Second 100 | done := make(chan error, 1) 101 | 102 | go func() { 103 | err := client.Call(config.Config.Server.RpcMethod, items, &reply) 104 | done <- err 105 | }() 106 | 107 | select { 108 | case <-time.After(timeout): 109 | logger.Warningf("rpc call timeout, transfer addr: %s", addr) 110 | rpcClients.Put(addr, nil) 111 | client.Close() 112 | return reply, fmt.Errorf("%s rpc call timeout", addr) 113 | case err := <-done: 114 | if err != nil { 115 | rpcClients.Del(addr) 116 | client.Close() 117 | return reply, fmt.Errorf("%s rpc call done, but fail: %v", addr, err) 118 | } 119 | } 120 | 121 | return reply, nil 122 | } 123 | 124 | func rpcClient(addr string) (*rpc.Client, error) { 125 | conn, err := net.DialTimeout("tcp", addr, time.Second*3) 126 | if err != nil { 127 | err = fmt.Errorf("dial transfer %s fail: %v", addr, err) 128 | logger.Error(err) 129 | return nil, err 130 | } 131 | 132 | var bufConn = struct { 133 | io.Closer 134 | *bufio.Reader 135 | *bufio.Writer 136 | }{conn, bufio.NewReader(conn), bufio.NewWriter(conn)} 137 | 138 | var mh codec.MsgpackHandle 139 | mh.MapType = reflect.TypeOf(map[string]interface{}(nil)) 140 | 141 | rpcCodec := codec.MsgpackSpecRpc.ClientCodec(bufConn, &mh) 142 | client := rpc.NewClientWithCodec(rpcCodec) 143 | return client, nil 144 | } 145 | 146 | func CounterToGauge(item *dataobj.MetricValue) error { 147 | key := item.PK() 148 | 149 | old, exists := cache.MetricHistory.Get(key) 150 | cache.MetricHistory.Set(key, *item) 151 | 152 | if !exists { 153 | return fmt.Errorf("not found old item:%v", item) 154 | } 155 | 156 | if old.Value > item.Value { 157 | return fmt.Errorf("item:%v old value:%v greater than new value:%v", item, old.Value, item.Value) 158 | } 159 | 160 | if old.Timestamp >= item.Timestamp { 161 | return fmt.Errorf("item:%v old timestamp:%v greater than new timestamp:%v", item, old.Timestamp, item.Timestamp) 162 | } 163 | 164 | item.ValueUntyped = (item.Value - old.Value) / float64(item.Timestamp-old.Timestamp) 165 | item.CounterType = dataobj.GAUGE 166 | return nil 167 | } 168 | -------------------------------------------------------------------------------- /sys/funcs/cpustat.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | 8 | "github.com/didi/nightingale/src/common/dataobj" 9 | "github.com/shirou/gopsutil/cpu" 10 | "github.com/toolkits/pkg/logger" 11 | ) 12 | 13 | const ( 14 | historyCount int = 2 15 | ) 16 | 17 | type CpuStats struct { 18 | User float64 19 | System float64 20 | Idle float64 21 | Irq float64 22 | Total float64 23 | } 24 | 25 | type ProcStat struct { 26 | Cpu CpuStats 27 | Cpus []CpuStats 28 | } 29 | 30 | var ( 31 | psHistory [historyCount]*ProcStat 32 | psLock = new(sync.RWMutex) 33 | ) 34 | 35 | func CurrentProcStat() (procStat ProcStat, err error) { 36 | psPer, err := cpu.Times(true) 37 | if err != nil { 38 | return 39 | } 40 | var cpuTotal CpuStats 41 | var cpus []CpuStats 42 | for _, ps := range psPer { 43 | var c CpuStats 44 | c.User = ps.User 45 | cpuTotal.User += c.User 46 | 47 | c.System = ps.System 48 | cpuTotal.System += c.System 49 | 50 | c.Idle = ps.Idle 51 | cpuTotal.Idle += c.Idle 52 | 53 | c.Irq = ps.Irq 54 | cpuTotal.Irq += c.Irq 55 | 56 | c.Total = ps.Total() 57 | cpuTotal.Total += c.Total 58 | 59 | cpus = append(cpus, c) 60 | } 61 | procStat.Cpu = cpuTotal 62 | procStat.Cpus = cpus 63 | return 64 | } 65 | 66 | func PrepareCpuStat() { 67 | d := time.Duration(3) * time.Second 68 | for { 69 | err := UpdateCpuStat() 70 | if err != nil { 71 | logger.Error("update cpu stat fail", err) 72 | } 73 | time.Sleep(d) 74 | } 75 | } 76 | 77 | func UpdateCpuStat() error { 78 | ps, err := CurrentProcStat() 79 | if err != nil { 80 | return err 81 | } 82 | psLock.Lock() 83 | defer psLock.Unlock() 84 | for i := historyCount - 1; i > 0; i-- { 85 | psHistory[i] = psHistory[i-1] 86 | } 87 | psHistory[0] = &ps 88 | return nil 89 | } 90 | 91 | func deltaTotal() float64 { 92 | if len(psHistory) < 2 { 93 | return 0 94 | } 95 | return psHistory[0].Cpu.Total - psHistory[1].Cpu.Total 96 | } 97 | 98 | func CpuIdles() (res []*CpuStats) { 99 | psLock.RLock() 100 | defer psLock.RUnlock() 101 | if len(psHistory) < 2 { 102 | return 103 | } 104 | if len(psHistory[0].Cpus) != len(psHistory[1].Cpus) { 105 | return 106 | } 107 | for i, c := range psHistory[0].Cpus { 108 | stats := new(CpuStats) 109 | dt := c.Total - psHistory[1].Cpus[i].Total 110 | if dt == 0 { 111 | return 112 | } 113 | invQuotient := 100.00 / float64(dt) 114 | stats.Idle = float64(c.Idle-psHistory[1].Cpus[i].Idle) * invQuotient 115 | stats.User = float64(c.User-psHistory[1].Cpus[i].User) * invQuotient 116 | stats.System = float64(c.System-psHistory[1].Cpus[i].System) * invQuotient 117 | stats.Irq = float64(c.Irq-psHistory[1].Cpus[i].Irq) * invQuotient 118 | res = append(res, stats) 119 | } 120 | return 121 | } 122 | 123 | func CpuIdle() float64 { 124 | psLock.RLock() 125 | defer psLock.RUnlock() 126 | dt := deltaTotal() 127 | if dt == 0 { 128 | return 0.0 129 | } 130 | invQuotient := 100.00 / float64(dt) 131 | return float64(psHistory[0].Cpu.Idle-psHistory[1].Cpu.Idle) * invQuotient 132 | } 133 | 134 | func CpuUser() float64 { 135 | psLock.Lock() 136 | defer psLock.Unlock() 137 | dt := deltaTotal() 138 | if dt == 0 { 139 | return 0.0 140 | } 141 | invQuotient := 100.00 / float64(dt) 142 | return float64(psHistory[0].Cpu.User-psHistory[1].Cpu.User) * invQuotient 143 | } 144 | 145 | func CpuSystem() float64 { 146 | psLock.RLock() 147 | defer psLock.RUnlock() 148 | dt := deltaTotal() 149 | if dt == 0 { 150 | return 0.0 151 | } 152 | invQuotient := 100.00 / float64(dt) 153 | return float64(psHistory[0].Cpu.System-psHistory[1].Cpu.System) * invQuotient 154 | } 155 | 156 | func CpuIrq() float64 { 157 | psLock.RLock() 158 | defer psLock.RUnlock() 159 | dt := deltaTotal() 160 | if dt == 0 { 161 | return 0.0 162 | } 163 | invQuotient := 100.00 / float64(dt) 164 | return float64(psHistory[0].Cpu.Irq-psHistory[1].Cpu.Irq) * invQuotient 165 | } 166 | 167 | func CpuPrepared() bool { 168 | psLock.RLock() 169 | defer psLock.RUnlock() 170 | return psHistory[1] != nil 171 | } 172 | 173 | func CpuMetrics() []*dataobj.MetricValue { 174 | if !CpuPrepared() { 175 | return []*dataobj.MetricValue{} 176 | } 177 | 178 | var ret []*dataobj.MetricValue 179 | 180 | cpuIdleVal := CpuIdle() 181 | idle := GaugeValue("cpu.idle", cpuIdleVal) 182 | util := GaugeValue("cpu.util", 100.0-cpuIdleVal) 183 | user := GaugeValue("cpu.user", CpuUser()) 184 | system := GaugeValue("cpu.sys", CpuSystem()) 185 | irq := GaugeValue("cpu.irq", CpuIrq()) 186 | ret = []*dataobj.MetricValue{idle, util, user, system, irq} 187 | 188 | idles := CpuIdles() 189 | for i, stats := range idles { 190 | tags := fmt.Sprintf("core=%d", i) 191 | ret = append(ret, GaugeValue("cpu.core.idle", stats.Idle, tags)) 192 | ret = append(ret, GaugeValue("cpu.core.util", 100.0-stats.Idle, tags)) 193 | ret = append(ret, GaugeValue("cpu.core.user", stats.User, tags)) 194 | ret = append(ret, GaugeValue("cpu.core.sys", stats.System, tags)) 195 | ret = append(ret, GaugeValue("cpu.core.irq", stats.Irq, tags)) 196 | } 197 | 198 | return ret 199 | } 200 | -------------------------------------------------------------------------------- /sys/funcs/ifstat.go: -------------------------------------------------------------------------------- 1 | package funcs 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "time" 7 | 8 | "github.com/n9e/win-collector/sys" 9 | 10 | "github.com/StackExchange/wmi" 11 | "github.com/didi/nightingale/src/common/dataobj" 12 | "github.com/shirou/gopsutil/net" 13 | "github.com/toolkits/pkg/logger" 14 | ) 15 | 16 | func netIoCountersStat(ifacePrefix []string) ([]net.IOCountersStat, error) { 17 | netIOCounter, err := net.IOCounters(true) 18 | netIfs := []net.IOCountersStat{} 19 | for _, iface := range ifacePrefix { 20 | for _, netIf := range netIOCounter { 21 | logger.Debug("discover netif names: ", netIf.Name) 22 | if strings.Contains(netIf.Name, iface) { 23 | logger.Debug("match netif names: ", netIf.Name) 24 | netIfs = append(netIfs, netIf) 25 | } 26 | } 27 | } 28 | return netIfs, err 29 | } 30 | 31 | type Win32_NetworkAdapter struct { 32 | Name string 33 | NetConnectionID string 34 | Speed uint64 35 | NetEnabled bool 36 | } 37 | 38 | func NetworkAdapterData(NetConnectionID string) ([]Win32_NetworkAdapter, error) { 39 | 40 | var dst []Win32_NetworkAdapter 41 | Query := `SELECT 42 | Name, 43 | NetConnectionID, 44 | Speed, 45 | NetEnabled 46 | FROM Win32_NetworkAdapter 47 | WHERE NetConnectionID = '` + NetConnectionID + `'` 48 | err := wmi.Query(Query, &dst) 49 | 50 | return dst, err 51 | } 52 | 53 | type CumIfStat struct { 54 | inBytes uint64 55 | outBytes uint64 56 | inPackets uint64 57 | outPackets uint64 58 | inDrop uint64 59 | outDrop uint64 60 | inErr uint64 61 | outErr uint64 62 | speed uint64 63 | } 64 | 65 | var ( 66 | historyIfStat map[string]CumIfStat 67 | lastTime time.Time 68 | ) 69 | 70 | func netMetrics(ifacePrefix []string) (ret []*dataobj.MetricValue) { 71 | netIfs, err := netIoCountersStat(ifacePrefix) 72 | if err != nil { 73 | logger.Error("get network iocounters failed: ", err) 74 | return []*dataobj.MetricValue{} 75 | } 76 | now := time.Now() 77 | newIfStat := make(map[string]CumIfStat) 78 | for _, netIf := range netIfs { 79 | ifstat := CumIfStat{ 80 | inBytes: netIf.BytesRecv, 81 | outBytes: netIf.BytesSent, 82 | inPackets: netIf.PacketsRecv, 83 | outPackets: netIf.PacketsSent, 84 | inDrop: netIf.Dropin, 85 | outDrop: netIf.Dropout, 86 | inErr: netIf.Errin, 87 | outErr: netIf.Errout, 88 | } 89 | networkAdapter, err := NetworkAdapterData(netIf.Name) 90 | if err != nil || len(networkAdapter) == 0 { 91 | logger.Error("get network adapter speed failed: ", netIf.Name, err) 92 | } else { 93 | if !networkAdapter[0].NetEnabled { 94 | logger.Debug("network adapter is not enbaled, ignore: ", netIf.Name) 95 | continue 96 | } 97 | ifstat.speed = networkAdapter[0].Speed 98 | } 99 | 100 | newIfStat[netIf.Name] = ifstat 101 | } 102 | interval := now.Unix() - lastTime.Unix() 103 | lastTime = now 104 | 105 | var totalBandwidth uint64 = 0 106 | inTotalUsed := 0.0 107 | outTotalUsed := 0.0 108 | 109 | if historyIfStat == nil { 110 | historyIfStat = newIfStat 111 | return []*dataobj.MetricValue{} 112 | } 113 | for iface, stat := range newIfStat { 114 | tags := fmt.Sprintf("iface=%s", strings.Replace(iface, " ", "", -1)) 115 | oldStat := historyIfStat[iface] 116 | inbytes := float64(stat.inBytes-oldStat.inBytes) / float64(interval) 117 | if inbytes < 0 { 118 | inbytes = 0 119 | } 120 | 121 | inbits := inbytes * 8 122 | ret = append(ret, GaugeValue("net.in.bits", inbits, tags)) 123 | 124 | outbytes := float64(stat.outBytes-oldStat.outBytes) / float64(interval) 125 | if outbytes < 0 { 126 | outbytes = 0 127 | } 128 | outbits := outbytes * 8 129 | ret = append(ret, GaugeValue("net.out.bits", outbits, tags)) 130 | 131 | v := float64(stat.inDrop-oldStat.inDrop) / float64(interval) 132 | if v < 0 { 133 | v = 0 134 | } 135 | ret = append(ret, GaugeValue("net.in.dropped", v, tags)) 136 | 137 | v = float64(stat.outDrop-oldStat.outDrop) / float64(interval) 138 | if v < 0 { 139 | v = 0 140 | } 141 | ret = append(ret, GaugeValue("net.out.dropped", v, tags)) 142 | 143 | v = float64(stat.inPackets-oldStat.inPackets) / float64(interval) 144 | if v < 0 { 145 | v = 0 146 | } 147 | ret = append(ret, GaugeValue("net.in.pps", v, tags)) 148 | 149 | v = float64(stat.outPackets-oldStat.outPackets) / float64(interval) 150 | if v < 0 { 151 | v = 0 152 | } 153 | ret = append(ret, GaugeValue("net.out.pps", v, tags)) 154 | 155 | v = float64(stat.inErr-oldStat.inErr) / float64(interval) 156 | if v < 0 { 157 | v = 0 158 | } 159 | ret = append(ret, GaugeValue("net.in.errs", v, tags)) 160 | 161 | v = float64(stat.outErr-oldStat.outErr) / float64(interval) 162 | if v < 0 { 163 | v = 0 164 | } 165 | ret = append(ret, GaugeValue("net.out.errs", v, tags)) 166 | 167 | if strings.HasPrefix(iface, "vnet") { //vnet采集到的stat.speed不准确,不计算percent 168 | continue 169 | } 170 | 171 | inTotalUsed += inbits 172 | 173 | inPercent := float64(inbits) * 100 / float64(stat.speed) 174 | 175 | if inPercent < 0 || stat.speed <= 0 { 176 | ret = append(ret, GaugeValue("net.in.percent", 0, tags)) 177 | } else { 178 | ret = append(ret, GaugeValue("net.in.percent", inPercent, tags)) 179 | } 180 | 181 | outTotalUsed += outbits 182 | outPercent := float64(outbits) * 100 / float64(stat.speed) 183 | if outPercent < 0 || stat.speed <= 0 { 184 | ret = append(ret, GaugeValue("net.out.percent", 0, tags)) 185 | } else { 186 | ret = append(ret, GaugeValue("net.out.percent", outPercent, tags)) 187 | } 188 | 189 | ret = append(ret, GaugeValue("net.bandwidth.mbits", stat.speed, tags)) 190 | totalBandwidth += stat.speed 191 | } 192 | 193 | ret = append(ret, GaugeValue("net.bandwidth.mbits.total", totalBandwidth)) 194 | ret = append(ret, GaugeValue("net.in.bits.total", inTotalUsed)) 195 | ret = append(ret, GaugeValue("net.out.bits.total", outTotalUsed)) 196 | 197 | if totalBandwidth <= 0 { 198 | ret = append(ret, GaugeValue("net.in.bits.total.percent", 0)) 199 | ret = append(ret, GaugeValue("net.out.bits.total.percent", 0)) 200 | } else { 201 | inTotalPercent := float64(inTotalUsed) / float64(totalBandwidth) * 100 202 | ret = append(ret, GaugeValue("net.in.bits.total.percent", inTotalPercent)) 203 | 204 | outTotalPercent := float64(outTotalUsed) / float64(totalBandwidth) * 100 205 | ret = append(ret, GaugeValue("net.out.bits.total.percent", outTotalPercent)) 206 | } 207 | 208 | historyIfStat = newIfStat 209 | return ret 210 | } 211 | 212 | func NetMetrics() (ret []*dataobj.MetricValue) { 213 | return netMetrics(sys.Config.IfacePrefix) 214 | } 215 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= 4 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 5 | cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= 6 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 7 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 8 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 9 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 10 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 11 | cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM= 12 | cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= 13 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 14 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 15 | cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= 16 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 17 | cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= 18 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 19 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 20 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 21 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 22 | collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= 23 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 24 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 25 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 26 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 27 | github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= 28 | github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= 29 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 30 | github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= 31 | github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= 32 | github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= 33 | github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= 34 | github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= 35 | github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= 36 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 37 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 38 | github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= 39 | github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= 40 | github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= 41 | github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= 42 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 43 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 44 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 45 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 46 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 47 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 48 | github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= 49 | github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= 50 | github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= 51 | github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= 52 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 53 | github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 54 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 55 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 56 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 57 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 58 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 59 | github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= 60 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 61 | github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 62 | github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= 63 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 64 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 65 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 66 | github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= 67 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 68 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 69 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 70 | github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o= 71 | github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= 72 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 73 | github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= 74 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= 75 | github.com/dgryski/go-tsz v0.0.0-20180227144327-03b7d791f4fe/go.mod h1:ft6P746mYUFQBCsH3OkFBG8FtjLx1XclLMo+9Jh1Yts= 76 | github.com/didi/nightingale v0.0.0-20201018021739-93c35fd0ec44 h1:9VvxSq3L1uhjGaLKNa/qFJoyuOPyAMNUVK6s+FlsmTo= 77 | github.com/didi/nightingale v0.0.0-20201018021739-93c35fd0ec44/go.mod h1:Yoi/P6BAv0PFcZP4ifttpH6CjslylQwB9EP+flDKL5w= 78 | github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= 79 | github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= 80 | github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= 81 | github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= 82 | github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= 83 | github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= 84 | github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= 85 | github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 86 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 87 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 88 | github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 89 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 90 | github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= 91 | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= 92 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 93 | github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM= 94 | github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= 95 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 96 | github.com/gin-contrib/pprof v1.3.0 h1:G9eK6HnbkSqDZBYbzG4wrjCsA4e+cvYAHUZw6W+W9K0= 97 | github.com/gin-contrib/pprof v1.3.0/go.mod h1:waMjT1H9b179t3CxuG1cV3DHpga6ybizwfBaM5OXaB0= 98 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 99 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 100 | github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= 101 | github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= 102 | github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= 103 | github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= 104 | github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= 105 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 106 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 107 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 108 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 109 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 110 | github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= 111 | github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= 112 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= 113 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 114 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 115 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 116 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 117 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 118 | github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= 119 | github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= 120 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 121 | github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= 122 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 123 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 124 | github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= 125 | github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= 126 | github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 127 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 128 | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 129 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 130 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 131 | github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= 132 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 133 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 134 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 135 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 136 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 137 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 138 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 139 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 140 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 141 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 142 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 143 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 144 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 145 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 146 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 147 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 148 | github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 149 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 150 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 151 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 152 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 153 | github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= 154 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 155 | github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= 156 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 157 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 158 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 159 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 160 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 161 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 162 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 163 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 164 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 165 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 166 | github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 167 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= 168 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 169 | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= 170 | github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 171 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 172 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 173 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 174 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 175 | github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= 176 | github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= 177 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 178 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 179 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 180 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= 181 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 182 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= 183 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= 184 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 185 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 186 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 187 | github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= 188 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 189 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 190 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 191 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 192 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 193 | github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= 194 | github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= 195 | github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= 196 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 197 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 198 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 199 | github.com/influxdata/flux v0.65.0/go.mod h1:BwN2XG2lMszOoquQaFdPET8FRQfrXiZsWmcMO9rkaVY= 200 | github.com/influxdata/influxdb v1.8.0/go.mod h1:SIzcnsjaHRFpmlxpJ4S3NT64qtEKYweNTUMb/vh0OMQ= 201 | github.com/influxdata/influxql v1.1.0/go.mod h1:KpVI7okXjK6PRi3Z5B+mtKZli+R1DnZgb3N+tzevNgo= 202 | github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= 203 | github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= 204 | github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= 205 | github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= 206 | github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= 207 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 208 | github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 209 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 210 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 211 | github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= 212 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 213 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 214 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 215 | github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= 216 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 217 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 218 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 219 | github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= 220 | github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= 221 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 222 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 223 | github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 224 | github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 225 | github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= 226 | github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= 227 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 228 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 229 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 230 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 231 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 232 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 233 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 234 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 235 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 236 | github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= 237 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 238 | github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= 239 | github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 240 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 241 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 242 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 243 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 244 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 245 | github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 246 | github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 247 | github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 248 | github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= 249 | github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= 250 | github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= 251 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 252 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 253 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= 254 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 255 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 256 | github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= 257 | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= 258 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 259 | github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= 260 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 261 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 262 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 263 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 264 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 265 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 266 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 267 | github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= 268 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 269 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 270 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 271 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 272 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 273 | github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 274 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 275 | github.com/open-falcon/rrdlite v0.0.0-20200214140804-bf5829f786ad/go.mod h1:pXROoG0iWVnqq4u2Ii97S0Vt9iCTVypshsl9HXsV6cs= 276 | github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 277 | github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 278 | github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= 279 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 280 | github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= 281 | github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= 282 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 283 | github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= 284 | github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= 285 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 286 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 287 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 288 | github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= 289 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 290 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 291 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 292 | github.com/pquerna/cachecontrol v0.0.0-20200819021114-67c6ae64274f/go.mod h1:hoLfEwdY11HjRfKFH6KqnPsfxlo3BP6bJehpDv8t6sQ= 293 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 294 | github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= 295 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= 296 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 297 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 298 | github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 299 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 300 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 301 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 302 | github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 303 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 304 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 305 | github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= 306 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 307 | github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 308 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 309 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 310 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= 311 | github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 312 | github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 313 | github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= 314 | github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62 h1:pyecQtsPmlkCsMkYhT5iZ+sUXuwee+OvfuJjinEA3ko= 315 | github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62/go.mod h1:65XQgovT59RWatovFwnwocoUxiI/eENTnOY5GK3STuY= 316 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 317 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 318 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 319 | github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 320 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= 321 | github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= 322 | github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= 323 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 324 | github.com/shirou/gopsutil v2.20.7+incompatible h1:Ymv4OD12d6zm+2yONe39VSmp2XooJe8za7ngOLW/o/w= 325 | github.com/shirou/gopsutil v2.20.7+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= 326 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 327 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= 328 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 329 | github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= 330 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 331 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 332 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= 333 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 334 | github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= 335 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 336 | github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= 337 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 338 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 339 | github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= 340 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 341 | github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 342 | github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= 343 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 344 | github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= 345 | github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= 346 | github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 347 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 348 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 349 | github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 350 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 351 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 352 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 353 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 354 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 355 | github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= 356 | github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 357 | github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= 358 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 359 | github.com/toolkits/pkg v1.1.3 h1:cjZMz9hmuTv4v7ivYERA9mWJCLKyr8JMd4S+CL/YzMM= 360 | github.com/toolkits/pkg v1.1.3/go.mod h1:ge83E8FQqUnFk+2wtVtZ8kvbmoSjE1l8FP3f+qmR0fY= 361 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= 362 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 363 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 364 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 365 | github.com/unrolled/render v1.0.3/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM= 366 | github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= 367 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 368 | github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= 369 | github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= 370 | github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= 371 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 372 | go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 373 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 374 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 375 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 376 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 377 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 378 | go.uber.org/automaxprocs v1.3.0 h1:II28aZoGdaglS5vVNnspf28lnZpXScxtIozx1lAjdb0= 379 | go.uber.org/automaxprocs v1.3.0/go.mod h1:9CWT6lKIep8U41DDaPiH6eFscnTyjfTANNQNx6LrIcA= 380 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 381 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 382 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 383 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 384 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 385 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 386 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 387 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 388 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 389 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 390 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 391 | golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig= 392 | golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 393 | golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 394 | golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 395 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 396 | golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 397 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 398 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 399 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 400 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 401 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 402 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 403 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 404 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 405 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 406 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 407 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 408 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 409 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 410 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 411 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 412 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 413 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 414 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 415 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 416 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 417 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 418 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 419 | golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 420 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 421 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 422 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 423 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 424 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 425 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 426 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 427 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 428 | golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 429 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 430 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 431 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 432 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 433 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 434 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 435 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 436 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 437 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 438 | golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 439 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 440 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 441 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 442 | golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 443 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 444 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 445 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 446 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 447 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 448 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 449 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 450 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 451 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 452 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 453 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 454 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 455 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 456 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 457 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 458 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 459 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 460 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 461 | golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 462 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 463 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 464 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 465 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 466 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 467 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 468 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 469 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 470 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 471 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 472 | golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 473 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 474 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 475 | golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d h1:QQrM/CCYEzTs91GZylDCQjGHudbPTxF/1fvXdVh5lMo= 476 | golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 477 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 478 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 479 | golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 480 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 481 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 482 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 483 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 484 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 485 | golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 486 | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 487 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 488 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 489 | golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 490 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 491 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 492 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 493 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 494 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 495 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 496 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 497 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 498 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 499 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 500 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 501 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 502 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 503 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 504 | golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 505 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 506 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 507 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 508 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 509 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 510 | golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 511 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 512 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 513 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 514 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 515 | gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= 516 | gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= 517 | gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= 518 | gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 519 | gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 520 | gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= 521 | google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= 522 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 523 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 524 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 525 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 526 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 527 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 528 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 529 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 530 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 531 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 532 | google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 533 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 534 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 535 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 536 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 537 | google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 538 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 539 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 540 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 541 | google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 542 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 543 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 544 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 545 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 546 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 547 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 548 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 549 | google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 550 | google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 551 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 552 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 553 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 554 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 555 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 556 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 557 | gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= 558 | gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= 559 | gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= 560 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 561 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 562 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 563 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 564 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 565 | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= 566 | gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 567 | gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= 568 | gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 569 | gopkg.in/ldap.v3 v3.1.0 h1:DIDWEjI7vQWREh0S8X5/NFPCZ3MCVd55LmXKPW4XLGE= 570 | gopkg.in/ldap.v3 v3.1.0/go.mod h1:dQjCc0R0kfyFjIlWNMH1DORwUASZyDxo2Ry1B51dXaQ= 571 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 572 | gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 573 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 574 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 575 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 576 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 577 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 578 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 579 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= 580 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 581 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 582 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 583 | honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 584 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 585 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 586 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 587 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 588 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 589 | k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d/go.mod h1:3jediapYqJ2w1BFw7lAZPCx7scubsTfosqHkhXCWJKw= 590 | k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 591 | k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= 592 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 593 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 594 | sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= 595 | xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= 596 | xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= 597 | xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= 598 | xorm.io/core v0.7.3 h1:W8ws1PlrnkS1CZU1YWaYLMQcQilwAmQXU0BJDJon+H0= 599 | xorm.io/core v0.7.3/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= 600 | xorm.io/xorm v0.8.1 h1:4f2KXuQxVdaX3RdI3Fw81NzMiSpZeyCZt8m3sEVeIkQ= 601 | xorm.io/xorm v0.8.1/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY= 602 | --------------------------------------------------------------------------------