From 5332f797a614bcad7d0dfb910d72682352d24bca Mon Sep 17 00:00:00 2001 From: Ulric Qin Date: Sun, 30 Oct 2022 17:11:51 +0800 Subject: [PATCH] add alert duration in wecom.tpl --- etc/template/wecom.tpl | 8 +- src/pkg/tplx/common.go | 197 +++++++++++++++++++++++++++++++++++++++++ src/pkg/tplx/conv.go | 73 +++++++++++++++ src/pkg/tplx/tplx.go | 39 ++++---- 4 files changed, 298 insertions(+), 19 deletions(-) create mode 100644 src/pkg/tplx/conv.go diff --git a/etc/template/wecom.tpl b/etc/template/wecom.tpl index 5a16cd61..5a901511 100644 --- a/etc/template/wecom.tpl +++ b/etc/template/wecom.tpl @@ -1,7 +1,9 @@ **级别状态**: {{if .IsRecovered}}S{{.Severity}} Recovered{{else}}S{{.Severity}} Triggered{{end}} **规则标题**: {{.RuleName}}{{if .RuleNote}} -**规则备注**: {{.RuleNote}}{{end}} -**监控指标**: {{.TagsJSON}} -{{if .IsRecovered}}**恢复时间**:{{timeformat .LastEvalTime}}{{else}}**触发时间**: {{timeformat .TriggerTime}} +**规则备注**: {{.RuleNote}}{{end}}{{if .TargetIdent}} +**监控对象**: {{.TargetIdent}}{{end}} +**监控指标**: {{.TagsJSON}}{{if not .IsRecovered}} **触发时值**: {{.TriggerValue}}{{end}} +{{if .IsRecovered}}**恢复时间**: {{timeformat .LastEvalTime}}{{else}}**首次触发时间**: {{timeformat .FirstTriggerTime}}{{end}} +{{$time_duration := sub now.Unix .FirstTriggerTime }}{{if .IsRecovered}}{{$time_duration = sub .LastEvalTime .FirstTriggerTime }}{{end}}**持续时长**: {{humanizeDurationInterface $time_duration}} **发送时间**: {{timestamp}} \ No newline at end of file diff --git a/src/pkg/tplx/common.go b/src/pkg/tplx/common.go index bf81e9c5..68950f64 100644 --- a/src/pkg/tplx/common.go +++ b/src/pkg/tplx/common.go @@ -4,6 +4,7 @@ import ( "fmt" "html/template" "math" + "reflect" "regexp" "strconv" "time" @@ -33,6 +34,10 @@ func Timestamp(pattern ...string) string { return time.Now().Format(defp) } +func Now() time.Time { + return time.Now() +} + func Args(args ...interface{}) map[string]interface{} { result := make(map[string]interface{}) for i, a := range args { @@ -95,11 +100,27 @@ func Humanize1024(s string) string { return fmt.Sprintf("%.4g%s", v, prefix) } +func ToString(v interface{}) string { + return fmt.Sprint(v) +} + func HumanizeDuration(s string) string { v, err := strconv.ParseFloat(s, 64) if err != nil { return s } + return HumanizeDurationFloat64(v) +} + +func HumanizeDurationInterface(i interface{}) string { + f, err := ToFloat64(i) + if err != nil { + return ToString(i) + } + return HumanizeDurationFloat64(f) +} + +func HumanizeDurationFloat64(v float64) string { if math.IsNaN(v) || math.IsInf(v, 0) { return fmt.Sprintf("%.4g", v) } @@ -155,3 +176,179 @@ func HumanizePercentageH(s string) string { } return fmt.Sprintf("%.2f%%", v) } + +// Add returns the sum of a and b. +func Add(a, b interface{}) (interface{}, error) { + av := reflect.ValueOf(a) + bv := reflect.ValueOf(b) + + switch av.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return av.Int() + bv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Int() + int64(bv.Uint()), nil + case reflect.Float32, reflect.Float64: + return float64(av.Int()) + bv.Float(), nil + default: + return nil, fmt.Errorf("add: unknown type for %q (%T)", bv, b) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return int64(av.Uint()) + bv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Uint() + bv.Uint(), nil + case reflect.Float32, reflect.Float64: + return float64(av.Uint()) + bv.Float(), nil + default: + return nil, fmt.Errorf("add: unknown type for %q (%T)", bv, b) + } + case reflect.Float32, reflect.Float64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return av.Float() + float64(bv.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Float() + float64(bv.Uint()), nil + case reflect.Float32, reflect.Float64: + return av.Float() + bv.Float(), nil + default: + return nil, fmt.Errorf("add: unknown type for %q (%T)", bv, b) + } + default: + return nil, fmt.Errorf("add: unknown type for %q (%T)", av, a) + } +} + +// Subtract returns the difference of b from a. +func Subtract(a, b interface{}) (interface{}, error) { + av := reflect.ValueOf(a) + bv := reflect.ValueOf(b) + + switch av.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return av.Int() - bv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Int() - int64(bv.Uint()), nil + case reflect.Float32, reflect.Float64: + return float64(av.Int()) - bv.Float(), nil + default: + return nil, fmt.Errorf("subtract: unknown type for %q (%T)", bv, b) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return int64(av.Uint()) - bv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Uint() - bv.Uint(), nil + case reflect.Float32, reflect.Float64: + return float64(av.Uint()) - bv.Float(), nil + default: + return nil, fmt.Errorf("subtract: unknown type for %q (%T)", bv, b) + } + case reflect.Float32, reflect.Float64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return av.Float() - float64(bv.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Float() - float64(bv.Uint()), nil + case reflect.Float32, reflect.Float64: + return av.Float() - bv.Float(), nil + default: + return nil, fmt.Errorf("subtract: unknown type for %q (%T)", bv, b) + } + default: + return nil, fmt.Errorf("subtract: unknown type for %q (%T)", av, a) + } +} + +// Multiply returns the product of a and b. +func Multiply(a, b interface{}) (interface{}, error) { + av := reflect.ValueOf(a) + bv := reflect.ValueOf(b) + + switch av.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return av.Int() * bv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Int() * int64(bv.Uint()), nil + case reflect.Float32, reflect.Float64: + return float64(av.Int()) * bv.Float(), nil + default: + return nil, fmt.Errorf("multiply: unknown type for %q (%T)", bv, b) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return int64(av.Uint()) * bv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Uint() * bv.Uint(), nil + case reflect.Float32, reflect.Float64: + return float64(av.Uint()) * bv.Float(), nil + default: + return nil, fmt.Errorf("multiply: unknown type for %q (%T)", bv, b) + } + case reflect.Float32, reflect.Float64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return av.Float() * float64(bv.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Float() * float64(bv.Uint()), nil + case reflect.Float32, reflect.Float64: + return av.Float() * bv.Float(), nil + default: + return nil, fmt.Errorf("multiply: unknown type for %q (%T)", bv, b) + } + default: + return nil, fmt.Errorf("multiply: unknown type for %q (%T)", av, a) + } +} + +// Divide returns the division of b from a. +func Divide(a, b interface{}) (interface{}, error) { + av := reflect.ValueOf(a) + bv := reflect.ValueOf(b) + + switch av.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return av.Int() / bv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Int() / int64(bv.Uint()), nil + case reflect.Float32, reflect.Float64: + return float64(av.Int()) / bv.Float(), nil + default: + return nil, fmt.Errorf("divide: unknown type for %q (%T)", bv, b) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return int64(av.Uint()) / bv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Uint() / bv.Uint(), nil + case reflect.Float32, reflect.Float64: + return float64(av.Uint()) / bv.Float(), nil + default: + return nil, fmt.Errorf("divide: unknown type for %q (%T)", bv, b) + } + case reflect.Float32, reflect.Float64: + switch bv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return av.Float() / float64(bv.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return av.Float() / float64(bv.Uint()), nil + case reflect.Float32, reflect.Float64: + return av.Float() / bv.Float(), nil + default: + return nil, fmt.Errorf("divide: unknown type for %q (%T)", bv, b) + } + default: + return nil, fmt.Errorf("divide: unknown type for %q (%T)", av, a) + } +} diff --git a/src/pkg/tplx/conv.go b/src/pkg/tplx/conv.go new file mode 100644 index 00000000..552706c4 --- /dev/null +++ b/src/pkg/tplx/conv.go @@ -0,0 +1,73 @@ +package tplx + +import ( + "fmt" + "strconv" +) + +// ToFloat64 convert interface to float64 +func ToFloat64(val interface{}) (float64, error) { + switch v := val.(type) { + case string: + if f, err := strconv.ParseFloat(v, 64); err == nil { + return f, nil + } + + // try int + if i, err := strconv.ParseInt(v, 0, 64); err == nil { + return float64(i), nil + } + + // try bool + b, err := strconv.ParseBool(v) + if err == nil { + if b { + return 1, nil + } else { + return 0, nil + } + } + + if v == "Yes" || v == "yes" || v == "YES" || v == "Y" || v == "ON" || v == "on" || v == "On" || v == "ok" || v == "up" { + return 1, nil + } + + if v == "No" || v == "no" || v == "NO" || v == "N" || v == "OFF" || v == "off" || v == "Off" || v == "fail" || v == "err" || v == "down" { + return 0, nil + } + + return 0, fmt.Errorf("unparseable value %v", v) + case float64: + return v, nil + case uint64: + return float64(v), nil + case uint32: + return float64(v), nil + case uint16: + return float64(v), nil + case uint8: + return float64(v), nil + case uint: + return float64(v), nil + case int64: + return float64(v), nil + case int32: + return float64(v), nil + case int16: + return float64(v), nil + case int8: + return float64(v), nil + case bool: + if v { + return 1, nil + } else { + return 0, nil + } + case int: + return float64(v), nil + case float32: + return float64(v), nil + default: + return strconv.ParseFloat(fmt.Sprint(v), 64) + } +} diff --git a/src/pkg/tplx/tplx.go b/src/pkg/tplx/tplx.go index 240840ee..2c494dbd 100644 --- a/src/pkg/tplx/tplx.go +++ b/src/pkg/tplx/tplx.go @@ -8,20 +8,27 @@ import ( ) var TemplateFuncMap = template.FuncMap{ - "escape": url.PathEscape, - "unescaped": Unescaped, - "urlconvert": Urlconvert, - "timeformat": Timeformat, - "timestamp": Timestamp, - "args": Args, - "reReplaceAll": ReReplaceAll, - "match": regexp.MatchString, - "toUpper": strings.ToUpper, - "toLower": strings.ToLower, - "contains": strings.Contains, - "humanize": Humanize, - "humanize1024": Humanize1024, - "humanizeDuration": HumanizeDuration, - "humanizePercentage": HumanizePercentage, - "humanizePercentageH": HumanizePercentageH, + "escape": url.PathEscape, + "unescaped": Unescaped, + "urlconvert": Urlconvert, + "timeformat": Timeformat, + "timestamp": Timestamp, + "args": Args, + "reReplaceAll": ReReplaceAll, + "match": regexp.MatchString, + "toUpper": strings.ToUpper, + "toLower": strings.ToLower, + "contains": strings.Contains, + "humanize": Humanize, + "humanize1024": Humanize1024, + "humanizeDuration": HumanizeDuration, + "humanizeDurationInterface": HumanizeDurationInterface, + "humanizePercentage": HumanizePercentage, + "humanizePercentageH": HumanizePercentageH, + "add": Add, + "sub": Subtract, + "mul": Multiply, + "div": Divide, + "now": Now, + "toString": ToString, }