github.com/thanos-io/thanos@v0.32.5/pkg/ui/rule.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package ui 5 6 import ( 7 "fmt" 8 "html/template" 9 "math" 10 "regexp" 11 "time" 12 13 "github.com/go-kit/log" 14 "github.com/prometheus/client_golang/prometheus" 15 "github.com/prometheus/common/route" 16 "github.com/prometheus/prometheus/rules" 17 18 "github.com/thanos-io/thanos/pkg/component" 19 extpromhttp "github.com/thanos-io/thanos/pkg/extprom/http" 20 thanosrules "github.com/thanos-io/thanos/pkg/rules" 21 ) 22 23 type Rule struct { 24 *BaseUI 25 26 externalPrefix, prefixHeader string 27 28 ruleManager *thanosrules.Manager 29 queryURL string 30 reg prometheus.Registerer 31 } 32 33 func NewRuleUI(logger log.Logger, reg prometheus.Registerer, ruleManager *thanosrules.Manager, queryURL, externalPrefix, prefixHeader string) *Rule { 34 tmplVariables := map[string]string{ 35 "Component": component.Rule.String(), 36 "queryURL": queryURL, 37 } 38 39 tmplFuncs := ruleTmplFuncs(queryURL) 40 41 return &Rule{ 42 BaseUI: NewBaseUI(logger, tmplFuncs, tmplVariables, externalPrefix, prefixHeader, component.Rule), 43 externalPrefix: externalPrefix, 44 prefixHeader: prefixHeader, 45 ruleManager: ruleManager, 46 queryURL: queryURL, 47 reg: reg, 48 } 49 } 50 51 func ruleTmplFuncs(queryURL string) template.FuncMap { 52 return template.FuncMap{ 53 "since": func(t time.Time) time.Duration { 54 return time.Since(t) / time.Millisecond * time.Millisecond 55 }, 56 "alertStateToClass": func(as rules.AlertState) string { 57 switch as { 58 case rules.StateInactive: 59 return "success" 60 case rules.StatePending: 61 return "warning" 62 case rules.StateFiring: 63 return "danger" 64 default: 65 panic("unknown alert state") 66 } 67 }, 68 "ruleHealthToClass": func(rh rules.RuleHealth) string { 69 switch rh { 70 case rules.HealthUnknown: 71 return "warning" 72 case rules.HealthGood: 73 return "success" 74 default: 75 return "danger" 76 } 77 }, 78 "queryURL": func() string { return queryURL }, 79 "reReplaceAll": func(pattern, repl, text string) string { 80 re := regexp.MustCompile(pattern) 81 return re.ReplaceAllString(text, repl) 82 }, 83 "humanizeDuration": func(v float64) string { 84 if math.IsNaN(v) || math.IsInf(v, 0) { 85 return fmt.Sprintf("%.4g", v) 86 } 87 if v == 0 { 88 return fmt.Sprintf("%.4gs", v) 89 } 90 if math.Abs(v) >= 1 { 91 sign := "" 92 if v < 0 { 93 sign = "-" 94 v = -v 95 } 96 seconds := int64(v) % 60 97 minutes := (int64(v) / 60) % 60 98 hours := (int64(v) / 60 / 60) % 24 99 days := (int64(v) / 60 / 60 / 24) 100 // For days to minutes, we display seconds as an integer. 101 if days != 0 { 102 return fmt.Sprintf("%s%dd %dh %dm %ds", sign, days, hours, minutes, seconds) 103 } 104 if hours != 0 { 105 return fmt.Sprintf("%s%dh %dm %ds", sign, hours, minutes, seconds) 106 } 107 if minutes != 0 { 108 return fmt.Sprintf("%s%dm %ds", sign, minutes, seconds) 109 } 110 // For seconds, we display 4 significant digits. 111 return fmt.Sprintf("%s%.4gs", sign, v) 112 } 113 prefix := "" 114 for _, p := range []string{"m", "u", "n", "p", "f", "a", "z", "y"} { 115 if math.Abs(v) >= 1 { 116 break 117 } 118 prefix = p 119 v *= 1000 120 } 121 return fmt.Sprintf("%.4g%ss", v, prefix) 122 }, 123 } 124 } 125 126 func (ru *Rule) Register(r *route.Router, ins extpromhttp.InstrumentationMiddleware) { 127 registerReactApp(r, ins, ru.BaseUI) 128 }