Compare commits
63 Commits
timerpool-
...
debug-dock
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29858bc0bb | ||
|
|
f91789eebd | ||
|
|
9b7fee13d6 | ||
|
|
c89825f64d | ||
|
|
2d0d96855b | ||
|
|
e32b1ba6a5 | ||
|
|
41267decd3 | ||
|
|
75fef7a011 | ||
|
|
b87c515d14 | ||
|
|
fb1344b5bf | ||
|
|
168ee75a3c | ||
|
|
e3a5e29a02 | ||
|
|
7dbe569fe7 | ||
|
|
8f3e96fa38 | ||
|
|
cd9d5619d9 | ||
|
|
fb60857b8f | ||
|
|
93f72c487d | ||
|
|
0eb465782a | ||
|
|
b703768e9c | ||
|
|
4e86ddfdaa | ||
|
|
7569d21123 | ||
|
|
5d36616d02 | ||
|
|
e31e0657c8 | ||
|
|
50af991677 | ||
|
|
5617b24cef | ||
|
|
ece3ee2427 | ||
|
|
4add451701 | ||
|
|
1c7d8d030f | ||
|
|
80b4ca6367 | ||
|
|
fafc754c11 | ||
|
|
e1e2b69b2c | ||
|
|
bc2b822d59 | ||
|
|
d9b0c5a268 | ||
|
|
772ac8803e | ||
|
|
4d35b359bd | ||
|
|
8c4faba658 | ||
|
|
5a29174b87 | ||
|
|
ab89bbba5d | ||
|
|
748c49cc9d | ||
|
|
a88851f4a0 | ||
|
|
e0a76e2552 | ||
|
|
a569224dad | ||
|
|
ef21fd6e2c | ||
|
|
57b16f0976 | ||
|
|
4fbf26df02 | ||
|
|
91f0738e67 | ||
|
|
c70fc288f1 | ||
|
|
921e6df382 | ||
|
|
e5dd794db5 | ||
|
|
cc87505f9d | ||
|
|
e198753f0d | ||
|
|
6b9fa21d30 | ||
|
|
e7abdce0de | ||
|
|
31adbf9094 | ||
|
|
dd508b9542 | ||
|
|
f151668188 | ||
|
|
17ca1ba8c4 | ||
|
|
7654536aab | ||
|
|
901de22894 | ||
|
|
96e514439d | ||
|
|
43e189a56c | ||
|
|
4dbf899d89 | ||
|
|
2fcbf75539 |
6
.github/workflows/codeql-analysis-go.yml
vendored
@@ -49,14 +49,14 @@ jobs:
|
||||
restore-keys: go-artifacts-${{ runner.os }}-codeql-analyze-
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: go
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
uses: github/codeql-action/autobuild@v4
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v4
|
||||
with:
|
||||
category: 'language:go'
|
||||
|
||||
2
.github/workflows/vmui.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '24.x'
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[](https://github.com/VictoriaMetrics/VictoriaMetrics/releases)
|
||||

|
||||
[](https://goreportcard.com/report/github.com/VictoriaMetrics/VictoriaMetrics)
|
||||
[](https://github.com/VictoriaMetrics/VictoriaMetrics/actions/workflows/main.yml)
|
||||
[](https://github.com/VictoriaMetrics/VictoriaMetrics/actions/workflows/build.yml)
|
||||
[](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics)
|
||||
[](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/LICENSE)
|
||||

|
||||
|
||||
@@ -111,6 +111,7 @@ func main() {
|
||||
flag.CommandLine.SetOutput(os.Stdout)
|
||||
flag.Usage = usage
|
||||
envflag.Parse()
|
||||
flagutil.ApplySecretFlags()
|
||||
remotewrite.InitSecretFlags()
|
||||
buildinfo.Init()
|
||||
logger.Init()
|
||||
|
||||
@@ -2,6 +2,7 @@ package opentelemetry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/common"
|
||||
@@ -24,6 +25,13 @@ var (
|
||||
rowsPerInsert = metrics.NewHistogram(`vmagent_rows_per_insert{type="opentelemetry"}`)
|
||||
)
|
||||
|
||||
// InsertHandler processes metrics from given reader.
|
||||
func InsertHandlerForReader(at *auth.Token, r io.Reader, encoding string) error {
|
||||
return stream.ParseStream(r, encoding, nil, func(tss []prompb.TimeSeries, mms []prompb.MetricMetadata) error {
|
||||
return insertRows(at, tss, mms, nil)
|
||||
})
|
||||
}
|
||||
|
||||
// InsertHandler processes opentelemetry metrics.
|
||||
func InsertHandler(at *auth.Token, req *http.Request) error {
|
||||
extraLabels, err := protoparserutil.GetExtraLabels(req)
|
||||
|
||||
@@ -173,9 +173,10 @@ func (c *Client) Query(ctx context.Context, query string, ts time.Time) (Result,
|
||||
return Result{}, nil, fmt.Errorf("second attempt: %w", err)
|
||||
}
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
// Process the received response.
|
||||
var parseFn func(req *http.Request, resp *http.Response) (Result, error)
|
||||
var parseFn func(resp *http.Response) (Result, error)
|
||||
switch c.dataSourceType {
|
||||
case datasourcePrometheus:
|
||||
parseFn = parsePrometheusResponse
|
||||
@@ -186,9 +187,12 @@ func (c *Client) Query(ctx context.Context, query string, ts time.Time) (Result,
|
||||
default:
|
||||
logger.Panicf("BUG: unsupported datasource type %q to parse query response", c.dataSourceType)
|
||||
}
|
||||
result, err := parseFn(req, resp)
|
||||
_ = resp.Body.Close()
|
||||
return result, req, err
|
||||
|
||||
result, err := parseFn(resp)
|
||||
if err != nil {
|
||||
return Result{}, nil, fmt.Errorf("error parsing response from %q: %w", req.URL.Redacted(), err)
|
||||
}
|
||||
return result, req, nil
|
||||
}
|
||||
|
||||
// QueryRange executes the given query on the given time range.
|
||||
@@ -229,9 +233,10 @@ func (c *Client) QueryRange(ctx context.Context, query string, start, end time.T
|
||||
return res, fmt.Errorf("second attempt: %w", err)
|
||||
}
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
// Process the received response.
|
||||
var parseFn func(req *http.Request, resp *http.Response) (Result, error)
|
||||
var parseFn func(resp *http.Response) (Result, error)
|
||||
switch c.dataSourceType {
|
||||
case datasourcePrometheus:
|
||||
parseFn = parsePrometheusResponse
|
||||
@@ -240,8 +245,11 @@ func (c *Client) QueryRange(ctx context.Context, query string, start, end time.T
|
||||
default:
|
||||
logger.Panicf("BUG: unsupported datasource type %q to parse query range response", c.dataSourceType)
|
||||
}
|
||||
res, err = parseFn(req, resp)
|
||||
_ = resp.Body.Close()
|
||||
|
||||
res, err = parseFn(resp)
|
||||
if err != nil {
|
||||
return Result{}, fmt.Errorf("error parsing response from %q: %w", req.URL.Redacted(), err)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
|
||||
@@ -33,10 +33,10 @@ func (r graphiteResponse) metrics() []Metric {
|
||||
return ms
|
||||
}
|
||||
|
||||
func parseGraphiteResponse(req *http.Request, resp *http.Response) (Result, error) {
|
||||
func parseGraphiteResponse(resp *http.Response) (Result, error) {
|
||||
r := &graphiteResponse{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(r); err != nil {
|
||||
return Result{}, fmt.Errorf("error parsing graphite metrics for %s: %w", req.URL.Redacted(), err)
|
||||
return Result{}, fmt.Errorf("error parsing graphite metrics: %w", err)
|
||||
}
|
||||
return Result{Data: r.metrics()}, nil
|
||||
}
|
||||
|
||||
@@ -172,16 +172,16 @@ const (
|
||||
rtVector, rtMatrix, rScalar = "vector", "matrix", "scalar"
|
||||
)
|
||||
|
||||
func parsePrometheusResponse(req *http.Request, resp *http.Response) (res Result, err error) {
|
||||
func parsePrometheusResponse(resp *http.Response) (res Result, err error) {
|
||||
r := &promResponse{}
|
||||
if err = json.NewDecoder(resp.Body).Decode(r); err != nil {
|
||||
return res, fmt.Errorf("error parsing response from %s: %w", req.URL.Redacted(), err)
|
||||
return res, fmt.Errorf("failed to decode response: %w", err)
|
||||
}
|
||||
if r.Status == statusError {
|
||||
return res, fmt.Errorf("response error, query: %s, errorType: %s, error: %s", req.URL.Redacted(), r.ErrorType, r.Error)
|
||||
return res, fmt.Errorf("response error %q: %s", r.ErrorType, r.Error)
|
||||
}
|
||||
if r.Status != statusSuccess {
|
||||
return res, fmt.Errorf("unknown status: %s, Expected success or error", r.Status)
|
||||
return res, fmt.Errorf("unknown response status %q", r.Status)
|
||||
}
|
||||
var parseFn func() ([]Metric, error)
|
||||
switch r.Data.ResultType {
|
||||
|
||||
@@ -135,7 +135,7 @@ func TestVMInstantQuery(t *testing.T) {
|
||||
expErr(vmQuery, "500") // 0
|
||||
expErr(vmQuery, "error parsing response") // 1
|
||||
expErr(vmQuery, "response error") // 2
|
||||
expErr(vmQuery, "unknown status") // 3
|
||||
expErr(vmQuery, "unknown response status") // 3
|
||||
expErr(vmQuery, "unexpected end of JSON input") // 4
|
||||
|
||||
res, _, err := pq.Query(ctx, vmQuery, ts) // 5 - vector
|
||||
|
||||
@@ -40,8 +40,8 @@ func (c *Client) setVLogsRangeReqParams(r *http.Request, query string, start, en
|
||||
c.setReqParams(r, query)
|
||||
}
|
||||
|
||||
func parseVLogsResponse(req *http.Request, resp *http.Response) (res Result, err error) {
|
||||
res, err = parsePrometheusResponse(req, resp)
|
||||
func parseVLogsResponse(resp *http.Response) (res Result, err error) {
|
||||
res, err = parsePrometheusResponse(resp)
|
||||
if err != nil {
|
||||
return Result{}, err
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ func main() {
|
||||
flag.CommandLine.SetOutput(os.Stdout)
|
||||
flag.Usage = usage
|
||||
envflag.Parse()
|
||||
flagutil.ApplySecretFlags()
|
||||
remoteread.InitSecretFlags()
|
||||
remotewrite.InitSecretFlags()
|
||||
datasource.InitSecretFlags()
|
||||
|
||||
@@ -389,7 +389,7 @@ func (ar *AlertingRule) execRange(ctx context.Context, start, end time.Time) ([]
|
||||
return []datasource.Metric{{Timestamps: []int64{0}, Values: []float64{math.NaN()}}}, nil
|
||||
}
|
||||
for _, s := range res.Data {
|
||||
ls, err := ar.expandLabelTemplates(s)
|
||||
ls, err := ar.expandLabelTemplates(s, qFn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -482,7 +482,7 @@ func (ar *AlertingRule) exec(ctx context.Context, ts time.Time, limit int) ([]pr
|
||||
expandedLabels := make([]*labelSet, len(res.Data))
|
||||
expandedAnnotations := make([]map[string]string, len(res.Data))
|
||||
for i, m := range res.Data {
|
||||
ls, err := ar.expandLabelTemplates(m)
|
||||
ls, err := ar.expandLabelTemplates(m, qFn)
|
||||
if err != nil {
|
||||
curState.Err = err
|
||||
return nil, curState.Err
|
||||
@@ -604,10 +604,7 @@ func (ar *AlertingRule) exec(ctx context.Context, ts time.Time, limit int) ([]pr
|
||||
return append(tss, ar.toTimeSeries(ts.Unix())...), nil
|
||||
}
|
||||
|
||||
func (ar *AlertingRule) expandLabelTemplates(m datasource.Metric) (*labelSet, error) {
|
||||
qFn := func(_ string) ([]datasource.Metric, error) {
|
||||
return nil, fmt.Errorf("`query` template isn't supported in rule label")
|
||||
}
|
||||
func (ar *AlertingRule) expandLabelTemplates(m datasource.Metric, qFn templates.QueryFn) (*labelSet, error) {
|
||||
ls, err := ar.toLabels(m, qFn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to expand label templates: %s", err)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"testing/synctest"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
@@ -1429,3 +1430,142 @@ func TestAlertingRuleExec_Partial(t *testing.T) {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlertingRule_QueryTemplateInLabels(t *testing.T) {
|
||||
fq := &datasource.FakeQuerier{}
|
||||
fakeGroup := Group{
|
||||
Name: "TestQueryTemplateInLabels",
|
||||
}
|
||||
|
||||
ar := &AlertingRule{
|
||||
Name: "test_alert",
|
||||
Labels: map[string]string{
|
||||
"suppress_for_mass_alert": `{{ if (printf "ALERTS{alertname='SomeAlert', alertstate='firing', device='%s'} == 1" $labels.device | query) }}true{{ else }}false{{ end }}`,
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"summary": "Test alert with query template in labels",
|
||||
},
|
||||
alerts: make(map[uint64]*notifier.Alert),
|
||||
}
|
||||
ar.GroupID = fakeGroup.GetID()
|
||||
ar.q = fq
|
||||
ar.state = &ruleState{
|
||||
entries: make([]StateEntry, 10),
|
||||
}
|
||||
|
||||
// Add a metric that should trigger the alert
|
||||
fq.Add(metricWithValueAndLabels(t, 1, "device", "sda1"))
|
||||
|
||||
ts := time.Now()
|
||||
_, err := ar.exec(context.TODO(), ts, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error with query template in labels: %s", err)
|
||||
}
|
||||
|
||||
// Verify that the alert was created and the query template was executed
|
||||
if len(ar.alerts) != 1 {
|
||||
t.Fatalf("expected 1 alert, got %d", len(ar.alerts))
|
||||
}
|
||||
|
||||
alert := ar.GetAlerts()[0]
|
||||
suppressLabel, exists := alert.Labels["suppress_for_mass_alert"]
|
||||
if !exists {
|
||||
t.Fatalf("expected 'suppress_for_mass_alert' label to exist")
|
||||
}
|
||||
// The query template should have been executed (even if it returns false due to mock data)
|
||||
if suppressLabel != "true" && suppressLabel != "false" {
|
||||
t.Fatalf("expected 'suppress_for_mass_alert' label to be 'true' or 'false', got '%s'", suppressLabel)
|
||||
}
|
||||
}
|
||||
|
||||
// TestAlertingRule_ActiveAtPreservedInAnnotations ensures that the fix for
|
||||
// https://github.com/VictoriaMetrics/VictoriaMetrics/issues/9543 is preserved
|
||||
// while allowing query templates in labels (https://github.com/VictoriaMetrics/VictoriaMetrics/issues/9783)
|
||||
func TestAlertingRule_ActiveAtPreservedInAnnotations(t *testing.T) {
|
||||
// wrap into synctest because of time manipulations
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
fq := &datasource.FakeQuerier{}
|
||||
|
||||
ar := &AlertingRule{
|
||||
Name: "TestActiveAtPreservation",
|
||||
Labels: map[string]string{
|
||||
"test_query_in_label": `{{ "static_value" }}`,
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"description": "Alert active since {{ $activeAt }}",
|
||||
},
|
||||
alerts: make(map[uint64]*notifier.Alert),
|
||||
q: fq,
|
||||
state: &ruleState{
|
||||
entries: make([]StateEntry, 10),
|
||||
},
|
||||
}
|
||||
|
||||
// Mock query result - return empty result to make suppress_for_mass_alert = false
|
||||
// (no need to add anything to fq for empty result)
|
||||
|
||||
// Add a metric that should trigger the alert
|
||||
fq.Add(metricWithValueAndLabels(t, 1, "instance", "server1"))
|
||||
|
||||
// First execution - creates new alert
|
||||
ts1 := time.Now()
|
||||
_, err := ar.exec(context.TODO(), ts1, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error on first exec: %s", err)
|
||||
}
|
||||
|
||||
if len(ar.alerts) != 1 {
|
||||
t.Fatalf("expected 1 alert, got %d", len(ar.alerts))
|
||||
}
|
||||
|
||||
firstAlert := ar.GetAlerts()[0]
|
||||
// Verify first execution: activeAt should be ts1 and annotation should reflect it
|
||||
if !firstAlert.ActiveAt.Equal(ts1) {
|
||||
t.Fatalf("expected activeAt to be %v, got %v", ts1, firstAlert.ActiveAt)
|
||||
}
|
||||
|
||||
// Extract time from annotation (format will be like "Alert active since 2025-09-30 08:55:13.638551611 -0400 EDT m=+0.002928464")
|
||||
expectedTimeStr := ts1.Format("2006-01-02 15:04:05")
|
||||
if !strings.Contains(firstAlert.Annotations["description"], expectedTimeStr) {
|
||||
t.Fatalf("first exec annotation should contain time %s, got: %s", expectedTimeStr, firstAlert.Annotations["description"])
|
||||
}
|
||||
|
||||
// Second execution - should preserve activeAt in annotation
|
||||
|
||||
// Ensure different timestamp with different seconds
|
||||
// sleep is non-blocking thanks to synctest
|
||||
time.Sleep(2 * time.Second)
|
||||
ts2 := time.Now()
|
||||
_, err = ar.exec(context.TODO(), ts2, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error on second exec: %s", err)
|
||||
}
|
||||
|
||||
// Get the alert again (should be the same alert)
|
||||
if len(ar.alerts) != 1 {
|
||||
t.Fatalf("expected 1 alert, got %d", len(ar.alerts))
|
||||
}
|
||||
secondAlert := ar.GetAlerts()[0]
|
||||
|
||||
// Critical test: activeAt should still be ts1, not ts2
|
||||
if !secondAlert.ActiveAt.Equal(ts1) {
|
||||
t.Fatalf("activeAt should be preserved as %v, but got %v", ts1, secondAlert.ActiveAt)
|
||||
}
|
||||
|
||||
// Critical test: annotation should still contain ts1 time, not ts2
|
||||
if !strings.Contains(secondAlert.Annotations["description"], expectedTimeStr) {
|
||||
t.Fatalf("second exec annotation should still contain original time %s, got: %s", expectedTimeStr, secondAlert.Annotations["description"])
|
||||
}
|
||||
|
||||
// Additional verification: annotation should NOT contain ts2 time
|
||||
ts2TimeStr := ts2.Format("2006-01-02 15:04:05")
|
||||
if strings.Contains(secondAlert.Annotations["description"], ts2TimeStr) {
|
||||
t.Fatalf("annotation should NOT contain new eval time %s, got: %s", ts2TimeStr, secondAlert.Annotations["description"])
|
||||
}
|
||||
|
||||
// Verify query template in labels still works (this would fail if query templates were broken)
|
||||
if firstAlert.Labels["test_query_in_label"] != "static_value" {
|
||||
t.Fatalf("expected test_query_in_label=static_value, got %s", firstAlert.Labels["test_query_in_label"])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ The list of MetricsQL features on top of PromQL:
|
||||
* `if` binary operator. `q1 if q2` removes values from `q1` for missing values from `q2`.
|
||||
* `ifnot` binary operator. `q1 ifnot q2` removes values from `q1` for existing values from `q2`.
|
||||
* `WITH` templates. This feature simplifies writing and managing complex queries.
|
||||
Go to [WITH templates playground](https://play.victoriametrics.com/select/accounting/1/6a716b0f-38bc-4856-90ce-448fd713e3fe/expand-with-exprs) and try it.
|
||||
Go to [WITH templates playground](https://play.victoriametrics.com/select/0/prometheus/graph/#/expand-with-exprs) and try it.
|
||||
* String literals may be concatenated. This is useful with `WITH` templates:
|
||||
`WITH (commonPrefix="long_metric_prefix_") {__name__=commonPrefix+"suffix1"} / {__name__=commonPrefix+"suffix2"}`.
|
||||
* `keep_metric_names` modifier can be applied to all the [rollup functions](#rollup-functions), [transform functions](#transform-functions)
|
||||
209
app/vmselect/vmui/assets/index-D13qGB62.js
Normal file
1
app/vmselect/vmui/assets/index-I8MVeF75.css
Normal file
@@ -6,6 +6,7 @@
|
||||
<link rel="apple-touch-icon" href="./favicon.svg"/>
|
||||
<link rel="mask-icon" href="./favicon.svg" color="#000000">
|
||||
|
||||
<meta name="robots" content="noindex">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5"/>
|
||||
<meta name="theme-color" content="#000000"/>
|
||||
<meta name="description" content="Explore and troubleshoot your VictoriaMetrics data"/>
|
||||
@@ -36,10 +37,10 @@
|
||||
<meta property="og:title" content="UI for VictoriaMetrics">
|
||||
<meta property="og:url" content="https://victoriametrics.com/">
|
||||
<meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data">
|
||||
<script type="module" crossorigin src="./assets/index-DQcPcJrn.js"></script>
|
||||
<script type="module" crossorigin src="./assets/index-D13qGB62.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-DY9kCvzk.js">
|
||||
<link rel="stylesheet" crossorigin href="./assets/vendor-D1GxaB_c.css">
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-dWApsAEM.css">
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-I8MVeF75.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.25.1 AS build-web-stage
|
||||
FROM golang:1.25.3 AS build-web-stage
|
||||
COPY build /build
|
||||
|
||||
WORKDIR /build
|
||||
@@ -6,7 +6,7 @@ COPY web/ /build/
|
||||
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o web-amd64 github.com/VictoriMetrics/vmui/ && \
|
||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o web-windows github.com/VictoriMetrics/vmui/
|
||||
|
||||
FROM alpine:3.22.1
|
||||
FROM alpine:3.22.2
|
||||
USER root
|
||||
|
||||
COPY --from=build-web-stage /build/web-amd64 /app/web
|
||||
|
||||
@@ -79,15 +79,13 @@ export default [...compat.extends(
|
||||
}],
|
||||
|
||||
"react/jsx-first-prop-new-line": [1, "multiline"],
|
||||
"object-curly-spacing": [2, "always"],
|
||||
|
||||
indent: ["error", 2, {
|
||||
SwitchCase: 1,
|
||||
}],
|
||||
// Disable core indent rule due to recursion issues in ESLint 9; use JSX-specific rules instead
|
||||
indent: "off",
|
||||
"react/jsx-indent": ["error", 2],
|
||||
"react/jsx-indent-props": ["error", 2],
|
||||
|
||||
"linebreak-style": ["error", "unix"],
|
||||
quotes: ["error", "double"],
|
||||
semi: ["error", "always"],
|
||||
// Formatting rules moved out of ESLint core; omit here to avoid deprecation noise
|
||||
"react/prop-types": 0,
|
||||
"react/react-in-jsx-scope": "off",
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ The list of MetricsQL features on top of PromQL:
|
||||
* `if` binary operator. `q1 if q2` removes values from `q1` for missing values from `q2`.
|
||||
* `ifnot` binary operator. `q1 ifnot q2` removes values from `q1` for existing values from `q2`.
|
||||
* `WITH` templates. This feature simplifies writing and managing complex queries.
|
||||
Go to [WITH templates playground](https://play.victoriametrics.com/select/accounting/1/6a716b0f-38bc-4856-90ce-448fd713e3fe/expand-with-exprs) and try it.
|
||||
Go to [WITH templates playground](https://play.victoriametrics.com/select/0/prometheus/graph/#/expand-with-exprs) and try it.
|
||||
* String literals may be concatenated. This is useful with `WITH` templates:
|
||||
`WITH (commonPrefix="long_metric_prefix_") {__name__=commonPrefix+"suffix1"} / {__name__=commonPrefix+"suffix2"}`.
|
||||
* `keep_metric_names` modifier can be applied to all the [rollup functions](#rollup-functions), [transform functions](#transform-functions)
|
||||
|
||||
@@ -116,7 +116,7 @@ const LegendConfigs: FC<Props> = ({ data, isCompact }) => {
|
||||
onEnter={onApplyFormat}
|
||||
/>
|
||||
<span className="vm-legend-configs-item__info vm-legend-configs-item__info_input">
|
||||
Customize legend labels with text and {{label_name}} placeholders.
|
||||
Customize legend labels with text and {{label_name}} placeholders.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -130,7 +130,7 @@ const LegendConfigs: FC<Props> = ({ data, isCompact }) => {
|
||||
searchable
|
||||
/>
|
||||
<span className="vm-legend-configs-item__info">
|
||||
Choose a label to group the legend. By default, legends are grouped by query.
|
||||
Choose a label to group the legend. By default, legends are grouped by query.
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -142,7 +142,7 @@ const StepConfigurator: FC = () => {
|
||||
startIcon={<TimelineIcon/>}
|
||||
onClick={toggleOpenOptions}
|
||||
>
|
||||
Step: {isAutoStep ? `auto (${customStep})` : customStep}
|
||||
Step: {isAutoStep ? `auto (${customStep})` : customStep}
|
||||
</Button>
|
||||
)}
|
||||
<Popper
|
||||
|
||||
@@ -9,6 +9,7 @@ import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
interface NotifiersHeaderProps {
|
||||
kinds: string[];
|
||||
allKinds: string[];
|
||||
search: string;
|
||||
onChangeKinds: (input: string) => void;
|
||||
onChangeSearch: (input: string) => void;
|
||||
}
|
||||
@@ -16,6 +17,7 @@ interface NotifiersHeaderProps {
|
||||
const NotifiersHeader: FC<NotifiersHeaderProps> = ({
|
||||
kinds,
|
||||
allKinds,
|
||||
search,
|
||||
onChangeKinds,
|
||||
onChangeSearch,
|
||||
}) => {
|
||||
@@ -46,6 +48,7 @@ const NotifiersHeader: FC<NotifiersHeaderProps> = ({
|
||||
<div className="vm-explore-alerts-header-search">
|
||||
<TextField
|
||||
label="Search"
|
||||
value={search}
|
||||
placeholder="Filter by kind, address or labels"
|
||||
startIcon={<SearchIcon />}
|
||||
onChange={onChangeSearch}
|
||||
|
||||
@@ -11,6 +11,7 @@ interface RulesHeaderProps {
|
||||
allTypes: string[];
|
||||
allStates: string[];
|
||||
states: string[];
|
||||
search: string;
|
||||
onChangeTypes: (input: string) => void;
|
||||
onChangeStates: (input: string) => void;
|
||||
onChangeSearch: (input: string) => void;
|
||||
@@ -21,6 +22,7 @@ const RulesHeader: FC<RulesHeaderProps> = ({
|
||||
allTypes,
|
||||
allStates,
|
||||
states,
|
||||
search,
|
||||
onChangeTypes,
|
||||
onChangeStates,
|
||||
onChangeSearch,
|
||||
@@ -69,6 +71,7 @@ const RulesHeader: FC<RulesHeaderProps> = ({
|
||||
<div className="vm-explore-alerts-header-search">
|
||||
<TextField
|
||||
label="Search"
|
||||
value={search}
|
||||
placeholder="Filter by rule, name or labels"
|
||||
startIcon={<SearchIcon />}
|
||||
onChange={onChangeSearch}
|
||||
|
||||
@@ -106,7 +106,7 @@ const ExploreMetricItemHeader: FC<ExploreMetricItemControlsProps> = ({
|
||||
onClick={handleClickRemove}
|
||||
fullWidth
|
||||
>
|
||||
Remove graph
|
||||
Remove graph
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
@@ -117,7 +117,7 @@ const Calendar: FC<DatePickerProps> = ({
|
||||
size="small"
|
||||
onClick={handleToday}
|
||||
>
|
||||
show today
|
||||
show today
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -59,7 +59,7 @@ const CalendarBody: FC<CalendarBodyProps> = ({ minDate, maxDate, viewDate: date,
|
||||
"vm-calendar-body-cell_day_disabled": isDisabled,
|
||||
})}
|
||||
key={d ? d.format(format) : i}
|
||||
onClick={createHandlerSelectDate(d)}
|
||||
onClick={isDisabled ? undefined : createHandlerSelectDate(d)}
|
||||
>
|
||||
{d && d.format("D")}
|
||||
</div>
|
||||
|
||||
@@ -8,13 +8,13 @@ import useBoolean from "../../../hooks/useBoolean";
|
||||
import useEventListener from "../../../hooks/useEventListener";
|
||||
|
||||
interface DatePickerProps {
|
||||
date: string | Date | Dayjs,
|
||||
date: string | Date | Dayjs;
|
||||
targetRef: React.RefObject<HTMLElement>;
|
||||
format?: string;
|
||||
label?: string;
|
||||
minDate?: Date | Dayjs;
|
||||
maxDate?: Date | Dayjs;
|
||||
onChange: (val: string) => void
|
||||
onChange: (val: string) => void;
|
||||
}
|
||||
|
||||
const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(({
|
||||
|
||||
@@ -142,6 +142,7 @@ const TextField: FC<TextFieldProps> = ({
|
||||
>
|
||||
{startIcon && <div className="vm-text-field__icon-start">{startIcon}</div>}
|
||||
{endIcon && <div className="vm-text-field__icon-end">{endIcon}</div>}
|
||||
{label && <span className="vm-text-field__label">{label}</span>}
|
||||
{type === "textarea"
|
||||
? (
|
||||
<textarea
|
||||
@@ -180,7 +181,6 @@ const TextField: FC<TextFieldProps> = ({
|
||||
/>
|
||||
)
|
||||
}
|
||||
{label && <span className="vm-text-field__label">{label}</span>}
|
||||
<TextFieldMessage
|
||||
error={error}
|
||||
warning={warning}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
@use "src/styles/variables" as *;
|
||||
|
||||
.vm-text-field {
|
||||
position: relative;
|
||||
display: grid;
|
||||
margin: 6px 0;
|
||||
width: 100%;
|
||||
@@ -31,7 +30,7 @@
|
||||
background-color: transparent;
|
||||
font-size: $font-size;
|
||||
line-height: 18px;
|
||||
grid-area: 1 / 1 / 2 / 2;
|
||||
grid-area: 2 / 1 / 2 / 2;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -40,8 +39,10 @@
|
||||
&__error,
|
||||
&__warning,
|
||||
&__helper-text, {
|
||||
position: absolute;
|
||||
left: calc($padding-global/2);
|
||||
width: fit-content;
|
||||
margin-top: calc(($font-size-small/-2) - 1px);
|
||||
margin-bottom: calc(($font-size-small/-2) - 1px);
|
||||
margin-left: calc($padding-global/2);
|
||||
max-width: calc(100% - $padding-global);
|
||||
padding: 0 3px;
|
||||
font-size: $font-size-small;
|
||||
@@ -59,16 +60,12 @@
|
||||
}
|
||||
|
||||
&__label {
|
||||
top: calc(($font-size-small/-2) - 2px);
|
||||
color: $color-text-secondary;
|
||||
}
|
||||
|
||||
&__helper-text,
|
||||
&__warning,
|
||||
&__error {
|
||||
position: relative;
|
||||
top: calc($font-size-small/-2);
|
||||
width: fit-content;
|
||||
overflow-wrap: anywhere;
|
||||
pointer-events: auto;
|
||||
user-select: text;
|
||||
@@ -152,28 +149,17 @@
|
||||
|
||||
&__icon-start,
|
||||
&__icon-end {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
align-self: center;
|
||||
max-width: 15px;
|
||||
top: 0;
|
||||
left: $padding-small;
|
||||
height: 36px;
|
||||
position: absolute;
|
||||
color: $color-text-secondary;
|
||||
}
|
||||
|
||||
&__icon-start {
|
||||
left: $padding-small;
|
||||
}
|
||||
|
||||
&__icon-end {
|
||||
left: auto;
|
||||
right: $padding-small;
|
||||
}
|
||||
|
||||
&__controls-info {
|
||||
position: absolute;
|
||||
bottom: $padding-small;
|
||||
right: $padding-global;
|
||||
color: $color-text-secondary;
|
||||
font-size: $font-size-small;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ const TableSettings: FC<TableSettingsProps> = ({
|
||||
{toggleTableCompact && tableCompact !== undefined && (
|
||||
<div className="vm-table-settings-modal-section">
|
||||
<div className="vm-table-settings-modal-section__title">
|
||||
Table view
|
||||
Table view
|
||||
</div>
|
||||
<div className="vm-table-settings-modal-columns-list__item">
|
||||
<Switch
|
||||
|
||||
@@ -75,7 +75,7 @@ const TracingsView: FC<TraceViewProps> = ({ traces, jsonEditor = false, onDelete
|
||||
>
|
||||
<div className="vm-tracings-view-trace-header">
|
||||
<h3 className="vm-tracings-view-trace-header-title">
|
||||
Trace for <b className="vm-tracings-view-trace-header-title__query">{trace.queryValue}</b>
|
||||
Trace for <b className="vm-tracings-view-trace-header-title__query">{trace.queryValue}</b>
|
||||
</h3>
|
||||
<Tooltip title={expandedTraces.includes(trace.idValue) ? "Collapse All" : "Expand All"}>
|
||||
<Button
|
||||
|
||||
@@ -128,7 +128,7 @@ const TableView: FC<GraphViewProps> = ({ data, displayColumns }) => {
|
||||
>
|
||||
<ArrowDropDownIcon/>
|
||||
</div>
|
||||
Value
|
||||
Value
|
||||
</div>
|
||||
</td>
|
||||
{hasCopyValue && <td className="vm-table-cell vm-table-cell_header"/>}
|
||||
|
||||
@@ -45,7 +45,7 @@ export const lightPalette = {
|
||||
"color-success": "#4caf50",
|
||||
"color-background-success": "#d4ecd5",
|
||||
"color-passive": "#5d6267",
|
||||
"color-code": "ecedee",
|
||||
"color-code": "#ecedee",
|
||||
"color-background-body": "#FEFEFF",
|
||||
"color-background-block": "#FFFFFF",
|
||||
"color-background-tooltip": "rgba(80,80,80,0.9)",
|
||||
|
||||
@@ -61,7 +61,7 @@ const DebugInfoClipboardApi = () => (
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Clipboard API documentation
|
||||
Clipboard API documentation
|
||||
</a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
@@ -1,42 +1,39 @@
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import { useCallback } from "preact/compat";
|
||||
|
||||
type ParamValue = string | number | boolean | null | undefined;
|
||||
|
||||
const useSearchParamsFromObject = () => {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
const setSearchParamsFromKeys = useCallback((objectParams: Record<string, string | number>) => {
|
||||
const hasSearchParams = !!searchParams.size;
|
||||
let hasChanged = false;
|
||||
const setSearchParamsFromKeys = useCallback((objectParams: Record<string, ParamValue>) => {
|
||||
const hadParams = !!searchParams.size;
|
||||
|
||||
const newSearchParams = new URLSearchParams(searchParams);
|
||||
searchParams.keys().forEach(key => {
|
||||
if (!(key in objectParams)) {
|
||||
const beforeParams = searchParams.toString();
|
||||
|
||||
for (const [key, newValue] of Object.entries(objectParams)) {
|
||||
const isEmpty = newValue === null || newValue === undefined || newValue === "";
|
||||
|
||||
if (isEmpty) {
|
||||
newSearchParams.delete(key);
|
||||
hasChanged = true;
|
||||
continue;
|
||||
}
|
||||
});
|
||||
|
||||
Object.entries(objectParams).forEach(([key, value]) => {
|
||||
if (newSearchParams.get(key) !== `${value}`) {
|
||||
newSearchParams.set(key, `${value}`);
|
||||
hasChanged = true;
|
||||
const next = String(newValue);
|
||||
if (newSearchParams.get(key) !== next) {
|
||||
newSearchParams.set(key, next);
|
||||
}
|
||||
});
|
||||
|
||||
if (!hasChanged) return;
|
||||
|
||||
if (hasSearchParams) {
|
||||
setSearchParams(newSearchParams);
|
||||
} else {
|
||||
navigate(`?${newSearchParams.toString()}`, { replace: true });
|
||||
}
|
||||
}, [searchParams, navigate]);
|
||||
|
||||
return {
|
||||
setSearchParamsFromKeys
|
||||
};
|
||||
if (beforeParams === newSearchParams.toString()) return;
|
||||
|
||||
setSearchParams(newSearchParams, { replace: !hadParams });
|
||||
},
|
||||
[searchParams, setSearchParams]
|
||||
);
|
||||
|
||||
return { setSearchParamsFromKeys };
|
||||
};
|
||||
|
||||
export default useSearchParamsFromObject;
|
||||
|
||||
@@ -67,39 +67,27 @@ const Header: FC<HeaderProps> = ({ controlsComponent }) => {
|
||||
})}
|
||||
style={{ background, color }}
|
||||
>
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-header-logo": true,
|
||||
"vm-header-logo_mobile": displaySidebar,
|
||||
})}
|
||||
onClick={onClickLogo}
|
||||
style={{ color }}
|
||||
>
|
||||
{<Logo/>}
|
||||
</div>
|
||||
|
||||
{displaySidebar ? (
|
||||
<SidebarHeader
|
||||
background={background}
|
||||
color={color}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{!appModeEnable && (
|
||||
<div
|
||||
className="vm-header-logo"
|
||||
onClick={onClickLogo}
|
||||
style={{ color }}
|
||||
>
|
||||
{<Logo/>}
|
||||
</div>
|
||||
)}
|
||||
<HeaderNav
|
||||
color={color}
|
||||
background={background}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{displaySidebar && (
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-header-logo": true,
|
||||
"vm-header-logo_mobile": true,
|
||||
})}
|
||||
onClick={onClickLogo}
|
||||
style={{ color }}
|
||||
>
|
||||
{<Logo/>}
|
||||
</div>
|
||||
<HeaderNav
|
||||
color={color}
|
||||
background={background}
|
||||
/>
|
||||
)}
|
||||
<HeaderControls
|
||||
controlsComponent={controlsComponent}
|
||||
|
||||
@@ -53,7 +53,7 @@ const HeaderControls: FC<ControlsProps & HeaderProps> = ({
|
||||
if (isMobile) {
|
||||
return (
|
||||
<>
|
||||
<div className="vm-header-controls">
|
||||
<div className="vm-header-controls vm-header-controls_mobile">
|
||||
<Button
|
||||
className={classNames({
|
||||
"vm-header-button": !appModeEnable
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@use "src/styles/variables" as *;
|
||||
|
||||
.vm-header-controls {
|
||||
order: 3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
@@ -11,6 +12,7 @@
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
padding: 0;
|
||||
flex-grow: initial;
|
||||
|
||||
.vm-header-button {
|
||||
border: none;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
$sidebar-transition: cubic-bezier(0.280, 0.840, 0.420, 1);
|
||||
|
||||
.vm-header-sidebar {
|
||||
order: 1;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: inherit;
|
||||
@@ -16,7 +17,7 @@ $sidebar-transition: cubic-bezier(0.280, 0.840, 0.420, 1);
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 51px;
|
||||
width: 51px;
|
||||
width: 48px;
|
||||
transition: left 350ms $sidebar-transition;
|
||||
|
||||
&_open {
|
||||
@@ -53,15 +54,6 @@ $sidebar-transition: cubic-bezier(0.280, 0.840, 0.420, 1);
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
&__logo {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
cursor: pointer;
|
||||
width: 65px;
|
||||
}
|
||||
|
||||
&-settings {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
@media (max-width: 1000px) {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
gap: $padding-small;
|
||||
padding: $padding-small;
|
||||
}
|
||||
|
||||
@@ -53,6 +52,7 @@
|
||||
}
|
||||
|
||||
&_mobile {
|
||||
order: 2;
|
||||
max-width: 75px;
|
||||
min-width: 75px;
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -13,6 +13,8 @@ import useSearchParamsFromObject from "../../../hooks/useSearchParamsFromObject"
|
||||
import useStateSearchParams from "../../../hooks/useStateSearchParams";
|
||||
import Hyperlink from "../../../components/Main/Hyperlink/Hyperlink";
|
||||
|
||||
const DEFAULT_TOP_N = 10;
|
||||
|
||||
const CardinalityConfigurator: FC<CardinalityTotalsProps> = ({ isPrometheus, isCluster, ...props }) => {
|
||||
const { isMobile } = useDeviceDetect();
|
||||
const [searchParams] = useSearchParams();
|
||||
@@ -21,7 +23,8 @@ const CardinalityConfigurator: FC<CardinalityTotalsProps> = ({ isPrometheus, isC
|
||||
const showTips = searchParams.get("tips") || "";
|
||||
const [match, setMatch] = useStateSearchParams("", "match");
|
||||
const [focusLabel, setFocusLabel] = useStateSearchParams("", "focusLabel");
|
||||
const [topN, setTopN] = useStateSearchParams(10, "topN");
|
||||
const [topN, setTopN] = useStateSearchParams(DEFAULT_TOP_N, "topN");
|
||||
const hasChanges = !!(match || focusLabel || (topN !== DEFAULT_TOP_N && !isPrometheus));
|
||||
|
||||
const errorTopN = useMemo(() => topN < 0 ? "Number must be bigger than zero" : "", [topN]);
|
||||
|
||||
@@ -35,7 +38,10 @@ const CardinalityConfigurator: FC<CardinalityTotalsProps> = ({ isPrometheus, isC
|
||||
};
|
||||
|
||||
const handleResetQuery = () => {
|
||||
setSearchParamsFromKeys({ match: "", focusLabel: "" });
|
||||
setSearchParamsFromKeys({ match: "", focusLabel: "", topN: "" });
|
||||
setMatch("");
|
||||
setFocusLabel("");
|
||||
setTopN(DEFAULT_TOP_N);
|
||||
};
|
||||
|
||||
const handleToggleTips = () => {
|
||||
@@ -45,7 +51,7 @@ const CardinalityConfigurator: FC<CardinalityTotalsProps> = ({ isPrometheus, isC
|
||||
|
||||
useEffect(() => {
|
||||
const matchQuery = searchParams.get("match");
|
||||
const topNQuery = +(searchParams.get("topN") || 10);
|
||||
const topNQuery = +(searchParams.get("topN") || DEFAULT_TOP_N);
|
||||
const focusLabelQuery = searchParams.get("focusLabel");
|
||||
if (matchQuery !== match) setMatch(matchQuery || "");
|
||||
if (topNQuery !== topN) setTopN(topNQuery);
|
||||
@@ -94,7 +100,7 @@ const CardinalityConfigurator: FC<CardinalityTotalsProps> = ({ isPrometheus, isC
|
||||
<TextField
|
||||
label="Limit entries"
|
||||
type="number"
|
||||
value={isPrometheus ? 10 : topN}
|
||||
value={isPrometheus ? DEFAULT_TOP_N : topN}
|
||||
error={errorTopN}
|
||||
disabled={isPrometheus}
|
||||
helperText={isPrometheus ? "not available for Prometheus" : ""}
|
||||
@@ -116,7 +122,7 @@ const CardinalityConfigurator: FC<CardinalityTotalsProps> = ({ isPrometheus, isC
|
||||
withIcon={true}
|
||||
>
|
||||
<WikiIcon/>
|
||||
Statistic inaccuracy explanation
|
||||
Statistic inaccuracy explanation
|
||||
</Hyperlink>
|
||||
</div>
|
||||
}
|
||||
@@ -145,8 +151,9 @@ const CardinalityConfigurator: FC<CardinalityTotalsProps> = ({ isPrometheus, isC
|
||||
variant="text"
|
||||
startIcon={<RestartIcon/>}
|
||||
onClick={handleResetQuery}
|
||||
disabled={!hasChanges}
|
||||
>
|
||||
Reset
|
||||
Reset filters
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<PlayIcon/>}
|
||||
|
||||
@@ -5,6 +5,7 @@ import usePrevious from "../../../hooks/usePrevious";
|
||||
import { MAX_QUERY_FIELDS } from "../../../constants/graph";
|
||||
import { useQueryDispatch, useQueryState } from "../../../state/query/QueryStateContext";
|
||||
import { useTimeDispatch } from "../../../state/time/TimeStateContext";
|
||||
import { getQueryStringValue } from "../../../utils/query-string";
|
||||
import {
|
||||
DeleteIcon,
|
||||
PlayIcon,
|
||||
@@ -21,6 +22,7 @@ import classNames from "classnames";
|
||||
import { MouseEvent as ReactMouseEvent } from "react";
|
||||
import { arrayEquals } from "../../../utils/array";
|
||||
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
import useSearchParamsFromObject from "../../../hooks/useSearchParamsFromObject";
|
||||
import { QueryStats } from "../../../api/types";
|
||||
import { usePrettifyQuery } from "./hooks/usePrettifyQuery";
|
||||
import QueryHistory from "../../../components/QueryHistory/QueryHistory";
|
||||
@@ -50,6 +52,9 @@ export interface QueryConfiguratorProps {
|
||||
}
|
||||
}
|
||||
|
||||
const defaultHideQueryStr = getQueryStringValue("expr.hide", "") as string;
|
||||
const defaultHideQuery: number[] = defaultHideQueryStr.split(",").filter(v => v).map(Number);
|
||||
|
||||
const QueryConfigurator: FC<QueryConfiguratorProps> = ({
|
||||
queryErrors,
|
||||
setQueryErrors,
|
||||
@@ -69,9 +74,10 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
|
||||
const { query, queryHistory, autocomplete, autocompleteQuick } = useQueryState();
|
||||
const queryDispatch = useQueryDispatch();
|
||||
const timeDispatch = useTimeDispatch();
|
||||
const { setSearchParamsFromKeys } = useSearchParamsFromObject();
|
||||
|
||||
const [stateQuery, setStateQuery] = useState(query || []);
|
||||
const [hideQuery, setHideQuery] = useState<number[]>([]);
|
||||
const [hideQuery, setHideQuery] = useState<number[]>(defaultHideQuery);
|
||||
const [awaitStateQuery, setAwaitStateQuery] = useState(false);
|
||||
const prevStateQuery = usePrevious(stateQuery) as (undefined | string[]);
|
||||
|
||||
@@ -176,6 +182,7 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
|
||||
|
||||
useEffect(() => {
|
||||
onHideQuery && onHideQuery(hideQuery);
|
||||
setSearchParamsFromKeys({ "expr.hide": hideQuery.join(",") });
|
||||
}, [hideQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -17,8 +17,8 @@ const WarningHeatmapToLine:FC = () => {
|
||||
<Alert variant="warning">
|
||||
<div className="vm-warning-heatmap-to-line">
|
||||
<p className="vm-warning-heatmap-to-line__text">
|
||||
The expression cannot be displayed as a heatmap.
|
||||
To make the graph work, disable the heatmap in the "Graph settings" or modify the expression.
|
||||
The expression cannot be displayed as a heatmap.
|
||||
To make the graph work, disable the heatmap in the "Graph settings" or modify the expression.
|
||||
</p>
|
||||
|
||||
<Button
|
||||
|
||||
@@ -40,7 +40,7 @@ const WarningLimitSeries: FC<Props> = ({ warning, query, onChange }) => {
|
||||
variant="outlined"
|
||||
onClick={handleShowAll}
|
||||
>
|
||||
Show all
|
||||
Show all
|
||||
</Button>
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
@@ -58,6 +58,11 @@ export const useSetQueryParams = () => {
|
||||
newSearchParams.set(`${group}.relative_time`, relativeTime || "none");
|
||||
}
|
||||
|
||||
const exprHide = searchParams.get("expr.hide") || "";
|
||||
if (exprHide !== "") {
|
||||
newSearchParams.set("expr.hide", exprHide);
|
||||
}
|
||||
|
||||
const stepFromUrl = searchParams.get(`${group}.step_input`) || step;
|
||||
if (stepFromUrl && (stepFromUrl !== customStep)) {
|
||||
newSearchParams.set(`${group}.step_input`, customStep);
|
||||
|
||||
@@ -105,6 +105,7 @@ const ExploreNotifiers: FC = () => {
|
||||
<NotifiersHeader
|
||||
kinds={kinds}
|
||||
allKinds={Array.from(allKinds)}
|
||||
search={searchInput}
|
||||
onChangeKinds={handleChangeKinds}
|
||||
onChangeSearch={debounce(handleChangeSearch, 500)}
|
||||
/>
|
||||
|
||||
@@ -90,14 +90,6 @@ const ExploreRules: FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleChangeStates = useCallback((title: string) => {
|
||||
setStates(getChanges(title, states));
|
||||
}, [states]);
|
||||
|
||||
const handleChangeTypes = useCallback((title: string) => {
|
||||
setTypes(getChanges(title, types));
|
||||
}, [types]);
|
||||
|
||||
const noRuleFound = "No rules found!";
|
||||
|
||||
const handleClose = (id: string) => {
|
||||
@@ -155,9 +147,24 @@ const ExploreRules: FC = () => {
|
||||
[groups, types, states, searchInput]
|
||||
);
|
||||
|
||||
if (!types.every(v => allTypes.has(v))) {
|
||||
setTypes([]);
|
||||
}
|
||||
const selectedTypes = allTypes.size === types.length ? [] : types;
|
||||
|
||||
if (!states.every(v => allStates.has(v))) {
|
||||
setStates([]);
|
||||
}
|
||||
const selectedStates = allStates.size === states.length ? [] : states;
|
||||
|
||||
const handleChangeStates = useCallback((title: string) => {
|
||||
setStates(getChanges(title, selectedStates));
|
||||
}, [states]);
|
||||
|
||||
const handleChangeTypes = useCallback((title: string) => {
|
||||
setTypes(getChanges(title, selectedTypes));
|
||||
}, [types]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{modalOpen && getModal()}
|
||||
@@ -168,6 +175,7 @@ const ExploreRules: FC = () => {
|
||||
allTypes={Array.from(allTypes)}
|
||||
states={selectedStates}
|
||||
allStates={Array.from(allStates)}
|
||||
search={searchInput}
|
||||
onChangeTypes={handleChangeTypes}
|
||||
onChangeStates={handleChangeStates}
|
||||
onChangeSearch={debounce(handleChangeSearch, 500)}
|
||||
|
||||
@@ -19,8 +19,8 @@ const getProxy = (): Record<string, ProxyOptions> | undefined => {
|
||||
});
|
||||
},
|
||||
},
|
||||
"/flags": {
|
||||
target: "https://play.victoriametrics.com",
|
||||
"/vmui/config.json": {
|
||||
target: "https://play.victoriametrics.com/select/0",
|
||||
changeOrigin: true,
|
||||
configure: (proxy) => {
|
||||
proxy.on("error", (err) => {
|
||||
|
||||
@@ -314,7 +314,7 @@ func testInstantQueryWithOffsetUsingCache(tc *apptest.TestCase, sut apptest.Prom
|
||||
DoNotRetry: true,
|
||||
Got: func() any {
|
||||
return sut.PrometheusAPIV1Query(t, `avg_over_time(vm_http_requests_total[1d] offset 12h)`, apptest.QueryOpts{
|
||||
Time: "2025-09-20T12:00:00.000Z",
|
||||
Time: "2025-09-20T12:00:01.000Z",
|
||||
})
|
||||
},
|
||||
Want: &apptest.PrometheusAPIV1QueryResponse{
|
||||
@@ -324,7 +324,7 @@ func testInstantQueryWithOffsetUsingCache(tc *apptest.TestCase, sut apptest.Prom
|
||||
Result: []*apptest.QueryResult{
|
||||
{
|
||||
Metric: map[string]string{},
|
||||
Sample: &apptest.Sample{Timestamp: 1758369600000, Value: 5.5},
|
||||
Sample: &apptest.Sample{Timestamp: 1758369601000, Value: 5.5},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -5739,7 +5739,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "min((vm_free_disk_space_bytes{job=~\"$job_storage\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job_storage\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d])) without (type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"})\n )\n) > 0)",
|
||||
"expr": "min((vm_free_disk_space_bytes{job=~\"$job_storage\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job_storage\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d])) without(type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type)\n )\n) > 0)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
@@ -10294,7 +10294,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "(vm_free_disk_space_bytes{job=~\"$job_storage\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job_storage\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d])) without (type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"})\n )\n) > 0",
|
||||
"expr": "(vm_free_disk_space_bytes{job=~\"$job_storage\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job_storage\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d])) without(type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type)\n )\n) > 0",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
|
||||
@@ -4991,7 +4991,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "(vm_free_disk_space_bytes{job=~\"$job\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job\", instance=~\"$instance\"}[1d])) without (type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job\", instance=~\"$instance\", type=\"indexdb/file\"}) /\n sum(vm_rows{job=~\"$job\", instance=~\"$instance\", type=\"indexdb/file\"})\n )\n) > 0",
|
||||
"expr": "(vm_free_disk_space_bytes{job=~\"$job\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job\", instance=~\"$instance\"}[1d])) without(type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type) /\n sum(vm_rows{job=~\"$job\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type)\n )\n) > 0",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"interval": "",
|
||||
@@ -6764,4 +6764,4 @@
|
||||
"uid": "wNf0q_kZk",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5739,7 +5739,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "min((vm_free_disk_space_bytes{job=~\"$job_storage\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job_storage\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d])) without (type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"})\n )\n) > 0)",
|
||||
"expr": "min((vm_free_disk_space_bytes{job=~\"$job_storage\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job_storage\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d])) without(type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type)\n )\n) > 0)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
@@ -10294,7 +10294,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "(vm_free_disk_space_bytes{job=~\"$job_storage\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job_storage\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d])) without (type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"})\n )\n) > 0",
|
||||
"expr": "(vm_free_disk_space_bytes{job=~\"$job_storage\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job_storage\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d])) without(type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job_storage\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type) /\n sum(vm_rows{job=~\"$job_storage\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type) \n )\n) > 0",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
|
||||
@@ -4992,7 +4992,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "(vm_free_disk_space_bytes{job=~\"$job\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job\", instance=~\"$instance\"}[1d])) without (type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job\", instance=~\"$instance\", type=\"indexdb/file\"}) /\n sum(vm_rows{job=~\"$job\", instance=~\"$instance\", type=\"indexdb/file\"})\n )\n) > 0",
|
||||
"expr": "(vm_free_disk_space_bytes{job=~\"$job\", instance=~\"$instance\"}-vm_free_disk_space_limit_bytes{job=~\"$job\", instance=~\"$instance\"}) \n/ \nignoring(path) (\n (rate(vm_rows_added_to_storage_total{job=~\"$job\", instance=~\"$instance\"}[1d]) - \n sum(rate(vm_deduplicated_samples_total{job=~\"$job\", instance=~\"$instance\"}[1d])) without(type)) * \n (\n sum(vm_data_size_bytes{job=~\"$job\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type) /\n sum(vm_rows{job=~\"$job\", instance=~\"$instance\", type!~\"indexdb.*\"}) without(type)\n )\n +\n rate(vm_new_timeseries_created_total{job=~\"$job\", instance=~\"$instance\"}[1d]) * \n (\n sum(vm_data_size_bytes{job=~\"$job\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type) /\n sum(vm_rows{job=~\"$job\", instance=~\"$instance\", type=\"indexdb/file\"}) without(type)\n )\n) > 0",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"interval": "",
|
||||
@@ -6765,4 +6765,4 @@
|
||||
"uid": "wNf0q_kZk_vm",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
DOCKER_REGISTRIES ?= docker.io quay.io
|
||||
DOCKER_NAMESPACE ?= victoriametrics
|
||||
|
||||
ROOT_IMAGE ?= alpine:3.22.1
|
||||
ROOT_IMAGE ?= alpine:3.22.2
|
||||
ROOT_IMAGE_SCRATCH ?= scratch
|
||||
CERTS_IMAGE := alpine:3.22.1
|
||||
CERTS_IMAGE := alpine:3.22.2
|
||||
|
||||
GO_BUILDER_IMAGE := golang:1.25.1
|
||||
GO_BUILDER_IMAGE := golang:1.25.3
|
||||
|
||||
BUILDER_IMAGE := local/builder:2.0.0-$(shell echo $(GO_BUILDER_IMAGE) | tr :/ __)-1
|
||||
BASE_IMAGE := local/base:1.1.4-$(shell echo $(ROOT_IMAGE) | tr :/ __)-$(shell echo $(CERTS_IMAGE) | tr :/ __)
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
# It scrapes targets defined in --promscrape.config
|
||||
# And forward them to --remoteWrite.url
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.126.0
|
||||
image: victoriametrics/vmagent:v1.127.0
|
||||
depends_on:
|
||||
- "vmauth"
|
||||
ports:
|
||||
@@ -37,14 +37,14 @@ services:
|
||||
# vmstorage shards. Each shard receives 1/N of all metrics sent to vminserts,
|
||||
# where N is number of vmstorages (2 in this case).
|
||||
vmstorage-1:
|
||||
image: victoriametrics/vmstorage:v1.126.0-cluster
|
||||
image: victoriametrics/vmstorage:v1.127.0-cluster
|
||||
volumes:
|
||||
- strgdata-1:/storage
|
||||
command:
|
||||
- "--storageDataPath=/storage"
|
||||
restart: always
|
||||
vmstorage-2:
|
||||
image: victoriametrics/vmstorage:v1.126.0-cluster
|
||||
image: victoriametrics/vmstorage:v1.127.0-cluster
|
||||
volumes:
|
||||
- strgdata-2:/storage
|
||||
command:
|
||||
@@ -54,7 +54,7 @@ services:
|
||||
# vminsert is ingestion frontend. It receives metrics pushed by vmagent,
|
||||
# pre-process them and distributes across configured vmstorage shards.
|
||||
vminsert-1:
|
||||
image: victoriametrics/vminsert:v1.126.0-cluster
|
||||
image: victoriametrics/vminsert:v1.127.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -63,7 +63,7 @@ services:
|
||||
- "--storageNode=vmstorage-2:8400"
|
||||
restart: always
|
||||
vminsert-2:
|
||||
image: victoriametrics/vminsert:v1.126.0-cluster
|
||||
image: victoriametrics/vminsert:v1.127.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -75,7 +75,7 @@ services:
|
||||
# vmselect is a query fronted. It serves read queries in MetricsQL or PromQL.
|
||||
# vmselect collects results from configured `--storageNode` shards.
|
||||
vmselect-1:
|
||||
image: victoriametrics/vmselect:v1.126.0-cluster
|
||||
image: victoriametrics/vmselect:v1.127.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -85,7 +85,7 @@ services:
|
||||
- "--vmalert.proxyURL=http://vmalert:8880"
|
||||
restart: always
|
||||
vmselect-2:
|
||||
image: victoriametrics/vmselect:v1.126.0-cluster
|
||||
image: victoriametrics/vmselect:v1.127.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -100,7 +100,7 @@ services:
|
||||
# read requests from Grafana, vmui, vmalert among vmselects.
|
||||
# It can be used as an authentication proxy.
|
||||
vmauth:
|
||||
image: victoriametrics/vmauth:v1.126.0
|
||||
image: victoriametrics/vmauth:v1.127.0
|
||||
depends_on:
|
||||
- "vmselect-1"
|
||||
- "vmselect-2"
|
||||
@@ -114,7 +114,7 @@ services:
|
||||
|
||||
# vmalert executes alerting and recording rules
|
||||
vmalert:
|
||||
image: victoriametrics/vmalert:v1.126.0
|
||||
image: victoriametrics/vmalert:v1.127.0
|
||||
depends_on:
|
||||
- "vmauth"
|
||||
ports:
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
# It scrapes targets defined in --promscrape.config
|
||||
# And forward them to --remoteWrite.url
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.126.0
|
||||
image: victoriametrics/vmagent:v1.127.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
@@ -18,7 +18,7 @@ services:
|
||||
# VictoriaMetrics instance, a single process responsible for
|
||||
# storing metrics and serve read requests.
|
||||
victoriametrics:
|
||||
image: victoriametrics/victoria-metrics:v1.126.0
|
||||
image: victoriametrics/victoria-metrics:v1.127.0
|
||||
ports:
|
||||
- 8428:8428
|
||||
- 8089:8089
|
||||
@@ -54,7 +54,7 @@ services:
|
||||
|
||||
# vmalert executes alerting and recording rules
|
||||
vmalert:
|
||||
image: victoriametrics/vmalert:v1.126.0
|
||||
image: victoriametrics/vmalert:v1.127.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
- "alertmanager"
|
||||
|
||||
@@ -13,14 +13,14 @@ groups:
|
||||
expr: |
|
||||
sum(vm_free_disk_space_bytes) without(path) /
|
||||
(
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without(type)) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
+
|
||||
rate(vm_new_timeseries_created_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) /
|
||||
sum(vm_rows{type="indexdb/file"})
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) without(type) /
|
||||
sum(vm_rows{type="indexdb/file"}) without(type)
|
||||
)
|
||||
) < 3 * 24 * 3600 > 0
|
||||
for: 30m
|
||||
@@ -37,14 +37,14 @@ groups:
|
||||
expr: |
|
||||
sum(vm_free_disk_space_bytes - vm_free_disk_space_limit_bytes) without(path) /
|
||||
(
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without(type)) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
+
|
||||
rate(vm_new_timeseries_created_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) /
|
||||
sum(vm_rows{type="indexdb/file"})
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) without(type) /
|
||||
sum(vm_rows{type="indexdb/file"}) without(type)
|
||||
)
|
||||
) < 3 * 24 * 3600 > 0
|
||||
for: 30m
|
||||
|
||||
@@ -13,14 +13,14 @@ groups:
|
||||
expr: |
|
||||
sum(vm_free_disk_space_bytes) without(path) /
|
||||
(
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without(type)) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
+
|
||||
rate(vm_new_timeseries_created_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) /
|
||||
sum(vm_rows{type="indexdb/file"})
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) without(type)/
|
||||
sum(vm_rows{type="indexdb/file"}) without(type)
|
||||
)
|
||||
) < 3 * 24 * 3600 > 0
|
||||
for: 30m
|
||||
@@ -37,14 +37,14 @@ groups:
|
||||
expr: |
|
||||
sum(vm_free_disk_space_bytes - vm_free_disk_space_limit_bytes) without(path) /
|
||||
(
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without(type)) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
+
|
||||
rate(vm_new_timeseries_created_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) /
|
||||
sum(vm_rows{type="indexdb/file"})
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) without(type) /
|
||||
sum(vm_rows{type="indexdb/file"}) without(type)
|
||||
)
|
||||
) < 3 * 24 * 3600 > 0
|
||||
for: 30m
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.126.0
|
||||
image: victoriametrics/vmagent:v1.127.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
@@ -14,7 +14,7 @@ services:
|
||||
restart: always
|
||||
|
||||
victoriametrics:
|
||||
image: victoriametrics/victoria-metrics:v1.126.0
|
||||
image: victoriametrics/victoria-metrics:v1.127.0
|
||||
ports:
|
||||
- 8428:8428
|
||||
volumes:
|
||||
@@ -40,7 +40,7 @@ services:
|
||||
restart: always
|
||||
|
||||
vmalert:
|
||||
image: victoriametrics/vmalert:v1.126.0
|
||||
image: victoriametrics/vmalert:v1.127.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
@@ -59,7 +59,7 @@ services:
|
||||
- '--external.alert.source=explore?orgId=1&left=["now-1h","now","VictoriaMetrics",{"expr": },{"mode":"Metrics"},{"ui":[true,true,true,"none"]}]'
|
||||
restart: always
|
||||
vmanomaly:
|
||||
image: victoriametrics/vmanomaly:v1.25.3
|
||||
image: victoriametrics/vmanomaly:v1.26.2
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
|
||||
@@ -14,6 +14,35 @@ aliases:
|
||||
---
|
||||
Please find the changelog for VictoriaMetrics Anomaly Detection below.
|
||||
|
||||
## v1.26.2
|
||||
Released: 2025-10-09
|
||||
|
||||
- IMPROVEMENT: Resolved an issue with readers ([VmReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader), [VLogsReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#victorialogs-reader)) connection pool size - which defaulted to max(10, `reader.queries` cardinality) - that could lead to warnings in logs when the number of queries exceeds 10, such as:
|
||||
```shellhelp
|
||||
{timestamp} - urllib3.connectionpool - WARNING - Connection pool is full, discarding connection: {host}. Connection pool size: {N}
|
||||
```
|
||||
This happened in scenarios with a large number of queries (e.g., in non-sharded deployments). Now the pool size is set dynamically to prevent such warnings and retain efficient connection reuse.
|
||||
|
||||
## v1.26.1
|
||||
Released: 2025-10-08
|
||||
|
||||
- IMPROVEMENT: Enriched lifecycle logs with the deterministic labelset hash for each query result (metric). This allows correlating model training, inference runs/skips, and on-disk artifacts presence or cleanup during incident triage.
|
||||
|
||||
## v1.26.0
|
||||
Released: 2025-10-02
|
||||
|
||||
- FEATURE: Introduced vmui-like [UI](https://docs.victoriametrics.com/anomaly-detection/ui/) for `vmanomaly` service to simplify the configuration and backtesting of anomaly detection models before it goes to production. It provides an intuitive interface to finetune model configurations, visualize its predictions and anomaly scores, and perform backtesting on historical data. The UI is accessible via a web browser and can be run as a [standalone service](https://docs.victoriametrics.com/anomaly-detection/ui/#preset-usage) or [integrated with productionalized deployments](https://docs.victoriametrics.com/anomaly-detection/ui/#mixed-usage). For more details, refer to the [documentation](https://docs.victoriametrics.com/anomaly-detection/ui/).
|
||||
|
||||
- FEATURE: Added support for reading data from [VictoriaLogs stats queries](https://docs.victoriametrics.com/victorialogs/querying/#querying-log-range-stats) with `VLogsReader`. This reader allows quering and analyzing log data stored in VictoriaLogs, enabling anomaly detection on metrics generated from logs. It supports similar configuration options as `VmReader`, including `datasource_url`, `tenant_id`, `queries`, etc. For more details, refer to the [documentation](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vlogs-reader). It can be also used in [UI mode](https://docs.victoriametrics.com/anomaly-detection/ui/) for backtesting log-based anomaly detection configurations.
|
||||
|
||||
- IMPROVEMENT: Resolved the case in the [`IsolationForestModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#isolation-forest-multivariate) with `provide_series` common model [argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#provide-series) including `yhat.*` series (prediction and confidence boundaries), which are not produced by this model. Now config validation will fail with a clear error message if such series names are requested.
|
||||
|
||||
- BUGFIX: Recursive and shallow merging of the config files with mixed class names (`class` argument, with aliases like `zscore` and fully qualified names like `model.zscore.ZscoreModel`) now works as expected and is properly resolved to the same entity. Previously, this could lead to validation errors during service startup.
|
||||
|
||||
- BUGFIX: Fixed an issue with `anomaly_score_outside_data_range` [argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#score-outside-data-range) not being properly set for some models, resulting in default value (1.01) being used instead of user-defined override.
|
||||
|
||||
- BUGFIX: Fixed an issue with `decay` [parameter](https://docs.victoriametrics.com/anomaly-detection/components/models/#decay) not being properly applied to the global smoothing in the `OnlineQuantileModel` (when `seasonal_interval` is not set), resulted in no decay being applied (equivalent to `decay=1.0`).
|
||||
|
||||
## v1.25.3
|
||||
Released: 2025-08-19
|
||||
|
||||
@@ -21,7 +50,7 @@ Released: 2025-08-19
|
||||
|
||||
- IMPROVEMENT: Added `logger_levels` argument to `settings` [config section](https://docs.victoriametrics.com/anomaly-detection/components/settings/#logger-levels) to allow setting specific log levels for individual components. Useful for debugging specific components. For example, `logger_levels: { "reader.vm": "DEBUG" }` will set the log level for the `VmReader` component to `DEBUG`, while leaving other components at their default log levels. Also is supported in [hot reload](https://docs.victoriametrics.com/anomaly-detection/components/#hot-reload) mode, allowing for dynamic log level changes without service restarts.
|
||||
|
||||
- IMPROVEMENT: Added logging of URLs used for querying VictoriaMetrics TSDB in [`VmReader`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) to ease the debugging of incomplete data retrieval, incorrect endpoints, or misconfigured tenant IDs. The URLs are logged at the `DEBUG` level, so you can control their verbosity using the `--loggerLevelComponents` argument with `reader.vm=DEBUG` or `reader=DEBUG` to see the URLs in the logs.
|
||||
- IMPROVEMENT: Added logging of URLs used for querying VictoriaMetrics TSDB in [`VmReader`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) to ease the debugging of incomplete data retrieval, incorrect endpoints, or misconfigured tenant IDs. The URLs are logged at the `DEBUG` level, so you can override individual verbosity using the [settings.logger_levels](https://docs.victoriametrics.com/anomaly-detection/components/settings/#logger-levels) configuration.
|
||||
|
||||
- IMPROVEMENT: Added `offset` [argument](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) to `VmReader` on reader and query levels to allow for flexible time offset adjustments in the reader. Useful for correcting for data collection delays. The `offset` can be specified as a string (e.g., "15s", "-20s") and will be applied to all queries processed by the reader. See [FAQ](https://docs.victoriametrics.com/anomaly-detection/faq/#using-offsets) for more details.
|
||||
|
||||
@@ -162,7 +191,7 @@ Released: 2025-03-03
|
||||
|
||||
- FEATURE: The `scale` argument is now a [common argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#scale), previously supported only by [`ProphetModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet) and [`OnlineQuantileModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#online-seasonal-quantile). Additionally, `scale` is now **two-sided**, represented as `[scale_lb, scale_ub]`. The previous format (`scale: x`) remains supported and will be automatically converted to `scale: [x, x]`.
|
||||
|
||||
- FEATURE: Introduced a post-processing step to clip `yhat`, `yhat_lower`, and `yhat_upper` to the configured `data_range` [values](https://docs.victoriametrics.com/anomaly-detection/components/reader/#config-parameters) in `VmReader`, if defined. This feature is disabled by default for backward compatibility. It can be enabled for models that generate predictions and estimates, such as [`ProphetModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet), by setting the [common argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#clip-predictions) `clip_predictions` to `True`.
|
||||
- FEATURE: Introduced a post-processing step to clip `yhat`, `yhat_lower`, and `yhat_upper` to the configured `data_range` [values](https://docs.victoriametrics.com/anomaly-detection/components/reader/) in `VmReader`, if defined. This feature is disabled by default for backward compatibility. It can be enabled for models that generate predictions and estimates, such as [`ProphetModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet), by setting the [common argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#clip-predictions) `clip_predictions` to `True`.
|
||||
|
||||
- IMPROVEMENT: Introduced the `anomaly_score_outside_data_range` [parameter](https://docs.victoriametrics.com/anomaly-detection/components/models/#score-outside-data-range) to allow overriding the default anomaly score (`1.01`) assigned when input values (`y`) fall outside the defined `data_range` (data domain violation). It improves flexibility for alerting rules and enables clearer visual distinction between different anomaly scenarios. Override can be configured at the **service level** (`settings`) or per **model instance** (`models.model_xxx`), with model-level values taking priority. If not explicitly set, the default anomaly score remains `1.01` for backward compatibility.
|
||||
|
||||
@@ -197,7 +226,7 @@ Released: 2025-01-20
|
||||
|
||||
- FEATURE: Added support for per-query `tenant_id` in the [`VmReader`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader). This allows overriding the reader-level `tenant_id` within a single global `vmanomaly` configuration on a *per-query* basis, enabling isolation of data for different tenants in separate queries when querying the [VictoriaMetrics cluster version](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/). For details, see the [documentation](https://docs.victoriametrics.com/anomaly-detection/components/reader/#per-query-parameters).
|
||||
- IMPROVEMEMT: Speedup the model infer stage on multicore systems.
|
||||
- IMPROVEMEMT: Speedup the model fitting stage by 1.25–3x, depending on configuration complexity.
|
||||
- IMPROVEMEMT: Speedup the model fitting stage by 1.25-3x, depending on configuration complexity.
|
||||
- IMPROVEMENT: Reduced service RAM usage by 5-10%, depending on configuration complexity.
|
||||
- BUGFIX: Now [`VmReader`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) properly handles the cases where the number of queries processed in parallel (up to `reader.queries` cardinality) exceeds the default limit of 10 HTTP(S) connections, preventing potential data loss from discarded queries. The pool limit will automatically adjust to match `reader.queries` cardinality.
|
||||
- BUGFIX: Corrected the construction of write endpoints for cluster VictoriaMetrics `url`s (`tenant_id` arg is set) in `monitoring.push` [section configurations](https://docs.victoriametrics.com/anomaly-detection/components/monitoring/#push-config-parameters).
|
||||
@@ -345,7 +374,7 @@ Released: 2024-10-01
|
||||
|
||||
> A bug was discovered in this release that causes the service to crash. Please use the patch [v1.16.1](#v1161) to resolve this issue.
|
||||
|
||||
- FEATURE: Introduced data dumps to a host filesystem for [VmReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader). Resource-intensive setups (multiple queries returning many metrics, bigger `fit_window` arg) will have RAM consumption reduced during fit calls.
|
||||
- FEATURE: Introduced data dumps to a host filesystem for [VmReader](https://docs.victoriametrics.com/anomaly-detection/#vm-reader). Resource-intensive setups (multiple queries returning many metrics, bigger `fit_window` arg) will have RAM consumption reduced during fit calls.
|
||||
- IMPROVEMENT: Added a `groupby` argument for logical grouping in [multivariate models](https://docs.victoriametrics.com/anomaly-detection/components/models/#multivariate-models). When specified, a separate multivariate model is trained for each unique combination of label values in the `groupby` columns. For example, to perform multivariate anomaly detection on metrics at the machine level without cross-entity interference, you can use `groupby: [host]` or `groupby: [instance]`, ensuring one model per entity being trained (e.g., per host). Please find more details [here](https://docs.victoriametrics.com/anomaly-detection/components/models/#group-by).
|
||||
- IMPROVEMENT: Improved performance of [VmReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) on multicore instances for reading and data processing.
|
||||
- IMPROVEMENT: Introduced new CLI argument aliases to enhance compatibility with [Helm charts](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-anomaly/README.md) (i.e. using secrets) and better align with [VictoriaMetrics flags](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#list-of-command-line-flags):
|
||||
@@ -423,7 +452,7 @@ Released: 2024-07-26
|
||||
|
||||
## v1.14.1
|
||||
Released: 2024-07-26
|
||||
- FEATURE: Allow to process larger data chunks in [VmReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) that exceed `-search.maxPointsPerTimeseries` [constraint in VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/#resource-usage-limits) by splitting the range and sending multiple requests. A warning is printed in logs, suggesting reducing the range or step, or increasing `search.maxPointsPerTimeseries` constraint in VictoriaMetrics, which is still a recommended option.
|
||||
- FEATURE: Allow to process larger data chunks in [VmReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) that exceed `-search.maxPointsPerTimeseries` [constraint in VictoriaMetrics](https://docs.victoriametrics.com/#resource-usage-limits) by splitting the range and sending multiple requests. A warning is printed in logs, suggesting reducing the range or step, or increasing `search.maxPointsPerTimeseries` constraint in VictoriaMetrics, which is still a recommended option.
|
||||
- FEATURE: Backward-compatible redesign of [`queries`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) arg of [VmReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader). Old format of `{q_alias1: q_expr1, q_alias2: q_expr2, ...}` will be implicitly converted to a new one with a warning raised in logs. New format allows to specify per-query parameters, like `step` to reduce amount of data read from VictoriaMetrics TSDB and to allow config flexibility. Find out more in [Per-query parameters section of VmReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#per-query-parameters).
|
||||
|
||||
- IMPROVEMENT: Added multi-platform builds for `linux/amd64` and `linux/arm64` architectures.
|
||||
|
||||
@@ -47,12 +47,15 @@ Please see example graph illustrating this logic below:
|
||||
|
||||
|
||||
## What data does vmanomaly operate on?
|
||||
`vmanomaly` operates on data fetched from VictoriaMetrics, where you can leverage full power of [MetricsQL](https://docs.victoriametrics.com/victoriametrics/metricsql/) for data selection, sampling, and processing. Users can also [apply global filters](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#prometheus-querying-api-enhancements) for more targeted data analysis, enhancing scope limitation and tenant visibility.
|
||||
|
||||
Respective config is defined in a [`reader`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) section.
|
||||
`vmanomaly` operates on timeseries (metrics) data, and supports both **VictoriaMetrics** and **VictoriaLogs** as data sources. Choose the source depending on the use case.
|
||||
|
||||
**VictoriaMetrics (metrics):** use full [MetricsQL](https://docs.victoriametrics.com/victoriametrics/metricsql/) for selection, sampling, and processing; [global filters](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#prometheus-querying-api-enhancements) are also supported. See the [VmReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) for the details.
|
||||
|
||||
**VictoriaLogs (logs → metrics):** {{% available_from "v1.26.0" anomaly %}} use [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/) via the [`VLogsReader`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vlogs-reader) to create log-derived metrics for anomaly detection (e.g., error rates, request latencies).
|
||||
|
||||
> Please note that only LogsQL queries with [stats pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe) functions [subset](https://docs.victoriametrics.com/anomaly-detection/components/reader/#valid-stats-functions) are supported, as they produce **numeric** time series.
|
||||
|
||||
## Handling noisy input data
|
||||
`vmanomaly` operates on data fetched from VictoriaMetrics using [MetricsQL](https://docs.victoriametrics.com/victoriametrics/metricsql/) queries, so the initial data quality can be fine-tuned with aggregation, grouping, and filtering to reduce noise and improve anomaly detection accuracy.
|
||||
|
||||
## Using offsets
|
||||
`vmanomaly` supports {{% available_from "v1.25.3" anomaly %}} the use of offsets in the [`reader`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) section to adjust the time range of the data being queried. This can be particularly useful for correcting for data collection delays or other timing issues. It can be also defined or overridden on [per-query basis](https://docs.victoriametrics.com/anomaly-detection/components/reader/#per-query-parameters).
|
||||
@@ -110,6 +113,8 @@ To visualize and interact with both [self-monitoring metrics](https://docs.victo
|
||||
|
||||
- For guidance on using the `vmanomaly` Grafana dashboard and drilling down into anomaly score visualizations, refer to the [default preset section](https://docs.victoriametrics.com/anomaly-detection/presets/#default).
|
||||
- To monitor `vmanomaly` health, operational performance, and potential issues in real time, visit the [self-monitoring section](https://docs.victoriametrics.com/anomaly-detection/self-monitoring/).
|
||||
- {{% available_from "v1.26.0" anomaly %}} For rapid exploration of how different models, their configurations and included domain knowledge impacts the results of anomaly detection, use the built-in [vmanomaly UI](https://docs.victoriametrics.com/anomaly-detection/ui/).
|
||||

|
||||
|
||||
## Is vmanomaly stateful?
|
||||
By default, `vmanomaly` is **stateless**, meaning it does not retain any state between service restarts. However, it can be configured {{% available_from "v1.24.0" anomaly %}} to be **stateful** by enabling the `restore_state` setting in the [settings section](https://docs.victoriametrics.com/anomaly-detection/components/settings/). This allows the service to restore its state from a previous run (training data, trained models), ensuring that models continue to produce [anomaly scores](#what-is-anomaly-score) right after restart and without requiring a full retraining process or re-querying training data from VictoriaMetrics. This is particularly useful for long-running services that need to maintain continuity in anomaly detection without losing previously learned patterns, especially when using [online models](https://docs.victoriametrics.com/anomaly-detection/components/models/#online-models) that continuously adapt to new data and update their internal state. Also, [hot-reloading](https://docs.victoriametrics.com/anomaly-detection/components/#hot-reload) works well with state restoration, allowing for on-the-fly configuration changes without losing the current state of the models and reusing unchanged models/data/scheduler combinations.
|
||||
@@ -219,6 +224,9 @@ Produced anomaly scores are designed in such a way that values from 0.0 to 1.0 i
|
||||
|
||||
## How to backtest particular configuration on historical data?
|
||||
|
||||
> {{% available_from "v1.26.0" anomaly %}} You can use the [vmanomaly UI](https://docs.victoriametrics.com/anomaly-detection/ui/) to backtest particular configuration on historical data with easy-to-use [preset](https://docs.victoriametrics.com/anomaly-detection/presets/#ui).
|
||||

|
||||
|
||||
Anomaly scores for historical ([backtesting](https://wikipedia.org/wiki/Backtesting)) data can be produced using [`backtesting` scheduler](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/#backtesting-scheduler) in `vmanomaly` config. This scheduler allows you to define a historical period for which the models will be trained and then used to produce anomaly scores, imitating the behavior of the [PeriodicScheduler](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/#periodic-scheduler) for that period. Especially useful for testing new models or configurations on historical data before deploying them in production, around labelled incidents.
|
||||
|
||||
```yaml
|
||||
@@ -389,7 +397,7 @@ services:
|
||||
# ...
|
||||
vmanomaly:
|
||||
container_name: vmanomaly
|
||||
image: victoriametrics/vmanomaly:v1.25.3
|
||||
image: victoriametrics/vmanomaly:v1.26.2
|
||||
# ...
|
||||
ports:
|
||||
- "8490:8490"
|
||||
@@ -574,6 +582,8 @@ For **horizontal** scalability, `vmanomaly` can be deployed as multiple independ
|
||||
|
||||
### Splitting the config
|
||||
|
||||
> Use this approach for versions older than `v1.21.0` (or if you prefer manual control over the splitting process). Prefer the newer approach described on [dedicated page](https://docs.victoriametrics.com/anomaly-detection/scaling-vmanomaly/) for horizontal scalability and high availability.
|
||||
|
||||
CLI utility named `config_splitter` is available in `vmanomaly` {{% available_from "v1.18.5" anomaly %}}. The config splitter tool enables splitting a parent vmanomaly YAML configuration file into multiple sub-configurations based on logical entities such as `schedulers`, `queries`, `models`, `extra_filters` and `complete` {{% available_from "v1.19.2" anomaly %}}. The resulting sub-configurations are fully validated, functional, account for many-to-many relationships between models and their associated queries, and the schedulers they are linked to. These sub-configurations can then be saved to a specified directory for further use:
|
||||
|
||||
```shellhelp
|
||||
@@ -602,7 +612,7 @@ options:
|
||||
Here’s an example of using the config splitter to divide configurations based on the `extra_filters` argument from the reader section:
|
||||
|
||||
```sh
|
||||
docker pull victoriametrics/vmanomaly:v1.25.3 && docker image tag victoriametrics/vmanomaly:v1.25.3 vmanomaly
|
||||
docker pull victoriametrics/vmanomaly:v1.26.2 && docker image tag victoriametrics/vmanomaly:v1.26.2 vmanomaly
|
||||
```
|
||||
|
||||
```sh
|
||||
|
||||
@@ -22,22 +22,31 @@ Each preset, including the [default](#default), comes with premade downstream as
|
||||
|
||||
|
||||
**Available presets:**
|
||||
- [UI](#ui)
|
||||
- [Default](#default)
|
||||
- [Node-Exporter](#node-exporter)
|
||||
|
||||
To enable preset mode, `preset` arg should be set to particular preset name:
|
||||
|
||||
```yaml
|
||||
preset: "chosen_preset_name" # i.e. "node-exporter"
|
||||
preset: "chosen_preset_name" # i.e. "node-exporter", "ui", etc.
|
||||
```
|
||||
|
||||
Also, additional minimal set of arguments may be required from user to run the preset. See corresponding preset sections below for the details.
|
||||
|
||||
Run a service using config file with one of the [available options](https://docs.victoriametrics.com/anomaly-detection/quickstart/#how-to-install-and-run-vmanomaly).
|
||||
|
||||
After you run `vmanomaly` with `preset` arg specified, available assets can be viewed, copied and downloaded at `http://localhost:8490/presets/` endpoint.
|
||||
## UI
|
||||
|
||||

|
||||
The UI preset is the easiest to start from and is designed for users who want to quickly experiment with `vmanomaly` in [UI mode](https://docs.victoriametrics.com/anomaly-detection/ui/). It requires minimal configuration and provides a user-friendly interface for exploring anomaly detection capabilities:
|
||||
|
||||
```yaml
|
||||
preset: "ui"
|
||||
```
|
||||
|
||||
Please refer to the [UI documentation](https://docs.victoriametrics.com/anomaly-detection/ui/) for detailed instructions on how to use the interface and [backtest your anomaly detection configurations guide](https://docs.victoriametrics.com/anomaly-detection/ui/#example-usage).
|
||||
|
||||

|
||||
|
||||
## Default
|
||||
|
||||
|
||||
@@ -121,13 +121,13 @@ Below are the steps to get `vmanomaly` up and running inside a Docker container:
|
||||
1. Pull Docker image:
|
||||
|
||||
```sh
|
||||
docker pull victoriametrics/vmanomaly:v1.25.3
|
||||
docker pull victoriametrics/vmanomaly:v1.26.2
|
||||
```
|
||||
|
||||
2. (Optional step) tag the `vmanomaly` Docker image:
|
||||
|
||||
```sh
|
||||
docker image tag victoriametrics/vmanomaly:v1.25.3 vmanomaly
|
||||
docker image tag victoriametrics/vmanomaly:v1.26.2 vmanomaly
|
||||
```
|
||||
|
||||
3. Start the `vmanomaly` Docker container with a *license file*, use the command below.
|
||||
@@ -163,7 +163,7 @@ docker run -it --user 1000:1000 \
|
||||
services:
|
||||
# ...
|
||||
vmanomaly:
|
||||
image: victoriametrics/vmanomaly:v1.25.3
|
||||
image: victoriametrics/vmanomaly:v1.26.2
|
||||
volumes:
|
||||
$YOUR_LICENSE_FILE_PATH:/license
|
||||
$YOUR_CONFIG_FILE_PATH:/config.yml
|
||||
@@ -189,7 +189,7 @@ See also:
|
||||
> To run `vmanomaly`, you need to have VictoriaMetrics Enterprise license. You can get a trial license key [**here**](https://victoriametrics.com/products/enterprise/trial/).
|
||||
|
||||
> With the forthcoming [DockerHub pull limits](https://docs.docker.com/docker-hub/usage/pulls) additional image registry was introduced (quay.io) for VictoriaMetric images, [vmanomaly images in particular](https://quay.io/repository/victoriametrics/vmanomaly).
|
||||
If hitting pull limits, try switching your `docker pull quay.io/victoriametrics/vmanomaly:vX.Y.Z` to `docker pull quay.io/victoriametrics/vmanomaly:vX.Y.Z`
|
||||
If hitting pull limits, try switching your `docker pull victoriametrics/vmanomaly:vX.Y.Z` to `docker pull quay.io/victoriametrics/vmanomaly:vX.Y.Z`
|
||||
|
||||
You can run `vmanomaly` in Kubernetes environment
|
||||
with [these Helm charts](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-anomaly/README.md).
|
||||
@@ -292,6 +292,8 @@ For optimal service behavior, consider the following tweaks when configuring `vm
|
||||
- Define queries for input data using [MetricsQL](https://docs.victoriametrics.com/victoriametrics/metricsql/) under `reader.queries` section. Note, it's possible to override reader-level arguments at query level for increased flexibility, e.g. specifying per-query [timezone](https://docs.victoriametrics.com/anomaly-detection/faq/#handling-timezones) or [sampling period](https://docs.victoriametrics.com/anomaly-detection/components/reader/#sampling-period).
|
||||
- For longer `fit_window` intervals in scheduler, consider splitting queries into smaller time ranges to avoid excessive memory usage, timeouts and hitting server-side constraints, so they can be queried separately and reconstructed on `vmanomaly` side. Please refer to this [example](https://docs.victoriametrics.com/anomaly-detection/faq/#handling-large-queries-in-vmanomaly) for more details.
|
||||
|
||||
> If applicable - consider trying [`VLogsReader`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vlogs-reader) {{% available_from "v1.26.0" anomaly %}} to perform anomaly detection on log-derived **metrics**. This is particularly useful for scenarios where log data needs to be analyzed for unusual patterns or behaviors, such as error rates or request latencies.
|
||||
|
||||
**Writer**:
|
||||
- Specify where and how to store anomaly detection metrics in the [writer](https://docs.victoriametrics.com/anomaly-detection/components/writer/) section.
|
||||
- Include tenant ID if using a [cluster version of VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/) for writing the results.
|
||||
|
||||
@@ -6,20 +6,21 @@ build:
|
||||
sitemap:
|
||||
disable: true
|
||||
---
|
||||
In today's fast-paced and complex landscape of system monitoring, [VictoriaMetrics Anomaly Detection](https://victoriametrics.com/products/enterprise/anomaly-detection/) (`vmanomaly`), part of our [Enterprise offering](https://victoriametrics.com/products/enterprise/), serves as a **powerful observability tool** for SREs and DevOps teams. It **automates the detection of anomalies in time-series data**, reducing manual efforts required to identify abnormal system behavior.
|
||||
|
||||
In today's fast-paced and complex landscape of system monitoring, [VictoriaMetrics Anomaly Detection](https://victoriametrics.com/products/enterprise/anomaly-detection/) (`vmanomaly`), a part of our [Enterprise offering](https://victoriametrics.com/products/enterprise/), serves as an **observability layer** for SREs and DevOps teams atop of collected data to **automate the detection of anomalies in time-series data**, reducing manual efforts required to identify abnormal system behavior.
|
||||
|
||||
Unlike traditional threshold-based alerting, which relies on **raw metric values** and requires constant tuning and maintenance of thresholds and alerting rules, `vmanomaly` introduces a **unified, interpretable [anomaly score](https://docs.victoriametrics.com/anomaly-detection/faq/#what-is-anomaly-score)** - a **de-trended, de-seasonalized metric** generated through machine learning. This approach eliminates the need for frequent manual adjustments by enabling **stable, long-term static thresholds (as simple as `anomaly_score > 1`)** that remain effective over time through continuous model retraining.
|
||||
|
||||
By shifting to anomaly-based detection, teams can **identify and respond to potential issues faster**, enhancing system reliability and operational efficiency while significantly **reducing the engineering effort spent on maintaining alerting rules**.
|
||||
By shifting to anomaly-based detection, teams can **identify and respond to potential issues faster**, enhancing system reliability and operational efficiency while significantly **reducing the engineering effort spent on handcrafting and maintaining alerting rules**.
|
||||
|
||||
|
||||
## What does it do?
|
||||
|
||||
`vmanomaly` is designed to **periodically analyze new data points** across selected metrics, generating a **unified metric** called [anomaly score](https://docs.victoriametrics.com/anomaly-detection/faq/#what-is-anomaly-score).
|
||||
`vmanomaly` is designed to **periodically analyze new data points** across selected metrics (either requested from [VictoriaMetrics TSDB](https://docs.victoriametrics.com/victoriametrics/) or produced by [VictoriaLogs](https://docs.victoriametrics.com/victorialogs/) metrics [endpoint](https://docs.victoriametrics.com/victorialogs/querying/#querying-log-range-stats)), generating a **unified metric** called [anomaly score](https://docs.victoriametrics.com/anomaly-detection/faq/#what-is-anomaly-score).
|
||||
|
||||
Key functions:
|
||||
- **Automated anomaly detection** – continuously scans time-series data to identify deviations from expected behavior.
|
||||
- **Seamless integration** – anomaly scores are stored in VictoriaMetrics TSDB for use in **alerting, visualization, and downstream analytics**.
|
||||
- **Automated anomaly detection** - continuously scans time-series data to identify deviations from expected behavior.
|
||||
- **Seamless integration** - anomaly scores are stored in VictoriaMetrics TSDB for use in **alerting, visualization, and downstream analytics**.
|
||||
|
||||
The diagram below illustrates how `vmanomaly` fits into an observability setup, such as detecting anomalies in metrics collected by `node_exporter`:
|
||||
|
||||
@@ -53,6 +54,7 @@ VictoriaMetrics Anomaly Detection **continuously re-fit and apply machine learni
|
||||
Get started with VictoriaMetrics Anomaly Detection by following our guides and installation options:
|
||||
|
||||
- **Quickstart**: Learn how to quickly set up `vmanomaly` by following the [Quickstart Guide](https://docs.victoriametrics.com/anomaly-detection/quickstart/).
|
||||
- **UI**: Explore anomaly detection configurations through the [vmanomaly UI](https://docs.victoriametrics.com/anomaly-detection/ui/).
|
||||
- **Integration**: Integrate anomaly detection into your existing observability stack. Find detailed steps [here](https://docs.victoriametrics.com/anomaly-detection/guides/guide-vmanomaly-vmalert/).
|
||||
- **Anomaly Detection Presets**: Enable anomaly detection on predefined sets of metrics. Learn more [here](https://docs.victoriametrics.com/anomaly-detection/presets/).
|
||||
|
||||
|
||||
325
docs/anomaly-detection/UI.md
Normal file
@@ -0,0 +1,325 @@
|
||||
---
|
||||
weight: 2
|
||||
title: UI
|
||||
menu:
|
||||
docs:
|
||||
parent: "anomaly-detection"
|
||||
identifier: "vmanomaly-ui"
|
||||
weight: 2
|
||||
title: UI
|
||||
tags:
|
||||
- metrics
|
||||
- enterprise
|
||||
- ui
|
||||
aliases:
|
||||
- /anomaly-detection/ui.html
|
||||
- /anomaly-detection/ui
|
||||
- /anomaly-detection/UI
|
||||
- /anomaly-detection/UI/
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
{{% available_from "v1.26.0" anomaly %}} `vmanomaly` is shipped with a built-in [vmui-like](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#vmui) [UI](https://en.wikipedia.org/wiki/Graphical_user_interface) that provides an intuitive interface for rapid exploration of how anomaly detection models, their configurations and included domain knowledge impacts the results of anomaly detection, before such configurations are deployed in production.
|
||||
|
||||

|
||||
|
||||
## Accessing the UI
|
||||
|
||||
The UI is available at `http://<vmanomaly-host>:8490` by default, however, the port can be changed in `server` section of the [configuration file](https://docs.victoriametrics.com/anomaly-detection/components/) using the `port` parameter:
|
||||
|
||||
```yaml
|
||||
server:
|
||||
port: 8490
|
||||
|
||||
# other vmanomaly configuration sections, e.g. schedulers, models, reader, writer, etc.
|
||||
```
|
||||
|
||||
For impactful parameters please refer to [optimize resource usage](#optimize-resource-usage) section of this page.
|
||||
|
||||
## Preset
|
||||
|
||||
Vmanomaly can be deployed in efficient "UI mode" [preset](https://docs.victoriametrics.com/anomaly-detection/presets/#ui), with as simple configuration as:
|
||||
|
||||
```yaml
|
||||
preset: ui
|
||||
```
|
||||
|
||||
This will start vmanomaly instance with a no-operation schedulers, readers, models and the other components, and **will only enable the UI for interactive exploration of anomaly detection models**, so all the resources are dedicated to the UI and no resources are wasted on other components, such as production jobs of anomaly detection (retrieving metrics, running models, writing results, etc.).
|
||||
|
||||
The best applications of this mode are:
|
||||
- Deploy vmanomaly UI as a service to hide the deployment complexity and allow internal users to explore anomaly detection models and their configurations, without the need to run any production jobs of anomaly detection.
|
||||
- When there is a quick need to explore and validate anomaly detection models and their configurations before deploying them in production jobs, at minimal resource usage.
|
||||
|
||||
|
||||
> However, the UI can be **combined with existing production jobs of anomaly detection, as it is available in non-blocking mode for all running vmanomaly instances** {{% available_from "v1.26.0" anomaly %}}, regardless of the preset or configuration used, just at a cost of increased resource usage.
|
||||
|
||||
## UI Navigation
|
||||
|
||||
The vmanomaly UI provides a user-friendly interface for exploring and configuring anomaly detection models. The main components of the UI include:
|
||||
|
||||
- [**Query Explorer**](#query-explorer): A vmui-like interface for typing and executing MetricsQL/LogsQL queries to visualize data.
|
||||
- [**Model Panel**](#model-panel): A form for editing anomaly detection model hyperparameters and applying domain knowledge settings.
|
||||
- [**Visualization Panel**](#visualization-panel): A space for visualizing model performance and anomalies.
|
||||
- [**Settings Panel**](#settings-panel): A section for configuring global settings and preferences for the vmanomaly UI, including data source configuration.
|
||||
|
||||
### Query Explorer
|
||||
|
||||
The Query Explorer provides a vmui-like interface for typing and executing MetricsQL/LogsQL queries to visualize data.
|
||||
|
||||

|
||||
|
||||
Users can:
|
||||
- Enter, autocomplete, prettify and execute queries to retrieve and plot the data from the configured data source (see [settings panel](#settings-panel) for data source configuration).
|
||||
- Adjust the (inference) time range and resolution (step) for data visualization and anomaly detection purposes.
|
||||
- Access query history and saved queries for quick access to frequently used queries.
|
||||
- Switch tenants (if data source supports multi-tenancy) and access [settings panel](#settings-panel) for global UI configuration.
|
||||
|
||||
[Back to UI navigation](#ui-navigation)
|
||||
|
||||
### Visualization Panel
|
||||
|
||||
The Visualization Panel has 2 modes of displaying data - either raw queried data or data with detected anomalies, depending on the action taken in the Model Panel.
|
||||
|
||||
**Visualizations of the queried data** ("Execute Query" button)
|
||||
|
||||

|
||||
|
||||
> All the metrics are shown in a single plot, similar to vmui, with zooming and panning capabilities.
|
||||
|
||||
**Initial data with detected anomalies** ("Detect Anomalies" button)
|
||||
|
||||

|
||||
|
||||
> The plot shows the queried data, **grouped by individual series**, iterated over legend, with the actual values (`y`) compared to the expected values (model predictions, `y_hat`), confidence intervals (`y_hat_lower`, `y_hat_upper`), and detected anomalies. The anomalies are marked with red circles, and hovering over them provides additional information such as the anomaly score and associated labels.
|
||||
|
||||
Also, timeseries (such as `y`, `y_hat`, etc.) can be toggled on/off by clicking on the legend items.
|
||||
|
||||
[Back to UI navigation](#ui-navigation)
|
||||
|
||||
### Model Panel
|
||||
|
||||

|
||||
|
||||
The Model Panel provides:
|
||||
|
||||
Parameters, such as "Fit Every" and "Fit Window", to control how often and over what time window the model is retrained on new data to imitate production behavior, as well as overriding default anomaly detection thresholds (1.0).
|
||||
|
||||
Controls for running/canceling anomaly detection on the queried data, downloading the results as CSV/JSON, accessing and downloading the model configuration in YAML format.
|
||||
|
||||
A form-based menu for finetuning model hyperparameters and applying domain knowledge settings:
|
||||
|
||||
- Model type selection (e.g., rolling quantile, Prophet, etc.)
|
||||

|
||||
- Wizard with **model-agnostic parameters** (e.g., detection direction, data range, scale, clipping, minimum deviation from expected, etc.) and **model-specific hyperparameters** for chosen model type (e.g., quantile and window steps for [rolling quantile](https://docs.victoriametrics.com/anomaly-detection/components/models/#rolling-quantile) model).
|
||||

|
||||
|
||||
[Back to UI navigation](#ui-navigation)
|
||||
|
||||
### Settings Panel
|
||||
|
||||
The vmui-like "Settings" panel allows users to configure global settings and preferences for the vmanomaly UI, including:
|
||||
|
||||
- Server URL (vmanomaly)
|
||||
- Datasource URL (VictoriaMetrics, VictoriaLogs)
|
||||
- Timezone
|
||||
- UI Theme
|
||||
|
||||

|
||||
|
||||
[Back to navigation](#ui-navigation)
|
||||
|
||||
## Configuration Sharing
|
||||
|
||||
Based on the needs, either
|
||||
- Full UI state can be [shared via URL](#url-sharing)
|
||||
- Or model part / full service configuration can be [viewed and exported in production-ready YAML format](#yaml-configuration).
|
||||
|
||||
### URL Sharing
|
||||
|
||||
Similarly to vmui, vmanomaly UI supports **configuration sharing via URL**. This allows users to share their UI state (including queries, time ranges, model type and hyperparameters, and other settings) by copying and sharing the URL from the browser's address bar.
|
||||
|
||||

|
||||
|
||||
<p></p>
|
||||
<p>Example URL content:</p>
|
||||
|
||||
```shellhelp
|
||||
http://localhost:8490/vmui/#/?anomaly_threshold=1.0&fit_window=1d&fit_every=7d&g0.range_input=7d&g0.end_input=2025-09-30T16%3A56%3A13&g0.relative_time=last_7_days&g0.tab=0&g0.tenantID=0&datasourceUrl=https%3A%2F%2Fplay.victoriametrics.com%2Fselect%2F0%2Fprometheus&g0.expr=sum%28rate%28node_cpu_seconds_total%7Bmode%3D%7E%22%28softirq%7Cuser%7Ciowait%29%22%7D%5B10m%5D%29%29+by+%28container%2C+mode%29&g0.step_input=30m&model_config=%257B%2522modelType%2522%253A%2522rolling_quantile%2522%252C%2522settings%2522%253A%257B%2522detection_direction%2522%253A%2522above_expected%2522%252C%2522data_range%2522%253A%255B0%252C100%255D%252C%2522scale%2522%253A%255B1%252C1%255D%252C%2522clip_predictions%2522%253Atrue%252C%2522min_dev_from_expected%2522%253A%255B0%252C6%255D%252C%2522anomaly_score_outside_data_range%2522%253A1.01%252C%2522quantile%2522%253A0.9%252C%2522window_steps%2522%253A48%257D%252C%2522modelSpec%2522%253A%257B%2522class_name%2522%253A%2522rolling_quantile%2522%252C%2522class%2522%253A%2522model.rolling_quantile.RollingQuantileModel%2522%252C%2522detection_direction%2522%253A%2522above_expected%2522%252C%2522data_range%2522%253A%255B0%252C100%255D%252C%2522scale%2522%253A%255B1%252C1%255D%252C%2522clip_predictions%2522%253Atrue%252C%2522min_dev_from_expected%2522%253A%255B0%252C6%255D%252C%2522anomaly_score_outside_data_range%2522%253A1.01%252C%2522window_steps%2522%253A48%252C%2522quantile%2522%253A0.9%257D%252C%2522isValidated%2522%253Atrue%257D
|
||||
```
|
||||
|
||||
### YAML Configuration
|
||||
|
||||
Once the configuration is set up and saved in the UI (selected model type and validated hyperparameters), equivalent configuration in production-ready YAML format can be obtained by:
|
||||
|
||||
Accessing the "YAML" Tab in the model configuration section
|
||||

|
||||

|
||||
|
||||
|
||||
Clicking the "Open Config" button to access (model-only or full) configuration and hitting "Download" button to get the configuration as a YAML file.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Optimize Resource Usage
|
||||
|
||||
Based on expected usage patterns (quick experiments, internal team serving, number of users, etc.) it is recommended to tune resource usage by adjusting the following parameters in the `server` and `settings` sections of the configuration file:
|
||||
|
||||
```yaml
|
||||
server:
|
||||
# Port for the UI server (default: 8490)
|
||||
port: 8490
|
||||
# Limit on concurrent tasks to manage UI load (default: 2)
|
||||
max_concurrent_tasks: 2
|
||||
|
||||
settings:
|
||||
# Number of workers for single job speed-ups (default: 1)
|
||||
n_workers: 2
|
||||
# Adjust logging levels to reduce verbosity
|
||||
logger_levels:
|
||||
vmanomaly: WARNING
|
||||
reader: INFO
|
||||
model: INFO
|
||||
# ...
|
||||
```
|
||||
|
||||
`max_concurrent_tasks` limits the number of concurrent tasks (e.g. running anomaly detection on queried data) to avoid overloading the UI when multiple users are using it simultaneously, and `n_workers` [option](https://docs.victoriametrics.com/anomaly-detection/components/settings/#parallelization) controls the number of workers for parallel processing of single tasks (e.g. running anomaly detection on queried data faster).
|
||||
|
||||
Please note that numbers <= 0 for `n_workers` mean number of available CPU cores, and these workers would be shared with other components of vmanomaly, such as production jobs of anomaly detection (retrieving metrics, running models, writing results, etc.), if they are enabled.
|
||||
|
||||
### Preset Usage
|
||||
|
||||
If using the `ui` preset, just specify:
|
||||
|
||||
```yaml
|
||||
preset: ui
|
||||
|
||||
server:
|
||||
# Port for the UI server (default: 8490)
|
||||
port: 8490
|
||||
# Limit on concurrent tasks to manage UI load (default: 2)
|
||||
max_concurrent_tasks: 5
|
||||
|
||||
settings:
|
||||
# Number of workers for single job speed-ups (default: 1)
|
||||
n_workers: 2
|
||||
# Adjust logging levels to reduce verbosity
|
||||
logger_levels:
|
||||
vmanomaly: WARNING
|
||||
# ...
|
||||
```
|
||||
|
||||
in instance configuration file, it will be recursively merged with preset pre-filled configuration to produce the final configuration.
|
||||
|
||||
### Mixed Usage
|
||||
|
||||
If mixing the UI alongside production jobs of anomaly detection is expected, it is recommended to adjust the parameters to optimize resource usage, as well as configuring the `reader` and `writer` components appropriately for the production jobs.
|
||||
|
||||
```yaml
|
||||
|
||||
settings:
|
||||
# Number of workers for mixed usage (numbers <= 0 mean number of available CPU cores)
|
||||
n_workers: -1
|
||||
# Adjust logging levels to reduce verbosity
|
||||
logger_levels:
|
||||
vmanomaly: WARNING
|
||||
reader: INFO
|
||||
model: INFO
|
||||
writer: INFO
|
||||
# ...
|
||||
|
||||
server:
|
||||
# Port for the UI server (default: 8490)
|
||||
port: 8490
|
||||
# Limit on concurrent tasks to manage UI load (default: 2)
|
||||
max_concurrent_tasks: 5
|
||||
|
||||
# other production components, e.g. schedulers, models, reader, writer, etc.
|
||||
```
|
||||
|
||||
## Example Usage
|
||||
|
||||
Run vmanomaly in `ui` preset mode (experimenting) with a configuration file `config.yaml` (see [preset usage](#preset-usage) section for details):
|
||||
|
||||
```yaml
|
||||
preset: ui
|
||||
|
||||
# other optional server/settings parameters, e.g. port, max_concurrent_tasks, n_workers, logger_levels, etc.
|
||||
```
|
||||
|
||||
using one of the [deployment methods](https://docs.victoriametrics.com/anomaly-detection/quickstart/#how-to-install-and-run-vmanomaly) in a [QuickStart guide](https://docs.victoriametrics.com/anomaly-detection/quickstart/#quickstart), e.g. via Docker.
|
||||
|
||||
Retrieve the UI at `http://<vmanomaly-host>:<port>` (e.g. at `http://localhost:8490` if running locally with default port) and start exploring anomaly detection models and their configurations interactively.
|
||||
|
||||
### Explore Input Data
|
||||
|
||||
Start by entering valid MetricsQL/LogsQL queries in the Query Explorer to visualize the data from the configured data source (see [settings panel](#settings-panel) for data source configuration) - that's the data on which anomaly detection models will be applied.
|
||||
|
||||
Set appropriate tenants (if data source supports multi-tenancy) and access [settings panel](#settings-panel) for global UI configuration, if needed.
|
||||
|
||||
Set up the time range and resolution (step) for data visualization and anomaly detection purposes - e.g. last 7 days with 30m step, especially if the data has daily/weekly seasonality. Also, set the step according to the desired granularity of anomaly detection results (e.g. 30m step for 30m granularity) which itself is based on alerting needs and latency requirements.
|
||||
|
||||

|
||||
|
||||
Pay attention to trends, seasonality, noise, outliers, and other patterns in the data, which can influence the choice of anomaly detection model and its hyperparameters (e.g. use seasonal models for seasonal data - like `Prophet`, robust models for noisy de-seasonalized data - like `MAD`, etc.).
|
||||
|
||||

|
||||
|
||||
|
||||
### Select and Configure Model
|
||||
|
||||
Choose an appropriate anomaly detection model from the Model Panel based on the characteristics of the data and the specific requirements (domain knowledge) of the use case.
|
||||
|
||||

|
||||
|
||||
Set the "Fit Every" and "Fit Window" parameters to control how often and over what time window the model is retrained on new data to imitate production behavior - e.g. fit every 7 days on a rolling window of last 14 days.
|
||||
|
||||
Tune the model hyperparameters and apply domain knowledge settings using the form-based menu in the Model Panel. See (i) tooltips for parameter descriptions and [model documentation](https://docs.victoriametrics.com/anomaly-detection/components/models/) link for recommended values and guidelines.
|
||||
|
||||

|
||||
|
||||
For example, for a `rolling quantile` [model](https://docs.victoriametrics.com/anomaly-detection/components/models/#rolling-quantile), that should be run on a query, returning per-mode CPU utilization (as fractions of 1, data range `[0, 1]`), where you are interested in capturing **spikes of at least 5% deviations** from expected behavior:
|
||||
|
||||
Set the **model-agnostic** parameters to encode the domain knowledge:
|
||||
- [detection direction](https://docs.victoriametrics.com/anomaly-detection/components/models/#detection-direction) to `above expected` for capturing high anomalies (spikes)
|
||||
- data range to `[0, 1]` for CPU utilization fractions and proper prediction clipping
|
||||
- [minimum deviation from expected](https://docs.victoriametrics.com/anomaly-detection/components/models/#minimal-deviation-from-expected) to `[0, 0.05]` for capturing spikes of at least 5% deviations in magnitude
|
||||
- [anomaly score outside data range](https://docs.victoriametrics.com/anomaly-detection/components/models/#score-outside-data-range) to `5.0` for automatically marking values outside data range as anomalies (e.g. to catch improper query returning CPU > 100% or < 0%)
|
||||
- [clip predictions](https://docs.victoriametrics.com/anomaly-detection/components/models/#clip-predictions) to `true` for avoiding nonsensical predictions outside data range
|
||||
- [scale](https://docs.victoriametrics.com/anomaly-detection/components/models/#scale) to `[1, 1]` unless you will see improper width of confidence intervals from the experiments (e.g. too wide/narrow) given the model-specific hyperparameters and false positives/negatives observed in the results.
|
||||
|
||||
Set the **model-specific** hyperparameters:
|
||||
- quantile to `0.9` for detecting high anomalies
|
||||
- window steps to `48` for capturing 1 day of active history with 30m step data (24/0.5 = 48)
|
||||
|
||||
Check the parameters for validity and consistency by hitting the "Validate" button, which will also provide warnings if some parameters seem inconsistent (e.g. quantile is set outside of `[0, 1]` range or window steps is set to a negative value), then hit "Save" to apply the changes.
|
||||
|
||||
### Detect Anomalies
|
||||
|
||||
Hit the "Detect Anomalies" button to run anomaly detection on the queried data with the selected model and its configuration.
|
||||
|
||||
> The long running task (e.g. detection on misconfigured query returning too much metrics) can be canceled by hitting the "Cancel" button.
|
||||
|
||||

|
||||
|
||||
Iterate over the legend to view **individual output series** (e.g. actual values, expected values, confidence intervals, anomalies, etc.) for different series returned by the query.
|
||||
|
||||
Iterate over **returned timeseries by query** to see how the model performed on different series, and whether the detected anomalies make sense in the context of the data and the use case (their % of total points, magnitude, duration, etc.).
|
||||
|
||||
Until satisfied with the results, finetune the model hyperparameters and domain knowledge settings in the Model Panel (or change the model type), and rerun anomaly detection on the queried data.
|
||||
|
||||
Once satisfied with the results, do the following.
|
||||
|
||||
> Many tabs can be opened in parallel in the browser, so multiple experiments can be run in parallel, and the results can be compared by switching between tabs. Local settings (e.g. queries, time ranges, model configurations, etc.) are preserved in each tab, so different experiments do not interfere with each other.
|
||||
|
||||
### Work with Results
|
||||
|
||||
If the **results** do not look good, the model hyperparameters and domain knowledge settings can be further finetuned in the Model Panel, and anomaly detection can be [rerun on the queried](#detect-anomalies) data until satisfactory results are achieved.
|
||||
|
||||
If the **results** look good, but should be shared with others first, timeseries can be downloaded as files by hitting the respective button in the Model Panel. See also [configuration sharing](#configuration-sharing) section for details.
|
||||
|
||||
If the **results** look good and the **model configuration should be deployed in production jobs of anomaly detection**, the equivalent configuration in production-ready YAML format can be obtained by accessing the "YAML" Tab in the model configuration section and hitting the "Open Config" button to access (model-only or full) configuration and hitting "Download" button to get the configuration as a YAML file.
|
||||
|
||||

|
||||
@@ -90,6 +90,8 @@ reader:
|
||||
sampling_period: "30s" # what data resolution to fetch from VictoriaMetrics' /query_range endpoint
|
||||
latency_offset: '1ms'
|
||||
query_from_last_seen_timestamp: False
|
||||
tz: "UTC" # timezone to use for queries without explicit timezone
|
||||
"offset": "0s" # offset to apply to all queries, e.g. to account for data delays, can be overridden on per-query basis
|
||||
queries: # aliases to MetricsQL expressions
|
||||
cpu_seconds_total:
|
||||
expr: 'avg(rate(node_cpu_seconds_total[5m])) by (mode)'
|
||||
|
||||
@@ -1312,7 +1312,7 @@ monitoring:
|
||||
Let's pull the docker image for `vmanomaly`:
|
||||
|
||||
```sh
|
||||
docker pull victoriametrics/vmanomaly:v1.25.3
|
||||
docker pull victoriametrics/vmanomaly:v1.26.2
|
||||
```
|
||||
|
||||
Now we can run the docker container putting as volumes both config and model file:
|
||||
@@ -1326,8 +1326,9 @@ docker run -it \
|
||||
-v $(PWD)/license:/license \
|
||||
-v $(PWD)/custom_model.py:/vmanomaly/model/custom.py \
|
||||
-v $(PWD)/custom.yaml:/config.yaml \
|
||||
victoriametrics/vmanomaly:v1.25.3 /config.yaml \
|
||||
victoriametrics/vmanomaly:v1.26.2 /config.yaml \
|
||||
--licenseFile=/license
|
||||
--watch
|
||||
```
|
||||
|
||||
Please find more detailed instructions (license, etc.) [here](https://docs.victoriametrics.com/anomaly-detection/quickstart/#docker)
|
||||
|
||||
@@ -146,6 +146,7 @@ Name of the class needed to enable reading from VictoriaMetrics or Prometheus. V
|
||||
<span style="white-space: nowrap;">`queries`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
See [per-query config example](#per-query-config-example) above
|
||||
</td>
|
||||
<td>
|
||||
@@ -226,7 +227,7 @@ Absolute or relative URL address where to check availability of the datasource.
|
||||
`USERNAME`
|
||||
</td>
|
||||
<td>
|
||||
BasicAuth username
|
||||
BasicAuth username. If set, it will be used to authenticate the request.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -239,7 +240,7 @@ BasicAuth username
|
||||
`PASSWORD`
|
||||
</td>
|
||||
<td>
|
||||
BasicAuth password
|
||||
BasicAuth password. If set, it will be used to authenticate the request.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -371,7 +372,7 @@ It allows overriding the default `-search.latencyOffset`{{% available_from "v1.1
|
||||
`10000`
|
||||
</td>
|
||||
<td>
|
||||
Optional arg{{% available_from "v1.17.0" anomaly %}} overrides how `search.maxPointsPerTimeseries` flag{{% available_from "v1.14.1" anomaly %}} impacts `vmanomaly` on splitting long `fit_window` [queries](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) into smaller sub-intervals. This helps users avoid hitting the `search.maxQueryDuration` limit for individual queries by distributing initial query across multiple subquery requests with minimal overhead. Set less than `search.maxPointsPerTimeseries` if hitting `maxQueryDuration` limits. You can also set it on [per-query](#per-query-parameters) basis to override this global one.
|
||||
Optional arg{{% available_from "v1.17.0" anomaly %}} overrides how `search.maxPointsPerTimeseries` flag{{% available_from "v1.14.1" anomaly %}} impacts `vmanomaly` on splitting long `fit_window` [queries](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) into smaller sub-intervals. This helps users avoid hitting the `search.maxQueryDuration` limit for individual queries by distributing initial query across multiple subquery requests with minimal overhead. Set less than `search.maxPointsPerTimeseries` if hitting `maxQueryDuration` limits. Can be also set on [per-query](#per-query-parameters) basis to override reader-level settings.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -477,3 +478,330 @@ reader:
|
||||
### Healthcheck metrics
|
||||
|
||||
`VmReader` exposes [several healthchecks metrics](https://docs.victoriametrics.com/anomaly-detection/components/monitoring/#reader-behaviour-metrics).
|
||||
|
||||
|
||||
## VictoriaLogs reader
|
||||
|
||||
{{% available_from "v1.26.0" anomaly %}} `vmanomaly` adds support for reading data from [VictoriaLogs stats queries](https://docs.victoriametrics.com/victorialogs/querying/#querying-log-range-stats) endpoint with `VLogsReader`. This reader allows quering and analyzing log data stored in VictoriaLogs, enabling anomaly detection on metrics generated from logs.
|
||||
|
||||
Its queries should be expressed in a subset of [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/), which is similar to MetricsQL/PromQL but adapted for log data.
|
||||
|
||||
> Please be aware that `VLogsReader` is designed to work with a `/select/stats_query_range` endpoint of [VictoriaLogs](https://docs.victoriametrics.com/victorialogs/), so the `<query>` expressions must contain `stats` [pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe) (see [query-examples](#query-examples) section below). The calculated stats is converted into metrics with labels from `by(...)` clause of the `| stats by(...)` pipe, where `stats_func*` is any of the supported [stats function subset](#valid-stats-functions) of [available stats functions](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe-functions), while the `result_name*` is the name of the log field to store the result of the corresponding stats function. The `as` keyword is optional.
|
||||
|
||||
### Valid stats functions
|
||||
`VLogsReader` relies on [stats pipe functions](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe-functions) that return **numeric values**, which can be used for anomaly detection on timeseries (metrics). The future addition of similar stats functions in VictoriaLogs will be supported automatically, as long as they return **numeric values**.
|
||||
|
||||
The supported stats functions currently include:
|
||||
- `avg` - returns the average value over the given numeric [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||
- `count` - returns the number of log entries.
|
||||
- `count_empty` - returns the number logs with empty [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||
- `count_uniq` - returns the number of unique non-empty values for the given [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||
- `count_uniq_hash` - returns the number of unique hashes for non-empty values at the given [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||
- `max` - returns the maximum value over the given [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||
- `median` - returns the [median](https://en.wikipedia.org/wiki/Median) value over the given [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||
- `min` - returns the minimum value over the given [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||
- `quantile` - returns the given quantile for the given [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||
- `rate` - returns the average per-second rate of matching logs on the selected time range.
|
||||
- `rate_sum` - returns the average per-second rate of sum for the given [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||
- `sum` - returns the sum for the given numeric [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||
- `sum_len` - returns the sum of lengths for the given [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
|
||||
|
||||
### Query Examples
|
||||
|
||||
> You can test your LogsQL queries with stats pipe functions using our [VictoriaLogs playground](https://play-vmlogs.victoriametrics.com/). Use either UI to access graphical results or the `/select/logsql/stats_query_range` endpoint to run your queries and see the raw results, e.g. as this [sample query](https://play-vmlogs.victoriametrics.com/select/logsql/stats_query_range?query=_time%3A5m%20%7C%20stats%20by%20%28_stream%29%20count%28%29%20as%20sample_row&step=1m).
|
||||
|
||||
Here are examples of simple valid LogsQL queries with stats pipe functions that can be used with `VLogsReader`.
|
||||
|
||||
The following query returns the average value for the duration field over logs matching the [filter](https://docs.victoriametrics.com/victorialogs/logsql/#filters) for `error` [word](https://docs.victoriametrics.com/victorialogs/logsql/#word):
|
||||
|
||||
```
|
||||
error | stats avg(duration) as avg_error_duration
|
||||
```
|
||||
|
||||
It is possible to calculate the average over fields with common prefix via `avg(prefix*)` syntax. For example, the following query calculates the number of logs with `foo` prefix having `error` [word](https://docs.victoriametrics.com/victorialogs/logsql/#word):
|
||||
|
||||
```
|
||||
error | stats count(foo*) as foo_error_count
|
||||
```
|
||||
|
||||
### Config parameters
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Example</th>
|
||||
<th><span style="white-space: nowrap;">Description</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<span style="white-space: nowrap;">`class`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`vlogs`
|
||||
</td>
|
||||
<td>
|
||||
The class name of the reader, must be `vlogs` (or `reader.vlogs.VLogsReader`).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`queries`
|
||||
</td>
|
||||
<td>
|
||||
See [per-query config example](#per-query-config-example-1) below
|
||||
</td>
|
||||
<td>
|
||||
Dictionary of queries. Keys are query aliases, values are LogsQL queries to select data in format: `QUERY_ALIAS:<query>`, as accepted by `/select/logsql/stats_query_range?query=%s` VictoriaLogs endpoint. The `<query>` must contain `stats` [pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe-functions). The calculated stats is converted into metrics with labels from `by(...)` clause of the `| stats by(...)` pipe. Only functions returning numeric values are supported, e.g. `count()`, `sum()`, `avg()`, `count_uniq()`, `median()`, `quantile()`, etc.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`datasource_url`
|
||||
</td>
|
||||
<td>
|
||||
`https://play-vmlogs.victoriametrics.com/`
|
||||
</td>
|
||||
<td>
|
||||
URL address of the VictoriaLogs datasource. Must be a valid URL.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`tenant_id`
|
||||
</td>
|
||||
<td>
|
||||
`0:0`
|
||||
</td>
|
||||
<td>
|
||||
Tenants are identified by `accountID` or `accountID:projectID`. See VictoriaLogs [multitenancy docs](https://docs.victoriametrics.com/victorialogs/#multitenancy).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`sampling_period`
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`1m`
|
||||
</td>
|
||||
<td>
|
||||
Frequency of the points returned. Will be converted to `/select/stats_query_range?step=%s` param (in seconds).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<span style="white-space: nowrap;">`data_range`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`[0, 'inf']`
|
||||
</td>
|
||||
<td>
|
||||
(Optional) Allows defining **valid** data ranges for input of all the queries in `queries`. Defaults to `["-inf", "inf"]` if not set and can be overridden on a [per-query basis](#per-query-parameters-1).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`tz`
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`America/New_York`
|
||||
</td>
|
||||
<td>
|
||||
(Optional) Specifies the [IANA](https://nodatime.org/TimeZones) timezone to account for local shifts, like [DST](https://en.wikipedia.org/wiki/Daylight_saving_time), in models sensitive to seasonal patterns (e.g., [`ProphetModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet) or [`OnlineQuantileModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#online-seasonal-quantile)). Defaults to `UTC` if not set and can be overridden on a [per-query basis](#per-query-parameters).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<span style="white-space: nowrap;">`max_points_per_query`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`10000`
|
||||
</td>
|
||||
<td>
|
||||
(Optional) For splitting long `fit_window` [queries](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vlogs-reader) into smaller sub-intervals. This helps users avoid hitting the timeout limits for individual queries by distributing initial query across multiple subquery requests with minimal overhead. Can be also set on [per-query](#per-query-parameters-1) basis to override reader-level settings.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<span style="white-space: nowrap;">`offset`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`0s`
|
||||
</td>
|
||||
<td>
|
||||
(Optional) Specifies the duration to shift the query window back (or forward) in time. This is useful for accounting for delays in data availability or for aligning the query window with specific events. Can be set on a [per-query basis](#per-query-parameters-1) to override the reader-level setting.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<span style="white-space: nowrap;">`timeout`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`30s`
|
||||
</td>
|
||||
<td>
|
||||
(Optional) Specifies the maximum duration to wait for a query to complete before timing out. Can be set on a [per-query basis](#per-query-parameters-1) to override the reader-level setting.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<span style="white-space: nowrap;">`verify_tls`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`false`
|
||||
</td>
|
||||
<td>
|
||||
Verify TLS certificate. If `False`, it will not verify the TLS certificate.
|
||||
If `True`, it will verify the certificate using the system's CA store.
|
||||
If a path to a CA bundle file (like `ca.crt`), it will verify the certificate using the provided CA bundle.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="white-space: nowrap;">`tls_cert_file`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`path/to/cert.crt`
|
||||
</td>
|
||||
<td>
|
||||
(Optional) Path to a file with the client certificate, i.e. `client.crt`.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="white-space: nowrap;">`tls_key_file`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`path/to/key.key`
|
||||
</td>
|
||||
<td>
|
||||
(Optional) Path to a file with the client key, i.e. `client.key`.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<span style="white-space: nowrap;">`bearer_token`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`token`
|
||||
</td>
|
||||
<td>
|
||||
|
||||
(Optional) Bearer token for authentication. If set, it will be used to authenticate the request as `Authorization: bearer {token}`.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="white-space: nowrap;">`bearer_token_file`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`path/to/token`
|
||||
</td>
|
||||
<td>
|
||||
(Optional) Path to a file containing the bearer token. If set, it will be used to authenticate the request.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`user`
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`USERNAME`
|
||||
</td>
|
||||
<td>
|
||||
(Optional) Username for BasicAuth authentication. If set, it will be used to authenticate the request.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
`password`
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`PASSWORD`
|
||||
</td>
|
||||
<td>
|
||||
(Optional) Password for authentication. If set, it will be used to authenticate the request.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Per-query parameters
|
||||
|
||||
The names, types and the logic of the per-query parameters subset used in `VLogsReader` are exactly the same as those of [`VmReader`](#vm-reader), please see [per-query parameters](#per-query-parameters) section above for the details. The only difference is that `expr` parameter should contain a valid [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/) expression with `stats` [pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe), as described in [query examples](#query-examples) section above.
|
||||
|
||||
### Per-query config example
|
||||
|
||||
```yaml
|
||||
reader:
|
||||
class: 'vlogs' # or 'reader.vlogs.VLogsReader'
|
||||
# don't include /select/stats_query_range part in the URL, it is added automatically
|
||||
datasource_url: 'https://play-vmlogs.victoriametrics.com/' # source victorialogs
|
||||
# tenant_id: '0:0' # for cluster version only
|
||||
sampling_period: '1m'
|
||||
max_points_per_query: 10000
|
||||
data_range: [0, 'inf'] # reader-level
|
||||
offset: '0s' # reader-level
|
||||
timeout: '30s'
|
||||
queries:
|
||||
# one query returning 1 result fields (avg_duration), it will have __name__ label (series name) as `duration_30m__avg`
|
||||
duration_avg_30m:
|
||||
expr: "* | stats avg(duration) as avg" # initial LogsQL expression
|
||||
step: '2m' # overrides global `sampling_period` of 1m
|
||||
data_range: [0, 'inf'] # meaning only positive values > 0 are expected, i.e. a value `y` < 0 will trigger anomaly score > 1
|
||||
tz: 'America/New_York' # to override reader-wise `tz`
|
||||
# tenant_id: '1:0' # overriding tenant_id to isolate data
|
||||
# offset: '-15s' # to override reader-wise `offset` and query data 15 seconds earlier to account for data collection delays
|
||||
# max_points_per_query: 5000 # overrides reader-level value of 10000 for `avg_duration` query
|
||||
|
||||
# one query returning 3 result fields (p50, p90, p99), they will have __name__ label (series name) as
|
||||
# `duration_quantiles_30m__p50`, `duration_quantiles_30m__p90`, `duration_quantiles_30m__p99`, respectively
|
||||
duration_quantiles_30m:
|
||||
expr: |
|
||||
* | stats
|
||||
quantile(0.5, request_duration_seconds) p50,
|
||||
quantile(0.9, request_duration_seconds) p90,
|
||||
quantile(0.99, request_duration_seconds) p99
|
||||
step: '2m' # overrides global `sampling_period` of 1m
|
||||
# other per-query parameters as needed
|
||||
# other reader-level parameters as needed
|
||||
|
||||
# other config sections, like models, schedulers, writer, ...
|
||||
```
|
||||
|
||||
### mTLS protection
|
||||
|
||||
Please refer to the [mTLS protection](#mtls-protection) section above for details on how to configure mTLS for `VLogsReader`. It uses the same config parameters as `VmReader` for mTLS setup.
|
||||
|
||||
### Healthcheck metrics
|
||||
|
||||
Similarly to `VmReader`, `VLogsReader` also exposes [several healthchecks metrics](https://docs.victoriametrics.com/anomaly-detection/components/monitoring/#reader-behaviour-metrics).
|
||||
|
||||
@@ -378,6 +378,8 @@ schedulers:
|
||||
|
||||
## Backtesting scheduler
|
||||
|
||||
> {{% available_from "v1.26.0" anomaly %}} `BacktestingScheduler` in [inference-only](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/#inference-only-mode) mode is used in UI for backtesting configurations on historical data to verify that it works as expected before it goes live. See [vmanomaly UI](https://docs.victoriametrics.com/anomaly-detection/ui/) on how to access and use the UI.
|
||||
|
||||
> As of latest version, the Backtesting scheduler can't be explicitly used with a combination of [state restoration](https://docs.victoriametrics.com/anomaly-detection/components/settings/#state-restoration). It is designed to run once and exit, so it does not maintain state across runs. A warning will be raised in logs and internal state for such scheduler will not be saved and restored upon restart. If you need to run the scheduler periodically and/or maintain state, consider using the [Periodic scheduler](#periodic-scheduler) instead.
|
||||
|
||||
> A new, more intuitive backtesting mode is available {{% available_from "v1.22.1" anomaly %}}. In **Inference only** mode, the window you specify via `[from, to]` (or `[from_iso, to_iso]`) is used *solely for inference*, and the corresponding training (“fit”) windows are determined automatically. To enable this behavior, set:
|
||||
|
||||
@@ -307,7 +307,7 @@ This means that the service upon restart:
|
||||
2. Will **partially** restore the state of `prophet` model, because its class and schedulers are unchanged, but **only instances trained on timeseries returned by `q1` query**. New fit/infer jobs will be set for new query `q3`. The old query `q2` artifacts will be dropped upon restart - all respective models and data for (`prophet`, `q2`) combination will be removed from the database file and from the disk.
|
||||
|
||||
|
||||
### Logger Levels
|
||||
## Logger Levels
|
||||
|
||||
{{% available_from "v1.25.3" anomaly %}} `vmanomaly` service supports per-component logger levels, allowing to control the verbosity of logs for each component independently. This can be useful for debugging or monitoring specific components without overwhelming the logs with information from other components. Prefixes are also supported, allowing to set the logger level for all components with a specific prefix.
|
||||
|
||||
@@ -324,8 +324,8 @@ settings:
|
||||
n_workers: 4
|
||||
restore_state: True # enables state restoration
|
||||
logger_levels:
|
||||
reader.vm: debug # affects only VmReader logs
|
||||
model: warning # applies to all components with 'model' prefix, such as 'model.zscore_online', 'model.prophet', etc.
|
||||
reader.vm: DEBUG # affects only VmReader logs
|
||||
model: WARNING # applies to all components with 'model' prefix, such as 'model.zscore_online', 'model.prophet', etc.
|
||||
# once commented out in hot-reload mode, will use the default logger level set by --loggerLevel command line argument
|
||||
# monitoring.push: critical
|
||||
```
|
||||
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 123 KiB |
@@ -10,9 +10,9 @@ sitemap:
|
||||
|
||||
- To use *vmanomaly*, part of the enterprise package, a license key is required. Obtain your key [here](https://victoriametrics.com/products/enterprise/trial/) for this tutorial or for enterprise use.
|
||||
- In the tutorial, we'll be using the following VictoriaMetrics components:
|
||||
- [VictoriaMetrics Single-Node](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) (v1.126.0)
|
||||
- [vmalert](https://docs.victoriametrics.com/victoriametrics/vmalert/) (v1.126.0)
|
||||
- [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) (v1.126.0)
|
||||
- [VictoriaMetrics Single-Node](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) (v1.127.0)
|
||||
- [vmalert](https://docs.victoriametrics.com/victoriametrics/vmalert/) (v1.127.0)
|
||||
- [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) (v1.127.0)
|
||||
- [Grafana](https://grafana.com/) (v.10.2.1)
|
||||
- [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/)
|
||||
- [Node exporter](https://github.com/prometheus/node_exporter#node-exporter) (v1.7.0) and [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) (v0.27.0)
|
||||
@@ -323,7 +323,7 @@ Let's wrap it all up together into the `docker-compose.yml` file.
|
||||
services:
|
||||
vmagent:
|
||||
container_name: vmagent
|
||||
image: victoriametrics/vmagent:v1.126.0
|
||||
image: victoriametrics/vmagent:v1.127.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
@@ -340,7 +340,7 @@ services:
|
||||
|
||||
victoriametrics:
|
||||
container_name: victoriametrics
|
||||
image: victoriametrics/victoria-metrics:v1.126.0
|
||||
image: victoriametrics/victoria-metrics:v1.127.0
|
||||
ports:
|
||||
- 8428:8428
|
||||
volumes:
|
||||
@@ -373,7 +373,7 @@ services:
|
||||
|
||||
vmalert:
|
||||
container_name: vmalert
|
||||
image: victoriametrics/vmalert:v1.126.0
|
||||
image: victoriametrics/vmalert:v1.127.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
@@ -395,7 +395,7 @@ services:
|
||||
restart: always
|
||||
vmanomaly:
|
||||
container_name: vmanomaly
|
||||
image: victoriametrics/vmanomaly:v1.25.3
|
||||
image: victoriametrics/vmanomaly:v1.26.2
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
|
||||
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/anomaly-detection/vmanomaly-ui-model-config-menu.webp
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/anomaly-detection/vmanomaly-ui-model-config-wizard.webp
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
docs/anomaly-detection/vmanomaly-ui-open-config-btn.webp
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
docs/anomaly-detection/vmanomaly-ui-open-config-menu.webp
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
docs/anomaly-detection/vmanomaly-ui-overview.webp
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
docs/anomaly-detection/vmanomaly-ui-sections-explore.webp
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/anomaly-detection/vmanomaly-ui-sections-model.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 180 KiB |
|
After Width: | Height: | Size: 118 KiB |
BIN
docs/anomaly-detection/vmanomaly-ui-sections-settings.webp
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/anomaly-detection/vmanomaly-ui-state-sharing-url.webp
Normal file
|
After Width: | Height: | Size: 19 KiB |
@@ -249,27 +249,27 @@ services:
|
||||
- grafana_data:/var/lib/grafana/
|
||||
|
||||
vmsingle:
|
||||
image: victoriametrics/victoria-metrics:v1.126.0
|
||||
image: victoriametrics/victoria-metrics:v1.127.0
|
||||
command:
|
||||
- -httpListenAddr=0.0.0.0:8429
|
||||
|
||||
vmstorage:
|
||||
image: victoriametrics/vmstorage:v1.126.0-cluster
|
||||
image: victoriametrics/vmstorage:v1.127.0-cluster
|
||||
|
||||
vminsert:
|
||||
image: victoriametrics/vminsert:v1.126.0-cluster
|
||||
image: victoriametrics/vminsert:v1.127.0-cluster
|
||||
command:
|
||||
- -storageNode=vmstorage:8400
|
||||
- -httpListenAddr=0.0.0.0:8480
|
||||
|
||||
vmselect:
|
||||
image: victoriametrics/vmselect:v1.126.0-cluster
|
||||
image: victoriametrics/vmselect:v1.127.0-cluster
|
||||
command:
|
||||
- -storageNode=vmstorage:8401
|
||||
- -httpListenAddr=0.0.0.0:8481
|
||||
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.126.0
|
||||
image: victoriametrics/vmagent:v1.127.0
|
||||
volumes:
|
||||
- ./scrape.yaml:/etc/vmagent/config.yaml
|
||||
command:
|
||||
@@ -278,7 +278,7 @@ services:
|
||||
- -remoteWrite.url=http://vmsingle:8429/api/v1/write
|
||||
|
||||
vmgateway-cluster:
|
||||
image: victoriametrics/vmgateway:v1.126.0-enterprise
|
||||
image: victoriametrics/vmgateway:v1.127.0-enterprise
|
||||
ports:
|
||||
- 8431:8431
|
||||
volumes:
|
||||
@@ -294,7 +294,7 @@ services:
|
||||
- -auth.oidcDiscoveryEndpoints=http://keycloak:8080/realms/master/.well-known/openid-configuration
|
||||
|
||||
vmgateway-single:
|
||||
image: victoriametrics/vmgateway:v1.126.0-enterprise
|
||||
image: victoriametrics/vmgateway:v1.127.0-enterprise
|
||||
ports:
|
||||
- 8432:8431
|
||||
volumes:
|
||||
@@ -405,7 +405,7 @@ Once iDP configuration is done, vmagent configuration needs to be updated to use
|
||||
|
||||
```yaml
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.126.0
|
||||
image: victoriametrics/vmagent:v1.127.0
|
||||
volumes:
|
||||
- ./scrape.yaml:/etc/vmagent/config.yaml
|
||||
- ./vmagent-client-secret:/etc/vmagent/oauth2-client-secret
|
||||
|
||||
18
docs/guides/k8s-ui-headlamp/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
build:
|
||||
list: never
|
||||
publishResources: false
|
||||
render: never
|
||||
sitemap:
|
||||
disable: true
|
||||
---
|
||||
|
||||
Headlamp is a user-friendly Kubernetes UI focused on extensibility. It supports displaying metrics for Kubernetes resources via a built-in Prometheus plugin. Here's the plugin configuration to use in-cluster VictoriaMetrics Single - set Prometheus Service Address to `<namespace>/<vmsingle service name>:8428`:
|
||||

|
||||
|
||||
In case of cluster installation, point to the vmselect service (
|
||||
` <namespace>/<vmselect service name>:8481`) and specify the prometheus-compatible subpath `select/<tenant id>/prometheus`:
|
||||

|
||||
|
||||
The plugin will display CPU/Memory/Network/Filesystem graphs for k8s resources:
|
||||

|
||||
15
docs/guides/k8s-ui-headlamp/_index.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
weight: 13
|
||||
title: Headlamp Kubernetes UI and VictoriaMetrics
|
||||
menu:
|
||||
docs:
|
||||
parent: "guides"
|
||||
weight: 13
|
||||
tags:
|
||||
- metrics
|
||||
- guide
|
||||
- kubernetes
|
||||
aliases:
|
||||
- /guides/k8s-ui-headlamp.html
|
||||
---
|
||||
{{% content "README.md" %}}
|
||||
BIN
docs/guides/k8s-ui-headlamp/cluster-metrics.webp
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/guides/k8s-ui-headlamp/vmcluster-plugin-settings.webp
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/guides/k8s-ui-headlamp/vmsingle-plugin-settings.webp
Normal file
|
After Width: | Height: | Size: 28 KiB |
@@ -13,7 +13,7 @@ and [VictoriaMetrics Cloud](https://docs.victoriametrics.com/victoriametrics-clo
|
||||
## Terminology
|
||||
|
||||
- [Active Time Series](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-an-active-time-series) - a [time series](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#time-series)
|
||||
that was update at least one time during the last hour;
|
||||
that was updated at least one time during the last hour;
|
||||
- Ingestion Rate - how many [samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) are ingest into the database per second;
|
||||
- [Churn Rate](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-high-churn-rate) - how frequently a new [time series](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#time-series)
|
||||
is created. For example, changing pod name in Kubernetes is a common source of time series churn;
|
||||
|
||||
@@ -780,7 +780,7 @@ See also [minimum downtime strategy](#minimum-downtime-strategy).
|
||||
|
||||
VictoriaMetrics uses lower amounts of CPU, RAM and storage space on production workloads compared to competing solutions (Prometheus, Thanos, Cortex, TimescaleDB, InfluxDB, QuestDB, M3DB) according to [our case studies](https://docs.victoriametrics.com/victoriametrics/casestudies/).
|
||||
|
||||
Each node type - `vminsert`, `vmselect` and `vmstorage` - can run on the most suitable hardware. Cluster capacity scales linearly with the available resources. The needed amounts of CPU and RAM per each node type highly depends on the workload - the number of [active time series](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-an-active-time-series), [series churn rate](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-high-churn-rate), query types, query qps, etc. It is recommended setting up a test VictoriaMetrics cluster for your production workload and iteratively scaling per-node resources and the number of nodes per node type until the cluster becomes stable. It is recommended setting up [monitoring for the cluster](#monitoring). It helps to determine bottlenecks in cluster setup. It is also recommended following [the troubleshooting docs](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#troubleshooting).
|
||||
Each node type - `vminsert`, `vmselect` and `vmstorage` - can run on the most suitable hardware. Cluster capacity scales linearly with the available resources. The needed amounts of CPU and RAM per each node type highly depends on the workload - the number of [active time series](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-an-active-time-series), [series churn rate](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-high-churn-rate), query types, query qps, etc. It is recommended to setup a test VictoriaMetrics cluster for your production workload and iteratively scale per-node resources and the number of nodes per node type until the cluster becomes stable. It is recommended to setup [monitoring for the cluster](#monitoring). It helps to determine bottlenecks in the cluster setup. It is also recommended to follow [the troubleshooting docs](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#troubleshooting).
|
||||
|
||||
The needed storage space for the given retention (the retention is set via `-retentionPeriod` command-line flag at `vmstorage`) can be extrapolated from disk space usage in a test run. For example, if the storage space usage is 10GB after a day-long test run on a production workload, then it will need at least `10GB*100=1TB` of disk space for `-retentionPeriod=100d` (100-days retention period). Storage space usage can be monitored with [the official Grafana dashboard for VictoriaMetrics cluster](#monitoring).
|
||||
|
||||
|
||||
@@ -27,5 +27,5 @@ to [the latest available releases](https://docs.victoriametrics.com/victoriametr
|
||||
|
||||
## Currently supported LTS release lines
|
||||
|
||||
- v1.122.x - the latest one is [v1.122.4 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.122.4)
|
||||
- v1.110.x - the latest one is [v1.110.19 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.110.19)
|
||||
- v1.122.x - the latest one is [v1.122.5 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.122.5)
|
||||
- v1.110.x - the latest one is [v1.110.20 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.110.20)
|
||||
|
||||
@@ -58,9 +58,9 @@ Download the newest available [VictoriaMetrics release](https://docs.victoriamet
|
||||
from [DockerHub](https://hub.docker.com/r/victoriametrics/victoria-metrics) or [Quay](https://quay.io/repository/victoriametrics/victoria-metrics?tab=tags):
|
||||
|
||||
```sh
|
||||
docker pull victoriametrics/victoria-metrics:v1.126.0
|
||||
docker pull victoriametrics/victoria-metrics:v1.127.0
|
||||
docker run -it --rm -v `pwd`/victoria-metrics-data:/victoria-metrics-data -p 8428:8428 \
|
||||
victoriametrics/victoria-metrics:v1.126.0 --selfScrapeInterval=5s -storageDataPath=victoria-metrics-data
|
||||
victoriametrics/victoria-metrics:v1.127.0 --selfScrapeInterval=5s -storageDataPath=victoria-metrics-data
|
||||
```
|
||||
|
||||
_For Enterprise images see [this link](https://docs.victoriametrics.com/victoriametrics/enterprise/#docker-images)._
|
||||
|
||||
@@ -1049,6 +1049,7 @@ for received measurements. The number of dropped unsupported samples is exposed
|
||||
|
||||
VictoriaMetrics stores the ingested OpenTelemetry [raw samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) as is without any transformations.
|
||||
Pass `-opentelemetry.usePrometheusNaming` command-line flag to VictoriaMetrics for automatic conversion of metric names and labels into Prometheus-compatible format.
|
||||
Pass `-opentelemetry.convertMetricNamesToPrometheus` command-line flag to VictoriaMetrics for applying Prometheus-compatible format conversion only for metrics names.
|
||||
OpenTelemetry [exponential histogram](https://opentelemetry.io/docs/specs/otel/metrics/data-model/#exponentialhistogram) is automatically converted
|
||||
to [VictoriaMetrics histogram format](https://valyala.medium.com/improving-histogram-usability-for-prometheus-and-grafana-bc7e5df0e350).
|
||||
|
||||
@@ -1734,6 +1735,7 @@ VictoriaMetrics provides the following security-related command-line flags:
|
||||
* `-configAuthKey` for protecting `/config` endpoint, since it may contain sensitive information such as passwords.
|
||||
* `-flagsAuthKey` for protecting `/flags` endpoint.
|
||||
* `-pprofAuthKey` for protecting `/debug/pprof/*` endpoints, which can be used for [profiling](#profiling).
|
||||
* `-metricNamesStatsResetAuthKey` for protecting `/api/v1/admin/status/metric_names_stats/reset` endpoint, used for [Metric Names Tracker](#track-ingested-metrics-usage).
|
||||
* `-denyQueryTracing` for disallowing [query tracing](#query-tracing).
|
||||
* `-http.header.hsts`, `-http.header.csp`, and `-http.header.frameOptions` for serving `Strict-Transport-Security`, `Content-Security-Policy`
|
||||
and `X-Frame-Options` HTTP response headers.
|
||||
@@ -1744,6 +1746,17 @@ For example, substitute `-graphiteListenAddr=:2003` with `-graphiteListenAddr=<i
|
||||
See also [security recommendation for VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#security)
|
||||
and [the general security page at VictoriaMetrics website](https://victoriametrics.com/security/).
|
||||
|
||||
### CVE handling policy
|
||||
|
||||
**Source code:** Go dependencies are scanned by [govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck) in CI.
|
||||
All vulnerabilities must be fixed before next scheduled release and backported to [LTS releases](https://docs.victoriametrics.com/victoriametrics/lts-releases/).
|
||||
|
||||
**Docker images:** CVE findings in [Alpine](https://security.alpinelinux.org/) base image pose minimal risk since VictoriaMetrics binaries are statically compiled with no OS dependencies.
|
||||
When detected, only the Alpine base tag is updated.
|
||||
Releases proceed as planned even if upstream fixes are not yet available.
|
||||
For maximum security, hardened [scratch](https://hub.docker.com/_/scratch)-based images are also provided.
|
||||
All images are continuously scanned by Docker Hub and verified before release using [grype](https://github.com/anchore/grype).
|
||||
|
||||
### mTLS protection
|
||||
|
||||
By default `VictoriaMetrics` accepts http requests at `8428` port (this port can be changed via `-httpListenAddr` command-line flags).
|
||||
@@ -1876,7 +1889,7 @@ The API endpoint returns the following `JSON` response:
|
||||
"records": [
|
||||
{
|
||||
"metricName": "node_disk_writes_completed_total",
|
||||
"queryRequests": 50,
|
||||
"queryRequestsCount": 50,
|
||||
"lastRequestTimestamp": 1737534262
|
||||
},
|
||||
{
|
||||
@@ -1892,7 +1905,7 @@ The API endpoint returns the following `JSON` response:
|
||||
* `statsCollectedRecordsTotal` total number of metric names it contains;
|
||||
* `records`:
|
||||
* `metricName` a metric name;
|
||||
* `queryRequests` a cumulative counter of times the metric was fetched. If metric name `foo` has 10 time series,
|
||||
* `queryRequestsCount` a cumulative counter of times the metric was fetched. If metric name `foo` has 10 time series,
|
||||
then one read query `foo` will increment counter by 10.
|
||||
* `lastRequestTimestamp` a timestamp when last time this statistic was updated.
|
||||
|
||||
@@ -1917,7 +1930,8 @@ can be used to notify the user of cache utilization exceeding 90%.
|
||||
The metric name tracker state can be **reset** via the API endpoint `/api/v1/admin/status/metric_names_stats/reset`
|
||||
for a single-node VictoriaMetrics (or at `http://<vmselect>:8481/admin/api/v1/admin/status/metric_names_stats/reset`
|
||||
in [cluster version of VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/)) or
|
||||
via [cache removal](#cache-removal) procedure.
|
||||
via [cache removal](https://docs.victoriametrics.com/victoriametrics/#cache-removal) procedure. This reset state endpoint can be protected via `-metricNamesStatsResetAuthKey`
|
||||
cmd-line flag. See [Security](https://docs.victoriametrics.com/victoriametrics/#security) for details.
|
||||
|
||||
## Query tracing
|
||||
|
||||
|
||||