mirror of
https://github.com/lollipopkit/server_box_monitor.git
synced 2025-01-07 03:17:06 +08:00
#1 fix & opt.
- opt.: interval must <= 10s - fix: speed wrong push unit - fix: wrong segments count - fix: threshold: parse endIdx
This commit is contained in:
parent
9c6953c178
commit
5913686cec
3
.gitignore
vendored
3
.gitignore
vendored
@ -1 +1,2 @@
|
||||
.config
|
||||
.config
|
||||
server_box_monitor
|
@ -72,8 +72,10 @@
|
||||
//
|
||||
// type: webhook, ios, serverchan (more to come)
|
||||
// iface: interface for the push type
|
||||
// success_body_regex: regex to match the response body
|
||||
// success_code: response code to match
|
||||
// body_regex: regex to match the response body
|
||||
// code: response code to match
|
||||
//
|
||||
// {{key}} and {{value}} will be replaced with the key and value of the check
|
||||
"pushes": [
|
||||
{
|
||||
// This is a example for QQ Group message
|
||||
@ -113,14 +115,9 @@
|
||||
"name": "ServerBox iOS App",
|
||||
// You can get it from settings page of ServerBox iOS app
|
||||
"token": "YOUR_TOKEN",
|
||||
// {{key}} and {{value}} will be replaced with the key and value of the check
|
||||
"title": "Server Notification",
|
||||
// {{key}} and {{value}} will be replaced with the key and value of the check
|
||||
"content": "{{key}}: {{value}}",
|
||||
// Regex to match the response body
|
||||
// If the response body matches the regex, the push is considered successful
|
||||
"body_regex": ".*",
|
||||
// If the response code equals, the push is considered successful
|
||||
"code": 200
|
||||
}
|
||||
},
|
||||
|
@ -67,10 +67,11 @@
|
||||
}
|
||||
],
|
||||
// 推送规则
|
||||
//
|
||||
// 类型 type: webhook, ios, server酱 (以后有更多)
|
||||
// 接口 iface: 推送类型的接口
|
||||
// body成功正则 body_regex: 正则表达式匹配响应体
|
||||
// 成功code code: 响应码匹配
|
||||
// body_regex: 正则表达式匹配响应体
|
||||
// code: 响应码匹配
|
||||
"pushes": [
|
||||
{
|
||||
// 这是一个推送到QQ群的例子
|
||||
|
@ -16,9 +16,9 @@ var (
|
||||
|
||||
type AppConfig struct {
|
||||
Version int `json:"version"`
|
||||
// Such as "30s" or "5m".
|
||||
// Valid time units are "s", "m", "h".
|
||||
// Values less than 10 seconds are not allowed.
|
||||
// Such as "7s".
|
||||
// Valid time units are "s".
|
||||
// Values bigger than 10 seconds are not allowed.
|
||||
Interval string `json:"interval"`
|
||||
Rules []Rule `json:"rules"`
|
||||
Pushes []Push `json:"pushes"`
|
||||
@ -61,13 +61,13 @@ func GetInterval() time.Duration {
|
||||
}
|
||||
d, err := time.ParseDuration(ac.Interval)
|
||||
if err == nil {
|
||||
if d < res.DefaultInterval {
|
||||
log.Warn("[CONFIG] interval is too short, use default interval: 1m")
|
||||
if d > res.DefaultInterval {
|
||||
log.Warn("[CONFIG] interval is too long, use default interval")
|
||||
return res.DefaultInterval
|
||||
}
|
||||
return d
|
||||
}
|
||||
log.Warn("[CONFIG] parse interval failed: %v, use default interval: 1m", err)
|
||||
log.Warn("[CONFIG] parse interval failed: %v", err)
|
||||
return res.DefaultInterval
|
||||
}
|
||||
|
||||
|
@ -280,7 +280,7 @@ func (r *Rule) shouldNotifyNetwork(s []networkStatus, t *Threshold) (bool, *Push
|
||||
}
|
||||
return ok, &PushPair{
|
||||
Key: r.Matcher,
|
||||
Value: speed.String(),
|
||||
Value: speed.String()+"/s",
|
||||
}, nil
|
||||
case ThresholdTypeSize:
|
||||
size := Size(0)
|
||||
|
@ -4,15 +4,12 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const programKilo float64 = 1024
|
||||
|
||||
var (
|
||||
sizeSuffix = []string{"b", "k", "m", "g", "t"}
|
||||
|
||||
zeroSpeed = Speed{0, time.Second}
|
||||
)
|
||||
|
||||
// Size is a type that represents a size in bytes.
|
||||
@ -26,6 +23,7 @@ func (s Size) String() string {
|
||||
return fmt.Sprintf("%.1f %s", temp, sizeSuffix[nth])
|
||||
}
|
||||
temp = temp / programKilo
|
||||
nth++
|
||||
}
|
||||
}
|
||||
func ParseToSize(s string) (Size, error) {
|
||||
@ -52,42 +50,3 @@ func ParseToSize(s string) (Size, error) {
|
||||
}
|
||||
return Size(temp), nil
|
||||
}
|
||||
|
||||
type Speed struct {
|
||||
Size
|
||||
Time time.Duration
|
||||
}
|
||||
|
||||
func (s *Speed) String() (string, error) {
|
||||
if s.Time == 0 {
|
||||
return "", fmt.Errorf("time equals zero: %#v", s)
|
||||
}
|
||||
return fmt.Sprintf("%s/s", Size(float64(s.Size)/s.Time.Seconds()).String()), nil
|
||||
}
|
||||
func (s *Speed) Compare(other *Speed) (int, error) {
|
||||
if s.Time == 0 || other.Time == 0 {
|
||||
return 0, fmt.Errorf("time equals zero: %#v, %#v", s, other)
|
||||
}
|
||||
return int(float64(s.Size)/s.Time.Seconds() - float64(other.Size)/other.Time.Seconds()), nil
|
||||
}
|
||||
|
||||
func ParseToSpeed(s string) (*Speed, error) {
|
||||
s = strings.ToLower(s)
|
||||
if s == "0" {
|
||||
return &zeroSpeed, nil
|
||||
}
|
||||
splited := strings.Split(s, "/")
|
||||
if len(splited) != 2 {
|
||||
return nil, fmt.Errorf("invalid speed: %s", s)
|
||||
}
|
||||
|
||||
size, err := ParseToSize(splited[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
time, err := time.ParseDuration(splited[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Speed{size, time}, nil
|
||||
}
|
||||
|
24
model/size_test.go
Normal file
24
model/size_test.go
Normal file
@ -0,0 +1,24 @@
|
||||
package model_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/lollipopkit/server_box_monitor/model"
|
||||
)
|
||||
|
||||
func TestParseToSize(t *testing.T) {
|
||||
_parseSize("1m", model.Size(1024*1024), t)
|
||||
_parseSize("1M", model.Size(1024*1024), t)
|
||||
_parseSize("3k", model.Size(3*1024), t)
|
||||
_parseSize("7b", model.Size(7), t)
|
||||
}
|
||||
|
||||
func _parseSize(s string, expect model.Size, t *testing.T) {
|
||||
size, err := model.ParseToSize(s)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if size != expect {
|
||||
t.Errorf("expect %s, got %s", expect, size)
|
||||
}
|
||||
}
|
@ -146,8 +146,8 @@ func ParseStatus(s string) error {
|
||||
segments[i] = strings.TrimSpace(segments[i])
|
||||
segments[i] = strings.Trim(segments[i], "\n")
|
||||
}
|
||||
if len(segments) != 10 {
|
||||
return ErrInvalidShellOutput
|
||||
if len(segments) != 7 {
|
||||
return errors.Join(ErrInvalidShellOutput, fmt.Errorf("expect 7 segments, but got %d", len(segments)))
|
||||
}
|
||||
err := parseNetworkStatus(segments[1])
|
||||
if err != nil {
|
||||
|
@ -32,13 +32,13 @@ func ParseToThreshold(s string) (*Threshold, error) {
|
||||
|
||||
} else if strings.HasSuffix(s, "/s") { // 10m/s
|
||||
thresholdType = ThresholdTypeSpeed
|
||||
// 10m/s -> m/s -> 3
|
||||
endIdx = runesLen - 3
|
||||
// 10m/s -> "/s" -> 2
|
||||
endIdx = runesLen - 2
|
||||
|
||||
} else if util.Contains(sizeSuffix, string(runes[runesLen-1])) { // 10m
|
||||
// 10m -> m -> 1
|
||||
// 10m -> "" -> 0
|
||||
thresholdType = ThresholdTypeSize
|
||||
endIdx = runesLen - 1
|
||||
endIdx = runesLen
|
||||
|
||||
} else if strings.HasSuffix(s, "c") { // 32c
|
||||
thresholdType = ThresholdTypeTemperature
|
||||
@ -68,10 +68,23 @@ func ParseToThreshold(s string) (*Threshold, error) {
|
||||
startIdx = 0
|
||||
}
|
||||
|
||||
value, err := strconv.ParseFloat(string(runes[startIdx:endIdx]), 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var value float64
|
||||
var err error
|
||||
|
||||
switch thresholdType {
|
||||
case ThresholdTypeSize, ThresholdTypeSpeed:
|
||||
size, err := ParseToSize(string(runes[startIdx:endIdx]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value = float64(size)
|
||||
default:
|
||||
value, err = strconv.ParseFloat(string(runes[startIdx:endIdx]), 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &Threshold{
|
||||
ThresholdType: thresholdType,
|
||||
Value: value,
|
||||
|
@ -30,7 +30,7 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultInterval = time.Second * 30
|
||||
DefaultInterval = time.Second * 7
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -17,8 +17,6 @@ import (
|
||||
var (
|
||||
pushPairs = []*model.PushPair{}
|
||||
pushPairsLock = new(sync.RWMutex)
|
||||
lastPushTime time.Time
|
||||
checkInterval = time.Second * 3
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -35,20 +33,20 @@ func init() {
|
||||
}
|
||||
|
||||
func Start() {
|
||||
go runMonitor()
|
||||
go runWeb()
|
||||
go runCheck()
|
||||
// 阻塞主线程
|
||||
select {}
|
||||
}
|
||||
|
||||
func runMonitor() {
|
||||
func runCheck() {
|
||||
err := model.ReadAppConfig()
|
||||
if err != nil {
|
||||
log.Err("[CONFIG] Read app config error: %v", err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for range time.NewTicker(checkInterval).C {
|
||||
for range time.NewTicker(model.GetInterval()).C {
|
||||
err = model.RefreshStatus()
|
||||
status := model.Status
|
||||
if err != nil {
|
||||
@ -59,7 +57,7 @@ func runMonitor() {
|
||||
for _, rule := range model.Config.Rules {
|
||||
notify, pushPair, err := rule.ShouldNotify(status)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "not ready") {
|
||||
if !strings.Contains(err.Error(), model.ErrNotReady.Error()) {
|
||||
log.Warn("[RULE] %s error: %v", rule.Id(), err)
|
||||
}
|
||||
}
|
||||
@ -75,10 +73,6 @@ func runMonitor() {
|
||||
continue
|
||||
}
|
||||
|
||||
if time.Now().Sub(lastPushTime) < model.GetInterval() {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Info("[PUSH] %d to push", len(pushPairs))
|
||||
|
||||
pushPairsLock.RLock()
|
||||
|
Loading…
Reference in New Issue
Block a user