💬 update notification text [skip ci]
This commit is contained in:
parent
cc5d8da952
commit
36432e31b2
@ -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 |
|
||||
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
|
||||
|
@ -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))
|
||||
},
|
||||
}
|
||||
|
24
resource/l10n/zh-CN.toml
vendored
24
resource/l10n/zh-CN.toml
vendored
@ -489,3 +489,27 @@ other = "报警规则"
|
||||
|
||||
[NotificationMethod]
|
||||
other = "通知方式"
|
||||
|
||||
[Incident]
|
||||
other = "故障"
|
||||
|
||||
[Resolved]
|
||||
other = "恢复"
|
||||
|
||||
[StatusNoData]
|
||||
other = "无数据"
|
||||
|
||||
[StatusGood]
|
||||
other = "良好"
|
||||
|
||||
[StatusLowAvailability]
|
||||
other = "低可用"
|
||||
|
||||
[ScheduledTaskExecutedSuccessfully]
|
||||
other = "任务成功"
|
||||
|
||||
[ScheduledTaskExecutedFailed]
|
||||
other = "任务失败"
|
||||
|
||||
[IPChanged]
|
||||
other = "IP变更"
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 ""
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user