From 7433fffb4f4a5400313a0a8adb8d18a1adae752f Mon Sep 17 00:00:00 2001 From: Feng_Qi Date: Mon, 2 Jan 2017 23:28:58 +0800 Subject: [PATCH] version 4.0.5 --- README.md | 8 ++ cfg.example.json => cfg.json.example | 20 +++-- custom.json | 17 ++++ funcs/custmetric.go | 125 +++++++++++++++++++++++++++ funcs/funcs.go | 1 + g/cfg.go | 54 ++++-------- g/const.go | 3 +- g/customcfg.go | 55 ++++++++++++ g/hostcfg.go | 53 ++++++++++++ g/var.go | 10 ++- hosts.json | 6 ++ main.go | 9 +- 12 files changed, 315 insertions(+), 46 deletions(-) rename cfg.example.json => cfg.json.example (76%) create mode 100644 custom.json create mode 100644 funcs/custmetric.go create mode 100644 g/customcfg.go create mode 100644 g/hostcfg.go create mode 100644 hosts.json diff --git a/README.md b/README.md index 674d5ec..2ba145f 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,14 @@ swcollector需要部署到有交换机SNMP访问权限的服务器上。 "limitConcur": 1000, #交换机采集的并发限制 "limitCon": 4 #对于单台交换机上,多个指标采集的并发限制 }, + "switchhosts":{ + "enabled":true, + "hosts":"./hosts.json" #自定义的host与Ip地址对应表,如果配置,则上报时会用这里的host替换ip地址 + }, + "customMetrics":{ + "enabled":true, + "template":"./custom.json" #自定义的metric列表,如果配置,会根据这个配置文件,采集额外的自定义metric + }, "transfer": { "enabled": true, "addr": "127.0.0.1:8433", diff --git a/cfg.example.json b/cfg.json.example similarity index 76% rename from cfg.example.json rename to cfg.json.example index 6b32835..0dca322 100644 --- a/cfg.example.json +++ b/cfg.json.example @@ -2,21 +2,19 @@ "debug": true, "lowermetrics": true, "debugmetric":{ - "endpoints":["192.168.56.101","192.168.56.102"], - "metrics":["switch.if.In","switch.if.Out"], - "tags":"ifName=Fa0/1" + "endpoints":["vpn-lw"], + "metrics":["AnyconnectSession","ConnectionStat"], + "tags":"" }, "switch":{ "enabled": true, "ipRange":[ - "192.168.56.101/32", - "192.168.56.102-192.168.56.120", - "172.16.114.233" + "10.10..88.168" ], "gosnmp":true, "pingTimeout":300, "pingRetry":4, - "community":"public", + "community":"123456", "snmpTimeout":1000, "snmpRetry":5, "ignoreIface": ["Nu","NU","Vlan","Vl"], @@ -40,6 +38,14 @@ "limitConcur": 1000, "limitCon": 4 }, + "switchhosts":{ + "enabled":true, + "hosts":"./hosts.json" + }, + "customMetrics":{ + "enabled":true, + "template":"./custom.json" + }, "transfer": { "enabled": true, "addr": "127.0.0.1:8433", diff --git a/custom.json b/custom.json new file mode 100644 index 0000000..ca3488e --- /dev/null +++ b/custom.json @@ -0,0 +1,17 @@ +{ + "metrics": + [ + { + "metric":"AnyconnectSession", + "tag":"", + "type":"GUAGE", + "oid":"1.3.6.1.4.1.9.9.392.1.3.35" + }, + { + "metric":"ConnectionStat", + "tag":"", + "type":"GUAGE", + "oid":"1.3.6.1.4.1.9.9.147.1.2.2.2.1.5.40.6" + } + ] +} \ No newline at end of file diff --git a/funcs/custmetric.go b/funcs/custmetric.go new file mode 100644 index 0000000..3755683 --- /dev/null +++ b/funcs/custmetric.go @@ -0,0 +1,125 @@ +package funcs + +import ( + "errors" + "log" + + "time" + + "github.com/gaochao1/sw" + "github.com/gaochao1/swcollector/g" + "github.com/open-falcon/common/model" +) + +type CustM struct { + Ip string + custmMetrics []CustmMetric +} +type CustmMetric struct { + metric string + tag string + value float64 + metrictype string +} + +func CustMetrics() (L []*model.MetricValue) { + chs := make([]chan CustM, len(AliveIp)) + for i, ip := range AliveIp { + if ip != "" { + chs[i] = make(chan CustM) + go custMetrics(ip, chs[i]) + } + } + for _, ch := range chs { + custm := <-ch + for _, custmmetric := range custm.custmMetrics { + if custmmetric.metrictype == "GUAGE" { + L = append(L, GaugeValueIp(time.Now().Unix(), custm.Ip, custmmetric.metric, custmmetric.value, custmmetric.tag)) + } + if custmmetric.metrictype == "COUNTER" { + L = append(L, CounterValueIp(time.Now().Unix(), custm.Ip, custmmetric.metric, custmmetric.value, custmmetric.tag)) + } + + } + + } + + return L +} + +func custMetrics(ip string, ch chan CustM) { + var custm CustM + var custmmetric CustmMetric + var custmmetrics []CustmMetric + + for _, metric := range g.CustConfig().Metrics { + value, err := GetCustMetric(ip, g.Config().Switch.Community, metric.Oid, g.Config().Switch.SnmpTimeout, g.Config().Switch.SnmpRetry) + if err != nil { + log.Println(err) + } else { + custmmetric.metric = metric.Metric + custmmetric.metrictype = metric.Type + custmmetric.tag = metric.Tag + custmmetric.value = value + custmmetrics = append(custmmetrics, custmmetric) + } + } + custm.Ip = ip + custm.custmMetrics = custmmetrics + ch <- custm + return +} + +func GetCustMetric(ip, community, oid string, timeout, retry int) (float64, error) { + defer func() { + if r := recover(); r != nil { + log.Println(ip+" Recovered in CustomMetric, Oid is ", oid, r) + } + }() + method := "get" + var value float64 + var err error + for i := 0; i < retry; i++ { + snmpPDUs, err := sw.RunSnmp(ip, community, oid, method, timeout) + if len(snmpPDUs) > 0 && err == nil { + value, err = interfaceTofloat64(snmpPDUs[0].Value) + break + } + time.Sleep(100 * time.Millisecond) + } + + return value, err +} + +func interfaceTofloat64(v interface{}) (float64, error) { + var err error + switch value := v.(type) { + case int: + return float64(value), nil + case int8: + return float64(value), nil + case int16: + return float64(value), nil + case int32: + return float64(value), nil + case int64: + return float64(value), nil + case uint: + return float64(value), nil + case uint8: + return float64(value), nil + case uint16: + return float64(value), nil + case uint32: + return float64(value), nil + case uint64: + return float64(value), nil + case float32: + return float64(value), nil + case float64: + return value, nil + default: + err = errors.New("value is not digital") + return 0, err + } +} diff --git a/funcs/funcs.go b/funcs/funcs.go index 8dc58f1..801d0e4 100644 --- a/funcs/funcs.go +++ b/funcs/funcs.go @@ -22,6 +22,7 @@ func BuildMappers() { MemMetrics, PingMetrics, ConnMetrics, + CustMetrics, }, Interval: interval, }, diff --git a/g/cfg.go b/g/cfg.go index ee30f10..3980bd4 100644 --- a/g/cfg.go +++ b/g/cfg.go @@ -3,7 +3,6 @@ package g import ( "encoding/json" "log" - "os" "sync" "github.com/toolkits/file" @@ -68,15 +67,25 @@ type HttpConfig struct { Listen string `json:"listen"` } +type SwitchHostsConfig struct { + Enabled bool `json:enabled` + Hosts string `json:hosts` +} + +type CustomMetricsConfig struct { + Enabled bool `json:enbaled` + Template string `json:template` +} + type GlobalConfig struct { - Debug bool `json:"debug"` - Debugmetric *DebugmetricConfig `json:"debugmetric` - IP string `json:"ip"` - Hostname string `json:"hostname"` - Switch *SwitchConfig `json:"switch"` - Heartbeat *HeartbeatConfig `json:"heartbeat"` - Transfer *TransferConfig `json:"transfer"` - Http *HttpConfig `json:"http"` + Debug bool `json:"debug"` + Debugmetric *DebugmetricConfig `json:"debugmetric` + Switch *SwitchConfig `json:"switch"` + Heartbeat *HeartbeatConfig `json:"heartbeat"` + Transfer *TransferConfig `json:"transfer"` + SwitchHosts *SwitchHostsConfig `json:switchhosts` + CustomMetrics *CustomMetricsConfig `json:customMetrics` + Http *HttpConfig `json:"http"` } var ( @@ -91,33 +100,6 @@ func Config() *GlobalConfig { return config } -func Hostname() (string, error) { - hostname := Config().Hostname - if hostname != "" { - return hostname, nil - } - - hostname, err := os.Hostname() - if err != nil { - log.Println("ERROR: os.Hostname() fail", err) - } - return hostname, err -} - -func IP() string { - ip := Config().IP - if ip != "" { - // use ip in configuration - return ip - } - - if len(LocalIps) > 0 { - ip = LocalIps[0] - } - - return ip -} - func ParseConfig(cfg string) { if cfg == "" { log.Fatalln("use -c to specify configuration file") diff --git a/g/const.go b/g/const.go index 75edbcc..2d8d16b 100644 --- a/g/const.go +++ b/g/const.go @@ -17,7 +17,8 @@ import ( // 4.0.1 fix sometimes ifstat pannic // 4.0.2 fix speedpercent bug // 4.0.4 add lock on map;add limconn for switch snmp request +// 4.0.5 add custom metric,custom host const ( - VERSION = "4.0.4" + VERSION = "4.0.5" COLLECT_INTERVAL = time.Second ) diff --git a/g/customcfg.go b/g/customcfg.go new file mode 100644 index 0000000..7ea4e63 --- /dev/null +++ b/g/customcfg.go @@ -0,0 +1,55 @@ +package g + +import ( + "encoding/json" + "log" + + "sync" + + "github.com/toolkits/file" +) + +type MetricConfig struct { + Metric string `json:metric` + Tag string `json:tag` + Type string `json:type` + Oid string `json:oid` +} +type CustomConfig struct { + Metrics []*MetricConfig `json:"metrics` +} + +var ( + CustConfigFile string + custconfig *CustomConfig + custlock = new(sync.RWMutex) +) + +func CustConfig() *CustomConfig { + custlock.RLock() + defer custlock.RUnlock() + return custconfig +} + +func ParseCustConfig(cfg string) { + + if !file.IsExist(cfg) { + log.Fatalln("config file:", cfg, "is not existent") + } + CustConfigFile = cfg + configContent, err := file.ToTrimString(cfg) + if err != nil { + log.Fatalln("read config file:", cfg, "fail:", err) + } + var c CustomConfig + err = json.Unmarshal([]byte(configContent), &c) + if err != nil { + log.Fatalln("parse config file:", cfg, "fail:", err) + } + custlock.Lock() + defer custlock.Unlock() + custconfig = &c + + log.Println("read customconfig file:", cfg, "successfully") + +} diff --git a/g/hostcfg.go b/g/hostcfg.go new file mode 100644 index 0000000..7699785 --- /dev/null +++ b/g/hostcfg.go @@ -0,0 +1,53 @@ +package g + +import ( + "encoding/json" + "log" + + "sync" + + "github.com/toolkits/file" +) + +type HostsConfig struct { + Hosts map[string]string `json:"hosts"` +} + +var ( + HostConfigFile string + hostconfig *HostsConfig + hostlock = new(sync.RWMutex) +) + +func HostConfig() *HostsConfig { + hostlock.RLock() + defer hostlock.RUnlock() + return hostconfig +} + +func ParseHostConfig(cfg string) { + if !file.IsExist(cfg) { + log.Fatalln("config file:", cfg, "is not existent") + } + + HostConfigFile = cfg + + configContent, err := file.ToTrimString(cfg) + if err != nil { + log.Fatalln("read config file:", cfg, "fail:", err) + } + + var c HostsConfig + err = json.Unmarshal([]byte(configContent), &c) + if err != nil { + log.Fatalln("parse config file:", cfg, "fail:", err) + } + + hostlock.Lock() + defer hostlock.Unlock() + + hostconfig = &c + + log.Println("read hostconfig file:", cfg, "successfully") + +} diff --git a/g/var.go b/g/var.go index c3dbafc..c2aa704 100644 --- a/g/var.go +++ b/g/var.go @@ -55,6 +55,15 @@ func SendToTransfer(metrics []*model.MetricValue) { debug_tags := Config().Debugmetric.Tags debug_Tags := strings.Split(debug_tags, ",") + if Config().SwitchHosts.Enabled { + hosts := HostConfig().Hosts + for i, metric := range metrics { + if hostname, ok := hosts[metric.Endpoint]; ok { + metrics[i].Endpoint = hostname + } + } + } + if debug { for _, metric := range metrics { metric_tags := strings.Split(metric.Tags, ",") @@ -69,7 +78,6 @@ func SendToTransfer(metrics []*model.MetricValue) { } } } - var resp model.TransferResponse err := TransferClient.Call("Transfer.Update", metrics, &resp) if err != nil { diff --git a/hosts.json b/hosts.json new file mode 100644 index 0000000..32c39f2 --- /dev/null +++ b/hosts.json @@ -0,0 +1,6 @@ +{ + "hosts": + { + "202.120.88.168":"vpn-lw" + } +} diff --git a/main.go b/main.go index 7c0b092..50e41b2 100644 --- a/main.go +++ b/main.go @@ -25,7 +25,14 @@ func main() { } g.ParseConfig(*cfg) - + if g.Config().SwitchHosts.Enabled { + hostcfg := g.Config().SwitchHosts.Hosts + g.ParseHostConfig(hostcfg) + } + if g.Config().CustomMetrics.Enabled { + custMetrics := g.Config().CustomMetrics.Template + g.ParseCustConfig(custMetrics) + } g.InitRootDir() g.InitLocalIps() g.InitRpcClients()