|
|
package main
|
|
|
|
|
|
import (
|
|
|
"fmt"
|
|
|
"github.com/gocarina/gocsv"
|
|
|
"io"
|
|
|
"log"
|
|
|
"net"
|
|
|
"net/http"
|
|
|
"os"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
func main() {
|
|
|
monitorsFile, err := os.OpenFile(OUTPUTFILE, os.O_RDWR|os.O_CREATE, os.ModePerm)
|
|
|
if err != nil {
|
|
|
panic(err)
|
|
|
}
|
|
|
defer monitorsFile.Close()
|
|
|
monitors := []*Monitor{}
|
|
|
|
|
|
hosts, err := GetHostListFromCSV()
|
|
|
if err != nil {
|
|
|
fmt.Println(err)
|
|
|
}
|
|
|
totalHosts := len(hosts)
|
|
|
count := 0
|
|
|
log.Println("本次要处理主机数量: ", totalHosts)
|
|
|
for _, host := range hosts {
|
|
|
fmt.Println(host)
|
|
|
var errorflag string
|
|
|
serverIP := strClean(host.IP)
|
|
|
if !isTCPOpen(serverIP, host.Port) {
|
|
|
count += 1
|
|
|
log.Println(count, "/", totalHosts, "端口不通: ", serverIP, host.Port)
|
|
|
continue
|
|
|
}
|
|
|
cpuCore, cpuUsage, err1 := getCPUInfo(serverIP, host.Port)
|
|
|
memTotal, memUsage, err2 := getMemoryInfo(serverIP, host.Port)
|
|
|
nodeLoad1, nodeLoad5, nodeLoad15, err3 := getLoadInfo(serverIP, host.Port)
|
|
|
if err1 != nil || err2 != nil || err3 != nil {
|
|
|
fmt.Println("host error: ", err)
|
|
|
errorflag = "error"
|
|
|
}
|
|
|
|
|
|
monitors = append(monitors, &Monitor{
|
|
|
IP: serverIP,
|
|
|
Port: host.Port,
|
|
|
CPUCore: cpuCore,
|
|
|
CPUUsage: cpuUsage,
|
|
|
MemTotal: memTotal,
|
|
|
MemUsage: memUsage,
|
|
|
NodeLoad1: nodeLoad1,
|
|
|
NodeLoad5: nodeLoad5,
|
|
|
NodeLoad15: nodeLoad15,
|
|
|
ERROR: errorflag,
|
|
|
})
|
|
|
count += 1
|
|
|
log.Println(count, "/", totalHosts, " handled: ", serverIP)
|
|
|
}
|
|
|
|
|
|
err = gocsv.MarshalFile(&monitors, monitorsFile) // Use this to save the CSV back to the file
|
|
|
if err != nil {
|
|
|
panic(err)
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
func getMetrics(ip, port string) (string, error) {
|
|
|
// 发送HTTP请求获取Node Exporter的metrics数据
|
|
|
address := "http://" + ip + ":" + port + "/metrics"
|
|
|
response, err := http.Get(address)
|
|
|
if err != nil {
|
|
|
log.Println("无法发送HTTP请求:", err)
|
|
|
//log.Fatal("无法发送HTTP请求:", err)
|
|
|
return "", err
|
|
|
}
|
|
|
defer response.Body.Close()
|
|
|
|
|
|
// 读取响应内容
|
|
|
body, err := io.ReadAll(response.Body)
|
|
|
if err != nil {
|
|
|
log.Println("无法读取响应内容:", err)
|
|
|
//log.Fatal("无法读取响应内容:", err)
|
|
|
return "", err
|
|
|
}
|
|
|
return string(body), nil
|
|
|
|
|
|
}
|
|
|
|
|
|
// 从指标行中提取指标值,并将其转换为浮点数类型
|
|
|
func extractMetricValue(value string) (float64, error) {
|
|
|
// 去除指标值的单位(此处假设单位为'count')
|
|
|
value = strings.Split(value, " ")[0]
|
|
|
// 将指标值转换为浮点数类型并返回
|
|
|
return parseFloat(value)
|
|
|
}
|
|
|
|
|
|
// 将字符串转换为浮点数类型,并处理可能的错误情况
|
|
|
func parseFloat(value string) (float64, error) {
|
|
|
f, err := strconv.ParseFloat(value, 64)
|
|
|
if err != nil {
|
|
|
return 0, err
|
|
|
}
|
|
|
return f, nil
|
|
|
}
|
|
|
|
|
|
func strClean(str string) string {
|
|
|
str = strings.ReplaceAll(str, " ", "")
|
|
|
str = strings.ReplaceAll(str, ",", "")
|
|
|
str = strings.ReplaceAll(str, "\"", "")
|
|
|
return str
|
|
|
}
|
|
|
|
|
|
func isTCPOpen(ip, port string) bool {
|
|
|
// 尝试在指定端口上建立连接
|
|
|
address := ip + ":" + port
|
|
|
conn, err := net.DialTimeout("tcp", address, time.Millisecond*10)
|
|
|
if err != nil {
|
|
|
return false
|
|
|
}
|
|
|
defer conn.Close()
|
|
|
return true
|
|
|
}
|