💬 update notification text [skip ci]

This commit is contained in:
naiba 2022-04-30 19:23:19 +08:00
parent cc5d8da952
commit 36432e31b2
6 changed files with 104 additions and 48 deletions

View File

@ -14,7 +14,7 @@
\>> QQ 交流群872069346 **加群要求:已搭建好哪吒监控 & 有 2+ 服务器, 机器人自动审核**
\>> [Use Cases | 我们的用户](https://www.google.com/search?q=%22powered+by+%E5%93%AA%E5%90%92%E7%9B%91%E6%8E%A7%22+OR+%22powered+by+Nezha+Monitoring%22&filter=0) (Google)
\>> [Use Cases | 我们的用户](https://www.google.com/search?q=%22powered+by+Nezha+Monitoring%22+OR+%22powered+by+%E5%93%AA%E5%90%92%E7%9B%91%E6%8E%A7%22) (Google)
| Default Theme | DayNight [@JackieSung](https://github.com/JackieSung4ev) | hotaru |
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |

View File

@ -87,7 +87,7 @@ var funcMap = template.FuncMap{
}
},
"tf": func(t time.Time) string {
return t.In(singleton.Loc).Format("2006年1月2号 15:04:05")
return t.In(singleton.Loc).Format("02/01/2006 15:04:05")
},
"len": func(slice []interface{}) string {
return strconv.Itoa(len(slice))
@ -99,7 +99,7 @@ var funcMap = template.FuncMap{
return template.HTML(`<` + s + `>`) // #nosec
},
"stf": func(s uint64) string {
return time.Unix(int64(s), 0).In(singleton.Loc).Format("2006年1月2号 15:04")
return time.Unix(int64(s), 0).In(singleton.Loc).Format("02/01/2006 15:04")
},
"sf": func(duration uint64) string {
return time.Duration(time.Duration(duration) * time.Second).String()
@ -151,7 +151,7 @@ var funcMap = template.FuncMap{
"dayBefore": func(i int) string {
year, month, day := time.Now().Date()
today := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
return today.AddDate(0, 0, i-29).Format("1月2号")
return today.AddDate(0, 0, i-29).Format("02/01")
},
"className": func(percent float32) string {
if percent == 0 {
@ -165,16 +165,7 @@ var funcMap = template.FuncMap{
}
return "danger"
},
"statusName": func(percent float32) string {
if percent == 0 {
return "无数据"
}
if percent > 95 {
return "良好"
}
if percent > 80 {
return "低可用"
}
return "故障"
"statusName": func(val float32) string {
return singleton.StatusCodeToString(singleton.GetStatusCode(val))
},
}

View File

@ -489,3 +489,27 @@ other = "报警规则"
[NotificationMethod]
other = "通知方式"
[Incident]
other = "故障"
[Resolved]
other = "恢复"
[StatusNoData]
other = "无数据"
[StatusGood]
other = "良好"
[StatusLowAvailability]
other = "低可用"
[ScheduledTaskExecutedSuccessfully]
other = "任务成功"
[ScheduledTaskExecutedFailed]
other = "任务失败"
[IPChanged]
other = "IP变更"

View File

@ -3,9 +3,11 @@ package rpc
import (
"context"
"fmt"
"github.com/jinzhu/copier"
"time"
"github.com/jinzhu/copier"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/naiba/nezha/model"
pb "github.com/naiba/nezha/proto"
"github.com/naiba/nezha/service/singleton"
@ -33,10 +35,18 @@ func (s *NezhaHandler) ReportTask(c context.Context, r *pb.TaskResult) (*pb.Rece
curServer := model.Server{}
copier.Copy(&curServer, singleton.ServerList[clientID])
if cr.PushSuccessful && r.GetSuccessful() {
singleton.SendNotification(cr.NotificationTag, fmt.Sprintf("[任务成功] %s ,服务器:%s日志\n%s", cr.Name, singleton.ServerList[clientID].Name, r.GetData()), false, &curServer)
singleton.SendNotification(cr.NotificationTag, fmt.Sprintf("[%s] %s, %s\n%s", singleton.Localizer.MustLocalize(
&i18n.LocalizeConfig{
MessageID: "ScheduledTaskExecutedSuccessfully",
},
), cr.Name, singleton.ServerList[clientID].Name, r.GetData()), false, &curServer)
}
if !r.GetSuccessful() {
singleton.SendNotification(cr.NotificationTag, fmt.Sprintf("[任务失败] %s ,服务器:%s日志\n%s", cr.Name, singleton.ServerList[clientID].Name, r.GetData()), false, &curServer)
singleton.SendNotification(cr.NotificationTag, fmt.Sprintf("[%s] %s, %s\n%s", singleton.Localizer.MustLocalize(
&i18n.LocalizeConfig{
MessageID: "ScheduledTaskExecutedFailed",
},
), cr.Name, singleton.ServerList[clientID].Name, r.GetData()), false, &curServer)
}
singleton.DB.Model(cr).Updates(model.Cron{
LastExecutedAt: time.Now().Add(time.Second * -1 * time.Duration(r.GetDelay())),
@ -108,7 +118,10 @@ func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rece
host.IP != "" &&
singleton.ServerList[clientID].Host.IP != host.IP {
singleton.SendNotification(singleton.Conf.IPChangeNotificationTag, fmt.Sprintf(
"[IP变更] %s 旧IP%s新IP%s。",
"[%s] %s, %s => %s",
singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "IPChanged",
}),
singleton.ServerList[clientID].Name, singleton.IPDesensitize(singleton.ServerList[clientID].Host.IP), singleton.IPDesensitize(host.IP)), true)
}

View File

@ -2,11 +2,13 @@ package singleton
import (
"fmt"
"github.com/jinzhu/copier"
"log"
"sync"
"time"
"github.com/jinzhu/copier"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/naiba/nezha/model"
)
@ -153,11 +155,15 @@ func checkStatus() {
copier.Copy(&curServer, server)
if !passed {
alertsPrevState[alert.ID][server.ID] = _RuleCheckFail
message := fmt.Sprintf("[主机故障] %s(%s) 规则:%s", server.Name, IPDesensitize(server.Host.IP), alert.Name)
message := fmt.Sprintf("[%s] %s(%s) %s", Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Incident",
}), server.Name, IPDesensitize(server.Host.IP), alert.Name)
go SendNotification(alert.NotificationTag, message, true, &curServer)
} else {
if alertsPrevState[alert.ID][server.ID] == _RuleCheckFail {
message := fmt.Sprintf("[主机恢复] %s(%s) 规则:%s", server.Name, IPDesensitize(server.Host.IP), alert.Name)
message := fmt.Sprintf("[%s] %s(%s) %s", Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Resolved",
}), server.Name, IPDesensitize(server.Host.IP), alert.Name)
go SendNotification(alert.NotificationTag, message, true, &curServer)
}
alertsPrevState[alert.ID][server.ID] = _RuleCheckPass

View File

@ -10,11 +10,11 @@ import (
"github.com/naiba/nezha/model"
pb "github.com/naiba/nezha/proto"
"github.com/nicksnyder/go-i18n/v2/i18n"
)
const (
_CurrentStatusSize = 30 // 统计 15 分钟内的数据为当前状态
_StatusOk = "良好"
)
var ServiceSentinelShared *ServiceSentinel
@ -39,7 +39,7 @@ func NewServiceSentinel(serviceSentinelDispatchBus chan<- model.Monitor) {
serviceCurrentStatusIndex: make(map[uint64]int),
serviceCurrentStatusData: make(map[uint64][]model.MonitorHistory),
latestDate: make(map[uint64]string),
lastStatus: make(map[uint64]string),
lastStatus: make(map[uint64]int),
serviceResponseDataStoreCurrentUp: make(map[uint64]uint64),
serviceResponseDataStoreCurrentDown: make(map[uint64]uint64),
monitors: make(map[uint64]*model.Monitor),
@ -97,7 +97,7 @@ type ServiceSentinel struct {
serviceCurrentStatusIndex map[uint64]int // [monitor_id] -> 该监控ID对应的 serviceCurrentStatusData 的最新索引下标
serviceCurrentStatusData map[uint64][]model.MonitorHistory // [monitor_id] -> []model.MonitorHistory
latestDate map[uint64]string // 最近一次更新时间
lastStatus map[uint64]string
lastStatus map[uint64]int
serviceResponseDataStoreCurrentUp map[uint64]uint64 // [monitor_id] -> 当前服务在线计数
serviceResponseDataStoreCurrentDown map[uint64]uint64 // [monitor_id] -> 当前服务离线计数
monitors map[uint64]*model.Monitor // [monitor_id] -> model.Monitor
@ -277,20 +277,6 @@ func (ss *ServiceSentinel) LoadStats() map[uint64]*model.ServiceItemResponse {
return ss.monthlyStatus
}
// getStateStr 根据服务在线率返回对应的状态字符串
func getStateStr(percent uint64) string {
if percent == 0 {
return "无数据"
}
if percent > 95 {
return _StatusOk
}
if percent > 80 {
return "低可用"
}
return "故障"
}
// worker 服务监控的实际工作流程
func (ss *ServiceSentinel) worker() {
// 从服务状态汇报管道获取汇报的服务数据
@ -321,7 +307,7 @@ func (ss *ServiceSentinel) worker() {
} else {
ss.serviceStatusToday[mh.MonitorID].Down++
ServerLock.RLock()
log.Println("NEZHA>> 服务故障上报:", ss.monitors[mh.MonitorID].Target, "上报者:", ServerList[r.Reporter].Name, "错误信息:", mh.Data)
log.Println("NEZHA>> Services Incident:", ss.monitors[mh.MonitorID].Target, "Reporter:", ServerList[r.Reporter].Name, "Error:", mh.Data)
ServerLock.RUnlock()
}
// 写入当前数据
@ -343,25 +329,25 @@ func (ss *ServiceSentinel) worker() {
if ss.serviceResponseDataStoreCurrentDown[mh.MonitorID]+ss.serviceResponseDataStoreCurrentUp[mh.MonitorID] > 0 {
upPercent = ss.serviceResponseDataStoreCurrentUp[mh.MonitorID] * 100 / (ss.serviceResponseDataStoreCurrentDown[mh.MonitorID] + ss.serviceResponseDataStoreCurrentUp[mh.MonitorID])
}
stateStr := getStateStr(upPercent)
stateCode := GetStatusCode(upPercent)
// 数据持久化
if ss.serviceCurrentStatusIndex[mh.MonitorID] == _CurrentStatusSize {
ss.serviceCurrentStatusIndex[mh.MonitorID] = 0
if err := DB.Create(&model.MonitorHistory{
MonitorID: mh.MonitorID,
Delay: ss.serviceStatusToday[mh.MonitorID].Delay,
Successful: stateStr == _StatusOk,
Successful: stateCode == StatusGood,
Data: mh.Data,
}).Error; err != nil {
log.Println("NEZHA>> 服务监控数据持久化失败:", err)
}
}
if stateStr == "故障" || stateStr != ss.lastStatus[mh.MonitorID] {
if stateCode == StatusDown || stateCode != ss.lastStatus[mh.MonitorID] {
ss.monitorsLock.RLock()
isNeedSendNotification := (ss.lastStatus[mh.MonitorID] != "" || stateStr == "故障") && ss.monitors[mh.MonitorID].Notify
ss.lastStatus[mh.MonitorID] = stateStr
isNeedSendNotification := (ss.lastStatus[mh.MonitorID] != 0 || stateCode == StatusDown) && ss.monitors[mh.MonitorID].Notify
ss.lastStatus[mh.MonitorID] = stateCode
if isNeedSendNotification {
go SendNotification(ss.monitors[mh.MonitorID].NotificationTag, fmt.Sprintf("[服务%s] %s", stateStr, ss.monitors[mh.MonitorID].Name), true)
go SendNotification(ss.monitors[mh.MonitorID].NotificationTag, fmt.Sprintf("[%s] %s", StatusCodeToString(stateCode), ss.monitors[mh.MonitorID].Name), true)
}
ss.monitorsLock.RUnlock()
}
@ -385,7 +371,7 @@ func (ss *ServiceSentinel) worker() {
// 证书过期提醒
if expiresNew.Before(time.Now().AddDate(0, 0, 7)) {
errMsg = fmt.Sprintf(
"SSL证书将在七天内过期过期时间%s。",
"The SSL certificate will expire within seven days. Expiration time: %s",
expiresNew.Format("2006-01-02 15:04:05"))
}
// 证书变更提醒
@ -397,7 +383,7 @@ func (ss *ServiceSentinel) worker() {
if oldCert[0] != newCert[0] && !expiresNew.Equal(expiresOld) {
ss.sslCertCache[mh.MonitorID] = mh.Data
errMsg = fmt.Sprintf(
"SSL证书变更,旧:%s, %s 过期;新:%s, %s 过期。",
"SSL certificate changed, old: %s, %s expired; new: %s, %s expired.",
oldCert[0], expiresOld.Format("2006-01-02 15:04:05"), newCert[0], expiresNew.Format("2006-01-02 15:04:05"))
}
}
@ -411,3 +397,39 @@ func (ss *ServiceSentinel) worker() {
}
}
}
const (
_ = iota
StatusNoData
StatusGood
StatusLowAvailability
StatusDown
)
func GetStatusCode[T float32 | uint64](percent T) int {
if percent == 0 {
return StatusNoData
}
if percent > 95 {
return StatusGood
}
if percent > 80 {
return StatusLowAvailability
}
return StatusDown
}
func StatusCodeToString(statusCode int) string {
switch statusCode {
case StatusNoData:
return Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "StatusNoData"})
case StatusGood:
return Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "StatusGood"})
case StatusLowAvailability:
return Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "StatusLowAvailability"})
case StatusDown:
return Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "StatusDown"})
default:
return ""
}
}