VictoriaMetrics/app/vmalert/rule/utils.go
Hui Wang 282f13cf11
app/vmalert: improve performances when rules produce large volumes of results
1. Avoid storing the last evaluation results outside of rules, check for
stale time series as soon as possible;
2. remove duplicated template `Clone()`.

This pull request is primarily reducing memory usage when rules produce
large volumes of results, as seen in
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6894.
The CPU time spent on garbage collection remains high and may be
addressed in a separate PR.
2024-11-14 18:21:20 +01:00

107 lines
2.2 KiB
Go

package rule
import (
"fmt"
"net/http"
"sort"
"strings"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/datasource"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
)
// newTimeSeries first sorts given labels, then returns new time series.
func newTimeSeries(values []float64, timestamps []int64, labels []prompbmarshal.Label) prompbmarshal.TimeSeries {
promrelabel.SortLabels(labels)
ts := prompbmarshal.TimeSeries{
Labels: labels,
Samples: make([]prompbmarshal.Sample, len(values)),
}
for i := range values {
ts.Samples[i] = prompbmarshal.Sample{
Value: values[i],
Timestamp: time.Unix(timestamps[i], 0).UnixNano() / 1e6,
}
}
return ts
}
type curlWriter struct {
b strings.Builder
}
func (cw *curlWriter) string() string {
res := "curl " + cw.b.String()
cw.b.Reset()
return strings.TrimSpace(res)
}
func (cw *curlWriter) addWithEsc(str string) {
escStr := `'` + strings.Replace(str, `'`, `'\''`, -1) + `'`
cw.add(escStr)
}
func (cw *curlWriter) add(str string) {
cw.b.WriteString(str)
cw.b.WriteString(" ")
}
func requestToCurl(req *http.Request) string {
if req == nil || req.URL == nil {
return ""
}
cw := &curlWriter{}
schema := req.URL.Scheme
requestURL := req.URL.String()
if !datasource.ShowDatasourceURL() {
requestURL = req.URL.Redacted()
}
if schema == "" {
schema = "http"
if req.TLS != nil {
schema = "https"
}
requestURL = schema + "://" + req.Host + requestURL
}
if schema == "https" {
cw.add("-k")
}
cw.add("-X")
cw.add(req.Method)
var keys []string
for k := range req.Header {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
cw.add("-H")
if !datasource.ShowDatasourceURL() && isSecreteHeader(k) {
cw.addWithEsc(fmt.Sprintf("%s: <secret>", k))
continue
}
cw.addWithEsc(fmt.Sprintf("%s: %s", k, strings.Join(req.Header[k], " ")))
}
cw.addWithEsc(requestURL)
return cw.string()
}
var secretWords = []string{"auth", "pass", "key", "secret", "token"}
func isSecreteHeader(str string) bool {
s := strings.ToLower(str)
for _, secret := range secretWords {
if strings.Contains(s, secret) {
return true
}
}
return false
}