主机状态监控程序网络版
(编辑:jimmy 日期: 2024/11/15 浏览:3 次 )
上次发了一个单机版的主机状态监控程序(https://www.52pojie.cn/thread-1680459-1-1.html)
这次来个网络版本的.
linux 和 windows 版本任意搭配.
只需要有一个server端用来接收client发送的消息就可以了。
运行截图.jpg
功能
server 端
启动 server 端, 监听指定端口, 生成状态信息页面.
发现接收到的状态信息中达到阈值,发送钉钉报警通知.
Usage of ./server_linux: -p string 监听端口,默认8080 (default "8080")root@test:~/run/server# ./server_linux -p 802022/09/06 06:49:39 服务已启动,监听端号 :80
client 端
给server 定时发送主机状态信息.
./client_linux -s "http://127.0.0.1:80"
源码:
server端:
[Golang] 纯文本查看 复制代码
package mainimport ( "flag" "fmt" "log" "net/http" "os" "time" "github.com/spf13/viper" "github.com/wanghuiyt/ding" "github.com/gin-gonic/gin")type ClientInfo struct { HostName string `json:"hostname"` Cpu float64 `json:"cpu"` Mem float64 `json:"mem"` Disk float64 `json:"disk"` ProcessNum uint64 `json:"processnum"` BootTime string `json:"bootTime"`}var htmlCode stringvar serversInfo stringvar num int// 全局配置变量var config *viper.Viperfunc Index(c *gin.Context) { htmlCode = `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="5" URL="#" /><script type="text/javascript"> window.onload=function(){ var tfrow = document.getElementById('tfhover').rows.length; var tbRow=[]; for (var i=1;i<tfrow;i++) { tbRow[i]=document.getElementById('tfhover').rows[i]; tbRow[i].onmouseover = function(){ this.style.backgroundColor = '#f3f8aa'; }; tbRow[i].onmouseout = function() { this.style.backgroundColor = '#ffffff'; }; }};</script><style type="text/css">table.tftable {font-size:12px;color:#333333;border-width: 1px;border-color: #9dcc7a;border-collapse: collapse;}table.tftable th {font-size:12px;background-color:#abd28e;border-width: 1px;padding: 8px;border-style: solid;border-color: #ffffff;text-align:left;}table.tftable tr {background-color:#ffffff;}table.tftable td {font-size:12px;border-width: 1px;padding: 8px;border-style: solid;border-color: #9dcc7a;}</style><title>vsyour 监控中心</title></head><body><table id="tfhover" class="tftable" border="1"><caption><b>有【%v】台服务器在线</b></caption><tr><th>序号</th><th>主机名</th><th>IP地址</th><th>CPU使用率</th><th>内存使用率</th><th>进程数量</th><th>开机时间</th></tr>%v</table></body></html>` c.Header("Content-Type", "text/html; charset=utf-8") c.String(http.StatusOK, fmt.Sprintf(htmlCode, num, serversInfo)) return}// 初始化全局map 参考 http://niliu.me/articles/1590.htmlvar hostList map[string]ClientInfo = make(map[string]ClientInfo)func Add(c *gin.Context) { reqInfo := ClientInfo{} err := c.BindJSON(&reqInfo) if err != nil { c.JSONP(http.StatusNotAcceptable, "Error: "+err.Error()) return } clientIP := c.ClientIP() //clientIP := reqInfo.IP 测试时直接写死方便用post man测试 hostList[clientIP] = ClientInfo{ reqInfo.HostName, reqInfo.Cpu, reqInfo.Mem, reqInfo.Disk, reqInfo.ProcessNum, reqInfo.BootTime, } n := 0 serversInfo = "" num = 0 for k, v := range hostList { num++ n++ // <tr><th>序号</th><th>主机名</th><th>IP地址</th><th>CPU占用率</th><th>内存占用</th><th>任务数量</th><th>执行命令</th></tr> serversInfo = serversInfo + fmt.Sprintf(`<tr><td>%v</td><td>%v</td><td>%v</td><td>%.2f%%</td><td>%.2f%%</td><td>%v</td><td>%v</td></tr>`, n, v.HostName, k, v.Cpu, v.Mem, v.ProcessNum, v.BootTime) //log.Println(v.CPU, v.Mem, v.Disk) if v.Cpu > config.GetFloat64(`checkItems.cpu`) || v.Mem > config.GetFloat64(`checkItems.mem`) || v.Disk > config.GetFloat64(`checkItems.disk`) { outStr := fmt.Sprintf(`异常主机信息: HostName:%v IP:%v CPU:%v Mem:%v Disk:%v`, v.HostName, c.ClientIP(), v.Cpu, v.Mem, v.Disk) log.Println(outStr) sendToDingDing(outStr) } } //log.Println(hostList) c.JSONP(http.StatusOK, hostList) return}func sendToDingDing(sendContent string) { // 接收string类型并发送内容 d := ding.Webhook{ AccessToken: config.GetString("dingding.AccessToken"), Secret: config.GetString("dingding.Secret"), EnableAt: true, // 开启艾特 AtAll: true, // 艾特所有人 } err := d.SendMessage(sendContent) if err != nil { fmt.Println(err) }}func main() { //获取项目的执行路径 path, _ := os.Getwd() config = viper.New() config.AddConfigPath(path) //设置读取的文件路径 config.SetConfigName("config") //设置读取的文件名 config.SetConfigType("yaml") //设置文件的类型 //尝试进行配置读取 if err := config.ReadInConfig(); err != nil { log.Println(err) log.Println("读取配置文件出错!") os.Exit(1) } // Set Gin to production mode gin.SetMode(gin.ReleaseMode) // Set the router as the default one provided by Gin router := gin.Default() //router := gin.New() router.GET("/", Index) router.POST("/", Add) go func() { sleepTime := config.GetInt32("checkTime") // 定期对服务器信息清空,达到下线后没有心跳信息不再显示 for { time.Sleep(time.Duration(sleepTime) * time.Second) //log.Println("Clear .... ") serversInfo = "" num = 0 } }() // 监听端口 var port string flag.StringVar(&port, "p", "8080", "监听端口,默认8080") flag.Parse() listenPort := fmt.Sprintf(":%v", port) log.Println("服务已启动,监听端号 " + listenPort) err := router.Run(listenPort) if err != nil { return }}
client端:
[Golang] 纯文本查看 复制代码
package mainimport ( "bytes" "encoding/json" "flag" "fmt" "log" "net/http" "os" "time" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/host" "github.com/shirou/gopsutil/v3/mem")func GetCpuPercent() float64 { percent, _ := cpu.Percent(time.Second, false) return percent[0]}func GetMemPercent() float64 { memInfo, _ := mem.VirtualMemory() return memInfo.UsedPercent}func GetDiskPercent() float64 { parts, _ := disk.Partitions(true) diskInfo, _ := disk.Usage(parts[1].Mountpoint) return diskInfo.UsedPercent}func GetHostName() string { name, _ := os.Hostname() return name}func GetBootTime() string { // BootTime 开机时间 t, _ := host.BootTime() return fmt.Sprintf("%v", time.Unix(int64(t), 0))}func GetProcessNum() uint64 { // 获取所有的pids infoStat, _ := host.Info() return infoStat.Procs}type ClientInfo struct { HostName string `json:"hostname"` Cpu float64 `json:"cpu"` Mem float64 `json:"mem"` Disk float64 `json:"disk"` ProcessNum uint64 `json:"processnum"` BootTime string `json:"bootTime"`}func sendInfo(server string) { defer func() { if r := recover(); r != nil { fmt.Println("发送状态信息出错,请检测server端.", r) } }() sendInfo := ClientInfo{ HostName: GetHostName(), Cpu: GetCpuPercent(), Mem: GetMemPercent(), Disk: GetDiskPercent(), ProcessNum: GetProcessNum(), BootTime: GetBootTime(), } //fmt.Println(sendInfo) body, _ := json.Marshal(sendInfo) resp, _ := http.Post(server, "application/json", bytes.NewBuffer(body)) defer resp.Body.Close()}func main() { var server string flag.StringVar(&server, "s", "http://127.0.0.1:8080", "服务器信息") flag.Parse() log.Println("52pojie_vsyour提醒: 采集端已启动. 每10秒发送状态信息到 " + server) for { sendInfo(server) //timeStr := time.Now().Format("2006-01-02 15:04:05") //fmt.Printf("[%v] 52pojie_vsyour提醒: 本次检测已完成, [%v秒] 后再次检测!\n", timeStr, 10) time.Sleep(time.Duration(10) * time.Second) }}
下载地址:
外链:https://vsyour.lanzoub.com/b02jl9ayb 密码:52pj