diff --git a/.gitignore b/.gitignore index affef48..5f4404c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,8 +10,11 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out +*.pprof .idea /data /dist .DS_Store /main +/cmd/agent/main +/cmd/dashboard/main \ No newline at end of file diff --git a/README.md b/README.md index 246a83b..f821c2d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@
LOGO designed by 熊大 .

-    +   

:trollface: 哪吒监控 一站式轻监控轻运维系统。支持系统状态、HTTP(SSL 证书变更、即将到期、到期)、TCP、Ping 监控报警,命令批量执行和计划任务。

@@ -14,9 +14,9 @@ \>> [我们的用户](https://www.google.com/search?q="powered+by+哪吒监控"&filter=0) (Google) -| 默认主题 | DayNight [@JackieSung](https://github.com/JackieSung4ev) | hotaru | -| ------------------------------------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------- | -| ![首页截图1](https://s3.ax1x.com/2020/12/07/DvTCwD.jpg) | | | +| 默认主题 | DayNight [@JackieSung](https://github.com/JackieSung4ev) | hotaru | +| ----------------------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------- | +| ![默认主题](resource/template/theme-default/screenshot.png) | ![daynight](resource/template/theme-daynight/screenshot.png) | | ## 安装脚本 @@ -36,11 +36,12 @@ CN=true sudo ./nezha.sh _\* 使用 WatchTower 可以自动更新面板,Windows 终端可以使用 nssm 配置自启动(见尾部教程)_ -### 特殊技能 +### 增强配置 通过执行 `./nezha-agent --help` 查看支持的参数,如果你使用一键脚本,可以编辑 `/etc/systemd/system/nezha-agent.service`,在 `ExecStart=` 这一行的末尾加上 - `--skip-conn` 不监控连接数,机场/连接密集型机器推荐设置,不然比较占 CPU([shirou/gopsutil/issues#220](https://github.com/shirou/gopsutil/issues/220)) +- `--skip-procs` 不监控进程数,也可以降低 agent 占用 - `--disable-auto-update` 禁止 Agent 自动更新 ## 功能说明 @@ -230,7 +231,7 @@ URL 里面也可放置占位符,请求时会进行简单的字符串替换。
- Agent 不断重启/无法启动 ? + Agent不上线不启动自检流程 1. 直接执行 `/opt/nezha/agent/nezha-agent -s 面板IP或非CDN域名:面板RPC端口 -p Agent密钥 -d` 查看日志是否是 DNS 问题。 2. `nc -v 域名/IP 面板RPC端口` 或者 `telnet 域名/IP 面板RPC端口` 检验是否是网络问题,检查本机与面板服务器出入站防火墙,如果单机无法判断可借助 提供的端口检查工具进行检测。 @@ -243,7 +244,7 @@ URL 里面也可放置占位符,请求时会进行简单的字符串替换。 首先在 release 下载对应的二进制解压 tar.gz 包后放置到 `/root`,然后 `chmod +x /root/nezha-agent` 赋予执行权限,然后创建 `/etc/init.d/nezha-service`: -``` +```shell #!/bin/sh /etc/rc.common START=99 @@ -272,8 +273,9 @@ restart() {
- 实时通道断开/终端连接失败 -使用反向代理时需要针对 `/ws` 路径的 WebSocket 进行特别配置以支持实时更新服务器状态。 + 实时通道断开/网页终端连接失败 + +使用反向代理时需要针对 `/ws`,`/terminal` 路径的 WebSocket 进行特别配置以支持实时更新服务器状态和 **WebSSH**。 - Nginx(宝塔):在你的 nginx 配置文件中加入以下代码 @@ -285,7 +287,6 @@ restart() { location ~ ^/(ws|terminal/.+)$ { proxy_pass http://ip:站点访问端口; - proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; @@ -295,6 +296,15 @@ restart() { } ``` + 如果非宝塔,还要在 `server{}` 中添加上这一段 + + ```nginx + location / { + proxy_pass http://ip:站点访问端口; + proxy_set_header Host $host; + } + ``` + - CaddyServer v1(v2 无需特别配置) ```Caddyfile diff --git a/cmd/agent/main.go b/cmd/agent/main.go index 17096c1..896531e 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -30,25 +30,21 @@ import ( type AgentConfig struct { SkipConnectionCount bool + SkipProcsCount bool DisableAutoUpdate bool Debug bool Server string ClientSecret string } -func init() { - http.DefaultClient.Timeout = time.Second * 5 - flag.CommandLine.ParseErrorsWhitelist.UnknownFlags = true -} - var ( - version string - agentConf AgentConfig + version string + client pb.NezhaServiceClient + inited bool ) var ( - client pb.NezhaServiceClient - inited bool + agentConf AgentConfig updateCh = make(chan struct{}) // Agent 自动更新间隔 httpClient = &http.Client{ CheckRedirect: func(req *http.Request, via []*http.Request) error { @@ -63,6 +59,11 @@ const ( networkTimeOut = time.Second * 5 // 普通网络超时 ) +func init() { + http.DefaultClient.Timeout = time.Second * 5 + flag.CommandLine.ParseErrorsWhitelist.UnknownFlags = true +} + func main() { // 来自于 GoReleaser 的版本号 monitor.Version = version @@ -71,6 +72,7 @@ func main() { flag.StringVarP(&agentConf.Server, "server", "s", "localhost:5555", "管理面板RPC端口") flag.StringVarP(&agentConf.ClientSecret, "password", "p", "", "Agent连接Secret") flag.BoolVar(&agentConf.SkipConnectionCount, "skip-conn", false, "不监控连接数") + flag.BoolVar(&agentConf.SkipProcsCount, "skip-procs", false, "不监控进程数") flag.BoolVar(&agentConf.DisableAutoUpdate, "disable-auto-update", false, "禁用自动升级") flag.Parse() @@ -88,7 +90,6 @@ func run() { } go pty.DownloadDependency() - // 上报服务器信息 go reportState() // 更新IP信息 @@ -168,8 +169,8 @@ func receiveTasks(tasks pb.NezhaService_RequestTaskClient) error { } go func() { defer func() { - if recover() != nil { - println("task panic", task) + if err := recover(); err != nil { + println("task panic", task, err) } }() doTask(task) @@ -209,7 +210,7 @@ func reportState() { if client != nil && inited { monitor.TrackNetworkSpeed() timeOutCtx, cancel := context.WithTimeout(context.Background(), networkTimeOut) - _, err = client.ReportSystemState(timeOutCtx, monitor.GetState(agentConf.SkipConnectionCount).PB()) + _, err = client.ReportSystemState(timeOutCtx, monitor.GetState(agentConf.SkipConnectionCount, agentConf.SkipProcsCount).PB()) cancel() if err != nil { println("reportState error", err) @@ -229,7 +230,7 @@ func doSelfUpdate() { println("检查更新:", v) latest, err := selfupdate.UpdateSelf(v, "naiba/nezha") if err != nil { - println("自动更新失败:", err) + println("更新失败:", err) return } if !latest.Version.Equals(v) { @@ -282,7 +283,7 @@ func handleHttpGetTask(task *pb.Task, result *pb.TaskResult) { } if err == nil { // 检查 SSL 证书信息 - if len(resp.TLS.PeerCertificates) > 0 { + if resp.TLS != nil && len(resp.TLS.PeerCertificates) > 0 { c := resp.TLS.PeerCertificates[0] result.Data = c.Issuer.CommonName + "|" + c.NotAfter.In(time.Local).String() } diff --git a/cmd/agent/monitor/monitor.go b/cmd/agent/monitor/monitor.go index d2febd5..40c76f7 100644 --- a/cmd/agent/monitor/monitor.go +++ b/cmd/agent/monitor/monitor.go @@ -5,7 +5,6 @@ import ( "regexp" "runtime" "strings" - "sync/atomic" "syscall" "time" @@ -15,20 +14,27 @@ import ( "github.com/shirou/gopsutil/v3/load" "github.com/shirou/gopsutil/v3/mem" "github.com/shirou/gopsutil/v3/net" + "github.com/shirou/gopsutil/v3/process" "github.com/naiba/nezha/model" ) -var Version string = "debug" -var netInSpeed, netOutSpeed, netInTransfer, netOutTransfer, lastUpdate uint64 -var expectDiskFsTypes = []string{ - "apfs", "ext4", "ext3", "ext2", "f2fs", "reiserfs", "jfs", "btrfs", - "fuseblk", "zfs", "simfs", "ntfs", "fat32", "exfat", "xfs", "fuse.rclone", -} -var excludeNetInterfaces = []string{ - "lo", "tun", "docker", "veth", "br-", "vmbr", "vnet", "kube", -} -var getMacDiskNo = regexp.MustCompile(`\/dev\/disk(\d)s.*`) +var ( + Version string = "debug" + expectDiskFsTypes = []string{ + "apfs", "ext4", "ext3", "ext2", "f2fs", "reiserfs", "jfs", "btrfs", + "fuseblk", "zfs", "simfs", "ntfs", "fat32", "exfat", "xfs", "fuse.rclone", + } + excludeNetInterfaces = []string{ + "lo", "tun", "docker", "veth", "br-", "vmbr", "vnet", "kube", + } + getMacDiskNo = regexp.MustCompile(`\/dev\/disk(\d)s.*`) +) + +var ( + netInSpeed, netOutSpeed, netInTransfer, netOutTransfer, lastUpdateNetStats uint64 + cachedBootTime time.Time +) func GetHost() *model.Host { hi, _ := host.Info() @@ -58,6 +64,8 @@ func GetHost() *model.Host { swapMemTotal = mv.SwapTotal } + cachedBootTime = time.Now().Add(time.Duration(-1 * int64(hi.BootTime*1000))) + return &model.Host{ Platform: hi.OS, PlatformVersion: hi.PlatformVersion, @@ -74,8 +82,12 @@ func GetHost() *model.Host { } } -func GetState(skipConnectionCount bool) *model.HostState { - hi, _ := host.Info() +func GetState(skipConnectionCount bool, skipProcsCount bool) *model.HostState { + var procs []int32 + if !skipProcsCount { + procs, _ = process.Pids() + } + mv, _ := mem.VirtualMemory() var swapMemUsed uint64 @@ -92,11 +104,11 @@ func GetState(skipConnectionCount bool) *model.HostState { if err == nil { cpuPercent = cp[0] } + _, diskUsed := getDiskTotalAndUsed() loadStat, _ := load.Avg() var tcpConnCount, udpConnCount uint64 - if !skipConnectionCount { conns, _ := net.Connections("all") for i := 0; i < len(conns); i++ { @@ -114,17 +126,17 @@ func GetState(skipConnectionCount bool) *model.HostState { MemUsed: mv.Total - mv.Available, SwapUsed: swapMemUsed, DiskUsed: diskUsed, - NetInTransfer: atomic.LoadUint64(&netInTransfer), - NetOutTransfer: atomic.LoadUint64(&netOutTransfer), - NetInSpeed: atomic.LoadUint64(&netInSpeed), - NetOutSpeed: atomic.LoadUint64(&netOutSpeed), - Uptime: hi.Uptime, + NetInTransfer: netInTransfer, + NetOutTransfer: netOutTransfer, + NetInSpeed: netInSpeed, + NetOutSpeed: netOutSpeed, + Uptime: uint64(time.Since(cachedBootTime).Seconds()), Load1: loadStat.Load1, Load5: loadStat.Load5, Load15: loadStat.Load15, TcpConnCount: tcpConnCount, UdpConnCount: udpConnCount, - ProcessCount: hi.Procs, + ProcessCount: uint64(len(procs)), } } @@ -140,14 +152,14 @@ func TrackNetworkSpeed() { innerNetOutTransfer += v.BytesSent } now := uint64(time.Now().Unix()) - diff := now - atomic.LoadUint64(&lastUpdate) + diff := now - lastUpdateNetStats if diff > 0 { - atomic.StoreUint64(&netInSpeed, (innerNetInTransfer-atomic.LoadUint64(&netInTransfer))/diff) - atomic.StoreUint64(&netOutSpeed, (innerNetOutTransfer-atomic.LoadUint64(&netOutTransfer))/diff) + netInSpeed = (innerNetInTransfer - netInTransfer) / diff + netOutSpeed = (innerNetOutTransfer - netOutTransfer) / diff } - atomic.StoreUint64(&netInTransfer, innerNetInTransfer) - atomic.StoreUint64(&netOutTransfer, innerNetOutTransfer) - atomic.StoreUint64(&lastUpdate, now) + netInTransfer = innerNetInTransfer + netOutTransfer = innerNetOutTransfer + lastUpdateNetStats = now } } diff --git a/cmd/agent/monitor/myip.go b/cmd/agent/monitor/myip.go index a0a2449..9ede603 100644 --- a/cmd/agent/monitor/myip.go +++ b/cmd/agent/monitor/myip.go @@ -35,13 +35,21 @@ func UpdateIP() { for { ipv4 := fetchGeoIP(geoIPApiList, false) ipv6 := fetchGeoIP(geoIPApiList, true) - cachedIP = fmt.Sprintf("ip(v4:%s,v6:[%s])", ipv4.IP, ipv6.IP) + if ipv4.IP == "" && ipv6.IP == "" { + time.Sleep(time.Minute) + continue + } + if ipv4.IP == "" || ipv6.IP == "" { + cachedIP = fmt.Sprintf("%s%s", ipv4.IP, ipv6.IP) + } else { + cachedIP = fmt.Sprintf("%s/%s", ipv4.IP, ipv6.IP) + } if ipv4.CountryCode != "" { cachedCountry = ipv4.CountryCode } else if ipv6.CountryCode != "" { cachedCountry = ipv6.CountryCode } - time.Sleep(time.Minute * 10) + time.Sleep(time.Minute * 30) } } diff --git a/cmd/dashboard/controller/controller.go b/cmd/dashboard/controller/controller.go index b20cb06..da84af9 100644 --- a/cmd/dashboard/controller/controller.go +++ b/cmd/dashboard/controller/controller.go @@ -112,7 +112,7 @@ func ServeWeb(port uint) *http.Server { }, }) r.Static("/static", "resource/static") - r.LoadHTMLGlob("resource/template/**/*") + r.LoadHTMLGlob("resource/template/**/*.html") routers(r) page404 := func(c *gin.Context) { diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index 25d65e8..9c9b3bd 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -267,19 +267,22 @@ func (ma *memberAPI) addOrEditCron(c *gin.Context) { cr.Cover = cf.Cover err = json.Unmarshal([]byte(cf.ServersRaw), &cr.Servers) } - if err == nil { - _, err = cron.ParseStandard(cr.Scheduler) - } + tx := dao.DB.Begin() if err == nil { if cf.ID == 0 { - err = dao.DB.Create(&cr).Error + err = tx.Create(&cr).Error } else { - err = dao.DB.Save(&cr).Error + err = tx.Save(&cr).Error } } if err == nil { cr.CronID, err = dao.Cron.AddFunc(cr.Scheduler, dao.CronTrigger(cr)) } + if err == nil { + err = tx.Commit().Error + } else { + tx.Rollback() + } if err != nil { c.JSON(http.StatusOK, model.Response{ Code: http.StatusBadRequest, diff --git a/cmd/dashboard/main.go b/cmd/dashboard/main.go index 071d942..1f1d030 100644 --- a/cmd/dashboard/main.go +++ b/cmd/dashboard/main.go @@ -25,7 +25,7 @@ func init() { // 初始化 dao 包 dao.Conf = &model.Config{} - dao.Cron = cron.New(cron.WithLocation(shanghai)) + dao.Cron = cron.New(cron.WithSeconds(), cron.WithLocation(shanghai)) dao.Crons = make(map[uint64]*model.Cron) dao.ServerList = make(map[uint64]*model.Server) dao.SecretToID = make(map[string]uint64) @@ -60,13 +60,13 @@ func initSystem() { loadCrons() //加载计划任务 // 清理 服务请求记录 和 流量记录 的旧数据 - _, err := dao.Cron.AddFunc("30 3 * * *", cleanMonitorHistory) + _, err := dao.Cron.AddFunc("0 30 3 * * *", cleanMonitorHistory) if err != nil { panic(err) } // 流量记录打点 - _, err = dao.Cron.AddFunc("0 * * * *", recordTransferHourlyUsage) + _, err = dao.Cron.AddFunc("0 0 * * * *", recordTransferHourlyUsage) if err != nil { panic(err) } @@ -162,10 +162,11 @@ func loadCrons() { } cr.CronID, err = dao.Cron.AddFunc(cr.Scheduler, dao.CronTrigger(cr)) - if err != nil { - panic(err) + if err == nil { + dao.Crons[cr.ID] = &cr + } else { + log.Println("NEZHA>> 计划任务调度失败", cr, err) } - dao.Crons[cr.ID] = &cr } dao.Cron.Start() } diff --git a/cmd/playground/main.go b/cmd/playground/main.go index 57b18b9..b2217c0 100644 --- a/cmd/playground/main.go +++ b/cmd/playground/main.go @@ -1,7 +1,25 @@ package main -import "github.com/naiba/nezha/cmd/agent/pty" +import ( + "log" + + "github.com/robfig/cron/v3" +) func main() { - pty.DownloadDependency() + c := cron.New(cron.WithSeconds()) + _, err := c.AddFunc("* * * * * *", func() { + log.Println("bingo second") + }) + if err != nil { + panic(err) + } + _, err = c.AddFunc("* * * * *", func() { + log.Println("bingo minute") + }) + if err != nil { + panic(err) + } + c.Start() + select {} } diff --git a/go.mod b/go.mod index 8654ef5..8cc6e39 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/artdarek/go-unzip v1.0.0 github.com/blang/semver v3.5.1+incompatible github.com/creack/pty v1.1.14 - github.com/fsnotify/fsnotify v1.4.9 + github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/gin-contrib/pprof v1.3.0 github.com/gin-gonic/gin v1.7.0 github.com/go-ping/ping v0.0.0-20210407214646-e4e642a95741 @@ -23,13 +23,14 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 // indirect github.com/robfig/cron/v3 v3.0.1 - github.com/shirou/gopsutil/v3 v3.21.7 + github.com/shirou/gopsutil/v3 v3.21.8 github.com/spf13/pflag v1.0.3 github.com/spf13/viper v1.7.1 github.com/stretchr/testify v1.7.0 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 // indirect golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect google.golang.org/grpc v1.33.1 google.golang.org/protobuf v1.25.0 gopkg.in/yaml.v2 v2.2.8 diff --git a/go.sum b/go.sum index 5373241..b03b7c9 100644 --- a/go.sum +++ b/go.sum @@ -290,8 +290,8 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shirou/gopsutil/v3 v3.21.7 h1:PnTqQamUjwEDSgn+nBGu0qSDV/CfvyiR/gwTH3i7HTU= -github.com/shirou/gopsutil/v3 v3.21.7/go.mod h1:RGl11Y7XMTQPmHh8F0ayC6haKNBgH4PXMJuTAcMOlz4= +github.com/shirou/gopsutil/v3 v3.21.8 h1:nKct+uP0TV8DjjNiHanKf8SAuub+GNsbrOtM9Nl9biA= +github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -320,10 +320,10 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw= github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE= -github.com/tklauser/go-sysconf v0.3.7 h1:HT7h4+536gjqeq1ZIJPgOl1rg1XFatQGVZWp7Py53eg= -github.com/tklauser/go-sysconf v0.3.7/go.mod h1:JZIdXh4RmBvZDBZ41ld2bGxRV3n4daiiqA3skYhAoQ4= -github.com/tklauser/numcpus v0.2.3 h1:nQ0QYpiritP6ViFhrKYsiv6VVxOpum2Gks5GhnJbS/8= -github.com/tklauser/numcpus v0.2.3/go.mod h1:vpEPS/JC+oZGGQ/My/vJnNsvMDQL6PwOqt8dsCw5j+E= +github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= +github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= +github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= +github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -469,8 +469,9 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/model/config.go b/model/config.go index 0c32d2d..7224b89 100644 --- a/model/config.go +++ b/model/config.go @@ -1,13 +1,11 @@ package model import ( - "fmt" "io/ioutil" "os" "strconv" "strings" - "github.com/fsnotify/fsnotify" "github.com/spf13/viper" "gopkg.in/yaml.v2" ) @@ -68,13 +66,6 @@ func (c *Config) Read(path string) error { } c.updateIgnoredIPNotificationID() - - c.v.OnConfigChange(func(in fsnotify.Event) { - c.v.Unmarshal(c) - fmt.Println("配置文件更新,重载配置", c) - }) - - go c.v.WatchConfig() return nil } diff --git a/resource/template/common/menu.html b/resource/template/common/menu.html index 8292a4f..bd5bb4f 100644 --- a/resource/template/common/menu.html +++ b/resource/template/common/menu.html @@ -5,7 +5,7 @@ {{if .IsAdminPage}} - 资产 + 主机 服务 任务 报警 diff --git a/resource/template/component/cron.html b/resource/template/component/cron.html index 9b315f9..3ee3da8 100644 --- a/resource/template/component/cron.html +++ b/resource/template/component/cron.html @@ -10,7 +10,7 @@
- +
@@ -41,7 +41,7 @@

- 计划的格式为:* * * * * 分 时 天 月 星期,详情见 * * * * * * 秒 分 时 天 月 星期,详情见 计划表达式格式
命令:就像写 shell/bat 脚本一样,但是不推荐换行,多个命令使用 &&/& 连接,如果遇到 xxx 命令找不到,可能是 diff --git a/resource/template/dashboard/monitor.html b/resource/template/dashboard/monitor.html index 52fe96c..bc69aaa 100644 --- a/resource/template/dashboard/monitor.html +++ b/resource/template/dashboard/monitor.html @@ -5,7 +5,7 @@

@@ -43,7 +43,7 @@
diff --git a/resource/template/dashboard/server.html b/resource/template/dashboard/server.html index 364376f..1fc31e1 100644 --- a/resource/template/dashboard/server.html +++ b/resource/template/dashboard/server.html @@ -6,7 +6,7 @@
@@ -56,7 +56,7 @@
diff --git a/resource/template/theme-daynight/screenshot.png b/resource/template/theme-daynight/screenshot.png new file mode 100644 index 0000000..c3d6d7f Binary files /dev/null and b/resource/template/theme-daynight/screenshot.png differ diff --git a/resource/template/theme-default/README.md b/resource/template/theme-default/README.md deleted file mode 100644 index 5df6215..0000000 --- a/resource/template/theme-default/README.md +++ /dev/null @@ -1 +0,0 @@ -# 默认主题 \ No newline at end of file diff --git a/resource/template/theme-default/screenshot.png b/resource/template/theme-default/screenshot.png new file mode 100644 index 0000000..90d24be Binary files /dev/null and b/resource/template/theme-default/screenshot.png differ diff --git a/resource/template/theme-hotaru/screenshot.png b/resource/template/theme-hotaru/screenshot.png new file mode 100644 index 0000000..74eab8a Binary files /dev/null and b/resource/template/theme-hotaru/screenshot.png differ diff --git a/service/dao/dao.go b/service/dao/dao.go index e5fec17..b8d8a0c 100644 --- a/service/dao/dao.go +++ b/service/dao/dao.go @@ -13,7 +13,7 @@ import ( pb "github.com/naiba/nezha/proto" ) -var Version = "v0.10.1" // !!记得修改 README 中的 badge 版本!! +var Version = "v0.10.2" // !!记得修改 README 中的 badge 版本!! var ( Conf *model.Config diff --git a/service/dao/servicesentinel.go b/service/dao/servicesentinel.go index 56f3db5..0cce017 100644 --- a/service/dao/servicesentinel.go +++ b/service/dao/servicesentinel.go @@ -10,7 +10,6 @@ import ( "github.com/naiba/nezha/model" pb "github.com/naiba/nezha/proto" - "github.com/robfig/cron/v3" ) const _CurrentStatusSize = 30 // 统计 15 分钟内的数据为当前状态 @@ -42,11 +41,9 @@ func NewServiceSentinel(serviceSentinelDispatchBus chan<- model.Monitor) { sslCertCache: make(map[uint64]string), // 30天数据缓存 monthlyStatus: make(map[uint64]*model.ServiceItemResponse), - dispatchCron: cron.New(cron.WithSeconds()), dispatchBus: serviceSentinelDispatchBus, } ServiceSentinelShared.loadMonitorHistory() - ServiceSentinelShared.dispatchCron.Start() year, month, day := time.Now().Date() today := time.Date(year, month, day, 0, 0, 0, 0, time.Local) @@ -75,7 +72,7 @@ func NewServiceSentinel(serviceSentinelDispatchBus chan<- model.Monitor) { go ServiceSentinelShared.worker() // 每日将游标往后推一天 - _, err := Cron.AddFunc("0 0 * * *", ServiceSentinelShared.refreshMonthlyServiceStatus) + _, err := Cron.AddFunc("0 0 0 * * *", ServiceSentinelShared.refreshMonthlyServiceStatus) if err != nil { panic(err) } @@ -102,8 +99,7 @@ type ServiceSentinel struct { monthlyStatusLock sync.Mutex monthlyStatus map[uint64]*model.ServiceItemResponse // 服务监控调度计划任务 - dispatchCron *cron.Cron - dispatchBus chan<- model.Monitor + dispatchBus chan<- model.Monitor } func (ss *ServiceSentinel) refreshMonthlyServiceStatus() { @@ -147,7 +143,7 @@ func (ss *ServiceSentinel) loadMonitorHistory() { ss.monitors = make(map[uint64]*model.Monitor) for i := 0; i < len(monitors); i++ { task := *monitors[i] - monitors[i].CronJobID, err = ss.dispatchCron.AddFunc(task.CronSpec(), func() { + monitors[i].CronJobID, err = Cron.AddFunc(task.CronSpec(), func() { ss.dispatchBus <- task }) log.Println("NEZHA>> 服务监控任务", monitors[i].ID, monitors[i].Name, monitors[i].CronJobID) @@ -194,7 +190,7 @@ func (ss *ServiceSentinel) OnMonitorUpdate(m model.Monitor) error { defer ss.monitorsLock.Unlock() var err error // 写入新任务 - m.CronJobID, err = ss.dispatchCron.AddFunc(m.CronSpec(), func() { + m.CronJobID, err = Cron.AddFunc(m.CronSpec(), func() { ss.dispatchBus <- m }) if err != nil { @@ -202,7 +198,7 @@ func (ss *ServiceSentinel) OnMonitorUpdate(m model.Monitor) error { } if ss.monitors[m.ID] != nil { // 停掉旧任务 - ss.dispatchCron.Remove(ss.monitors[m.ID].CronJobID) + Cron.Remove(ss.monitors[m.ID].CronJobID) } else { // 新任务初始化数据 ss.monthlyStatusLock.Lock() @@ -236,7 +232,7 @@ func (ss *ServiceSentinel) OnMonitorDelete(id uint64) { ss.monitorsLock.Lock() defer ss.monitorsLock.Unlock() // 停掉定时任务 - ss.dispatchCron.Remove(ss.monitors[id].CronJobID) + Cron.Remove(ss.monitors[id].CronJobID) delete(ss.monitors, id) ss.monthlyStatusLock.Lock() defer ss.monthlyStatusLock.Unlock()