Compare commits

..

1 Commits

Author SHA1 Message Date
Haley Wang
e237e35c9c test alert annotation 2025-01-16 15:52:33 +08:00
1273 changed files with 399501 additions and 15509 deletions

View File

@@ -513,19 +513,19 @@ check-all: fmt vet golangci-lint govulncheck
clean-checkers: remove-golangci-lint remove-govulncheck
test:
go test ./lib/... ./app/...
DISABLE_FSYNC_FOR_TESTING=1 go test ./lib/... ./app/...
test-race:
go test -race ./lib/... ./app/...
DISABLE_FSYNC_FOR_TESTING=1 go test -race ./lib/... ./app/...
test-pure:
CGO_ENABLED=0 go test ./lib/... ./app/...
DISABLE_FSYNC_FOR_TESTING=1 CGO_ENABLED=0 go test ./lib/... ./app/...
test-full:
go test -coverprofile=coverage.txt -covermode=atomic ./lib/... ./app/...
DISABLE_FSYNC_FOR_TESTING=1 go test -coverprofile=coverage.txt -covermode=atomic ./lib/... ./app/...
test-full-386:
GOARCH=386 go test -coverprofile=coverage.txt -covermode=atomic ./lib/... ./app/...
DISABLE_FSYNC_FOR_TESTING=1 GOARCH=386 go test -coverprofile=coverage.txt -covermode=atomic ./lib/... ./app/...
integration-test: victoria-metrics vmagent vmalert vmauth
go test ./apptest/... -skip="^TestCluster.*"

View File

