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  }