@@ -199,8 +199,8 @@ func (lmp *logMessageProcessor) AddRow(timestamp int64, fields, streamFields []l
lmp.bytesIngestedTotal.Add(n)
if len(fields) > *MaxFieldsPerLine {
line := logstorage.MarshalFieldsToJSON(nil, fields)
logger.Warnf("dropping log line with %d fields; it exceeds -insert.maxFieldsPerLine=%d; %s", len(fields), *MaxFieldsPerLine, line)
rf := logstorage.RowFormatter(fields)
logger.Warnf("dropping log line with %d fields; it exceeds -insert.maxFieldsPerLine=%d; %s", len(fields), *MaxFieldsPerLine, rf)
rowsDroppedTotalTooManyFields.Inc()
return
}

View File

@@ -8,10 +8,8 @@ import (
var (
// MaxLineSizeBytes is the maximum length of a single line for /insert/* handlers
MaxLineSizeBytes = flagutil.NewBytes("insert.maxLineSizeBytes", 256*1024, "The maximum size of a single line, which can be read by /insert/* handlers; "+
"see https://docs.victoriametrics.com/victorialogs/faq/#what-length-a-log-record-is-expected-to-have")
MaxLineSizeBytes = flagutil.NewBytes("insert.maxLineSizeBytes", 256*1024, "The maximum size of a single line, which can be read by /insert/* handlers")
// MaxFieldsPerLine is the maximum number of fields per line for /insert/* handlers
MaxFieldsPerLine = flag.Int("insert.maxFieldsPerLine", 1000, "The maximum number of log fields per line, which can be read by /insert/* handlers; "+
"see https://docs.victoriametrics.com/victorialogs/faq/#how-many-fields-a-single-log-entry-may-contain")
MaxFieldsPerLine = flag.Int("insert.maxFieldsPerLine", 1000, "The maximum number of log fields per line, which can be read by /insert/* handlers")
)

View File

@@ -270,7 +270,7 @@ func printCommandsHelp(w io.Writer) {
\h - show this help
\s - singleline json output mode
\m - multiline json output mode
\c - compact output mode
\c - compact output
\logfmt - logfmt output mode
\wrap_long_lines - toggles wrapping long lines
\tail <query> - live tail <query> results

View File

@@ -688,13 +688,13 @@ func ProcessStatsQueryRangeRequest(ctx context.Context, w http.ResponseWriter, r
m := make(map[string]*statsSeries)
var mLock sync.Mutex
timestamp := q.GetTimestamp()
writeBlock := func(_ uint, timestamps []int64, columns []logstorage.BlockColumn) {
clonedColumnNames := make([]string, len(columns))
for i, c := range columns {
clonedColumnNames[i] = strings.Clone(c.Name)
}
for i := range timestamps {
timestamp := q.GetTimestamp()
labels := make([]logstorage.Field, 0, len(byFields))
for j, c := range columns {
if c.Name == "_time" {

View File

@@ -28,7 +28,7 @@ func TestParseExtraFilters_Success(t *testing.T) {
// LogsQL filter
f(`foobar`, `foobar`)
f(`foo:bar`, `foo:bar`)
f(`foo:(bar or baz) error _time:5m {"foo"=bar,baz="z"}`, `{foo="bar",baz="z"} (foo:bar or foo:baz) error _time:5m`)
f(`foo:(bar or baz) error _time:5m {"foo"=bar,baz="z"}`, `(foo:bar or foo:baz) error _time:5m {foo="bar",baz="z"}`)
}
func TestParseExtraFilters_Failure(t *testing.T) {
@@ -77,7 +77,7 @@ func TestParseExtraStreamFilters_Success(t *testing.T) {
// LogsQL filter
f(`foobar`, `foobar`)
f(`foo:bar`, `foo:bar`)
f(`foo:(bar or baz) error _time:5m {"foo"=bar,baz="z"}`, `{foo="bar",baz="z"} (foo:bar or foo:baz) error _time:5m`)
f(`foo:(bar or baz) error _time:5m {"foo"=bar,baz="z"}`, `(foo:bar or foo:baz) error _time:5m {foo="bar",baz="z"}`)
}
func TestParseExtraStreamFilters_Failure(t *testing.T) {

View File

@@ -1,12 +1,12 @@
{
"files": {
"main.css": "./static/css/main.02a1c6cb.css",
"main.js": "./static/js/main.55c8060b.js",
"main.css": "./static/css/main.4aacd559.css",
"main.js": "./static/js/main.5ce54a05.js",
"static/js/685.f772060c.chunk.js": "./static/js/685.f772060c.chunk.js",
"index.html": "./index.html"
},
"entrypoints": [
"static/css/main.02a1c6cb.css",
"static/js/main.55c8060b.js"
"static/css/main.4aacd559.css",
"static/js/main.5ce54a05.js"
]
}

View File

@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.svg"/><link rel="apple-touch-icon" href="./favicon.svg"/><link rel="mask-icon" href="./favicon.svg" color="#000000"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=5"/><meta name="theme-color" content="#000000"/><meta name="description" content="Explore your log data with VictoriaLogs UI"/><link rel="manifest" href="./manifest.json"/><title>UI for VictoriaLogs</title><meta name="twitter:card" content="summary"><meta name="twitter:title" content="UI for VictoriaLogs"><meta name="twitter:site" content="@https://victoriametrics.com/products/victorialogs/"><meta name="twitter:description" content="Explore your log data with VictoriaLogs UI"><meta name="twitter:image" content="./preview.jpg"><meta property="og:type" content="website"><meta property="og:title" content="UI for VictoriaLogs"><meta property="og:url" content="https://victoriametrics.com/products/victorialogs/"><meta property="og:description" content="Explore your log data with VictoriaLogs UI"><script defer="defer" src="./static/js/main.55c8060b.js"></script><link href="./static/css/main.02a1c6cb.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.svg"/><link rel="apple-touch-icon" href="./favicon.svg"/><link rel="mask-icon" href="./favicon.svg" color="#000000"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=5"/><meta name="theme-color" content="#000000"/><meta name="description" content="Explore your log data with VictoriaLogs UI"/><link rel="manifest" href="./manifest.json"/><title>UI for VictoriaLogs</title><meta name="twitter:card" content="summary"><meta name="twitter:title" content="UI for VictoriaLogs"><meta name="twitter:site" content="@https://victoriametrics.com/products/victorialogs/"><meta name="twitter:description" content="Explore your log data with VictoriaLogs UI"><meta name="twitter:image" content="./preview.jpg"><meta property="og:type" content="website"><meta property="og:title" content="UI for VictoriaLogs"><meta property="og:url" content="https://victoriametrics.com/products/victorialogs/"><meta property="og:description" content="Explore your log data with VictoriaLogs UI"><script defer="defer" src="./static/js/main.5ce54a05.js"></script><link href="./static/css/main.4aacd559.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -222,7 +222,8 @@ func processRequest(w http.ResponseWriter, r *http.Request, ui *UserInfo) {
isDefault = true
}
rtb := newReadTrackingBody(r.Body, maxRequestBodySizeToRetry.IntN())
rtb := getReadTrackingBody(r.Body, maxRequestBodySizeToRetry.IntN())
defer putReadTrackingBody(rtb)
r.Body = rtb
maxAttempts := up.getBackendsCount()
@@ -558,11 +559,22 @@ type readTrackingBody struct {
bufComplete bool
}
func newReadTrackingBody(r io.ReadCloser, maxBodySize int) *readTrackingBody {
// do not use sync.Pool there
// since http.RoundTrip may still use request body after return
// See this issue for details https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8051
rtb := &readTrackingBody{}
func (rtb *readTrackingBody) reset() {
rtb.maxBodySize = 0
rtb.r = nil
rtb.buf = rtb.buf[:0]
rtb.readBuf = nil
rtb.cannotRetry = false
rtb.bufComplete = false
}
func getReadTrackingBody(r io.ReadCloser, maxBodySize int) *readTrackingBody {
v := readTrackingBodyPool.Get()
if v == nil {
v = &readTrackingBody{}
}
rtb := v.(*readTrackingBody)
if maxBodySize < 0 {
maxBodySize = 0
}
@@ -585,6 +597,13 @@ func (r *zeroReader) Close() error {
return nil
}
func putReadTrackingBody(rtb *readTrackingBody) {
rtb.reset()
readTrackingBodyPool.Put(rtb)
}
var readTrackingBodyPool sync.Pool
// Read implements io.Reader interface.
func (rtb *readTrackingBody) Read(p []byte) (int, error) {
if len(rtb.readBuf) > 0 {

View File

@@ -195,7 +195,7 @@ unauthorized_user:
}
responseExpected = `
statusCode=401
Expected to receive non-empty authKey when -reloadAuthKey is set`
The provided authKey doesn't match -reloadAuthKey`
f(cfgStr, requestURL, backendHandler, responseExpected)
if err := reloadAuthKey.Set(origAuthKey); err != nil {
t.Fatalf("unexpected error: %s", err)
@@ -545,7 +545,8 @@ func TestReadTrackingBody_RetrySuccess(t *testing.T) {
f := func(s string, maxBodySize int) {
t.Helper()
rtb := newReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
rtb := getReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
defer putReadTrackingBody(rtb)
if !rtb.canRetry() {
t.Fatalf("canRetry() must return true before reading anything")
@@ -580,7 +581,8 @@ func TestReadTrackingBody_RetrySuccessPartialRead(t *testing.T) {
t.Helper()
// Check the case with partial read
rtb := newReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
rtb := getReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
defer putReadTrackingBody(rtb)
for i := 0; i < len(s); i++ {
buf := make([]byte, i)
@@ -629,7 +631,8 @@ func TestReadTrackingBody_RetryFailureTooBigBody(t *testing.T) {
f := func(s string, maxBodySize int) {
t.Helper()
rtb := newReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
rtb := getReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
defer putReadTrackingBody(rtb)
if !rtb.canRetry() {
t.Fatalf("canRetry() must return true before reading anything")
@@ -678,7 +681,8 @@ func TestReadTrackingBody_RetryFailureZeroOrNegativeMaxBodySize(t *testing.T) {
f := func(s string, maxBodySize int) {
t.Helper()
rtb := newReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
rtb := getReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
defer putReadTrackingBody(rtb)
if !rtb.canRetry() {
t.Fatalf("canRetry() must return true before reading anything")

View File

@@ -29,13 +29,13 @@ import (
)
var (
deleteAuthKey = flagutil.NewPassword("deleteAuthKey", "authKey for metrics' deletion via /api/v1/admin/tsdb/delete_series and /tags/delSeries. It could be passed via authKey query arg. It overrides -httpAuth.*")
deleteAuthKey = flagutil.NewPassword("deleteAuthKey", "authKey for metrics' deletion via /api/v1/admin/tsdb/delete_series and /tags/delSeries. It overrides -httpAuth.*")
maxConcurrentRequests = flag.Int("search.maxConcurrentRequests", getDefaultMaxConcurrentRequests(), "The maximum number of concurrent search requests. "+
"It shouldn't be high, since a single request can saturate all the CPU cores, while many concurrently executed requests may require high amounts of memory. "+
"See also -search.maxQueueDuration and -search.maxMemoryPerQuery")
maxQueueDuration = flag.Duration("search.maxQueueDuration", 10*time.Second, "The maximum time the request waits for execution when -search.maxConcurrentRequests "+
"limit is reached; see also -search.maxQueryDuration")
resetCacheAuthKey = flagutil.NewPassword("search.resetCacheAuthKey", "Optional authKey for resetting rollup cache via /internal/resetRollupResultCache call. It could be passed via authKey query arg. It overrides -httpAuth.*")
resetCacheAuthKey = flagutil.NewPassword("search.resetCacheAuthKey", "Optional authKey for resetting rollup cache via /internal/resetRollupResultCache call. It overrides -httpAuth.*")
logSlowQueryDuration = flag.Duration("search.logSlowQueryDuration", 5*time.Second, "Log queries with execution time exceeding this value. Zero disables slow query logging. "+
"See also -search.logQueryMemoryUsage")
vmalertProxyURL = flag.String("vmalert.proxyURL", "", "Optional URL for proxying requests to vmalert. For example, if -vmalert.proxyURL=http://vmalert:8880 , then alerting API requests such as /api/v1/rules from Grafana will be proxied to http://vmalert:8880/api/v1/rules")

View File

@@ -481,8 +481,6 @@ func DeleteHandler(startTime time.Time, r *http.Request) error {
if err != nil {
return err
}
cp.deadline = searchutils.GetDeadlineForDelete(r, startTime)
if !cp.IsDefaultTimeRange() {
return fmt.Errorf("start=%d and end=%d args aren't supported. Remove these args from the query in order to delete all the matching metrics", cp.start, cp.end)
}

View File

@@ -374,8 +374,8 @@ func getRollupConfigs(funcName string, rf rollupFunc, expr metricsql.Expr, start
preFunc := func(_ []float64, _ []int64) {}
funcName = strings.ToLower(funcName)
if rollupFuncsRemoveCounterResets[funcName] {
preFunc = func(values []float64, timestamps []int64) {
removeCounterResets(values, timestamps, lookbackDelta)
preFunc = func(values []float64, _ []int64) {
removeCounterResets(values)
}
}
samplesScannedPerCall := rollupFuncsSamplesScannedPerCall[funcName]
@@ -486,8 +486,8 @@ func getRollupConfigs(funcName string, rf rollupFunc, expr metricsql.Expr, start
for _, aggrFuncName := range aggrFuncNames {
if rollupFuncsRemoveCounterResets[aggrFuncName] {
// There is no need to save the previous preFunc, since it is either empty or the same.
preFunc = func(values []float64, timestamps []int64) {
removeCounterResets(values, timestamps, lookbackDelta)
preFunc = func(values []float64, _ []int64) {
removeCounterResets(values)
}
}
rf := rollupAggrFuncs[aggrFuncName]
@@ -521,7 +521,7 @@ type rollupFuncArg struct {
timestamps []int64
// Real value preceding values.
// Is populated if preceding value is within the -search.maxStalenessInterval (rc.LookbackDelta).
// Is populated if preceding value is within the staleness interval.
realPrevValue float64
// Real value which goes after values.
@@ -768,13 +768,7 @@ func (rc *rollupConfig) doInternal(dstValues []float64, tsm *timeseriesMap, valu
rfa.realPrevValue = nan
if i > 0 {
prevValue, prevTimestamp := values[i-1], timestamps[i-1]
// set realPrevValue if rc.LookbackDelta == 0
// or if distance between datapoint in prev interval and beginning of this interval
// doesn't exceed LookbackDelta.
// https://github.com/VictoriaMetrics/VictoriaMetrics/pull/1381
// https://github.com/VictoriaMetrics/VictoriaMetrics/issues/894
// https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8045
if rc.LookbackDelta == 0 || (tStart-prevTimestamp) < rc.LookbackDelta {
if (tEnd - prevTimestamp) < maxPrevInterval {
rfa.realPrevValue = prevValue
}
}
@@ -900,7 +894,7 @@ func getMaxPrevInterval(scrapeInterval int64) int64 {
return scrapeInterval + scrapeInterval/8
}
func removeCounterResets(values []float64, timestamps []int64, maxStalenessInterval int64) {
func removeCounterResets(values []float64) {
// There is no need in handling NaNs here, since they are impossible
// on values from vmstorage.
if len(values) == 0 {
@@ -919,16 +913,6 @@ func removeCounterResets(values []float64, timestamps []int64, maxStalenessInter
correction += prevValue
}
}
if i > 0 && maxStalenessInterval > 0 {
gap := timestamps[i] - timestamps[i-1]
if gap > maxStalenessInterval {
// reset correction if gap between samples exceeds staleness interval
// see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8072
correction = 0
prevValue = v
continue
}
}
prevValue = v
values[i] = v + correction
// Check again, there could be precision error in float operations,

View File

@@ -117,49 +117,31 @@ func TestRollupIderivDuplicateTimestamps(t *testing.T) {
}
func TestRemoveCounterResets(t *testing.T) {
removeCounterResets(nil, nil, 0)
removeCounterResets(nil)
values := append([]float64{}, testValues...)
timestamps := append([]int64{}, testTimestamps...)
removeCounterResets(values, timestamps, 0)
removeCounterResets(values)
valuesExpected := []float64{123, 157, 167, 188, 221, 255, 320, 332, 364, 396, 398, 398}
testRowsEqual(t, values, testTimestamps, valuesExpected, testTimestamps)
// removeCounterResets doesn't expect negative values, so it doesn't work properly with them.
values = []float64{-100, -200, -300, -400}
timestampsExpected := []int64{0, 1, 2, 3}
removeCounterResets(values, timestampsExpected, 0)
removeCounterResets(values)
valuesExpected = []float64{-100, -100, -100, -100}
timestampsExpected := []int64{0, 1, 2, 3}
testRowsEqual(t, values, timestampsExpected, valuesExpected, timestampsExpected)
// verify how partial counter reset is handled.
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2787
values = []float64{100, 95, 120, 119, 139, 50}
timestampsExpected = []int64{0, 1, 2, 3, 4, 5}
removeCounterResets(values, timestampsExpected, 0)
removeCounterResets(values)
valuesExpected = []float64{100, 100, 125, 125, 145, 195}
timestampsExpected = []int64{0, 1, 2, 3, 4, 5}
testRowsEqual(t, values, timestampsExpected, valuesExpected, timestampsExpected)
// verify that staleness interval is respected during resets
// see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8072
values = []float64{10, 12, 14, 4, 6, 8, 6, 8, 4, 6}
timestamps = []int64{10, 20, 30, 60, 70, 80, 90, 100, 120, 130}
valuesExpected = []float64{10, 12, 14, 4, 6, 8, 14, 16, 4, 6}
removeCounterResets(values, timestamps, 10)
testRowsEqual(t, values, timestamps, valuesExpected, timestamps)
// verify that staleness is respected if there was no counter reset
// but correction was made previously
values = []float64{10, 12, 2, 4}
timestamps = []int64{10, 20, 30, 60}
valuesExpected = []float64{10, 12, 14, 4}
removeCounterResets(values, timestamps, 10)
testRowsEqual(t, values, timestamps, valuesExpected, timestamps)
// verify results always increase monotonically with possible float operations precision error
values = []float64{34.094223, 2.7518, 2.140669, 0.044878, 1.887095, 2.546569, 2.490149, 0.045, 0.035684, 0.062454, 0.058296}
timestampsExpected = []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
removeCounterResets(values, timestampsExpected, 0)
removeCounterResets(values)
var prev float64
for i, v := range values {
if v < prev {
@@ -184,7 +166,7 @@ func TestDeltaValues(t *testing.T) {
// remove counter resets
values = append([]float64{}, testValues...)
removeCounterResets(values, testTimestamps, 0)
removeCounterResets(values)
deltaValues(values)
valuesExpected = []float64{34, 10, 21, 33, 34, 65, 12, 32, 32, 2, 0, 0}
testRowsEqual(t, values, testTimestamps, valuesExpected, testTimestamps)
@@ -206,7 +188,7 @@ func TestDerivValues(t *testing.T) {
// remove counter resets
values = append([]float64{}, testValues...)
removeCounterResets(values, testTimestamps, 0)
removeCounterResets(values)
derivValues(values, testTimestamps)
valuesExpected = []float64{3400, 1111.111111111111, 1750, 2538.4615384615386, 3090.909090909091, 3611.1111111111113,
6000, 1882.3529411764705, 1777.7777777777778, 400, 0, 0}
@@ -237,7 +219,7 @@ func testRollupFunc(t *testing.T, funcName string, args []any, vExpected float64
rfa.timestamps = append(rfa.timestamps, testTimestamps...)
rfa.window = rfa.timestamps[len(rfa.timestamps)-1] - rfa.timestamps[0]
if rollupFuncsRemoveCounterResets[funcName] {
removeCounterResets(rfa.values, rfa.timestamps, 0)
removeCounterResets(rfa.values)
}
for i := 0; i < 5; i++ {
v := rf(&rfa)
@@ -1608,60 +1590,17 @@ func TestRollupDelta(t *testing.T) {
f(100, nan, nan, nil, 0)
}
func TestRollupDeltaWithStaleness(t *testing.T) {
func TestRollupIncreaseWithStaleness(t *testing.T) {
// there is a gap between samples in the dataset below
timestamps := []int64{0, 15000, 30000, 70000}
values := []float64{1, 1, 1, 1}
// if step > gap, then delta will always respect value before gap
t.Run("step>gap", func(t *testing.T) {
t.Run("step > gap", func(t *testing.T) {
rc := rollupConfig{
Func: rollupDelta,
Start: 0,
End: 70000,
Step: 45000,
Window: 0,
MaxPointsPerSeries: 1e4,
}
rc.Timestamps = rc.getTimestamps()
gotValues, samplesScanned := rc.Do(nil, values, timestamps)
if samplesScanned != 7 {
t.Fatalf("expecting 8 samplesScanned from rollupConfig.Do; got %d", samplesScanned)
}
valuesExpected := []float64{1, 0}
timestampsExpected := []int64{0, 45e3}
testRowsEqual(t, gotValues, rc.Timestamps, valuesExpected, timestampsExpected)
})
// even if LookbackDelta < gap
t.Run("step>gap;LookbackDelta<gap", func(t *testing.T) {
rc := rollupConfig{
Func: rollupDelta,
Start: 0,
End: 70000,
Step: 45000,
LookbackDelta: 10e3,
Window: 0,
MaxPointsPerSeries: 1e4,
}
rc.Timestamps = rc.getTimestamps()
gotValues, samplesScanned := rc.Do(nil, values, timestamps)
if samplesScanned != 7 {
t.Fatalf("expecting 8 samplesScanned from rollupConfig.Do; got %d", samplesScanned)
}
valuesExpected := []float64{1, 0}
timestampsExpected := []int64{0, 45e3}
testRowsEqual(t, gotValues, rc.Timestamps, valuesExpected, timestampsExpected)
})
// if step < gap and LookbackDelta==0 then delta will always respect value before gap
// as LookbackDelta=0 ignores staleness
t.Run("step<gap;LookbackDelta=0", func(t *testing.T) {
rc := rollupConfig{
Func: rollupDelta,
Start: 0,
End: 70000,
Step: 10000,
LookbackDelta: 0,
Step: 35000,
Window: 0,
MaxPointsPerSeries: 1e4,
}
@@ -1670,14 +1609,12 @@ func TestRollupDeltaWithStaleness(t *testing.T) {
if samplesScanned != 8 {
t.Fatalf("expecting 8 samplesScanned from rollupConfig.Do; got %d", samplesScanned)
}
valuesExpected := []float64{1, 0, 0, 0, 0, 0, 0, 0}
timestampsExpected := []int64{0, 10e3, 20e3, 30e3, 40e3, 50e3, 60e3, 70e3}
valuesExpected := []float64{1, 0, 0}
timestampsExpected := []int64{0, 35e3, 70e3}
testRowsEqual(t, gotValues, rc.Timestamps, valuesExpected, timestampsExpected)
})
// if step < gap and LookbackDelta>0 then delta will respect value before gap
// only if it is not stale according to LookbackDelta
t.Run("step<gap;LookbackDelta>0", func(t *testing.T) {
t.Run("step < gap", func(t *testing.T) {
rc := rollupConfig{
Func: rollupDelta,
Start: 0,
@@ -1685,7 +1622,6 @@ func TestRollupDeltaWithStaleness(t *testing.T) {
Step: 10000,
Window: 0,
MaxPointsPerSeries: 1e4,
LookbackDelta: 30e3,
}
rc.Timestamps = rc.getTimestamps()
gotValues, samplesScanned := rc.Do(nil, values, timestamps)
@@ -1720,116 +1656,3 @@ func TestRollupDeltaWithStaleness(t *testing.T) {
testRowsEqual(t, gotValues, rc.Timestamps, valuesExpected, timestampsExpected)
})
}
func TestRollupIncreasePureWithStaleness(t *testing.T) {
// there is a gap between samples in the dataset below
timestamps := []int64{0, 15000, 30000, 70000}
values := []float64{1, 1, 1, 1}
// if step > gap, then delta will always respect value before gap
t.Run("step>gap", func(t *testing.T) {
rc := rollupConfig{
Func: rollupIncreasePure,
Start: 0,
End: 70000,
Step: 45000,
Window: 0,
MaxPointsPerSeries: 1e4,
}
rc.Timestamps = rc.getTimestamps()
gotValues, samplesScanned := rc.Do(nil, values, timestamps)
if samplesScanned != 7 {
t.Fatalf("expecting 8 samplesScanned from rollupConfig.Do; got %d", samplesScanned)
}
valuesExpected := []float64{1, 0}
timestampsExpected := []int64{0, 45e3}
testRowsEqual(t, gotValues, rc.Timestamps, valuesExpected, timestampsExpected)
})
// even if LookbackDelta < gap
t.Run("step>gap;LookbackDelta<gap", func(t *testing.T) {
rc := rollupConfig{
Func: rollupIncreasePure,
Start: 0,
End: 70000,
Step: 45000,
LookbackDelta: 10e3,
Window: 0,
MaxPointsPerSeries: 1e4,
}
rc.Timestamps = rc.getTimestamps()
gotValues, samplesScanned := rc.Do(nil, values, timestamps)
if samplesScanned != 7 {
t.Fatalf("expecting 8 samplesScanned from rollupConfig.Do; got %d", samplesScanned)
}
valuesExpected := []float64{1, 0}
timestampsExpected := []int64{0, 45e3}
testRowsEqual(t, gotValues, rc.Timestamps, valuesExpected, timestampsExpected)
})
// if step < gap and LookbackDelta==0 then delta will always respect value before gap
// as LookbackDelta=0 ignores staleness
t.Run("step<gap;LookbackDelta=0", func(t *testing.T) {
rc := rollupConfig{
Func: rollupIncreasePure,
Start: 0,
End: 70000,
Step: 10000,
LookbackDelta: 0,
Window: 0,
MaxPointsPerSeries: 1e4,
}
rc.Timestamps = rc.getTimestamps()
gotValues, samplesScanned := rc.Do(nil, values, timestamps)
if samplesScanned != 8 {
t.Fatalf("expecting 8 samplesScanned from rollupConfig.Do; got %d", samplesScanned)
}
valuesExpected := []float64{1, 0, 0, 0, 0, 0, 0, 0}
timestampsExpected := []int64{0, 10e3, 20e3, 30e3, 40e3, 50e3, 60e3, 70e3}
testRowsEqual(t, gotValues, rc.Timestamps, valuesExpected, timestampsExpected)
})
// if step < gap and LookbackDelta>0 then delta will respect value before gap
// only if it is not stale according to LookbackDelta
t.Run("step<gap;LookbackDelta>0", func(t *testing.T) {
rc := rollupConfig{
Func: rollupIncreasePure,
Start: 0,
End: 70000,
Step: 10000,
Window: 0,
MaxPointsPerSeries: 1e4,
LookbackDelta: 30e3,
}
rc.Timestamps = rc.getTimestamps()
gotValues, samplesScanned := rc.Do(nil, values, timestamps)
if samplesScanned != 8 {
t.Fatalf("expecting 8 samplesScanned from rollupConfig.Do; got %d", samplesScanned)
}
valuesExpected := []float64{1, 0, 0, 0, 0, 0, 0, 1}
timestampsExpected := []int64{0, 10e3, 20e3, 30e3, 40e3, 50e3, 60e3, 70e3}
testRowsEqual(t, gotValues, rc.Timestamps, valuesExpected, timestampsExpected)
})
// there is a staleness marker between samples in the dataset below
timestamps = []int64{0, 10000, 20000, 30000, 40000}
values = []float64{1, 1, 1, decimal.StaleNaN, 1}
t.Run("staleness marker", func(t *testing.T) {
rc := rollupConfig{
Func: rollupIncreasePure,
Start: 0,
End: 40000,
Step: 10000,
Window: 0,
MaxPointsPerSeries: 1e4,
}
rc.Timestamps = rc.getTimestamps()
gotValues, samplesScanned := rc.Do(nil, values, timestamps)
if samplesScanned != 10 {
t.Fatalf("expecting 10 samplesScanned from rollupConfig.Do; got %d", samplesScanned)
}
valuesExpected := []float64{1, 0, 0, nan, 1}
timestampsExpected := []int64{0, 10e3, 20e3, 30e3, 40e3}
testRowsEqual(t, gotValues, rc.Timestamps, valuesExpected, timestampsExpected)
})
}

View File

@@ -15,7 +15,6 @@ import (
var (
maxExportDuration = flag.Duration("search.maxExportDuration", time.Hour*24*30, "The maximum duration for /api/v1/export call")
maxDeleteDuration = flag.Duration("search.maxDeleteDuration", time.Minute*5, "The maximum duration for /api/v1/admin/tsdb/delete_series call")
maxQueryDuration = flag.Duration("search.maxQueryDuration", time.Second*30, "The maximum duration for query execution. It can be overridden to a smaller value on a per-query basis via 'timeout' query arg")
maxStatusRequestDuration = flag.Duration("search.maxStatusRequestDuration", time.Minute*5, "The maximum duration for /api/v1/status/* requests")
maxLabelsAPIDuration = flag.Duration("search.maxLabelsAPIDuration", time.Second*5, "The maximum duration for /api/v1/labels, /api/v1/label/.../values and /api/v1/series requests. "+
@@ -59,12 +58,6 @@ func GetDeadlineForLabelsAPI(r *http.Request, startTime time.Time) Deadline {
return getDeadlineWithMaxDuration(r, startTime, dMax, "-search.maxLabelsAPIDuration")
}
// GetDeadlineForDelete returns deadline for the given request to /api/v1/admin/tsdb/delete_series.
func GetDeadlineForDelete(r *http.Request, startTime time.Time) Deadline {
dMax := maxDeleteDuration.Milliseconds()
return getDeadlineWithMaxDuration(r, startTime, dMax, "-search.maxDeleteDuration")
}
func getDeadlineWithMaxDuration(r *http.Request, startTime time.Time, dMax int64, flagHint string) Deadline {
d, err := httputils.GetDuration(r, "timeout", 0)
if err != nil {

View File

@@ -1,13 +1,13 @@
{
"files": {
"main.css": "./static/css/main.af583aad.css",
"main.js": "./static/js/main.1413b18d.js",
"main.css": "./static/css/main.63479b72.css",
"main.js": "./static/js/main.256ee243.js",
"static/js/685.f772060c.chunk.js": "./static/js/685.f772060c.chunk.js",
"static/media/MetricsQL.md": "./static/media/MetricsQL.a00044c91d9781cf8557.md",
"index.html": "./index.html"
},
"entrypoints": [
"static/css/main.af583aad.css",
"static/js/main.1413b18d.js"
"static/css/main.63479b72.css",
"static/js/main.256ee243.js"
]
}

View File

@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.svg"/><link rel="apple-touch-icon" href="./favicon.svg"/><link rel="mask-icon" href="./favicon.svg" color="#000000"><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"/><link rel="manifest" href="./manifest.json"/><title>vmui</title><script src="./dashboards/index.js" type="module"></script><meta name="twitter:card" content="summary"><meta name="twitter:title" content="UI for VictoriaMetrics"><meta name="twitter:site" content="@https://victoriametrics.com/"><meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta name="twitter:image" content="./preview.jpg"><meta property="og:type" content="website"><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 defer="defer" src="./static/js/main.1413b18d.js"></script><link href="./static/css/main.af583aad.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.svg"/><link rel="apple-touch-icon" href="./favicon.svg"/><link rel="mask-icon" href="./favicon.svg" color="#000000"><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"/><link rel="manifest" href="./manifest.json"/><title>vmui</title><script src="./dashboards/index.js" type="module"></script><meta name="twitter:card" content="summary"><meta name="twitter:title" content="UI for VictoriaMetrics"><meta name="twitter:site" content="@https://victoriametrics.com/"><meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta name="twitter:image" content="./preview.jpg"><meta property="og:type" content="website"><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 defer="defer" src="./static/js/main.256ee243.js"></script><link href="./static/css/main.63479b72.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
FROM golang:1.23.5 AS build-web-stage
FROM golang:1.23.4 AS build-web-stage
COPY build /build
WORKDIR /build

View File

@@ -1,6 +1,3 @@
import uPlot from "uplot";
import { ReactNode } from "react";
export interface MetricBase {
group: number;
metric: {
@@ -9,13 +6,13 @@ export interface MetricBase {
}
export interface MetricResult extends MetricBase {
values: [number, string][];
values: [number, string][]
}
export interface InstantMetricResult extends MetricBase {
value?: [number, string];
values?: [number, string][];
value?: [number, string]
values?: [number, string][]
}
export interface ExportMetricResult extends MetricBase {
@@ -47,23 +44,9 @@ export interface LogHits {
timestamps: string[];
values: number[];
total?: number;
fields: { [key: string]: string; };
_isOther: boolean;
}
export interface LegendLogHits {
label: string;
total: number;
totalHits: number;
isOther: boolean;
fields: { [key: string]: string; };
stroke?: uPlot.Series.Stroke;
}
export interface LegendLogHitsMenu {
title: string;
icon?: ReactNode;
handler?: () => void;
fields: {
[key: string]: string;
};
}
export interface ReportMetaData {

View File

@@ -1,23 +1,22 @@
import React, { FC, useCallback, useMemo, useRef, useState } from "preact/compat";
import React, { FC, useMemo, useRef, useState } from "preact/compat";
import "./style.scss";
import "uplot/dist/uPlot.min.css";
import useElementSize from "../../../hooks/useElementSize";
import uPlot, { AlignedData } from "uplot";
import { useEffect } from "react";
import useBarHitsOptions, { getLabelFromLogHit } from "./hooks/useBarHitsOptions";
import useBarHitsOptions from "./hooks/useBarHitsOptions";
import BarHitsTooltip from "./BarHitsTooltip/BarHitsTooltip";
import { TimeParams } from "../../../types";
import usePlotScale from "../../../hooks/uplot/usePlotScale";
import useReadyChart from "../../../hooks/uplot/useReadyChart";
import useZoomChart from "../../../hooks/uplot/useZoomChart";
import classNames from "classnames";
import { LegendLogHits, LogHits } from "../../../api/types";
import { LogHits } from "../../../api/types";
import { addSeries, delSeries, setBand } from "../../../utils/uplot";
import { GraphOptions, GRAPH_STYLES } from "./types";
import BarHitsOptions from "./BarHitsOptions/BarHitsOptions";
import stack from "../../../utils/uplot/stack";
import BarHitsLegend from "./BarHitsLegend/BarHitsLegend";
import { calculateTotalHits, sortLogHits } from "../../../utils/logs";
interface Props {
logHits: LogHits[];
@@ -58,29 +57,6 @@ const BarHitsChart: FC<Props> = ({ logHits, data: _data, period, setPeriod, onAp
graphOptions
});
const prepareLegend = useCallback((hits: LogHits[], totalHits: number): LegendLogHits[] => {
return hits.map((hit) => {
const label = getLabelFromLogHit(hit);
const legendItem: LegendLogHits = {
label,
isOther: hit._isOther,
fields: hit.fields,
total: hit.total || 0,
totalHits,
stroke: series.find((s) => s.label === label)?.stroke,
};
return legendItem;
}).sort(sortLogHits("total"));
}, [series]);
const legendDetails: LegendLogHits[] = useMemo(() => {
const totalHits = calculateTotalHits(logHits);
return prepareLegend(logHits, totalHits);
}, [logHits, prepareLegend]);
useEffect(() => {
if (!uPlotInst) return;
delSeries(uPlotInst);
@@ -145,7 +121,6 @@ const BarHitsChart: FC<Props> = ({ logHits, data: _data, period, setPeriod, onAp
<BarHitsLegend
uPlotInst={uPlotInst}
onApplyFilter={onApplyFilter}
legendDetails={legendDetails}
/>
)}
</div>

View File

@@ -1,53 +1,83 @@
import React, { FC, useEffect, useState } from "preact/compat";
import React, { FC, useCallback, useEffect, useState } from "preact/compat";
import uPlot, { Series } from "uplot";
import "./style.scss";
import "../../Line/Legend/style.scss";
import BarHitsLegendItem from "./BarHitsLegendItem";
import { LegendLogHits } from "../../../../api/types";
import classNames from "classnames";
import { MouseEvent } from "react";
import { isMacOs } from "../../../../utils/detect-device";
import Tooltip from "../../../Main/Tooltip/Tooltip";
import { getStreamPairs } from "../../../../utils/logs";
interface Props {
uPlotInst: uPlot;
legendDetails: LegendLogHits[];
onApplyFilter: (value: string) => void;
}
const BarHitsLegend: FC<Props> = ({ uPlotInst, legendDetails, onApplyFilter }) => {
const BarHitsLegend: FC<Props> = ({ uPlotInst, onApplyFilter }) => {
const [series, setSeries] = useState<Series[]>([]);
const totalHits = legendDetails[0]?.totalHits || 0;
const [pairs, setPairs] = useState<string[][]>([]);
const getSeries = () => {
return uPlotInst.series.filter(s => s.scale !== "x");
};
const handleRedrawGraph = () => {
uPlotInst.redraw();
setSeries(getSeries());
};
useEffect(() => {
setSeries(getSeries());
const updateSeries = useCallback(() => {
const series = uPlotInst.series.filter(s => s.scale !== "x");
setSeries(series);
setPairs(series.map(s => getStreamPairs(s.label || "")));
}, [uPlotInst]);
const handleClickByValue = (value: string) => (e: MouseEvent<HTMLDivElement>) => {
const metaKey = e.metaKey || e.ctrlKey;
if (!metaKey) return;
onApplyFilter(`{${value}}` || "");
updateSeries();
uPlotInst.redraw();
};
const handleClickByStream = (target: Series) => (e: MouseEvent<HTMLDivElement>) => {
const metaKey = e.metaKey || e.ctrlKey;
if (metaKey) return;
target.show = !target.show;
updateSeries();
uPlotInst.redraw();
};
useEffect(updateSeries, [uPlotInst]);
return (
<div className="vm-bar-hits-legend">
{legendDetails.map((legend) => (
<BarHitsLegendItem
key={legend.label}
legend={legend}
series={series}
onRedrawGraph={handleRedrawGraph}
onApplyFilter={onApplyFilter}
/>
{series.map((s, i) => (
<Tooltip
key={s.label}
title={(
<ul className="vm-bar-hits-legend-info">
<li>Click to {s.show ? "hide" : "show"} the _stream.</li>
<li>{isMacOs() ? "Cmd" : "Ctrl"} + Click to filter by the _stream.</li>
</ul>
)}
>
<div
className={classNames({
"vm-bar-hits-legend-item": true,
"vm-bar-hits-legend-item_hide": !s.show,
})}
onClick={handleClickByStream(s)}
>
<div
className="vm-bar-hits-legend-item__marker"
style={{ backgroundColor: `${(s?.stroke as () => string)?.()}` }}
/>
<div className="vm-bar-hits-legend-item-pairs">
{pairs[i].map(value => (
<span
className="vm-bar-hits-legend-item-pairs__value"
key={value}
onClick={handleClickByValue(value)}
>
{value}
</span>
))}
</div>
</div>
</Tooltip>
))}
<div className="vm-bar-hits-legend-info">
<div>
Total hits: <b>{totalHits.toLocaleString("en-US")}</b>
</div>
<div>
<code>L-Click</code> toggles visibility.&nbsp;
<code>R-Click</code> opens menu.
</div>
</div>
</div>
);
};

View File

@@ -1,92 +0,0 @@
import React, { FC, useMemo, useRef, useState } from "preact/compat";
import classNames from "classnames";
import { Series } from "uplot";
import { MouseEvent } from "react";
import { LegendLogHits } from "../../../../api/types";
import { getStreamPairs } from "../../../../utils/logs";
import { formatNumberShort } from "../../../../utils/math";
import Popper from "../../../Main/Popper/Popper";
import useBoolean from "../../../../hooks/useBoolean";
import LegendHitsMenu from "../LegendHitsMenu/LegendHitsMenu";
interface Props {
legend: LegendLogHits;
series: Series[];
onRedrawGraph: () => void;
onApplyFilter: (value: string) => void;
}
const BarHitsLegendItem: FC<Props> = ({ legend, series, onRedrawGraph, onApplyFilter }) => {
const {
value: openContextMenu,
setTrue: handleOpenContextMenu,
setFalse: handleCloseContextMenu,
} = useBoolean(false);
const legendRef = useRef<HTMLDivElement>(null);
const [clickPosition, setClickPosition] = useState<{ top: number; left: number } | null>(null);
const targetSeries = useMemo(() => series.find(s => s.label === legend.label), [series]);
const fields = useMemo(() => getStreamPairs(legend.label), [legend.label]);
const label = fields.join(", ");
const totalShortFormatted = formatNumberShort(legend.total);
const handleClickByStream = (e: MouseEvent<HTMLDivElement>) => {
if (!targetSeries) return;
if (e.metaKey || e.ctrlKey) {
targetSeries.show = !targetSeries.show;
} else {
const isOnlyTargetVisible = series.every(s => s === targetSeries || !s.show);
series.forEach(s => {
s.show = isOnlyTargetVisible || (s === targetSeries);
});
}
onRedrawGraph();
};
const handleContextMenu = (e: MouseEvent<HTMLDivElement>) => {
e.preventDefault();
setClickPosition({ top: e.clientY, left: e.clientX });
handleOpenContextMenu();
};
return (
<div
ref={legendRef}
className={classNames({
"vm-bar-hits-legend-item": true,
"vm-bar-hits-legend-item_other": legend.isOther,
"vm-bar-hits-legend-item_hide": !targetSeries?.show,
})}
onClick={handleClickByStream}
onContextMenu={handleContextMenu}
>
<div
className="vm-bar-hits-legend-item__marker"
style={{ backgroundColor: `${legend.stroke}` }}
/>
<div className="vm-bar-hits-legend-item__label">{label}</div>
<span className="vm-bar-hits-legend-item__total">({totalShortFormatted})</span>
<Popper
placement="fixed"
open={openContextMenu}
buttonRef={legendRef}
placementPosition={clickPosition}
onClose={handleCloseContextMenu}
>
<LegendHitsMenu
legend={legend}
fields={fields}
onApplyFilter={onApplyFilter}
onClose={handleCloseContextMenu}
/>
</Popper>
</div>
);
};
export default BarHitsLegendItem;

View File

@@ -3,16 +3,16 @@
.vm-bar-hits-legend {
display: flex;
flex-wrap: wrap;
gap: $padding-small;
padding: 0 $padding-small $padding-small;
color: $color-text;
&-item {
max-width: 50%;
display: flex;
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
gap: $padding-small;
font-size: $font-size-small;
padding: $padding-small $padding-global;
font-size: 12px;
padding: 0 $padding-small;
border-radius: $border-radius-small;
cursor: pointer;
transition: 0.2s;
@@ -27,44 +27,34 @@
}
&__marker {
min-width: 14px;
max-width: 14px;
width: 14px;
height: 14px;
border: $color-background-block;
}
&__label {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&-pairs {
display: flex;
gap: $padding-small;
&__total {
color: $color-text-secondary;
font-style: italic;
grid-column: 2;
&__value {
padding: $padding-small 0;
&:hover {
text-decoration: underline;
}
&:after {
content: ",";
}
&:last-child:after {
content: "";
}
}
}
}
&-info {
flex-grow: 1;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding-top: $padding-small;
color: $color-text-secondary;
font-size: $font-size-small;
code {
display: inline-block;
padding: calc($padding-small / 2) $padding-small;
font-size: $font-size-small;
text-align: center;
background-color: $color-background-body;
background-repeat: repeat-x;
border: $border-divider;
border-radius: 4px;
}
list-style-position: inside;
}
}

View File

@@ -5,6 +5,7 @@ import "./style.scss";
import useStateSearchParams from "../../../../hooks/useStateSearchParams";
import { useSearchParams } from "react-router-dom";
import Button from "../../../Main/Button/Button";
import classNames from "classnames";
import { SettingsIcon, VisibilityIcon, VisibilityOffIcon } from "../../../Main/Icons";
import Tooltip from "../../../Main/Tooltip/Tooltip";
import Popper from "../../../Main/Popper/Popper";
@@ -23,20 +24,27 @@ const BarHitsOptions: FC<Props> = ({ onChange }) => {
setFalse: handleCloseOptions,
} = useBoolean(false);
const [graphStyle, setGraphStyle] = useStateSearchParams(GRAPH_STYLES.LINE_STEPPED, "graph");
const [stacked, setStacked] = useStateSearchParams(false, "stacked");
const [fill, setFill] = useStateSearchParams("true", "fill");
const [fill, setFill] = useStateSearchParams(false, "fill");
const [hideChart, setHideChart] = useStateSearchParams(false, "hide_chart");
const options: GraphOptions = useMemo(() => ({
graphStyle: GRAPH_STYLES.BAR,
graphStyle,
stacked,
fill: fill === "true",
fill,
hideChart,
}), [stacked, fill, hideChart]);
}), [graphStyle, stacked, fill, hideChart]);
const handleChangeGraphStyle = (val: string) => () => {
setGraphStyle(val as GRAPH_STYLES);
searchParams.set("graph", val);
setSearchParams(searchParams);
};
const handleChangeFill = (val: boolean) => {
setFill(`${val}`);
searchParams.set("fill", `${val}`);
setFill(val);
val ? searchParams.set("fill", "true") : searchParams.delete("fill");
setSearchParams(searchParams);
};
@@ -89,6 +97,21 @@ const BarHitsOptions: FC<Props> = ({ onChange }) => {
title={"Graph settings"}
>
<div className="vm-bar-hits-options-settings">
<div className="vm-bar-hits-options-settings-item vm-bar-hits-options-settings-item_list">
<p className="vm-bar-hits-options-settings-item__title">Graph style:</p>
{Object.values(GRAPH_STYLES).map(style => (
<div
key={style}
className={classNames({
"vm-list-item": true,
"vm-list-item_active": graphStyle === style,
})}
onClick={handleChangeGraphStyle(style)}
>
{style}
</div>
))}
</div>
<div className="vm-bar-hits-options-settings-item">
<Switch
label={"Stacked"}
@@ -99,7 +122,7 @@ const BarHitsOptions: FC<Props> = ({ onChange }) => {
<div className="vm-bar-hits-options-settings-item">
<Switch
label={"Fill"}
value={fill === "true"}
value={fill}
onChange={handleChangeFill}
/>
</div>

View File

@@ -11,12 +11,12 @@
&-settings {
display: grid;
align-items: flex-start;
min-width: 200px;
gap: $padding-global;
padding-bottom: $padding-global;
min-width: 200px;
&-item {
padding: 0 $padding-global;
border-bottom: $border-divider;
padding: 0 $padding-global $padding-global;
&_list {
padding: 0;

View File

@@ -5,7 +5,6 @@ import { DATE_TIME_FORMAT } from "../../../../constants/date";
import classNames from "classnames";
import "./style.scss";
import "../../ChartTooltip/style.scss";
import { sortLogHits } from "../../../../utils/logs";
interface Props {
data: AlignedData;
@@ -27,7 +26,7 @@ const BarHitsTooltip: FC<Props> = ({ data, focusDataIdx, uPlotInst }) => {
const tooltipItems = values.map((value, i) => {
const targetSeries = series[i + 1];
const stroke = (targetSeries?.stroke as () => string)?.();
const label = targetSeries?.label;
const label = targetSeries?.label || "other";
const show = targetSeries?.show;
return {
label,
@@ -35,7 +34,7 @@ const BarHitsTooltip: FC<Props> = ({ data, focusDataIdx, uPlotInst }) => {
value,
show
};
}).filter(item => item.value > 0 && item.show).sort(sortLogHits("value"));
}).filter(item => item.value > 0 && item.show).sort((a, b) => b.value - a.value);
const point = {
top: tooltipItems[0] ? uPlotInst?.valToPos?.(tooltipItems[0].value, "y") || 0 : 0,
@@ -105,19 +104,16 @@ const BarHitsTooltip: FC<Props> = ({ data, focusDataIdx, uPlotInst }) => {
className="vm-chart-tooltip-data__marker"
style={{ background: item.stroke }}
/>
<p className="vm-bar-hits-tooltip-item">
<span className="vm-bar-hits-tooltip-item__label">{item.label}</span>
<span>{item.value.toLocaleString("en-US")}</span>
<p>
{item.label}: <b>{item.value}</b>
</p>
</div>
))}
</div>
{tooltipData.values.length > 1 && (
<div className="vm-chart-tooltip-data">
<span/>
<p className="vm-bar-hits-tooltip-item">
<span className="vm-bar-hits-tooltip-item__label">Total</span>
<span>{tooltipData.total.toLocaleString("en-US")}</span>
<p>
Total records: <b>{tooltipData.total}</b>
</p>
</div>
)}

View File

@@ -9,19 +9,4 @@
opacity: 1;
pointer-events: auto;
}
&-item {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
gap: $padding-global;
max-width: 100%;
&__label {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}

View File

@@ -1,50 +0,0 @@
import React, { FC } from "preact/compat";
import "./style.scss";
import { LegendLogHits } from "../../../../api/types";
import LegendHitsMenuStats from "./LegendHitsMenuStats";
import LegendHitsMenuBase from "./LegendHitsMenuBase";
import LegendHitsMenuRow from "./LegendHitsMenuRow";
import LegendHitsMenuFields from "./LegendHitsMenuFields";
import { LOGS_LIMIT_HITS } from "../../../../constants/logs";
const otherDescription = `aggregated results for fields not in the top ${LOGS_LIMIT_HITS}`;
interface Props {
legend: LegendLogHits;
fields: string[];
onApplyFilter: (value: string) => void;
onClose: () => void;
}
const LegendHitsMenu: FC<Props> = ({ legend, fields, onApplyFilter, onClose }) => {
return (
<div className="vm-legend-hits-menu">
<div className="vm-legend-hits-menu-section">
<LegendHitsMenuRow
className="vm-legend-hits-menu-row_info"
title={legend.isOther ? otherDescription : legend.label}
/>
</div>
{!legend.isOther && (
<LegendHitsMenuBase
legend={legend}
onApplyFilter={onApplyFilter}
onClose={onClose}
/>
)}
{!legend.isOther && (
<LegendHitsMenuFields
fields={fields}
onApplyFilter={onApplyFilter}
onClose={onClose}
/>
)}
<LegendHitsMenuStats legend={legend}/>
</div>
);
};
export default LegendHitsMenu;

View File

@@ -1,64 +0,0 @@
import React, { FC } from "preact/compat";
import LegendHitsMenuRow from "./LegendHitsMenuRow";
import useCopyToClipboard from "../../../../hooks/useCopyToClipboard";
import { CopyIcon, FilterIcon, FilterOffIcon } from "../../../Main/Icons";
import { LegendLogHits, LegendLogHitsMenu } from "../../../../api/types";
import { LOGS_GROUP_BY } from "../../../../constants/logs";
interface Props {
legend: LegendLogHits;
onApplyFilter: (value: string) => void;
onClose: () => void;
}
const LegendHitsMenuBase: FC<Props> = ({ legend, onApplyFilter, onClose }) => {
const copyToClipboard = useCopyToClipboard();
const handleAddStreamToFilter = () => {
onApplyFilter(`${LOGS_GROUP_BY}: ${legend.label}`);
onClose();
};
const handleExcludeStreamToFilter = () => {
onApplyFilter(`(NOT ${LOGS_GROUP_BY}: ${legend.label})`);
onClose();
};
const handlerCopyLabel = async () => {
await copyToClipboard(legend.label, `${legend.label} has been copied`);
onClose();
};
const options: LegendLogHitsMenu[] = [
{
title: `Copy ${LOGS_GROUP_BY} name`,
icon: <CopyIcon/>,
handler: handlerCopyLabel,
},
{
title: `Add ${LOGS_GROUP_BY} to filter`,
icon: <FilterIcon/>,
handler: handleAddStreamToFilter,
},
{
title: `Exclude ${LOGS_GROUP_BY} to filter`,
icon: <FilterOffIcon/>,
handler: handleExcludeStreamToFilter,
}
];
return (
<div className="vm-legend-hits-menu-section">
{options.map(({ icon, title, handler }) => (
<LegendHitsMenuRow
key={title}
iconStart={icon}
title={title}
handler={handler}
/>
))}
</div>
);
};
export default LegendHitsMenuBase;

View File

@@ -1,74 +0,0 @@
import React, { FC, useMemo } from "preact/compat";
import LegendHitsMenuRow from "./LegendHitsMenuRow";
import { CopyIcon, FilterIcon, FilterOffIcon } from "../../../Main/Icons";
import { convertToFieldFilter } from "../../../../utils/logs";
import { LegendLogHitsMenu } from "../../../../api/types";
import useCopyToClipboard from "../../../../hooks/useCopyToClipboard";
interface Props {
fields: string[];
onApplyFilter: (value: string) => void;
onClose: () => void;
}
const LegendHitsMenuFields: FC<Props> = ({ fields, onApplyFilter, onClose }) => {
const copyToClipboard = useCopyToClipboard();
const handleCopy = (field: string) => async () => {
await copyToClipboard(field, `${field} has been copied`);
onClose();
};
const handleAddToFilter = (field: string) => () => {
onApplyFilter(field);
onClose();
};
const handleExcludeToFilter = (field: string) => () => {
onApplyFilter(`-${field}`);
onClose();
};
const generateFieldMenu = (field: string): LegendLogHitsMenu[] => {
return [
{
title: "Copy",
icon: <CopyIcon/>,
handler: handleCopy(field),
},
{
title: "Add to filter",
icon: <FilterIcon/>,
handler: handleAddToFilter(field),
},
{
title: "Exclude to filter",
icon: <FilterOffIcon/>,
handler: handleExcludeToFilter(field),
}
];
};
const fieldsWithMenu: LegendLogHitsMenu[] = useMemo(() => {
return fields.map(field => {
const title = convertToFieldFilter(field);
return {
title,
submenu: generateFieldMenu(title),
};
});
}, [fields]);
return (
<div className="vm-legend-hits-menu-section">
{fieldsWithMenu?.map((field) => (
<LegendHitsMenuRow
key={field.title}
{...field}
/>
))}
</div>
);
};
export default LegendHitsMenuFields;

View File

@@ -1,116 +0,0 @@
import React, { FC, useRef, useState } from "preact/compat";
import classNames from "classnames";
import { ReactNode, useEffect } from "react";
import Tooltip from "../../../Main/Tooltip/Tooltip";
import { LegendLogHitsMenu } from "../../../../api/types";
import { ArrowDropDownIcon } from "../../../Main/Icons";
import useClickOutside from "../../../../hooks/useClickOutside";
interface Props {
title: string | ReactNode;
handler?: () => void;
iconStart?: ReactNode;
iconEnd?: ReactNode;
className?: string;
submenu?: LegendLogHitsMenu[];
}
const LegendHitsMenuRow: FC<Props> = ({ title, handler, iconStart, iconEnd, className, submenu }) => {
const containerRef = useRef<HTMLDivElement>(null);
const titleRef = useRef<HTMLDivElement>(null);
const submenuRef = useRef<HTMLDivElement>(null);
const [isOverflownTitle, setIsOverflownTitle] = useState(false);
const [openSubmenu, setOpenSubmenu] = useState(false);
const [posSubmenuLeft, setPosSubmenuLeft] = useState(false);
const hasSubmenu = !!submenu?.length;
const handleToggleContextMenu = () => {
setOpenSubmenu(prev => !prev);
};
const handleCloseContextMenu = () => {
setOpenSubmenu(false);
};
const handleClick = () => {
handler && handler();
hasSubmenu && handleToggleContextMenu();
};
useEffect(() => {
if (!titleRef.current) return;
setIsOverflownTitle(titleRef.current.scrollWidth > titleRef.current.clientWidth);
}, [title, titleRef]);
useEffect(() => {
requestAnimationFrame(() => {
if (!openSubmenu || !submenuRef.current) {
setPosSubmenuLeft(false);
return;
}
const { left, width } = submenuRef.current.getBoundingClientRect();
setPosSubmenuLeft(left + width > window.innerWidth);
});
}, [submenuRef, openSubmenu]);
useClickOutside(containerRef, handleCloseContextMenu);
const titleContent = (
<div
ref={titleRef}
className="vm-legend-hits-menu-row__title"
>
{title}
</div>
);
return (
<div
ref={containerRef}
className={classNames({
"vm-legend-hits-menu-row": true,
"vm-legend-hits-menu-row_interactive": !!handler || hasSubmenu,
[`${className}`]: className
})}
onClick={handleClick}
>
{iconStart && <div className="vm-legend-hits-menu-row__icon">{iconStart}</div>}
{isOverflownTitle ? (<Tooltip title={title}>{titleContent}</Tooltip>) : titleContent}
{iconEnd && !hasSubmenu && <div className="vm-legend-hits-menu-row__icon">{iconEnd}</div>}
{hasSubmenu && (
<div className="vm-legend-hits-menu-row__icon vm-legend-hits-menu-row__icon_drop">
<ArrowDropDownIcon/>
</div>
)}
{openSubmenu && submenu && (
<div
ref={submenuRef}
className={classNames({
"vm-legend-hits-menu": true,
"vm-legend-hits-menu_submenu": true,
"vm-legend-hits-menu_submenu_left": posSubmenuLeft
})}
>
<div className="vm-legend-hits-menu-section">
{submenu.map(({ icon, title, handler }) => (
<LegendHitsMenuRow
key={title}
iconStart={icon}
title={title}
handler={handler}
/>
))}
</div>
</div>
)}
</div>
);
};
export default LegendHitsMenuRow;

View File

@@ -1,23 +0,0 @@
import React, { FC } from "preact/compat";
import { LegendLogHits } from "../../../../api/types";
interface Props {
legend: LegendLogHits;
}
const LegendHitsMenuStats: FC<Props> = ({ legend }) => {
const totalFormatted = legend.total.toLocaleString("en-US");
const percentage = Math.round((legend.total / legend.totalHits) * 100);
return (
<div className="vm-legend-hits-menu-section">
<div className="vm-legend-hits-menu-row">
<div className="vm-legend-hits-menu-row__title">
Total: {totalFormatted} ({percentage}%)
</div>
</div>
</div>
);
};
export default LegendHitsMenuStats;

View File

@@ -1,178 +0,0 @@
@use "src/styles/variables" as *;
.vm-legend-hits-menu {
min-width: 160px;
z-index: 1;
&_submenu {
position: absolute;
top: calc(-1 * $padding-small);
background-color: $color-background-block;
left: calc(100% + ($padding-small / 2));
box-shadow: $box-shadow-popper;
border-radius: $border-radius-small;
animation: vm-submenu-show 150ms cubic-bezier(0.280, 0.840, 0.2, 1);
transform-origin: top left;
&_left {
left: auto;
right: calc(100% + ($padding-small / 2));
transform-origin: top right;
}
}
&-section {
border-bottom: $border-divider;
&:last-child {
border-bottom: none;
}
}
&-row {
position: relative;
display: flex;
gap: $padding-small;
align-items: center;
justify-content: flex-start;
padding: 0 $padding-global;
transition: background-color 0.3s;
color: $color-text;
&_interactive {
cursor: pointer;
&:hover {
background-color: rgba(0, 0, 0, 0.05);
}
}
&_info {
font-size: $font-size-small;
font-weight: 500;
padding-block: $padding-small;
}
&_info &__icon {
color: $color-info;
}
&__icon {
display: flex;
align-items: center;
justify-content: center;
width: 14px;
height: 14px;
&_drop {
transform: rotate(-90deg);
}
}
&__title {
flex-grow: 1;
padding: $padding-global 0;
position: relative;
max-width: 400px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
&-other-list {
width: 80vw;
height: 80vh;
overflow: auto;
&__search {
position: sticky;
top: 0;
padding: $padding-small 0;
background-color: $color-background-block;
border-bottom: $border-divider;
z-index: 2;
}
&-row {
border-bottom: $border-divider;
&_header {
border-bottom: none;
position: sticky;
top: 65px;
background-color: $color-background-block;
z-index: 1;
width: 100%;
&:after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 1px;
border-bottom: $border-divider;
}
}
}
&-cell {
padding: calc($padding-small / 2) 0;
text-align: left;
&_header {
padding: $padding-small;
font-weight: 500;
}
&_number {
padding: $padding-small;
text-align: right;
font-variant-numeric: tabular-nums;
}
&_fields {
width: 100%;
}
}
&-fields {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-start;
&__field {
padding: calc($padding-small / 2) $padding-small;
border-radius: $border-radius-small;
transition: background-color 0.3s;
&:hover {
background-color: $color-hover-black;
}
&:not(:last-child) {
&:after {
content: ',';
}
}
}
}
&-actions {
display: flex;
align-items: center;
justify-content: center;
}
}
}
@keyframes vm-submenu-show {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}

View File

@@ -36,14 +36,6 @@ interface UseGetBarHitsOptionsArgs {
graphOptions: GraphOptions;
}
export const OTHER_HITS_LABEL = "other";
export const getLabelFromLogHit = (logHit: LogHits) => {
if (logHit?._isOther) return OTHER_HITS_LABEL;
const fields = Object.values(logHit?.fields || {});
return fields.map((value) => value || "\"\"").join(", ");
};
const useBarHitsOptions = ({
data,
logHits,
@@ -67,12 +59,12 @@ const useBarHitsOptions = ({
let colorN = 0;
return data.map((_d, i) => {
if (i === 0) return {}; // 0 index is xAxis(timestamps)
const target = logHits?.[i - 1];
const label = getLabelFromLogHit(target);
const color = getCssVariable(target?._isOther ? "color-log-hits-bar-0" : seriesColors[colorN]);
if (!target?._isOther) colorN++;
const fields = Object.values(logHits?.[i - 1]?.fields || {});
const label = fields.map((value) => value || "\"\"").join(", ");
const color = getCssVariable(label ? seriesColors[colorN] : "color-log-hits-bar-0");
if (label) colorN++;
return {
label,
label: label || "other",
width: strokeWidth[graphOptions.graphStyle],
spanGaps: true,
stroke: color,

View File

@@ -32,11 +32,6 @@ $chart-tooltip-y: -1 * ($padding-global + $chart-tooltip-half-icon);
max-width: calc(100vw/3);
}
&_hits &-data {
display: grid;
grid-template-columns: $font-size 1fr;
}
&_sticky {
pointer-events: auto;
z-index: 99;
@@ -95,8 +90,6 @@ $chart-tooltip-y: -1 * ($padding-global + $chart-tooltip-half-icon);
}
&__marker {
min-width: $font-size;
max-width: $font-size;
width: $font-size;
height: $font-size;
border: 1px solid rgba($color-white, 0.5);

View File

@@ -124,7 +124,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
};
useEffect(() => {
setOpenAutocomplete(!!AutocompleteEl && autocompleteQuick);
setOpenAutocomplete(!!AutocompleteEl);
}, [autocompleteQuick]);
useEffect(() => {

View File

@@ -1,246 +0,0 @@
import React, { FC, useMemo, useState } from "preact/compat";
import useBoolean from "../../../hooks/useBoolean";
import { RestartIcon, SettingsIcon } from "../../Main/Icons";
import Button from "../../Main/Button/Button";
import Modal from "../../Main/Modal/Modal";
import Tooltip from "../../Main/Tooltip/Tooltip";
import { Logs } from "../../../api/types";
import Select from "../../Main/Select/Select";
import { useSearchParams } from "react-router-dom";
import "./style.scss";
import Switch from "../../Main/Switch/Switch";
import TextField from "../../Main/TextField/TextField";
import dayjs from "dayjs";
import Hyperlink from "../../Main/Hyperlink/Hyperlink";
import {
LOGS_DISPLAY_FIELDS,
LOGS_GROUP_BY,
LOGS_DATE_FORMAT,
LOGS_URL_PARAMS,
WITHOUT_GROUPING
} from "../../../constants/logs";
const {
GROUP_BY,
NO_WRAP_LINES,
COMPACT_GROUP_HEADER,
DISPLAY_FIELDS,
DATE_FORMAT
} = LOGS_URL_PARAMS;
const title = "Group view settings";
interface Props {
logs: Logs[];
}
const GroupLogsConfigurators: FC<Props> = ({ logs }) => {
const [searchParams, setSearchParams] = useSearchParams();
const groupBy = searchParams.get(GROUP_BY) || LOGS_GROUP_BY;
const noWrapLines = searchParams.get(NO_WRAP_LINES) === "true";
const compactGroupHeader = searchParams.get(COMPACT_GROUP_HEADER) === "true";
const displayFieldsString = searchParams.get(DISPLAY_FIELDS) || "";
const displayFields = displayFieldsString ? displayFieldsString.split(",") : [];
const [dateFormat, setDateFormat] = useState(searchParams.get(DATE_FORMAT) || LOGS_DATE_FORMAT);
const [errorFormat, setErrorFormat] = useState("");
const isGroupChanged = groupBy !== LOGS_GROUP_BY;
const isDisplayFieldsChanged = displayFields.length > 0;
const isTimeChanged = searchParams.get(DATE_FORMAT) !== LOGS_DATE_FORMAT;
const hasChanges = [
isGroupChanged,
isDisplayFieldsChanged,
noWrapLines,
compactGroupHeader,
isTimeChanged
].some(Boolean);
const logsKeys = useMemo(() => {
const excludeKeys = ["_msg", "_time"];
const uniqKeys = Array.from(new Set(logs.map(l => Object.keys(l)).flat()));
return uniqKeys.filter(k => !excludeKeys.includes(k));
}, [logs]);
const {
value: openModal,
toggle: toggleOpen,
setFalse: handleClose,
} = useBoolean(false);
const handleSelectGroupBy = (key: string) => {
searchParams.set(GROUP_BY, key);
setSearchParams(searchParams);
};
const handleSelectDisplayField = (value: string) => {
const prev = displayFields;
const newDisplayFields = prev.includes(value) ? prev.filter(v => v !== value) : [...prev, value];
searchParams.set(DISPLAY_FIELDS, newDisplayFields.join(","));
setSearchParams(searchParams);
};
const handleResetDisplayFields = () => {
searchParams.delete(DISPLAY_FIELDS);
setSearchParams(searchParams);
};
const toggleWrapLines = () => {
searchParams.set(NO_WRAP_LINES, String(!noWrapLines));
setSearchParams(searchParams);
};
const toggleCompactGroupHeader = () => {
searchParams.set(COMPACT_GROUP_HEADER, String(!compactGroupHeader));
setSearchParams(searchParams);
};
const handleChangeDateFormat = (format: string) => {
const date = new Date();
if (!dayjs(date, format, true).isValid()) {
setErrorFormat("Invalid date format");
}
setDateFormat(format);
};
const handleSaveAndClose = () => {
searchParams.set(DATE_FORMAT, dateFormat);
setSearchParams(searchParams);
handleClose();
};
const tooltipContent = () => {
if (!hasChanges) return title;
return (
<div className="vm-group-logs-configurator__tooltip">
<p>{title}</p>
<hr/>
<ul>
{isGroupChanged && <li>Group by <code>{`"${groupBy}"`}</code></li>}
{isDisplayFieldsChanged && <li>Display fields: {displayFields.length || 1}</li>}
{noWrapLines && <li>Single-line text is enabled</li>}
{compactGroupHeader && <li>Compact group header is enabled</li>}
{isTimeChanged && <li>Date format: <code>{dateFormat}</code></li>}
</ul>
</div>
);
};
return (
<>
<div className="vm-group-logs-configurator-button">
<Tooltip title={tooltipContent()}>
<Button
variant="text"
startIcon={<SettingsIcon/>}
onClick={toggleOpen}
ariaLabel={title}
/>
</Tooltip>
{hasChanges && <span className="vm-group-logs-configurator-button__marker"/>}
</div>
{openModal && (
<Modal
title={title}
onClose={handleSaveAndClose}
>
<div className="vm-group-logs-configurator">
<div className="vm-group-logs-configurator-item">
<Select
value={groupBy}
list={[WITHOUT_GROUPING, ...logsKeys]}
label="Group by field"
placeholder="Group by field"
onChange={handleSelectGroupBy}
searchable
/>
<Tooltip title={"Reset grouping"}>
<Button
variant="text"
color="primary"
startIcon={<RestartIcon/>}
onClick={() => handleSelectGroupBy(LOGS_GROUP_BY)}
/>
</Tooltip>
<span className="vm-group-logs-configurator-item__info">
Select a field to group logs by (default: <code>{LOGS_GROUP_BY}</code>).
</span>
</div>
<div className="vm-group-logs-configurator-item">
<Select
value={displayFields}
list={logsKeys}
label="Display fields"
placeholder="Display fields"
onChange={handleSelectDisplayField}
searchable
/>
<Tooltip title={"Clear fields"}>
<Button
variant="text"
color="primary"
startIcon={<RestartIcon/>}
onClick={handleResetDisplayFields}
/>
</Tooltip>
<span className="vm-group-logs-configurator-item__info">
Select fields to display instead of the message (default: <code>{LOGS_DISPLAY_FIELDS}</code>).
</span>
</div>
<div className="vm-group-logs-configurator-item">
<TextField
autofocus
label="Date format"
value={dateFormat}
onChange={handleChangeDateFormat}
error={errorFormat}
/>
<Tooltip title={"Reset format"}>
<Button
variant="text"
color="primary"
startIcon={<RestartIcon/>}
onClick={() => setDateFormat(LOGS_DATE_FORMAT)}
/>
</Tooltip>
<span className="vm-group-logs-configurator-item__info vm-group-logs-configurator-item__info_input">
Set the date format (e.g., <code>YYYY-MM-DD HH:mm:ss</code>).
Learn more in <Hyperlink
href="https://day.js.org/docs/en/display/format"
>this documentation</Hyperlink>. <br/>
Your current date format: <code>{dayjs().format(dateFormat || LOGS_DATE_FORMAT)}</code>
</span>
</div>
<div className="vm-group-logs-configurator-item">
<Switch
value={noWrapLines}
onChange={toggleWrapLines}
label="Single-line message"
/>
<span className="vm-group-logs-configurator-item__info">
Displays message in a single line and truncates it with an ellipsis if it exceeds the available space
</span>
</div>
<div className="vm-group-logs-configurator-item">
<Switch
value={compactGroupHeader}
onChange={toggleCompactGroupHeader}
label="Compact group header"
/>
<span className="vm-group-logs-configurator-item__info">
Shows group headers in one line with a &quot;+N more&quot; badge for extra fields.
</span>
</div>
</div>
</Modal>
)}
</>
);
};
export default GroupLogsConfigurators;

View File

@@ -1,48 +0,0 @@
@use "src/styles/variables" as *;
.vm-group-logs-configurator {
display: grid;
gap: calc($padding-large * 2);
padding: $padding-global 0;
width: 600px;
&-item {
display: grid;
grid-template-columns: 1fr 31px;
align-items: center;
justify-content: stretch;
gap: 0 $padding-small;
&__info {
margin-top: $padding-small;
grid-column: 1/span 2;
font-size: $font-size-small;
color: $color-text-secondary;
line-height: 130%;
&_input {
margin-top: 0;
}
}
}
&-button {
position: relative;
&__marker {
position: absolute;
top: 6px;
left: 6px;
width: 5px;
height: 5px;
border-radius: 50%;
background-color: $color-secondary;
}
}
&__tooltip {
ul {
list-style-position: inside;
}
}
}

View File

@@ -30,10 +30,6 @@ const Accordion: FC<AccordionProps> = ({
onChange && onChange(isOpen);
}, [isOpen]);
useEffect(() => {
setIsOpen(defaultExpanded);
}, [defaultExpanded]);
return (
<>
<header

View File

@@ -581,45 +581,3 @@ export const CommentIcon = () => (
></path>
</svg>
);
export const FilterIcon = () => (
<svg
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39c.51-.66.04-1.61-.79-1.61H5.04c-.83 0-1.3.95-.79 1.61"
></path>
</svg>
);
export const FilterOffIcon = () => (
<svg
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M19.79 5.61C20.3 4.95 19.83 4 19 4H6.83l7.97 7.97zM2.81 2.81 1.39 4.22 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-2.17l5.78 5.78 1.41-1.41z"
></path>
</svg>
);
export const OpenNewIcon = () => (
<svg
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3z"
></path>
</svg>
);
export const ModalIcon = () => (
<svg
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2m0 14H5V8h14z"></path>
</svg>
);

View File

@@ -67,11 +67,11 @@ const Modal: FC<ModalProps> = ({
})}
onMouseDown={onClose}
>
<div
className="vm-modal-content"
onMouseDown={handleMouseDown}
>
<div className="vm-modal-content-header">
<div className="vm-modal-content">
<div
className="vm-modal-content-header"
onMouseDown={handleMouseDown}
>
{title && (
<div className="vm-modal-content-header__title">
{title}
@@ -91,6 +91,7 @@ const Modal: FC<ModalProps> = ({
{/* tabIndex to fix Ctrl-A */}
<div
className="vm-modal-content-body"
onMouseDown={handleMouseDown}
tabIndex={0}
>
{children}

View File

@@ -15,10 +15,9 @@ interface PopperProps {
open: boolean
onClose: () => void
buttonRef: React.RefObject<HTMLElement>
placement?: "bottom-right" | "bottom-left" | "top-left" | "top-right" | "fixed"
placementPosition?: { top: number, left: number } | null
placement?: "bottom-right" | "bottom-left" | "top-left" | "top-right"
animation?: string
offset?: { top: number, left: number }
offset?: {top: number, left: number}
clickOutside?: boolean,
fullWidth?: boolean
title?: string
@@ -30,7 +29,6 @@ const Popper: FC<PopperProps> = ({
children,
buttonRef,
placement = "bottom-left",
placementPosition,
open = false,
onClose,
offset = { top: 6, left: 0 },
@@ -94,18 +92,13 @@ const Popper: FC<PopperProps> = ({
if (needAlignRight) position.left = buttonPos.right - popperSize.width;
if (needAlignTop) position.top = buttonPos.top - popperSize.height - offsetTop;
if (placement === "fixed" && placementPosition) {
position.top = Math.max(placementPosition.top + offset.top, 0);
position.left = Math.max(placementPosition.left + offset.left, 0);
return position;
}
const { innerWidth, innerHeight } = window;
const margin = 20;
const isOverflowBottom = (position.top + popperSize.height) > innerHeight;
const isOverflowTop = (position.top) < 0;
const isOverflowRight = (position.left + popperSize.width) > innerWidth;
const isOverflowLeft = (position.left) < 0;
const isOverflowBottom = (position.top + popperSize.height + margin) > innerHeight;
const isOverflowTop = (position.top - margin) < 0;
const isOverflowRight = (position.left + popperSize.width + margin) > innerWidth;
const isOverflowLeft = (position.left - margin) < 0;
if (isOverflowBottom) position.top = buttonPos.top - popperSize.height - offsetTop;
if (isOverflowTop) position.top = buttonPos.height + buttonPos.top + offsetTop;
@@ -113,11 +106,11 @@ const Popper: FC<PopperProps> = ({
if (isOverflowLeft) position.left = buttonPos.left + offsetLeft;
if (fullWidth) position.width = `${buttonPos.width}px`;
if (position.top < 0) position.top = 0;
if (position.left < 0) position.left = 0;
if (position.top < 0) position.top = 20;
if (position.left < 0) position.left = 20;
return position;
}, [buttonRef, placement, isOpen, children, fullWidth]);
},[buttonRef, placement, isOpen, children, fullWidth]);
const handleClickClose = (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => {
e.stopPropagation();
@@ -138,10 +131,10 @@ const Popper: FC<PopperProps> = ({
if (!popperRef.current || !isOpen || (isMobile && !disabledFullScreen)) return;
const { right, width } = popperRef.current.getBoundingClientRect();
if (right > window.innerWidth) {
const left = window.innerWidth - width;
popperRef.current.style.left = `${left}px`;
const left = window.innerWidth - 20 - width;
popperRef.current.style.left = left < window.innerWidth ? "0" : `${left}px`;
}
}, [isOpen, popperRef, placementPosition]);
}, [isOpen, popperRef]);
const handlePopstate = useCallback(() => {
if (isOpen && isMobile && !disabledFullScreen) {

View File

@@ -11,7 +11,7 @@
border-radius: $border-radius-small;
&_open {
z-index: 100;
z-index: 101;
opacity: 1;
transform-origin: top center;
animation: vm-slider 150ms cubic-bezier(0.280, 0.840, 0.420, 1.1);

View File

@@ -33,9 +33,9 @@
align-items: center;
justify-content: center;
background-color: $color-hover-black;
padding: 2px 2px 2px $padding-small;
padding: 2px 2px 2px 6px;
border-radius: $border-radius-small;
font-size: $font-size-small;
font-size: $font-size;
line-height: $font-size;
max-width: 100%;

View File

@@ -11,7 +11,7 @@ import useBoolean from "../../../hooks/useBoolean";
import TextField from "../../Main/TextField/TextField";
import { KeyboardEvent, useState } from "react";
import Modal from "../../Main/Modal/Modal";
import { useSearchParams } from "react-router-dom";
import { getFromStorage, removeFromStorage, saveToStorage } from "../../../utils/storage";
const title = "Table settings";
@@ -30,8 +30,6 @@ const TableSettings: FC<TableSettingsProps> = ({
onChangeColumns,
toggleTableCompact
}) => {
const [searchParams, setSearchParams] = useSearchParams();
const buttonRef = useRef<HTMLDivElement>(null);
const {
@@ -40,6 +38,11 @@ const TableSettings: FC<TableSettingsProps> = ({
setFalse: handleClose,
} = useBoolean(false);
const {
value: saveColumns,
toggle: toggleSaveColumns,
} = useBoolean(Boolean(getFromStorage("TABLE_COLUMNS")));
const [searchColumn, setSearchColumn] = useState("");
const [indexFocusItem, setIndexFocusItem] = useState(-1);
@@ -57,34 +60,15 @@ const TableSettings: FC<TableSettingsProps> = ({
return filteredColumns.every(col => selectedColumns.includes(col));
}, [selectedColumns, filteredColumns]);
const handleChangeDisplayColumns = (displayColumns: string[]) => {
onChangeColumns(displayColumns);
const updatedParams = new URLSearchParams(searchParams.toString());
const isAllCheck = displayColumns.length === columns.length;
if (isAllCheck) {
updatedParams.delete("columns");
} else {
updatedParams.set("columns", displayColumns.map(encodeURIComponent).join(","));
}
setSearchParams(updatedParams);
};
const handleChange = (key: string) => {
const displayColumns = selectedColumns.includes(key)
? selectedColumns.filter(col => col !== key)
: [...selectedColumns, key];
handleChangeDisplayColumns(displayColumns);
onChangeColumns(selectedColumns.includes(key) ? selectedColumns.filter(col => col !== key) : [...selectedColumns, key]);
};
const toggleAllColumns = () => {
if (isAllChecked) {
handleChangeDisplayColumns(selectedColumns.filter(col => !filteredColumns.includes(col)));
onChangeColumns(selectedColumns.filter(col => !filteredColumns.includes(col)));
} else {
handleChangeDisplayColumns(filteredColumns);
onChangeColumns(filteredColumns);
}
};
@@ -111,16 +95,22 @@ const TableSettings: FC<TableSettingsProps> = ({
};
useEffect(() => {
if (arrayEquals(columns, selectedColumns) || searchParams.has("columns")) return;
if (arrayEquals(columns, selectedColumns) || saveColumns) return;
onChangeColumns(columns);
}, [columns]);
useEffect(() => {
const hasColumns = searchParams.has("columns");
if (!hasColumns) return;
const columnsParam = searchParams.get("columns") || "";
const columnsArray = columnsParam.split(",").map(decodeURIComponent).filter(Boolean);
onChangeColumns(columnsArray);
if (!saveColumns) {
removeFromStorage(["TABLE_COLUMNS"]);
} else if (selectedColumns.length) {
saveToStorage("TABLE_COLUMNS", selectedColumns.join(","));
}
}, [saveColumns, selectedColumns]);
useEffect(() => {
const saveColumns = getFromStorage("TABLE_COLUMNS") as string;
if (!saveColumns) return;
onChangeColumns(saveColumns.split(","));
}, []);
return (
@@ -193,6 +183,19 @@ const TableSettings: FC<TableSettingsProps> = ({
</div>
))}
</div>
<div className="vm-table-settings-modal-preserve">
<Checkbox
checked={saveColumns}
onChange={toggleSaveColumns}
label={"Preserve column settings"}
disabled={tableCompact}
color={"primary"}
/>
<p className="vm-table-settings-modal-preserve__info">
This label indicates that when the checkbox is activated,
the current column configurations will not be reset.
</p>
</div>
</div>
</div>
<div className="vm-table-settings-modal-section">

View File

@@ -3,7 +3,6 @@
.vm-table-settings {
&-modal {
.vm-modal-content-body {
min-width: clamp(300px, 600px, 90vw);
padding: 0;
}
@@ -84,5 +83,16 @@
}
}
}
&-preserve {
padding: $padding-global;
&__info {
padding-top: $padding-small;
font-size: $font-size-small;
color: $color-text-secondary;
line-height: 130%;
}
}
}
}

View File

@@ -1,22 +1,2 @@
import { DATE_TIME_FORMAT } from "./date";
export const LOGS_ENTRIES_LIMIT = 50;
export const LOGS_BARS_VIEW = 100;
export const LOGS_LIMIT_HITS = 5;
// "Ungrouped" is a string that is used as a value for the "groupBy" parameter.
export const WITHOUT_GROUPING = "Ungrouped";
// Default values for the logs configurators.
export const LOGS_GROUP_BY = "_stream";
export const LOGS_DISPLAY_FIELDS = "_msg";
export const LOGS_DATE_FORMAT = `${DATE_TIME_FORMAT}.SSS`;
// URL parameters for the logs page.
export const LOGS_URL_PARAMS = {
GROUP_BY: "groupBy",
DISPLAY_FIELDS: "displayFields",
NO_WRAP_LINES: "noWrapLines",
COMPACT_GROUP_HEADER: "compactGroupHeader",
DATE_FORMAT: "dateFormat",
};

View File

@@ -20,7 +20,7 @@ const useClickOutside = <T extends HTMLElement = HTMLElement>(
handler(event); // Call the handler only if the click is outside of the element passed.
}, [ref, handler]);
useEventListener("mouseup", listener);
useEventListener("mousedown", listener);
useEventListener("touchstart", listener);
};

View File

@@ -69,7 +69,7 @@ const ExploreLogs: FC = () => {
};
const handleApplyFilter = (val: string) => {
setQuery(prev => `${val} AND (${prev})`);
setQuery(prev => `_stream: ${val === "other" ? "{}" : val} AND (${prev})`);
setIsUpdatingQuery(true);
};

View File

@@ -1,19 +1,24 @@
import React, { FC, useCallback, useEffect, useMemo } from "preact/compat";
import { useState } from "react";
import React, { FC, useCallback, useEffect, useMemo, useRef } from "preact/compat";
import { MouseEvent, useState } from "react";
import "./style.scss";
import { Logs } from "../../../api/types";
import Accordion from "../../../components/Main/Accordion/Accordion";
import { groupByMultipleKeys } from "../../../utils/array";
import Tooltip from "../../../components/Main/Tooltip/Tooltip";
import useCopyToClipboard from "../../../hooks/useCopyToClipboard";
import GroupLogsItem from "./GroupLogsItem";
import { useAppState } from "../../../state/common/StateContext";
import classNames from "classnames";
import Button from "../../../components/Main/Button/Button";
import { CollapseIcon, ExpandIcon } from "../../../components/Main/Icons";
import { CollapseIcon, ExpandIcon, StorageIcon } from "../../../components/Main/Icons";
import Popper from "../../../components/Main/Popper/Popper";
import TextField from "../../../components/Main/TextField/TextField";
import useBoolean from "../../../hooks/useBoolean";
import useStateSearchParams from "../../../hooks/useStateSearchParams";
import { useSearchParams } from "react-router-dom";
import { getStreamPairs } from "../../../utils/logs";
import GroupLogsConfigurators
from "../../../components/LogsConfigurators/GroupLogsConfigurators/GroupLogsConfigurators";
import GroupLogsHeader from "./GroupLogsHeader";
import { LOGS_DISPLAY_FIELDS, LOGS_GROUP_BY, LOGS_URL_PARAMS, WITHOUT_GROUPING } from "../../../constants/logs";
const WITHOUT_GROUPING = "No Grouping";
interface Props {
logs: Logs[];
@@ -21,31 +26,73 @@ interface Props {
}
const GroupLogs: FC<Props> = ({ logs, settingsRef }) => {
const [searchParams] = useSearchParams();
const { isDarkTheme } = useAppState();
const copyToClipboard = useCopyToClipboard();
const [searchParams, setSearchParams] = useSearchParams();
const [expandGroups, setExpandGroups] = useState<boolean[]>([]);
const [groupBy, setGroupBy] = useStateSearchParams("_stream", "groupBy");
const [copied, setCopied] = useState<string | null>(null);
const [searchKey, setSearchKey] = useState("");
const optionsButtonRef = useRef<HTMLDivElement>(null);
const groupBy = searchParams.get(LOGS_URL_PARAMS.GROUP_BY) || LOGS_GROUP_BY;
const displayFieldsString = searchParams.get(LOGS_URL_PARAMS.DISPLAY_FIELDS) || LOGS_DISPLAY_FIELDS;
const displayFields = displayFieldsString.split(",");
const {
value: openOptions,
toggle: toggleOpenOptions,
setFalse: handleCloseOptions,
} = useBoolean(false);
const expandAll = useMemo(() => expandGroups.every(Boolean), [expandGroups]);
const logsKeys = useMemo(() => {
const excludeKeys = ["_msg", "_time"];
const uniqKeys = Array.from(new Set(logs.map(l => Object.keys(l)).flat()));
return [WITHOUT_GROUPING, ...uniqKeys.filter(k => !excludeKeys.includes(k))];
}, [logs]);
const filteredLogsKeys = useMemo(() => {
if (!searchKey) return logsKeys;
try {
const regexp = new RegExp(searchKey, "i");
return logsKeys.filter(item => regexp.test(item))
.sort((a, b) => (a.match(regexp)?.index || 0) - (b.match(regexp)?.index || 0));
} catch (e) {
return [];
}
}, [logsKeys, searchKey]);
const groupData = useMemo(() => {
return groupByMultipleKeys(logs, [groupBy]).map((item) => {
const streamValue = item.values[0]?.[groupBy] || "";
const pairs = getStreamPairs(streamValue);
// values sorting by time
const values = item.values.sort((a, b) => new Date(b._time).getTime() - new Date(a._time).getTime());
const values = item.values.sort((a,b) => new Date(b._time).getTime() - new Date(a._time).getTime());
return {
keys: item.keys,
keysString: item.keys.join(""),
values,
pairs,
};
}).sort((a, b) => b.values.length - a.values.length); // groups sorting
}).sort((a, b) => a.keysString.localeCompare(b.keysString)); // groups sorting
}, [logs, groupBy]);
const handleClickByPair = (value: string) => async (e: MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
const isKeyValue = /(.+)?=(".+")/.test(value);
const copyValue = isKeyValue ? `${value.replace(/=/, ": ")}` : `${groupBy}: "${value}"`;
const isCopied = await copyToClipboard(copyValue);
if (isCopied) {
setCopied(value);
}
};
const handleSelectGroupBy = (key: string) => () => {
setGroupBy(key);
searchParams.set("groupBy", key);
setSearchParams(searchParams);
handleCloseOptions();
};
const handleToggleExpandAll = useCallback(() => {
setExpandGroups(new Array(groupData.length).fill(!expandAll));
}, [expandAll, groupData.length]);
@@ -58,6 +105,11 @@ const GroupLogs: FC<Props> = ({ logs, settingsRef }) => {
});
}, []);
useEffect(() => {
if (copied === null) return;
const timeout = setTimeout(() => setCopied(null), 2000);
return () => clearTimeout(timeout);
}, [copied]);
useEffect(() => {
setExpandGroups(new Array(groupData.length).fill(true));
@@ -72,16 +124,38 @@ const GroupLogs: FC<Props> = ({ logs, settingsRef }) => {
key={item.keysString}
>
<Accordion
key={String(expandGroups[i])}
defaultExpanded={expandGroups[i]}
onChange={handleChangeExpand(i)}
title={groupBy !== WITHOUT_GROUPING && <GroupLogsHeader group={item}/>}
title={groupBy !== WITHOUT_GROUPING && (
<div className="vm-group-logs-section-keys">
<span className="vm-group-logs-section-keys__title">Group by <code>{groupBy}</code>:</span>
{item.pairs.map((pair) => (
<Tooltip
title={copied === pair ? "Copied" : "Copy to clipboard"}
key={`${item.keysString}_${pair}`}
placement={"top-center"}
>
<div
className={classNames({
"vm-group-logs-section-keys__pair": true,
"vm-group-logs-section-keys__pair_dark": isDarkTheme
})}
onClick={handleClickByPair(pair)}
>
{pair}
</div>
</Tooltip>
))}
<span className="vm-group-logs-section-keys__count">{item.values.length} entries</span>
</div>
)}
>
<div className="vm-group-logs-section-rows">
{item.values.map((value) => (
<GroupLogsItem
key={`${value._msg}${value._time}`}
log={value}
displayFields={displayFields}
/>
))}
</div>
@@ -101,7 +175,47 @@ const GroupLogs: FC<Props> = ({ logs, settingsRef }) => {
ariaLabel={expandAll ? "Collapse All" : "Expand All"}
/>
</Tooltip>
<GroupLogsConfigurators logs={logs}/>
<Tooltip title={"Group by"}>
<div ref={optionsButtonRef}>
<Button
variant="text"
startIcon={<StorageIcon/>}
onClick={toggleOpenOptions}
ariaLabel={"Group by"}
/>
</div>
</Tooltip>
{
<Popper
open={openOptions}
placement="bottom-right"
onClose={handleCloseOptions}
buttonRef={optionsButtonRef}
>
<div className="vm-list vm-group-logs-header-keys">
<div className="vm-group-logs-header-keys__search">
<TextField
label="Search key"
value={searchKey}
onChange={setSearchKey}
type="search"
/>
</div>
{filteredLogsKeys.map(id => (
<div
className={classNames({
"vm-list-item": true,
"vm-list-item_active": id === groupBy
})}
key={id}
onClick={handleSelectGroupBy(id)}
>
{id}
</div>
))}
</div>
</Popper>
}
</div>
), settingsRef.current)}
</>

View File

@@ -1,10 +1,8 @@
import React, { FC, memo, useCallback, useEffect, useState } from "preact/compat";
import Tooltip from "../../../components/Main/Tooltip/Tooltip";
import Button from "../../../components/Main/Button/Button";
import { CopyIcon, StorageIcon, VisibilityIcon } from "../../../components/Main/Icons";
import { CopyIcon } from "../../../components/Main/Icons";
import useCopyToClipboard from "../../../hooks/useCopyToClipboard";
import { useSearchParams } from "react-router-dom";
import { LOGS_GROUP_BY, LOGS_URL_PARAMS } from "../../../constants/logs";
interface Props {
field: string;
@@ -13,17 +11,8 @@ interface Props {
const GroupLogsFieldRow: FC<Props> = ({ field, value }) => {
const copyToClipboard = useCopyToClipboard();
const [searchParams, setSearchParams] = useSearchParams();
const [copied, setCopied] = useState<boolean>(false);
const groupBy = searchParams.get(LOGS_URL_PARAMS.GROUP_BY) || LOGS_GROUP_BY;
const displayFieldsString = searchParams.get(LOGS_URL_PARAMS.DISPLAY_FIELDS) || "";
const displayFields = displayFieldsString ? displayFieldsString.split(",") : [];
const isSelectedField = displayFields.includes(field);
const isGroupByField = groupBy === field;
const handleCopy = useCallback(async () => {
if (copied) return;
try {
@@ -34,18 +23,6 @@ const GroupLogsFieldRow: FC<Props> = ({ field, value }) => {
}
}, [copied, copyToClipboard]);
const handleSelectDisplayField = () => {
const prev = displayFields;
const newDisplayFields = prev.includes(field) ? prev.filter(v => v !== field) : [...prev, field];
searchParams.set(LOGS_URL_PARAMS.DISPLAY_FIELDS, newDisplayFields.join(","));
setSearchParams(searchParams);
};
const handleSelectGroupBy = () => {
isGroupByField ? searchParams.delete(LOGS_URL_PARAMS.GROUP_BY) : searchParams.set(LOGS_URL_PARAMS.GROUP_BY, field);
setSearchParams(searchParams);
};
useEffect(() => {
if (copied === null) return;
const timeout = setTimeout(() => setCopied(false), 2000);
@@ -58,7 +35,6 @@ const GroupLogsFieldRow: FC<Props> = ({ field, value }) => {
<div className="vm-group-logs-row-fields-item-controls__wrapper">
<Tooltip title={copied ? "Copied" : "Copy to clipboard"}>
<Button
className="vm-group-logs-row-fields-item-controls__button"
variant="text"
color="gray"
size="small"
@@ -67,34 +43,6 @@ const GroupLogsFieldRow: FC<Props> = ({ field, value }) => {
ariaLabel="copy to clipboard"
/>
</Tooltip>
<Tooltip
key={`${field}_${isSelectedField}_${isGroupByField}`}
title={isSelectedField ? "Hide this field" : "Show this field instead of the message"}
>
<Button
className="vm-group-logs-row-fields-item-controls__button"
variant="text"
color={isSelectedField ? "secondary" : "gray"}
size="small"
startIcon={isSelectedField ? <VisibilityIcon/> : <VisibilityIcon/>}
onClick={handleSelectDisplayField}
ariaLabel="copy to clipboard"
/>
</Tooltip>
<Tooltip
key={`${field}_${isSelectedField}_${isGroupByField}`}
title={isGroupByField ? "Ungroup this field" : "Group by this field"}
>
<Button
className="vm-group-logs-row-fields-item-controls__button"
variant="text"
color={isGroupByField ? "secondary" : "gray"}
size="small"
startIcon={<StorageIcon/>}
onClick={handleSelectGroupBy}
ariaLabel="copy to clipboard"
/>
</Tooltip>
</div>
</td>
<td className="vm-group-logs-row-fields-item__key">{field}</td>

View File

@@ -1,127 +0,0 @@
import React, { FC, useCallback, useEffect, useRef } from "preact/compat";
import classNames from "classnames";
import { useSearchParams } from "react-router-dom";
import { MouseEvent, useState } from "react";
import { useAppState } from "../../../state/common/StateContext";
import { Logs } from "../../../api/types";
import useEventListener from "../../../hooks/useEventListener";
import Popper from "../../../components/Main/Popper/Popper";
import useBoolean from "../../../hooks/useBoolean";
import GroupLogsHeaderItem from "./GroupLogsHeaderItem";
import { LOGS_GROUP_BY, LOGS_URL_PARAMS } from "../../../constants/logs";
interface Props {
group: {
keys: string[]
keysString: string
values: Logs[]
pairs: string[]
};
}
const GroupLogsHeader: FC<Props> = ({ group }) => {
const { isDarkTheme } = useAppState();
const [searchParams] = useSearchParams();
const containerRef = useRef<HTMLDivElement>(null);
const moreRef = useRef<HTMLDivElement>(null);
const {
value: openMore,
toggle: handleToggleMore,
setFalse: handleCloseMore,
} = useBoolean(false);
const [hideParisCount, setHideParisCount] = useState<number>(0);
const groupBy = searchParams.get(LOGS_URL_PARAMS.GROUP_BY) || LOGS_GROUP_BY;
const compactGroupHeader = searchParams.get(LOGS_URL_PARAMS.COMPACT_GROUP_HEADER) === "true";
const pairs = group.pairs;
const hideAboveIndex = pairs.length - hideParisCount - 1;
const handleClickMore = (e: MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
handleToggleMore();
};
const calcVisiblePairsCount = useCallback(() => {
if (!compactGroupHeader || !containerRef.current) {
setHideParisCount(0);
return;
}
const container = containerRef.current;
const containerSize = container.getBoundingClientRect();
const selector = ".vm-group-logs-section-keys__pair:not(.vm-group-logs-section-keys__pair_more)";
const children = Array.from(container.querySelectorAll(selector));
let count = 0;
for (const child of children) {
const { right } = (child as HTMLElement).getBoundingClientRect();
if ((right + 220) > containerSize.width) {
count++;
}
}
setHideParisCount(count);
}, [compactGroupHeader, containerRef]);
useEffect(calcVisiblePairsCount, [group.pairs, compactGroupHeader, containerRef]);
useEventListener("resize", calcVisiblePairsCount);
return (
<div
className={classNames({
"vm-group-logs-section-keys": true,
"vm-group-logs-section-keys_compact": compactGroupHeader,
})}
ref={containerRef}
>
<span className="vm-group-logs-section-keys__title">Group by <code>{groupBy}</code>:</span>
{pairs.map((pair, i) => (
<GroupLogsHeaderItem
key={`${group.keysString}_${pair}`}
pair={pair}
isHide={hideParisCount ? i > hideAboveIndex : false}
/>
))}
{hideParisCount > 0 && (
<>
<div
className={classNames({
"vm-group-logs-section-keys__pair": true,
"vm-group-logs-section-keys__pair_more": true,
"vm-group-logs-section-keys__pair_dark": isDarkTheme
})}
ref={moreRef}
onClick={handleClickMore}
>
+{hideParisCount} more
</div>
<Popper
open={openMore}
buttonRef={moreRef}
placement="bottom-left"
onClose={handleCloseMore}
>
<div className="vm-group-logs-section-keys vm-group-logs-section-keys_popper">
{pairs.slice(hideAboveIndex + 1).map((pair) => (
<GroupLogsHeaderItem
key={`${group.keysString}_${pair}`}
pair={pair}
/>
))}
</div>
</Popper>
</>
)}
<span className="vm-group-logs-section-keys__count">{group.values.length} entries</span>
</div>
)
;
};
export default GroupLogsHeader;

View File

@@ -1,59 +0,0 @@
import React, { FC, useEffect } from "preact/compat";
import { useAppState } from "../../../state/common/StateContext";
import Tooltip from "../../../components/Main/Tooltip/Tooltip";
import classNames from "classnames";
import { MouseEvent, useState } from "react";
import useCopyToClipboard from "../../../hooks/useCopyToClipboard";
import { useSearchParams } from "react-router-dom";
import { LOGS_GROUP_BY, LOGS_URL_PARAMS } from "../../../constants/logs";
import { convertToFieldFilter } from "../../../utils/logs";
interface Props {
pair: string;
isHide?: boolean;
}
const GroupLogsHeaderItem: FC<Props> = ({ pair, isHide }) => {
const { isDarkTheme } = useAppState();
const copyToClipboard = useCopyToClipboard();
const [searchParams] = useSearchParams();
const [copied, setCopied] = useState<string | null>(null);
const groupBy = searchParams.get(LOGS_URL_PARAMS.GROUP_BY) || LOGS_GROUP_BY;
const handleClickByPair = (value: string) => async (e: MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
const copyValue = convertToFieldFilter(value, groupBy);
const isCopied = await copyToClipboard(copyValue);
if (isCopied) {
setCopied(value);
}
};
useEffect(() => {
if (copied === null) return;
const timeout = setTimeout(() => setCopied(null), 2000);
return () => clearTimeout(timeout);
}, [copied]);
return (
<Tooltip
title={copied === pair ? "Copied" : "Copy to clipboard"}
placement={"top-center"}
>
<div
className={classNames({
"vm-group-logs-section-keys__pair": true,
"vm-group-logs-section-keys__pair_hide": isHide,
"vm-group-logs-section-keys__pair_dark": isDarkTheme
})}
onClick={handleClickByPair(pair)}
>
{pair}
</div>
</Tooltip>
);
};
export default GroupLogsHeaderItem;

View File

@@ -6,34 +6,28 @@ import { ArrowDownIcon } from "../../../components/Main/Icons";
import classNames from "classnames";
import { useLogsState } from "../../../state/logsPanel/LogsStateContext";
import dayjs from "dayjs";
import { DATE_TIME_FORMAT } from "../../../constants/date";
import { useTimeState } from "../../../state/time/TimeStateContext";
import GroupLogsFieldRow from "./GroupLogsFieldRow";
import { marked } from "marked";
import { useSearchParams } from "react-router-dom";
import { LOGS_DATE_FORMAT, LOGS_URL_PARAMS } from "../../../constants/logs";
interface Props {
log: Logs;
displayFields?: string[];
}
const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
const GroupLogsItem: FC<Props> = ({ log }) => {
const {
value: isOpenFields,
toggle: toggleOpenFields,
} = useBoolean(false);
const [searchParams] = useSearchParams();
const { markdownParsing } = useLogsState();
const { timezone } = useTimeState();
const noWrapLines = searchParams.get(LOGS_URL_PARAMS.NO_WRAP_LINES) === "true";
const dateFormat = searchParams.get(LOGS_URL_PARAMS.DATE_FORMAT) || LOGS_DATE_FORMAT;
const formattedTime = useMemo(() => {
if (!log._time) return "";
return dayjs(log._time).tz().format(dateFormat);
}, [log._time, timezone, dateFormat]);
return dayjs(log._time).tz().format(`${DATE_TIME_FORMAT}.SSS`);
}, [log._time, timezone]);
const formattedMarkdown = useMemo(() => {
if (!markdownParsing || !log._msg) return "";
@@ -44,14 +38,6 @@ const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
const hasFields = fields.length > 0;
const displayMessage = useMemo(() => {
if (displayFields.length) {
return displayFields.filter(field => log[field]).map((field, i) => (
<span
className="vm-group-logs-row-content__sub-msg"
key={field + i}
>{log[field]}</span>
));
}
if (log._msg) return log._msg;
if (!hasFields) return;
const dataObject = fields.reduce<{ [key: string]: string }>((obj, [key, value]) => {
@@ -59,7 +45,7 @@ const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
return obj;
}, {});
return JSON.stringify(dataObject);
}, [log, fields, hasFields, displayFields]);
}, [log, fields, hasFields]);
return (
<div className="vm-group-logs-row">
@@ -90,8 +76,7 @@ const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
className={classNames({
"vm-group-logs-row-content__msg": true,
"vm-group-logs-row-content__msg_empty-msg": !log._msg,
"vm-group-logs-row-content__msg_missing": !displayMessage,
"vm-group-logs-row-content__msg_single-line": noWrapLines,
"vm-group-logs-row-content__msg_missing": !displayMessage
})}
dangerouslySetInnerHTML={(markdownParsing && formattedMarkdown) ? { __html: formattedMarkdown } : undefined}
>

View File

@@ -1,7 +1,5 @@
@use "src/styles/variables" as *;
$font-size-logs: var(--font-size-logs, $font-size-small);
.vm-group-logs {
margin-top: calc(-1 * $padding-medium);
@@ -21,44 +19,22 @@ $font-size-logs: var(--font-size-logs, $font-size-small);
}
&-section {
border-bottom: $border-divider;
&-keys {
position: relative;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: $padding-small;
padding: $padding-small 120px $padding-small 0;
font-size: $font-size-logs;
&_compact {
flex-wrap: nowrap;
overflow: hidden;
}
&_popper {
display: flex;
flex-wrap: nowrap;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
padding: $padding-global;
max-height: 400px;
overflow: auto;
}
border-bottom: $border-divider;
padding: $padding-small 0;
&__title {
font-weight: bold;
white-space: nowrap;
code {
font-family: monospace;
&:before {
content: "\"";
}
&:after {
content: "\"";
}
@@ -66,35 +42,19 @@ $font-size-logs: var(--font-size-logs, $font-size-small);
}
&__count {
position: absolute;
top: auto;
right: 0;
flex-grow: 1;
text-align: right;
font-size: $font-size-logs;
font-size: $font-size-small;
color: $color-text-secondary;
padding-right: calc($padding-large * 3);
}
&__pair {
order: 0;
padding: calc($padding-global / 2) $padding-global;
background-color: lighten($color-tropical-blue, 6%);
color: darken($color-dodger-blue, 20%);
border-radius: $border-radius-medium;
transition: background-color 0.3s ease-in, transform 0.1s ease-in, opacity 0.3s ease-in;
white-space: nowrap;
&_hide {
order: 2;
visibility: hidden;
opacity: 0;
pointer-events: none;
}
&_more {
order: 1;
}
&:hover {
background-color: $color-tropical-blue;
@@ -124,19 +84,13 @@ $font-size-logs: var(--font-size-logs, $font-size-small);
&-row {
position: relative;
&:last-child {
margin-bottom: $padding-small;
}
border-bottom: $border-divider;
&-content {
position: relative;
display: grid;
grid-template-columns: auto max-content 1fr;
padding: calc($padding-small / 4) 0;
font-size: $font-size-logs;
font-variant-numeric: tabular-nums;
line-height: 1.3;
grid-template-columns: auto minmax(180px, max-content) 1fr;
padding: $padding-global 0;
cursor: pointer;
transition: background-color 0.2s ease-in;
@@ -162,7 +116,8 @@ $font-size-logs: var(--font-size-logs, $font-size-small);
display: flex;
align-items: flex-start;
justify-content: flex-end;
padding: 0 $padding-global 0 $padding-small;
margin-right: $padding-small;
line-height: 1;
white-space: nowrap;
&_missing {
@@ -175,12 +130,7 @@ $font-size-logs: var(--font-size-logs, $font-size-small);
&__msg {
font-family: $font-family-monospace;
overflow-wrap: anywhere;
&_single-line {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
line-height: 1.1;
&_empty-msg {
overflow: hidden;
@@ -208,7 +158,7 @@ $font-size-logs: var(--font-size-logs, $font-size-small);
border-radius: $border-radius-small;
tab-size: 4;
font-variant-ligatures: none;
margin: calc($padding-small / 4) 0;
margin: calc($padding-small/4) 0;
}
p {
@@ -221,7 +171,7 @@ $font-size-logs: var(--font-size-logs, $font-size-small);
}
code {
font-size: $font-size-logs;
font-size: $font-size-small;
padding: calc($padding-small / 4) calc($padding-small / 2);
}
@@ -244,35 +194,25 @@ $font-size-logs: var(--font-size-logs, $font-size-small);
blockquote {
border-left: 4px solid $color-hover-black;
margin: calc($padding-small / 2) $padding-small;
padding: calc($padding-small / 2) $padding-small;
margin: calc($padding-small/2) $padding-small;
padding: calc($padding-small/2) $padding-small;
}
ul, ol {
list-style-position: inside;
}
/* end styles for markdown */
}
&__sub-msg {
padding-right: $padding-global;
}
}
&-fields {
position: relative;
grid-row: 2;
padding: $padding-small 0;
margin: $padding-small 0 $padding-small calc($padding-global * 2);
margin-bottom: $padding-small;
border: $border-divider;
border-radius: $border-radius-small;
overflow: auto;
max-height: 300px;
resize: vertical;
font-family: $font-family-monospace;
font-size: $font-size-logs;
font-variant-numeric: tabular-nums;
&-item {
border-radius: $border-radius-small;
@@ -283,26 +223,19 @@ $font-size-logs: var(--font-size-logs, $font-size-small);
}
&-controls {
padding: 0 calc($padding-small / 2);
padding: 0;
&__wrapper {
display: flex;
align-items: center;
justify-content: center;
}
&__button.vm-button_small {
width: 22px;
height: 22px;
min-height: 22px;
}
}
&__key,
&__value {
vertical-align: top;
line-height: $font-size;
padding: calc($padding-small / 2);
padding: calc($padding-small / 2) $padding-global;
}
&__key {

View File

@@ -4,8 +4,6 @@ import { ErrorTypes, TimeParams } from "../../../types";
import { LogHits } from "../../../api/types";
import { useSearchParams } from "react-router-dom";
import { getHitsTimeParams } from "../../../utils/logs";
import { LOGS_GROUP_BY, LOGS_LIMIT_HITS } from "../../../constants/logs";
import { isEmptyObject } from "../../../utils/object";
export const useFetchLogHits = (server: string, query: string) => {
const [searchParams] = useSearchParams();
@@ -32,12 +30,46 @@ export const useFetchLogHits = (server: string, query: string) => {
step: `${step}ms`,
start: start.toISOString(),
end: end.toISOString(),
fields_limit: `${LOGS_LIMIT_HITS}`,
field: LOGS_GROUP_BY,
field: "_stream" // In the future, this field can be made configurable
})
};
};
const accumulateHits = (resultHit: LogHits, hit: LogHits) => {
resultHit.total = (resultHit.total || 0) + (hit.total || 0);
hit.timestamps.forEach((timestamp, i) => {
const index = resultHit.timestamps.findIndex(t => t === timestamp);
if (index === -1) {
resultHit.timestamps.push(timestamp);
resultHit.values.push(hit.values[i]);
} else {
resultHit.values[index] += hit.values[i];
}
});
return resultHit;
};
const getHitsWithTop = (hits: LogHits[]) => {
const topN = 5;
const defaultHit = { fields: {}, timestamps: [], values: [], total: 0 };
const hitsByTotal = hits.sort((a, b) => (b.total || 0) - (a.total || 0));
const result = [];
const otherHits: LogHits = hitsByTotal.slice(topN).reduce(accumulateHits, defaultHit);
if (otherHits.total) {
result.push(otherHits);
}
const topHits: LogHits[] = hitsByTotal.slice(0, topN);
if (topHits.length) {
result.push(...topHits);
}
return result;
};
const fetchLogHits = useCallback(async (period: TimeParams) => {
abortControllerRef.current.abort();
abortControllerRef.current = new AbortController();
@@ -66,7 +98,7 @@ export const useFetchLogHits = (server: string, query: string) => {
setError(error);
}
setLogHits(hits.map(hit => ({ ...hit, _isOther: isEmptyObject(hit.fields) })));
setLogHits(!hits ? [] : getHitsWithTop(hits));
} catch (e) {
if (e instanceof Error && e.name !== "AbortError") {
setError(String(e));

View File

@@ -1,8 +1,6 @@
import { TimeParams } from "../types";
import dayjs from "dayjs";
import { LOGS_BARS_VIEW, LOGS_GROUP_BY } from "../constants/logs";
import { LogHits } from "../api/types";
import { OTHER_HITS_LABEL } from "../components/Chart/BarHitsChart/hooks/useBarHitsOptions";
import { LOGS_BARS_VIEW } from "../constants/logs";
export const getStreamPairs = (value: string): string[] => {
const pairs = /^{.+}$/.test(value) ? value.slice(1, -1).split(",") : [value];
@@ -16,27 +14,3 @@ export const getHitsTimeParams = (period: TimeParams) => {
const step = Math.ceil(totalSeconds / LOGS_BARS_VIEW) || 1;
return { start, end, step };
};
export const convertToFieldFilter = (value: string, field = LOGS_GROUP_BY) => {
const isKeyValue = /(.+)?=(".+")/.test(value);
if (isKeyValue) {
return value.replace(/=/, ": ");
}
return `${field}: "${value}"`;
};
export const calculateTotalHits = (hits: LogHits[]): number => {
return hits.reduce((acc, item) => acc + (item.total || 0), 0);
};
export const sortLogHits = <T extends { label?: string }>(key: keyof T) => (a: T, b: T): number => {
if (a.label === OTHER_HITS_LABEL) return 1;
if (b.label === OTHER_HITS_LABEL) return -1;
const aValue = a[key] as unknown as number;
const bValue = b[key] as unknown as number;
return bValue - aValue;
};

View File

@@ -57,15 +57,3 @@ export const getLastFromArray = (a: number[]) => {
}
}
};
export const formatNumberShort = (value: number) => {
if (value >= 1_000_000_000) {
return (value / 1_000_000_000).toFixed(1).replace(/\.0$/, "") + "B"; // Миллиарды
} else if (value >= 1_000_000) {
return (value / 1_000_000).toFixed(1).replace(/\.0$/, "") + "M"; // Миллионы
} else if (value >= 1_000) {
return (value / 1_000).toFixed(1).replace(/\.0$/, "") + "K"; // Тысячи
} else {
return value.toString(); // Для чисел меньше 1000
}
};

View File

@@ -14,7 +14,3 @@ export function filterObject<T extends object>(
export function compactObject<T extends object>(obj: T) {
return filterObject(obj, (entry) => !!entry[1] || typeof entry[1] === "number");
}
export function isEmptyObject(obj: object) {
return Object.keys(obj).length === 0;
}

View File

@@ -3,6 +3,7 @@ export type StorageKeys = "AUTOCOMPLETE"
| "QUERY_TRACING"
| "SERIES_LIMITS"
| "TABLE_COMPACT"
| "TABLE_COLUMNS"
| "TIMEZONE"
| "DISABLED_DEFAULT_TIMEZONE"
| "THEME"

View File

@@ -10,7 +10,7 @@ import (
// specific files
// static content
//
//go:embed favicon.svg robots.txt index.html manifest.json asset-manifest.json
//go:embed favicon-32x32.png robots.txt index.html manifest.json asset-manifest.json
//go:embed static
var files embed.FS

View File

@@ -171,49 +171,4 @@ func TestClusterMultiTenantSelect(t *testing.T) {
t.Errorf("unexpected response (-want, +got):\n%s", diff)
}
// Delete series from specific tenant
vmselect.DeleteSeries(t, "foo_bar", apptest.QueryOpts{
Tenant: "5:15",
})
wantSR = apptest.NewPrometheusAPIV1SeriesResponse(t,
`{"data": [
{"__name__":"foo_bar", "vm_account_id":"0", "vm_project_id":"10"},
{"__name__":"foo_bar", "vm_account_id":"1", "vm_project_id":"1"},
{"__name__":"foo_bar", "vm_account_id":"1", "vm_project_id":"15"},
{"__name__":"foo_bar", "vm_account_id":"5", "vm_project_id":"0"}
]
}`)
wantSR.Sort()
gotSR = vmselect.PrometheusAPIV1Series(t, "foo_bar", apptest.QueryOpts{
Tenant: "multitenant",
Start: "2022-05-10T08:03:00.000Z",
})
gotSR.Sort()
if diff := cmp.Diff(wantSR, gotSR, cmpSROpt); diff != "" {
t.Errorf("unexpected response (-want, +got):\n%s", diff)
}
// Delete series for multitenant with tenant filter
vmselect.DeleteSeries(t, `foo_bar{vm_account_id="1"}`, apptest.QueryOpts{
Tenant: "multitenant",
})
wantSR = apptest.NewPrometheusAPIV1SeriesResponse(t,
`{"data": [
{"__name__":"foo_bar", "vm_account_id":"0", "vm_project_id":"10"},
{"__name__":"foo_bar", "vm_account_id":"5", "vm_project_id":"0"}
]
}`)
wantSR.Sort()
gotSR = vmselect.PrometheusAPIV1Series(t, `foo_bar`, apptest.QueryOpts{
Tenant: "multitenant",
Start: "2022-05-10T08:03:00.000Z",
})
gotSR.Sort()
if diff := cmp.Diff(wantSR, gotSR, cmpSROpt); diff != "" {
t.Errorf("unexpected response (-want, +got):\n%s", diff)
}
}

View File

@@ -1,76 +0,0 @@
package tests
import (
"fmt"
"math/rand/v2"
"testing"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/apptest"
)
func TestStorageUsesSparseCacheForFinalMerge(t *testing.T) {
tc := apptest.NewTestCase(t)
defer tc.Stop()
sut := tc.MustStartVmsingle("sparse-cache-final-merge", []string{`-retentionPeriod=100y`, `-downsampling.period={__name__=~"metric.*"}:5m:1s`})
// insert metrics daily over past 2 months
const metricsPerStep = 10
const steps = 35
const stepSize = int64(1 * 24 * 60 * 60 * 1000)
records := make([]string, metricsPerStep)
ts := time.Now().Add(-2 * 30 * 24 * time.Hour).UnixMilli()
for range steps {
for i := range metricsPerStep {
name := fmt.Sprintf("metric_%d", i)
records[i] = fmt.Sprintf("%s %d %d", name, rand.IntN(1000), ts)
}
sut.PrometheusAPIV1ImportPrometheus(t, records, apptest.QueryOpts{})
ts += stepSize
}
sut.ForceFlush(t)
sut.ForceMerge(t)
// todo: replace with a more reliable way to check if the merge is completed
// wait for merge to be completed
time.Sleep(5 * time.Second)
v := sut.GetIntMetric(t, `vm_cache_requests_total{type="indexdb/dataBlocksSparse"}`)
if v <= 0 {
t.Fatalf(`unexpected vm_cache_requests_total{type="indexdb/dataBlocksSparse"} value: %d`, v)
}
}
func TestStorageDoesNotUseSparseCacheForRegularMerge(t *testing.T) {
tc := apptest.NewTestCase(t)
defer tc.Stop()
sut := tc.MustStartVmsingle("sparse-cache-regular-merge", []string{`-retentionPeriod=100y`, `-downsampling.period={__name__=~"metric.*"}:5m:1s`})
// insert metrics into current month only
const metricsPerStep = 10
const steps = 2
const stepSize = 60 * 1000
records := make([]string, metricsPerStep)
ts := time.Now().Add(-1 * time.Hour).UnixMilli()
for range steps {
for i := range metricsPerStep {
name := fmt.Sprintf("metric_%d", i)
records[i] = fmt.Sprintf("%s %d %d", name, rand.IntN(1000), ts)
}
sut.PrometheusAPIV1ImportPrometheus(t, records, apptest.QueryOpts{})
ts += stepSize
}
sut.ForceFlush(t)
sut.ForceMerge(t)
// todo: replace with a more reliable way to check if the merge is completed
// wait for merge to be completed
time.Sleep(5 * time.Second)
v := sut.GetIntMetric(t, `vm_cache_requests_total{type="indexdb/dataBlocksSparse"}`)
if v == 0 {
t.Fatalf(`unexpected vm_cache_requests_total{type="indexdb/dataBlocksSparse"} value: %d`, v)
}
}

View File

@@ -117,22 +117,6 @@ func (app *Vmselect) PrometheusAPIV1Series(t *testing.T, matchQuery string, opts
return NewPrometheusAPIV1SeriesResponse(t, res)
}
// DeleteSeries sends a query to a /prometheus/api/v1/admin/tsdb/delete_series
//
// See https://docs.victoriametrics.com/url-examples/#apiv1admintsdbdelete_series
func (app *Vmselect) DeleteSeries(t *testing.T, matchQuery string, opts QueryOpts) {
t.Helper()
seriesURL := fmt.Sprintf("http://%s/delete/%s/prometheus/api/v1/admin/tsdb/delete_series", app.httpListenAddr, opts.getTenant())
values := opts.asURLValues()
values.Add("match[]", matchQuery)
res := app.cli.PostForm(t, seriesURL, values, http.StatusNoContent)
if res != "" {
t.Fatalf("unexpected non-empty DeleteSeries response=%q", res)
}
}
// String returns the string representation of the vmselect app state.
func (app *Vmselect) String() string {
return fmt.Sprintf("{app: %s httpListenAddr: %q}", app.app, app.httpListenAddr)

View File

@@ -24,7 +24,6 @@ type Vmsingle struct {
// vmstorage URLs.
forceFlushURL string
forceMergeURL string
// vminsert URLs.
influxLineWriteURL string
@@ -66,7 +65,6 @@ func StartVmsingle(instance string, flags []string, cli *Client) (*Vmsingle, err
httpListenAddr: stderrExtracts[1],
forceFlushURL: fmt.Sprintf("http://%s/internal/force_flush", stderrExtracts[1]),
forceMergeURL: fmt.Sprintf("http://%s/internal/force_merge", stderrExtracts[1]),
influxLineWriteURL: fmt.Sprintf("http://%s/influx/write", stderrExtracts[1]),
prometheusAPIV1ImportPrometheusURL: fmt.Sprintf("http://%s/prometheus/api/v1/import/prometheus", stderrExtracts[1]),
prometheusAPIV1WriteURL: fmt.Sprintf("http://%s/prometheus/api/v1/write", stderrExtracts[1]),
@@ -85,13 +83,6 @@ func (app *Vmsingle) ForceFlush(t *testing.T) {
app.cli.Get(t, app.forceFlushURL, http.StatusOK)
}
// ForceMerge is a test helper function that forces the merging of parts.
func (app *Vmsingle) ForceMerge(t *testing.T) {
t.Helper()
app.cli.Get(t, app.forceMergeURL, http.StatusOK)
}
// InfluxWrite is a test helper function that inserts a
// collection of records in Influx line format by sending a HTTP
// POST request to /influx/write vmsingle endpoint.

View File

@@ -21,7 +21,6 @@ type Vmstorage struct {
vmselectAddr string
forceFlushURL string
forceMergeURL string
}
// StartVmstorage starts an instance of vmstorage with the given flags. It also
@@ -58,7 +57,6 @@ func StartVmstorage(instance string, flags []string, cli *Client) (*Vmstorage, e
vmselectAddr: stderrExtracts[3],
forceFlushURL: fmt.Sprintf("http://%s/internal/force_flush", stderrExtracts[1]),
forceMergeURL: fmt.Sprintf("http://%s/internal/force_merge", stderrExtracts[1]),
}, nil
}
@@ -82,12 +80,6 @@ func (app *Vmstorage) ForceFlush(t *testing.T) {
app.cli.Get(t, app.forceFlushURL, http.StatusOK)
}
// ForceMerge is a test helper function that forces the merging of parts.
func (app *Vmstorage) ForceMerge(t *testing.T) {
t.Helper()
app.cli.Get(t, app.forceMergeURL, http.StatusOK)
}
// String returns the string representation of the vmstorage app state.
func (app *Vmstorage) String() string {
return fmt.Sprintf("{app: %s storageDataPath: %q httpListenAddr: %q vminsertAddr: %q vmselectAddr: %q}", []any{

View File

@@ -1,7 +1,7 @@
dashboard-copy:
echo "" > dashboards/vm/${SRC}
cat dashboards/${SRC} >> dashboards/vm/${SRC}
sed -i='.tmp' 's/prometheus/victoriametrics-metrics-datasource/g' dashboards/vm/${SRC}
sed -i='.tmp' 's/prometheus/victoriametrics-datasource/g' dashboards/vm/${SRC}
sed -i='.tmp' 's/Prometheus/VictoriaMetrics/g' dashboards/vm/${SRC}
sed -i='.tmp' 's/${D_UID}/${D_UID}_vm/g' dashboards/vm/${SRC}
sed -i='.tmp' 's/"title": "${TITLE}"/"title": "${TITLE} (VM)"/g' dashboards/vm/${SRC}

View File

@@ -1686,7 +1686,7 @@
},
"editorMode": "code",
"exemplar": false,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(instance)",
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n vm_available_cpu_cores{job=~\"$job\", instance=~\"$instance\"}\n) by(instance)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,

View File

@@ -1933,7 +1933,7 @@
},
"editorMode": "code",
"exemplar": true,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n vm_available_cpu_cores{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,

View File

@@ -1981,7 +1981,7 @@
},
"editorMode": "code",
"exemplar": false,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(instance)",
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n vm_available_cpu_cores{job=~\"$job\", instance=~\"$instance\"}\n) by(instance)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,

View File

@@ -17,7 +17,7 @@
},
{
"type": "datasource",
"id": "victoriametrics-metrics-datasource",
"id": "victoriametrics-datasource",
"name": "VictoriaMetrics",
"version": "1.0.0"
},
@@ -85,7 +85,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -133,7 +133,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -150,7 +150,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Status of last backup operation.",
@@ -210,7 +210,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -225,7 +225,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Number of backups stored in remote storage.",
@@ -275,7 +275,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -290,7 +290,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Space used in remote storage.",
@@ -341,7 +341,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -356,7 +356,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "",
@@ -420,7 +420,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -435,7 +435,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Status of last retention run.\n\nRetention is a process of removing old backups from remote storage.",
@@ -495,7 +495,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -510,7 +510,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -573,7 +573,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -588,7 +588,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -674,7 +674,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -715,7 +715,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -801,7 +801,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -852,7 +852,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Max duration of backup run. Lower better.\n\nEach backup starts with data upload during `latest` backup. Subsequent backups (`hourly`, `daily`, `weekly`, `monthly`) are copying date by using server-side copy. ",
@@ -931,7 +931,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -946,7 +946,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1020,7 +1020,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1035,7 +1035,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1110,7 +1110,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1125,7 +1125,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1184,7 +1184,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1227,7 +1227,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1298,7 +1298,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1313,7 +1313,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1387,7 +1387,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1416,7 +1416,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Max duration of retention run. Lower better.\n\nRetention is a process of removing old backups from remote storage.",
@@ -1485,7 +1485,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1500,7 +1500,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1574,7 +1574,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1603,7 +1603,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Duration of backup run. Lower better.\n\nEach backup starts with data upload during `latest` backup. Subsequent backups (`hourly`, `daily`, `weekly`, `monthly`) are copying date by using server-side copy.\n",
@@ -1671,7 +1671,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1705,7 +1705,7 @@
"multi": false,
"name": "ds",
"options": [],
"query": "victoriametrics-metrics-datasource",
"query": "victoriametrics-datasource",
"queryValue": "",
"refresh": 1,
"regex": "",
@@ -1764,7 +1764,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"filters": [],

View File

@@ -17,7 +17,7 @@
},
{
"type": "datasource",
"id": "victoriametrics-metrics-datasource",
"id": "victoriametrics-datasource",
"name": "VictoriaMetrics",
"version": "1.0.0"
},
@@ -80,7 +80,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "How many datapoints are inserted into storage per second by accountID and projectID",
@@ -168,7 +168,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -184,7 +184,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Request rate accepted by vmselect nodes per tenant",
@@ -272,7 +272,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -290,7 +290,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the number of active time series with new data points inserted during the last hour. High value may result in ingestion slowdown. \n\nSee following link for details:",
@@ -385,7 +385,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -403,7 +403,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Time spent on query execution per tenant per second",
@@ -491,7 +491,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -509,7 +509,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the amount of on-disk space occupied by data points only. The disk space is used for storing by datapoint and indexdb. There is no option to expose per tenant statistic for indexdb. Usually, indexed takes much less space compared to datapoints. But with a high churn rate, the size of the indexdb could grow significantly.",
@@ -596,7 +596,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -614,7 +614,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Number of new series created over last 24h.",
@@ -702,7 +702,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -731,7 +731,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -785,7 +785,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -800,7 +800,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -853,7 +853,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -868,7 +868,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -921,7 +921,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -936,7 +936,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -991,7 +991,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1006,7 +1006,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1059,7 +1059,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1074,7 +1074,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1127,7 +1127,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1142,7 +1142,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1242,7 +1242,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1260,7 +1260,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1360,7 +1360,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1378,7 +1378,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1478,7 +1478,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1496,7 +1496,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1596,7 +1596,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1614,7 +1614,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1714,7 +1714,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1732,7 +1732,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1832,7 +1832,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1868,7 +1868,7 @@
"multi": false,
"name": "ds",
"options": [],
"query": "victoriametrics-metrics-datasource",
"query": "victoriametrics-datasource",
"queryValue": "",
"refresh": 1,
"regex": "",
@@ -1879,7 +1879,7 @@
"allValue": ".*",
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vm_tenant_active_timeseries, accountID)",
@@ -1905,7 +1905,7 @@
"allValue": ".*",
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vm_tenant_active_timeseries{accountID=~\"$accountID\"},projectID)",
@@ -1929,7 +1929,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "PE8D8DB4BEE4E4B22"
},
"filters": [],

View File

@@ -33,7 +33,7 @@
{
"collapsed": false,
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"gridPos": {
@@ -47,7 +47,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"refId": "A"
@@ -58,7 +58,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"gridPos": {
@@ -81,7 +81,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"refId": "A"
@@ -92,7 +92,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Number of objects at kubernetes cluster per each controller",
@@ -147,7 +147,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -162,7 +162,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -215,7 +215,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -234,7 +234,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": " Shows per namespace watchers for VictoriaMetrics Operator objects (ServiceMonitors, PodMonitors, etc) ",
@@ -288,11 +288,11 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
"expr": "sum(operator_victoriametrics-metrics-datasource_converter_active_watchers)",
"expr": "sum(operator_victoriametrics-datasource_converter_active_watchers)",
"instant": false,
"legendFormat": "__auto",
"range": true,
@@ -304,7 +304,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": " Number of operator instances with obtained leader status. \n Value above 1 indicates that instances with the same job may behave incorrectly.\n It's recommend to check Operator logs. ",
@@ -358,7 +358,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -374,7 +374,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": " Shows number of active reconcile workers",
@@ -428,7 +428,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -444,7 +444,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": " Shows amount of VictoriaMetrics Operator objects processed by Operator.",
@@ -527,11 +527,11 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
"expr": "sum(rate(operator_victoriametrics-metrics-datasource_converter_watch_events_total{job=~\"$job\"}[$__interval])) by (event_type,object_type_name)",
"expr": "sum(rate(operator_victoriametrics-datasource_converter_watch_events_total{job=~\"$job\"}[$__interval])) by (event_type,object_type_name)",
"instant": false,
"legendFormat": "{{object_type_name}} {{event_type}}",
"range": true,
@@ -543,7 +543,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -627,7 +627,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -642,7 +642,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the rate of logging the messages by their level. Unexpected spike in rate is a good reason to check logs.",
@@ -727,7 +727,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -743,7 +743,7 @@
{
"collapsed": false,
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"gridPos": {
@@ -757,7 +757,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"refId": "A"
@@ -768,7 +768,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Non zero metrics indicates about error with CR object definition (typos or incorrect values) or errors with kubernetes API connection.",
@@ -852,7 +852,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -865,7 +865,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -881,7 +881,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Operator limits number of reconcile configuration events to 5 events per 2 seconds by default.",
@@ -965,7 +965,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -980,7 +980,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Number of objects waiting in the queue for reconciliation. Non-zero values indicate that operator cannot process CR objects changes with the given resources.",
@@ -1064,7 +1064,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1079,7 +1079,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": " For controllers with StatefulSet it's ok to see latency greater then 3 seconds. It could be vmalertmanager,vmcluster or vmagent in statefulMode.\n\n For other controllers, latency greater then 2 second may indicate issues with kubernetes cluster or operator's performance.\n ",
@@ -1165,7 +1165,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1180,7 +1180,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Number of HTTP requests to the Kubernetes API server break down by code and method",
@@ -1262,7 +1262,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1278,7 +1278,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows how many ongoing reconcile events are taking place, where:\n* `max` - equal to the value of flag`-controller.maxConcurrentReconciles`;\n* `current` - current number of reconcile workers processing CRD objects.\n\nWhen `current` hits `max` constantly, it means operator cannot process events in time. It should be either increased value for flag `-controller.maxConcurrentReconciles` or allocated additional CPU resources to the operator.",
@@ -1377,7 +1377,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1389,7 +1389,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1406,7 +1406,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the time goroutines have spent in runnable state before actually running. The lower is better.\n\nHigh values or values exceeding the threshold is usually a sign of insufficient CPU resources or CPU throttling. \n\nVerify that service has enough CPU resources. Otherwise, the service could work unreliably with delays in processing.",
@@ -1486,7 +1486,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1502,7 +1502,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": " Requests latency to the Kubernetes API server.",
@@ -1585,7 +1585,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1602,7 +1602,7 @@
{
"collapsed": true,
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"gridPos": {
@@ -1615,7 +1615,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1699,7 +1699,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1710,7 +1710,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1722,7 +1722,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1734,7 +1734,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1750,7 +1750,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1830,7 +1830,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1845,7 +1845,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1925,7 +1925,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1940,7 +1940,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -2023,7 +2023,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2040,7 +2040,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"refId": "A"
@@ -2065,7 +2065,7 @@
"multi": false,
"name": "ds",
"options": [],
"query": "victoriametrics-metrics-datasource",
"query": "victoriametrics-datasource",
"queryValue": "te",
"refresh": 1,
"regex": "",
@@ -2075,7 +2075,7 @@
{
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(operator_log_messages_total,job)",
@@ -2097,7 +2097,7 @@
{
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(operator_log_messages_total{job=~\"$job\"},instance)",
@@ -2119,7 +2119,7 @@
{
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vm_app_version{job=\"$job\", instance=\"$instance\"}, version)",

View File

@@ -11,7 +11,7 @@
},
{
"type": "datasource",
"id": "victoriametrics-metrics-datasource",
"id": "victoriametrics-datasource",
"name": "VictoriaMetrics",
"version": "1.0.0"
},
@@ -50,7 +50,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"enable": true,
@@ -63,7 +63,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"enable": true,
@@ -97,7 +97,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "How many log entries are in storage",
@@ -149,7 +149,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -168,7 +168,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the logs ingestion rate.",
@@ -220,7 +220,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -239,7 +239,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "The ratio of original data size and compressed data stored on disk",
@@ -291,7 +291,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -310,7 +310,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Total number of available CPUs for VM process",
@@ -366,7 +366,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -385,7 +385,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -439,7 +439,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -456,7 +456,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Total amount of used disk space",
@@ -508,7 +508,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -527,7 +527,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the rate of HTTP read requests.",
@@ -579,7 +579,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -598,7 +598,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Total size of available memory for VM process",
@@ -680,7 +680,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "How many logs are inserted into storage per second",
@@ -769,7 +769,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -787,7 +787,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "* `*` - unsupported query path\n* `/insert` - insert into VM\n* `/metrics` - query VL system metrics\n* `/query` - read the data",
@@ -877,7 +877,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -895,7 +895,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the amount of on-disk space occupied by data before and after compressiom",
@@ -985,7 +985,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1003,7 +1003,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "The number of the new log streams created over the last 24h",
@@ -1093,7 +1093,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1111,7 +1111,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the number of restarts per job. The chart can be useful to identify periodic process restarts and correlate them with potential issues or anomalies. Normally, processes shouldn't restart unless restart was inited by user. The reason of restarts should be figured out by checking the logs of each specific service. ",
@@ -1200,7 +1200,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1226,7 +1226,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Percentage of used memory (resident).\nThe application's performance will significantly degrade when memory usage is close to 100%.",
@@ -1315,7 +1315,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1332,7 +1332,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "",
@@ -1421,7 +1421,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(go_memstats_sys_bytes{job=~\"$job\", instance=~\"$instance\"}) + sum(vm_cache_size_bytes{job=~\"$job\", instance=~\"$instance\"})",
@@ -1433,7 +1433,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(go_memstats_heap_inuse_bytes{job=~\"$job\", instance=~\"$instance\"}) + sum(vm_cache_size_bytes{job=~\"$job\", instance=~\"$instance\"})",
@@ -1445,7 +1445,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(go_memstats_stack_inuse_bytes{job=~\"$job\", instance=~\"$instance\"})",
@@ -1457,7 +1457,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(process_resident_memory_bytes{job=~\"$job\", instance=~\"$instance\"})",
@@ -1470,7 +1470,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"exemplar": false,
@@ -1488,7 +1488,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Share for memory allocated by the process itself. When memory usage reaches 100% it will be likely OOM-killed.\nSafe memory usage % considered to be below 80%",
@@ -1577,7 +1577,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1594,7 +1594,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1682,12 +1682,12 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
"exemplar": false,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(instance)",
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n vm_available_cpu_cores{job=~\"$job\", instance=~\"$instance\"}\n) by(instance)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -1701,7 +1701,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the percentage of open file descriptors compared to the limit set in the OS.\nReaching the limit of open files can cause various issues and must be prevented.\n\nSee how to change limits here https://medium.com/@muhammadtriwibowo/set-permanently-ulimit-n-open-files-in-ubuntu-4d61064429a",
@@ -1807,7 +1807,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1826,7 +1826,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "",
@@ -1931,7 +1931,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1945,7 +1945,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"exemplar": false,
@@ -1963,7 +1963,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -2052,7 +2052,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2069,7 +2069,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the number of bytes read/write from the storage layer.",
@@ -2170,7 +2170,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(rate(process_io_storage_read_bytes_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval]))",
@@ -2183,7 +2183,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(rate(process_io_storage_written_bytes_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval]))",
@@ -2200,7 +2200,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -2289,7 +2289,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2306,7 +2306,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the number of read/write syscalls such as read, pread, write, pwrite.",
@@ -2407,7 +2407,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2422,7 +2422,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2441,7 +2441,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "",
@@ -2530,7 +2530,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2548,7 +2548,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "",
@@ -2637,7 +2637,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2655,7 +2655,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the time goroutines have spent in runnable state before actually running. The lower is better.\n\nHigh values or values exceeding the threshold is usually a sign of insufficient CPU resources or CPU throttling. \n\nVerify that service has enough CPU resources. Otherwise, the service could work unreliably with delays in processing.",
@@ -2743,7 +2743,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2780,7 +2780,7 @@
"multi": false,
"name": "ds",
"options": [],
"query": "victoriametrics-metrics-datasource",
"query": "victoriametrics-datasource",
"queryValue": "",
"refresh": 1,
"regex": "",
@@ -2790,7 +2790,7 @@
{
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vm_app_version{version=~\"victoria-logs-.*\"}, job)",
@@ -2812,7 +2812,7 @@
{
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vm_app_version{job=~\"$job\"}, instance)",
@@ -2833,7 +2833,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"filters": [],

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@
},
{
"type": "datasource",
"id": "victoriametrics-metrics-datasource",
"id": "victoriametrics-datasource",
"name": "VictoriaMetrics",
"version": "1.0.0"
},
@@ -56,7 +56,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"enable": true,
@@ -69,7 +69,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"enable": true,
@@ -140,7 +140,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows if the last configuration update was successful. \"Not Ok\" means there was an unsuccessful attempt to update the configuration due to some error. Check the log for details.",
@@ -210,7 +210,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"exemplar": false,
@@ -225,7 +225,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the total number of loaded alerting rules across selected instances and groups.",
@@ -273,7 +273,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"exemplar": false,
@@ -288,7 +288,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the total number of loaded recording rules across selected instances and groups.",
@@ -336,7 +336,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"exemplar": false,
@@ -351,7 +351,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the total number of errors generated by recording/alerting rules for selected instances and groups.",
@@ -403,7 +403,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"exemplar": false,
@@ -418,7 +418,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows number of Recording Rules which produce no data.\n\n Usually it means that such rules are misconfigured, since they give no output during the evaluation.\nPlease check if rule's expression is correct and it is working as expected.",
@@ -470,7 +470,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -487,7 +487,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -568,7 +568,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -584,7 +584,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -672,7 +672,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -716,7 +716,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the number of fired alerts by job.",
@@ -804,7 +804,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -821,7 +821,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Top $topk groups by evaluation duration. Shows groups that take the most of time during the evaluation across all instances.\n\nThe panel uses MetricsQL functions and may not work with VictoriaMetrics.",
@@ -909,7 +909,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -926,7 +926,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows how many requests (executions) per second vmalert sends to the configured datasource.",
@@ -1011,7 +1011,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1028,7 +1028,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the error rate while executing configured rules. Non-zero value means there are some issues with existing rules. Check the logs to get more details.",
@@ -1113,7 +1113,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1144,7 +1144,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "The precentage of used RSS memory\n\nIf you think that usage is abnormal or unexpected, please file an issue and attach memory profile if possible.",
@@ -1241,7 +1241,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1258,7 +1258,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Amount of used RSS memory\n\nIf you think that usage is abnormal or unexpected, please file an issue and attach memory profile if possible.",
@@ -1354,7 +1354,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1371,7 +1371,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the CPU usage percentage per vmalert instance. \nIf you think that usage is abnormal or unexpected pls file an issue and attach CPU profile if possible.",
@@ -1468,12 +1468,12 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
"exemplar": false,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval]) \n / \n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval]) \n / \n vm_available_cpu_cores{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -1487,7 +1487,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the max number of CPU cores used by a `job` and the corresponding limit.",
@@ -1584,7 +1584,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1599,7 +1599,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1619,7 +1619,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Panel shows the percentage of open file descriptors in the OS.\nReaching the limit of open files can cause various issues and must be prevented.\n\nSee how to change limits here https://medium.com/@muhammadtriwibowo/set-permanently-ulimit-n-open-files-in-ubuntu-4d61064429a",
@@ -1709,7 +1709,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1728,7 +1728,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1817,7 +1817,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1835,7 +1835,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the percent of CPU spent on garbage collection.\n\nIf % is high, then CPU usage can be decreased by changing GOGC to higher values. Increasing GOGC value will increase memory usage, and decrease CPU usage.\n\nTry searching for keyword `GOGC` at https://docs.victoriametrics.com/troubleshooting/ ",
@@ -1925,7 +1925,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1943,7 +1943,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the time goroutines have spent in runnable state before actually running. The lower is better.\n\nHigh values or values exceeding the threshold is usually a sign of insufficient CPU resources or CPU throttling. \n\nVerify that service has enough CPU resources. Otherwise, the service could work unreliably with delays in processing.",
@@ -2031,7 +2031,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2072,7 +2072,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -2157,7 +2157,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2202,7 +2202,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Missed evaluation means that group evaluation time takes longer than the configured evaluation interval. \nThis may result in missed alerting notifications or recording rules samples. Try increasing evaluation interval or concurrency for such groups. See https://docs.victoriametrics.com/vmalert/#groups\n\nIf rule expressions are taking longer than expected, please see https://docs.victoriametrics.com/troubleshooting/#slow-queries.\"",
@@ -2287,7 +2287,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2304,7 +2304,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the number of restarts per job. The chart can be useful to identify periodic process restarts and correlate them with potential issues or anomalies. Normally, processes shouldn't restart unless restart was inited by user. The reason of restarts should be figured out by checking the logs of each specific service. ",
@@ -2392,7 +2392,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2426,7 +2426,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows top $topk current active (firing) alerting rules.\n\nThe panel uses MetricsQL functions and may not work with VictoriaMetrics.",
@@ -2511,7 +2511,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2528,7 +2528,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the events when rule execution resulted into an error. Check the logs for more details.",
@@ -2613,7 +2613,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2630,7 +2630,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the current pending alerting rules per group.\nBy pending means the rule which remains active less than configured `for` parameter.",
@@ -2715,7 +2715,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2732,7 +2732,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the error rate for the attempts to send alerts to Alertmanager. If not zero it means there issues on attempt to send notification to Alertmanager and some alerts may be not delivered properly. Check the logs for more details.",
@@ -2816,7 +2816,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"exemplar": false,
@@ -2831,7 +2831,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows how many alerts are sent to Alertmanager per second. Only active alerts are sent.",
@@ -2915,7 +2915,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2959,7 +2959,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the top $topk recording rules which generate the most of [samples](https://docs.victoriametrics.com/keyconcepts/#raw-samples). Each generated sample is basically a time series which then ingested into configured remote storage. Rules with high numbers may cause the most pressure on the remote database and become a source of too high cardinality.\n\nThe panel uses MetricsQL functions and may not work with VictoriaMetrics.",
@@ -3044,7 +3044,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -3061,7 +3061,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the rules which do not produce any [samples](https://docs.victoriametrics.com/keyconcepts/#raw-samples) during the evaluation. Usually it means that such rules are misconfigured, since they give no output during the evaluation.\nPlease check if rule's expression is correct and it is working as expected.",
@@ -3146,7 +3146,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -3163,7 +3163,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -3245,7 +3245,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -3285,7 +3285,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -3361,7 +3361,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -3376,7 +3376,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the number of datapoints dropped by vmalert while sending to the configured remote write URL. vmalert performs up to 5 retries before dropping the data. Check vmalert's error logs for the specific error message.",
@@ -3453,7 +3453,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -3468,7 +3468,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows current number of established connections to remote write endpoints.\n\n",
@@ -3554,7 +3554,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -3571,7 +3571,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the global rate for number of written bytes via remote write connections.",
@@ -3657,7 +3657,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -3696,7 +3696,7 @@
"multi": false,
"name": "ds",
"options": [],
"query": "victoriametrics-metrics-datasource",
"query": "victoriametrics-datasource",
"queryValue": "",
"refresh": 1,
"regex": "",
@@ -3706,7 +3706,7 @@
{
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vm_app_version{version=~\"^vmalert.*\"}, job)",
@@ -3729,7 +3729,7 @@
"allValue": ".*",
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vm_app_version{job=~\"$job\"}, instance)",
@@ -3752,7 +3752,7 @@
"allValue": ".*",
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vmalert_iteration_total{job=~\"$job\", instance=~\"$instance\"},file)",
@@ -3775,7 +3775,7 @@
"allValue": ".*",
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vmalert_iteration_total{job=~\"$job\", instance=~\"$instance\"}, group)",
@@ -3843,7 +3843,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"filters": [],

View File

@@ -11,7 +11,7 @@
},
{
"type": "datasource",
"id": "victoriametrics-metrics-datasource",
"id": "victoriametrics-datasource",
"name": "VictoriaMetrics",
"version": "1.0.0"
},
@@ -116,7 +116,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -204,7 +204,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -222,7 +222,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows if the last configuration update was successful. \"Not Ok\" means there was an unsuccessful attempt to update the configuration due to some error. Check the log for details.",
@@ -292,7 +292,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"exemplar": false,
@@ -307,7 +307,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the rate of requests.",
@@ -356,7 +356,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -372,7 +372,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the total number of users defined at configuration file.",
@@ -420,7 +420,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -437,7 +437,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the rate of request errors.",
@@ -486,7 +486,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -502,7 +502,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -581,7 +581,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -611,7 +611,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -690,7 +690,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -702,7 +702,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -718,7 +718,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows percent utilization of per concurrent requests capacity.",
@@ -805,7 +805,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -822,7 +822,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the rate of rejected requests by a reason.",
@@ -902,7 +902,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -918,7 +918,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": " The number of concurrent connections processed by vmauth reached one of limits. Possible solutions:\n- increase global limit with flag -maxConcurrentRequests\n- increase limit with flag: -maxConcurrentPerUserRequests for all users or with config option `max_concurrent_requests` per user.\n- deploy additional vmauth replicas\n- check requests latency at backend service and allocate resources to it if needed",
@@ -998,7 +998,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1010,7 +1010,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1022,7 +1022,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1038,7 +1038,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows duration in seconds of user requests by quantile.",
@@ -1124,7 +1124,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1136,7 +1136,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1162,7 +1162,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Percentage of used memory (resident).\nThe application's performance will significantly degrade when memory usage is close to 100%.",
@@ -1251,7 +1251,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1268,7 +1268,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -1356,12 +1356,12 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
"exemplar": false,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n vm_available_cpu_cores{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -1375,7 +1375,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "",
@@ -1464,7 +1464,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(go_memstats_sys_bytes{job=~\"$job\", instance=~\"$instance\"}) + sum(vm_cache_size_bytes{job=~\"$job\", instance=~\"$instance\"})",
@@ -1476,7 +1476,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(go_memstats_heap_inuse_bytes{job=~\"$job\", instance=~\"$instance\"}) + sum(vm_cache_size_bytes{job=~\"$job\", instance=~\"$instance\"})",
@@ -1488,7 +1488,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(go_memstats_stack_inuse_bytes{job=~\"$job\", instance=~\"$instance\"})",
@@ -1500,7 +1500,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(process_resident_memory_bytes{job=~\"$job\", instance=~\"$instance\"})",
@@ -1513,7 +1513,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"exemplar": false,
@@ -1531,7 +1531,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "",
@@ -1636,7 +1636,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])",
@@ -1648,7 +1648,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"exemplar": false,
@@ -1666,7 +1666,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "",
@@ -1755,7 +1755,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(vm_tcplistener_conns{job=~\"$job\", instance=~\"$instance\"})",
@@ -1771,7 +1771,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "",
@@ -1860,7 +1860,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -1878,7 +1878,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the percentage of open file descriptors compared to the limit set in the OS.\nReaching the limit of open files can cause various issues and must be prevented.\n\nSee how to change limits here https://medium.com/@muhammadtriwibowo/set-permanently-ulimit-n-open-files-in-ubuntu-4d61064429a",
@@ -1984,7 +1984,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2003,7 +2003,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -2092,7 +2092,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(go_goroutines{job=~\"$job\", instance=~\"$instance\"})",
@@ -2107,7 +2107,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -2196,7 +2196,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"expr": "sum(process_num_threads{job=~\"$job\", instance=~\"$instance\"})",
@@ -2225,7 +2225,7 @@
"panels": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
@@ -2311,7 +2311,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2352,7 +2352,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows number of generated error and warning messages in logs. Non-zero value may be a sign of connectivity or missconfiguration errors.",
@@ -2433,7 +2433,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2448,7 +2448,7 @@
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"description": "Shows the number of restarts per job. The chart can be useful to identify periodic process restarts and correlate them with potential issues or anomalies. Normally, processes shouldn't restart unless restart was inited by user. The reason of restarts should be figured out by checking the logs of each specific service. ",
@@ -2537,7 +2537,7 @@
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
@@ -2573,7 +2573,7 @@
"multi": false,
"name": "ds",
"options": [],
"query": "victoriametrics-metrics-datasource",
"query": "victoriametrics-datasource",
"queryValue": "",
"refresh": 1,
"regex": "",
@@ -2583,7 +2583,7 @@
{
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vm_app_version{version=~\"^vmauth.*\"}, job)",
@@ -2606,7 +2606,7 @@
"allValue": ".*",
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vm_app_version{job=~\"$job\"}, instance)",
@@ -2628,7 +2628,7 @@
{
"current": {},
"datasource": {
"type": "victoriametrics-metrics-datasource",
"type": "victoriametrics-datasource",
"uid": "$ds"
},
"definition": "label_values(vmauth_user_requests_total{job=~\"$job\", instance=~\"$instance\"}, username)",

View File

@@ -1665,7 +1665,7 @@
},
"editorMode": "code",
"exemplar": true,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n vm_available_cpu_cores{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,

View File

@@ -1472,7 +1472,7 @@
},
"editorMode": "code",
"exemplar": false,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval]) \n / \n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval]) \n / \n vm_available_cpu_cores{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,

View File

@@ -1360,7 +1360,7 @@
},
"editorMode": "code",
"exemplar": false,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n vm_available_cpu_cores{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,

View File

@@ -6,7 +6,7 @@ ROOT_IMAGE ?= alpine:3.21.2
ROOT_IMAGE_SCRATCH ?= scratch
CERTS_IMAGE := alpine:3.21.2
GO_BUILDER_IMAGE := golang:1.23.5-alpine
GO_BUILDER_IMAGE := golang:1.23.4-alpine
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 :/ __)
DOCKER ?= docker

View File

@@ -4,7 +4,7 @@ services:
# And forward them to --remoteWrite.url
vmagent:
container_name: vmagent
image: victoriametrics/vmagent:v1.110.0
image: victoriametrics/vmagent:v1.109.0
depends_on:
- "vminsert"
ports:
@@ -39,7 +39,7 @@ services:
# where N is number of vmstorages (2 in this case).
vmstorage-1:
container_name: vmstorage-1
image: victoriametrics/vmstorage:v1.110.0-cluster
image: victoriametrics/vmstorage:v1.109.0-cluster
ports:
- 8482
- 8400
@@ -51,7 +51,7 @@ services:
restart: always
vmstorage-2:
container_name: vmstorage-2
image: victoriametrics/vmstorage:v1.110.0-cluster
image: victoriametrics/vmstorage:v1.109.0-cluster
ports:
- 8482
- 8400
@@ -66,7 +66,7 @@ services:
# pre-process them and distributes across configured vmstorage shards.
vminsert:
container_name: vminsert
image: victoriametrics/vminsert:v1.110.0-cluster
image: victoriametrics/vminsert:v1.109.0-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -81,7 +81,7 @@ services:
# vmselect collects results from configured `--storageNode` shards.
vmselect-1:
container_name: vmselect-1
image: victoriametrics/vmselect:v1.110.0-cluster
image: victoriametrics/vmselect:v1.109.0-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -94,7 +94,7 @@ services:
restart: always
vmselect-2:
container_name: vmselect-2
image: victoriametrics/vmselect:v1.110.0-cluster
image: victoriametrics/vmselect:v1.109.0-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -112,7 +112,7 @@ services:
# It can be used as an authentication proxy.
vmauth:
container_name: vmauth
image: victoriametrics/vmauth:v1.110.0
image: victoriametrics/vmauth:v1.109.0
depends_on:
- "vmselect-1"
- "vmselect-2"
@@ -127,7 +127,7 @@ services:
# vmalert executes alerting and recording rules
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.110.0
image: victoriametrics/vmalert:v1.109.0
depends_on:
- "vmauth"
ports:

View File

@@ -16,7 +16,7 @@ services:
- ./../../dashboards/victoriametrics.json:/var/lib/grafana/dashboards/vm.json
- ./../../dashboards/victorialogs.json:/var/lib/grafana/dashboards/vl.json
environment:
- "GF_INSTALL_PLUGINS=https://github.com/VictoriaMetrics/victorialogs-datasource/releases/download/v0.13.4/victoriametrics-logs-datasource-v0.13.4.zip;victoriametrics-logs-datasource"
- "GF_INSTALL_PLUGINS=https://github.com/VictoriaMetrics/victorialogs-datasource/releases/download/v0.13.0/victoriametrics-logs-datasource-v0.13.0.zip;victoriametrics-logs-datasource"
- "GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=victoriametrics-logs-datasource"
networks:
- vm_net
@@ -45,7 +45,7 @@ services:
# storing logs and serving read queries.
victorialogs:
container_name: victorialogs
image: victoriametrics/victoria-logs:v1.8.0-victorialogs
image: victoriametrics/victoria-logs:v1.6.0-victorialogs
command:
- "--storageDataPath=/vlogs"
- "--httpListenAddr=:9428"
@@ -60,7 +60,7 @@ services:
# scraping, storing metrics and serve read requests.
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.110.0
image: victoriametrics/victoria-metrics:v1.109.0
ports:
- 8428:8428
volumes:
@@ -79,7 +79,7 @@ services:
# depending on the requested path.
vmauth:
container_name: vmauth
image: victoriametrics/vmauth:v1.110.0
image: victoriametrics/vmauth:v1.109.0
depends_on:
- "victoriametrics"
- "victorialogs"
@@ -96,7 +96,7 @@ services:
# vmalert executes alerting and recording rules according to given rule type.
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.110.0
image: victoriametrics/vmalert:v1.109.0
depends_on:
- "vmauth"
- "alertmanager"

View File

@@ -4,7 +4,7 @@ services:
# And forward them to --remoteWrite.url
vmagent:
container_name: vmagent
image: victoriametrics/vmagent:v1.110.0
image: victoriametrics/vmagent:v1.109.0
depends_on:
- "victoriametrics"
ports:
@@ -22,7 +22,7 @@ services:
# storing metrics and serve read requests.
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.110.0
image: victoriametrics/victoria-metrics:v1.109.0
ports:
- 8428:8428
- 8089:8089
@@ -65,7 +65,7 @@ services:
# vmalert executes alerting and recording rules
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.110.0
image: victoriametrics/vmalert:v1.109.0
depends_on:
- "victoriametrics"
- "alertmanager"

View File

@@ -2,7 +2,7 @@ apiVersion: 1
datasources:
- name: VictoriaMetrics - cluster
type: victoriametrics-metrics-datasource
type: victoriametrics-datasource
access: proxy
url: http://vmauth:8427/select/0/prometheus
isDefault: true

View File

@@ -2,7 +2,7 @@ apiVersion: 1
datasources:
- name: VictoriaMetrics
type: victoriametrics-metrics-datasource
type: victoriametrics-datasource
access: proxy
url: http://victoriametrics:8428
isDefault: true

View File

@@ -3,6 +3,16 @@
# The alerts below are just recommendations and may require some updates
# and threshold calibration according to every specific setup.
groups:
- name: alwayFiring
rules:
- alert: AlwaysFiring
expr: up==1
labels:
severity: critical
annotations:
summary: "job {{ $labels.job }} has an instance {{ $labels.instance | stripPort }}"
instance: "{{ $labels.instance }}"
description: "This alert is fine"
- name: vm-health
# note the `job` filter and update accordingly to your setup
rules:

View File

@@ -1,7 +1,7 @@
services:
# meta service will be ignored by compose
.victorialogs:
image: docker.io/victoriametrics/victoria-logs:v1.8.0-victorialogs
image: docker.io/victoriametrics/victoria-logs:v1.6.0-victorialogs
command:
- -storageDataPath=/vlogs
- -loggerFormat=json
@@ -19,7 +19,7 @@ services:
retries: 10
dd-proxy:
image: docker.io/victoriametrics/vmauth:v1.110.0
image: docker.io/victoriametrics/vmauth:v1.109.0
restart: on-failure
volumes:
- ./:/etc/vmauth
@@ -45,7 +45,7 @@ services:
replicas: 0
victoriametrics:
image: victoriametrics/victoria-metrics:v1.110.0
image: victoriametrics/victoria-metrics:latest
ports:
- '8428:8428'
command:

View File

@@ -16,6 +16,6 @@ services:
- ./../../dashboards/vm/vmalert.json:/var/lib/grafana/dashboards/vmalert.json
- ./../../dashboards/vm/vmauth.json:/var/lib/grafana/dashboards/vmauth.json
environment:
- "GF_INSTALL_PLUGINS=https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/v0.12.1/victoriametrics-metrics-datasource-v0.12.1.zip;victoriametrics-metrics-datasource"
- "GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=victoriametrics-metrics-datasource"
- "GF_INSTALL_PLUGINS=https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/v0.10.3/victoriametrics-datasource-v0.10.3.zip;victoriametrics-datasource"
- "GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=victoriametrics-datasource"
restart: always

Some files were not shown because too many files have changed in this diff Show More