mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-05-19 01:36:27 +03:00
Compare commits
115 Commits
test-templ
...
add-tests-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e5527ae57 | ||
|
|
0e08a7a125 | ||
|
|
13c4324bb5 | ||
|
|
95f182053b | ||
|
|
ec64a1fd7c | ||
|
|
f61b5da617 | ||
|
|
3c036e0d31 | ||
|
|
aacb9b2726 | ||
|
|
c753f75e18 | ||
|
|
330461c635 | ||
|
|
5a1a28ba87 | ||
|
|
5b18dc0214 | ||
|
|
10abdf34ab | ||
|
|
e55b5fc605 | ||
|
|
3b34241380 | ||
|
|
de144899b2 | ||
|
|
dc9dba71b2 | ||
|
|
fd1568531d | ||
|
|
46bb2d4308 | ||
|
|
8fa8101677 | ||
|
|
204cec7913 | ||
|
|
17988942ab | ||
|
|
ed05ae12c4 | ||
|
|
256924e2d6 | ||
|
|
b5392337bf | ||
|
|
fa4e3607c3 | ||
|
|
043d066133 | ||
|
|
900159a2d3 | ||
|
|
4464c5a254 | ||
|
|
90fed18b83 | ||
|
|
1480ecc129 | ||
|
|
c67f4d4d86 | ||
|
|
c2f5088adc | ||
|
|
87739bbbef | ||
|
|
dce4dc0a33 | ||
|
|
ad6c587494 | ||
|
|
467cdd8a3d | ||
|
|
026894054b | ||
|
|
db9107acef | ||
|
|
f8a0f2fe44 | ||
|
|
bfd83e3cca | ||
|
|
6b20ec9c7d | ||
|
|
f0d55a1c25 | ||
|
|
f31dece58d | ||
|
|
a6951b8b14 | ||
|
|
d56e3df770 | ||
|
|
d88c1fbdbb | ||
|
|
a947ccf228 | ||
|
|
5747e8b5d0 | ||
|
|
aab0174c94 | ||
|
|
2c271aa9b2 | ||
|
|
7cdeb3a32c | ||
|
|
8c4ac815cb | ||
|
|
dcb6dd5dcb | ||
|
|
be24fbe8ae | ||
|
|
fc1a89f51c | ||
|
|
eddeccfcfb | ||
|
|
b620b5cff5 | ||
|
|
42c21ff671 | ||
|
|
b9eb9fe72d | ||
|
|
9ae49b405c | ||
|
|
f932deb47a | ||
|
|
77f446d095 | ||
|
|
5f8810fc8d | ||
|
|
80ead7cfa4 | ||
|
|
8772288bd6 | ||
|
|
338095fdd3 | ||
|
|
299d66fd98 | ||
|
|
77218c5848 | ||
|
|
9e6fc9269d | ||
|
|
661f9fc3e2 | ||
|
|
2adb5fe014 | ||
|
|
ce917a4cc3 | ||
|
|
b3de1c029c | ||
|
|
461c7a5ad7 | ||
|
|
489631b227 | ||
|
|
e78ff0dc2a | ||
|
|
ab4d9f6213 | ||
|
|
81c313fd89 | ||
|
|
e9de665289 | ||
|
|
bfbe06e912 | ||
|
|
71a7d0db4a | ||
|
|
e8748e4747 | ||
|
|
ad3a5be097 | ||
|
|
17b3f24a37 | ||
|
|
1f0b03aebe | ||
|
|
fc8710c071 | ||
|
|
a7f36eef0e | ||
|
|
54ab08d839 | ||
|
|
a3ea6d9e61 | ||
|
|
f19c760f4f | ||
|
|
86e74de9db | ||
|
|
4d4253ee17 | ||
|
|
8c7b5d22c9 | ||
|
|
513f5da5de | ||
|
|
fb4d545555 | ||
|
|
abaf8574a8 | ||
|
|
f346b5aaaa | ||
|
|
31398cc739 | ||
|
|
4574958e2e | ||
|
|
d623105ef4 | ||
|
|
aac5cd8574 | ||
|
|
d3c02b8f5d | ||
|
|
7f252c1800 | ||
|
|
f73b40619a | ||
|
|
0f7b853a88 | ||
|
|
70f0a974b8 | ||
|
|
2eb15cf30c | ||
|
|
499f0b9588 | ||
|
|
43d615ae87 | ||
|
|
82e1c6fc3f | ||
|
|
45bfe1f44c | ||
|
|
58d2c18423 | ||
|
|
feeda42560 | ||
|
|
7d2a6764e7 |
10
Makefile
10
Makefile
@@ -513,19 +513,19 @@ check-all: fmt vet golangci-lint govulncheck
|
||||
clean-checkers: remove-golangci-lint remove-govulncheck
|
||||
|
||||
test:
|
||||
DISABLE_FSYNC_FOR_TESTING=1 go test ./lib/... ./app/...
|
||||
go test ./lib/... ./app/...
|
||||
|
||||
test-race:
|
||||
DISABLE_FSYNC_FOR_TESTING=1 go test -race ./lib/... ./app/...
|
||||
go test -race ./lib/... ./app/...
|
||||
|
||||
test-pure:
|
||||
DISABLE_FSYNC_FOR_TESTING=1 CGO_ENABLED=0 go test ./lib/... ./app/...
|
||||
CGO_ENABLED=0 go test ./lib/... ./app/...
|
||||
|
||||
test-full:
|
||||
DISABLE_FSYNC_FOR_TESTING=1 go test -coverprofile=coverage.txt -covermode=atomic ./lib/... ./app/...
|
||||
go test -coverprofile=coverage.txt -covermode=atomic ./lib/... ./app/...
|
||||
|
||||
test-full-386:
|
||||
DISABLE_FSYNC_FOR_TESTING=1 GOARCH=386 go test -coverprofile=coverage.txt -covermode=atomic ./lib/... ./app/...
|
||||
GOARCH=386 go test -coverprofile=coverage.txt -covermode=atomic ./lib/... ./app/...
|
||||
|
||||
integration-test: victoria-metrics vmagent vmalert vmauth
|
||||
go test ./apptest/... -skip="^TestCluster.*"
|
||||
|
||||
@@ -199,8 +199,8 @@ func (lmp *logMessageProcessor) AddRow(timestamp int64, fields, streamFields []l
|
||||
lmp.bytesIngestedTotal.Add(n)
|
||||
|
||||
if len(fields) > *MaxFieldsPerLine {
|
||||
rf := logstorage.RowFormatter(fields)
|
||||
logger.Warnf("dropping log line with %d fields; it exceeds -insert.maxFieldsPerLine=%d; %s", len(fields), *MaxFieldsPerLine, rf)
|
||||
line := logstorage.MarshalFieldsToJSON(nil, fields)
|
||||
logger.Warnf("dropping log line with %d fields; it exceeds -insert.maxFieldsPerLine=%d; %s", len(fields), *MaxFieldsPerLine, line)
|
||||
rowsDroppedTotalTooManyFields.Inc()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ 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")
|
||||
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")
|
||||
|
||||
// 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")
|
||||
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")
|
||||
)
|
||||
|
||||
@@ -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
|
||||
\c - compact output mode
|
||||
\logfmt - logfmt output mode
|
||||
\wrap_long_lines - toggles wrapping long lines
|
||||
\tail <query> - live tail <query> results
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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 or foo:baz) error _time:5m {foo="bar",baz="z"}`)
|
||||
f(`foo:(bar or baz) error _time:5m {"foo"=bar,baz="z"}`, `{foo="bar",baz="z"} (foo:bar or foo:baz) error _time:5m`)
|
||||
}
|
||||
|
||||
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 or foo:baz) error _time:5m {foo="bar",baz="z"}`)
|
||||
f(`foo:(bar or baz) error _time:5m {"foo"=bar,baz="z"}`, `{foo="bar",baz="z"} (foo:bar or foo:baz) error _time:5m`)
|
||||
}
|
||||
|
||||
func TestParseExtraStreamFilters_Failure(t *testing.T) {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.4aacd559.css",
|
||||
"main.js": "./static/js/main.5ce54a05.js",
|
||||
"main.css": "./static/css/main.02a1c6cb.css",
|
||||
"main.js": "./static/js/main.55c8060b.js",
|
||||
"static/js/685.f772060c.chunk.js": "./static/js/685.f772060c.chunk.js",
|
||||
"index.html": "./index.html"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.4aacd559.css",
|
||||
"static/js/main.5ce54a05.js"
|
||||
"static/css/main.02a1c6cb.css",
|
||||
"static/js/main.55c8060b.js"
|
||||
]
|
||||
}
|
||||
@@ -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.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>
|
||||
<!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>
|
||||
1
app/vlselect/vmui/static/css/main.02a1c6cb.css
Normal file
1
app/vlselect/vmui/static/css/main.02a1c6cb.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
app/vlselect/vmui/static/js/main.55c8060b.js
Normal file
2
app/vlselect/vmui/static/js/main.55c8060b.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -222,8 +222,7 @@ func processRequest(w http.ResponseWriter, r *http.Request, ui *UserInfo) {
|
||||
isDefault = true
|
||||
}
|
||||
|
||||
rtb := getReadTrackingBody(r.Body, maxRequestBodySizeToRetry.IntN())
|
||||
defer putReadTrackingBody(rtb)
|
||||
rtb := newReadTrackingBody(r.Body, maxRequestBodySizeToRetry.IntN())
|
||||
r.Body = rtb
|
||||
|
||||
maxAttempts := up.getBackendsCount()
|
||||
@@ -559,22 +558,11 @@ type readTrackingBody struct {
|
||||
bufComplete bool
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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{}
|
||||
if maxBodySize < 0 {
|
||||
maxBodySize = 0
|
||||
}
|
||||
@@ -597,13 +585,6 @@ 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 {
|
||||
|
||||
@@ -195,7 +195,7 @@ unauthorized_user:
|
||||
}
|
||||
responseExpected = `
|
||||
statusCode=401
|
||||
The provided authKey doesn't match -reloadAuthKey`
|
||||
Expected to receive non-empty authKey when -reloadAuthKey is set`
|
||||
f(cfgStr, requestURL, backendHandler, responseExpected)
|
||||
if err := reloadAuthKey.Set(origAuthKey); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
@@ -545,8 +545,7 @@ func TestReadTrackingBody_RetrySuccess(t *testing.T) {
|
||||
f := func(s string, maxBodySize int) {
|
||||
t.Helper()
|
||||
|
||||
rtb := getReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
|
||||
defer putReadTrackingBody(rtb)
|
||||
rtb := newReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
|
||||
|
||||
if !rtb.canRetry() {
|
||||
t.Fatalf("canRetry() must return true before reading anything")
|
||||
@@ -581,8 +580,7 @@ func TestReadTrackingBody_RetrySuccessPartialRead(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
// Check the case with partial read
|
||||
rtb := getReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
|
||||
defer putReadTrackingBody(rtb)
|
||||
rtb := newReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
|
||||
|
||||
for i := 0; i < len(s); i++ {
|
||||
buf := make([]byte, i)
|
||||
@@ -631,8 +629,7 @@ func TestReadTrackingBody_RetryFailureTooBigBody(t *testing.T) {
|
||||
f := func(s string, maxBodySize int) {
|
||||
t.Helper()
|
||||
|
||||
rtb := getReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
|
||||
defer putReadTrackingBody(rtb)
|
||||
rtb := newReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
|
||||
|
||||
if !rtb.canRetry() {
|
||||
t.Fatalf("canRetry() must return true before reading anything")
|
||||
@@ -681,8 +678,7 @@ func TestReadTrackingBody_RetryFailureZeroOrNegativeMaxBodySize(t *testing.T) {
|
||||
f := func(s string, maxBodySize int) {
|
||||
t.Helper()
|
||||
|
||||
rtb := getReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
|
||||
defer putReadTrackingBody(rtb)
|
||||
rtb := newReadTrackingBody(io.NopCloser(bytes.NewBufferString(s)), maxBodySize)
|
||||
|
||||
if !rtb.canRetry() {
|
||||
t.Fatalf("canRetry() must return true before reading anything")
|
||||
|
||||
@@ -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 overrides -httpAuth.*")
|
||||
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.*")
|
||||
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 overrides -httpAuth.*")
|
||||
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.*")
|
||||
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")
|
||||
|
||||
@@ -481,6 +481,8 @@ 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)
|
||||
}
|
||||
|
||||
@@ -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, _ []int64) {
|
||||
removeCounterResets(values)
|
||||
preFunc = func(values []float64, timestamps []int64) {
|
||||
removeCounterResets(values, timestamps, lookbackDelta)
|
||||
}
|
||||
}
|
||||
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, _ []int64) {
|
||||
removeCounterResets(values)
|
||||
preFunc = func(values []float64, timestamps []int64) {
|
||||
removeCounterResets(values, timestamps, lookbackDelta)
|
||||
}
|
||||
}
|
||||
rf := rollupAggrFuncs[aggrFuncName]
|
||||
@@ -521,7 +521,7 @@ type rollupFuncArg struct {
|
||||
timestamps []int64
|
||||
|
||||
// Real value preceding values.
|
||||
// Is populated if preceding value is within the staleness interval.
|
||||
// Is populated if preceding value is within the -search.maxStalenessInterval (rc.LookbackDelta).
|
||||
realPrevValue float64
|
||||
|
||||
// Real value which goes after values.
|
||||
@@ -768,7 +768,13 @@ func (rc *rollupConfig) doInternal(dstValues []float64, tsm *timeseriesMap, valu
|
||||
rfa.realPrevValue = nan
|
||||
if i > 0 {
|
||||
prevValue, prevTimestamp := values[i-1], timestamps[i-1]
|
||||
if (tEnd - prevTimestamp) < maxPrevInterval {
|
||||
// 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 {
|
||||
rfa.realPrevValue = prevValue
|
||||
}
|
||||
}
|
||||
@@ -894,7 +900,7 @@ func getMaxPrevInterval(scrapeInterval int64) int64 {
|
||||
return scrapeInterval + scrapeInterval/8
|
||||
}
|
||||
|
||||
func removeCounterResets(values []float64) {
|
||||
func removeCounterResets(values []float64, timestamps []int64, maxStalenessInterval int64) {
|
||||
// There is no need in handling NaNs here, since they are impossible
|
||||
// on values from vmstorage.
|
||||
if len(values) == 0 {
|
||||
@@ -913,6 +919,16 @@ func removeCounterResets(values []float64) {
|
||||
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,
|
||||
|
||||
@@ -117,31 +117,49 @@ func TestRollupIderivDuplicateTimestamps(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRemoveCounterResets(t *testing.T) {
|
||||
removeCounterResets(nil)
|
||||
removeCounterResets(nil, nil, 0)
|
||||
|
||||
values := append([]float64{}, testValues...)
|
||||
removeCounterResets(values)
|
||||
timestamps := append([]int64{}, testTimestamps...)
|
||||
removeCounterResets(values, timestamps, 0)
|
||||
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}
|
||||
removeCounterResets(values)
|
||||
valuesExpected = []float64{-100, -100, -100, -100}
|
||||
timestampsExpected := []int64{0, 1, 2, 3}
|
||||
removeCounterResets(values, timestampsExpected, 0)
|
||||
valuesExpected = []float64{-100, -100, -100, -100}
|
||||
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}
|
||||
removeCounterResets(values)
|
||||
valuesExpected = []float64{100, 100, 125, 125, 145, 195}
|
||||
timestampsExpected = []int64{0, 1, 2, 3, 4, 5}
|
||||
removeCounterResets(values, timestampsExpected, 0)
|
||||
valuesExpected = []float64{100, 100, 125, 125, 145, 195}
|
||||
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}
|
||||
removeCounterResets(values)
|
||||
timestampsExpected = []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
removeCounterResets(values, timestampsExpected, 0)
|
||||
var prev float64
|
||||
for i, v := range values {
|
||||
if v < prev {
|
||||
@@ -166,7 +184,7 @@ func TestDeltaValues(t *testing.T) {
|
||||
|
||||
// remove counter resets
|
||||
values = append([]float64{}, testValues...)
|
||||
removeCounterResets(values)
|
||||
removeCounterResets(values, testTimestamps, 0)
|
||||
deltaValues(values)
|
||||
valuesExpected = []float64{34, 10, 21, 33, 34, 65, 12, 32, 32, 2, 0, 0}
|
||||
testRowsEqual(t, values, testTimestamps, valuesExpected, testTimestamps)
|
||||
@@ -188,7 +206,7 @@ func TestDerivValues(t *testing.T) {
|
||||
|
||||
// remove counter resets
|
||||
values = append([]float64{}, testValues...)
|
||||
removeCounterResets(values)
|
||||
removeCounterResets(values, testTimestamps, 0)
|
||||
derivValues(values, testTimestamps)
|
||||
valuesExpected = []float64{3400, 1111.111111111111, 1750, 2538.4615384615386, 3090.909090909091, 3611.1111111111113,
|
||||
6000, 1882.3529411764705, 1777.7777777777778, 400, 0, 0}
|
||||
@@ -219,7 +237,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)
|
||||
removeCounterResets(rfa.values, rfa.timestamps, 0)
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
v := rf(&rfa)
|
||||
@@ -1590,17 +1608,60 @@ func TestRollupDelta(t *testing.T) {
|
||||
f(100, nan, nan, nil, 0)
|
||||
}
|
||||
|
||||
func TestRollupIncreaseWithStaleness(t *testing.T) {
|
||||
func TestRollupDeltaWithStaleness(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}
|
||||
|
||||
t.Run("step > gap", func(t *testing.T) {
|
||||
// if step > gap, then delta will always respect value before gap
|
||||
t.Run("step>gap", func(t *testing.T) {
|
||||
rc := rollupConfig{
|
||||
Func: rollupDelta,
|
||||
Start: 0,
|
||||
End: 70000,
|
||||
Step: 35000,
|
||||
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,
|
||||
Window: 0,
|
||||
MaxPointsPerSeries: 1e4,
|
||||
}
|
||||
@@ -1609,12 +1670,14 @@ func TestRollupIncreaseWithStaleness(t *testing.T) {
|
||||
if samplesScanned != 8 {
|
||||
t.Fatalf("expecting 8 samplesScanned from rollupConfig.Do; got %d", samplesScanned)
|
||||
}
|
||||
valuesExpected := []float64{1, 0, 0}
|
||||
timestampsExpected := []int64{0, 35e3, 70e3}
|
||||
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)
|
||||
})
|
||||
|
||||
t.Run("step < gap", func(t *testing.T) {
|
||||
// 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: rollupDelta,
|
||||
Start: 0,
|
||||
@@ -1622,6 +1685,7 @@ func TestRollupIncreaseWithStaleness(t *testing.T) {
|
||||
Step: 10000,
|
||||
Window: 0,
|
||||
MaxPointsPerSeries: 1e4,
|
||||
LookbackDelta: 30e3,
|
||||
}
|
||||
rc.Timestamps = rc.getTimestamps()
|
||||
gotValues, samplesScanned := rc.Do(nil, values, timestamps)
|
||||
@@ -1656,3 +1720,116 @@ func TestRollupIncreaseWithStaleness(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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ 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. "+
|
||||
@@ -58,6 +59,12 @@ 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 {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.63479b72.css",
|
||||
"main.js": "./static/js/main.256ee243.js",
|
||||
"main.css": "./static/css/main.af583aad.css",
|
||||
"main.js": "./static/js/main.1413b18d.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.63479b72.css",
|
||||
"static/js/main.256ee243.js"
|
||||
"static/css/main.af583aad.css",
|
||||
"static/js/main.1413b18d.js"
|
||||
]
|
||||
}
|
||||
@@ -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.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>
|
||||
<!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>
|
||||
File diff suppressed because one or more lines are too long
2
app/vmselect/vmui/static/js/main.1413b18d.js
Normal file
2
app/vmselect/vmui/static/js/main.1413b18d.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.23.4 AS build-web-stage
|
||||
FROM golang:1.23.5 AS build-web-stage
|
||||
COPY build /build
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import uPlot from "uplot";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
export interface MetricBase {
|
||||
group: number;
|
||||
metric: {
|
||||
@@ -6,13 +9,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 {
|
||||
@@ -44,9 +47,23 @@ export interface LogHits {
|
||||
timestamps: string[];
|
||||
values: number[];
|
||||
total?: number;
|
||||
fields: {
|
||||
[key: string]: string;
|
||||
};
|
||||
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;
|
||||
}
|
||||
|
||||
export interface ReportMetaData {
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
import React, { FC, useMemo, useRef, useState } from "preact/compat";
|
||||
import React, { FC, useCallback, 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 from "./hooks/useBarHitsOptions";
|
||||
import useBarHitsOptions, { getLabelFromLogHit } 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 { LogHits } from "../../../api/types";
|
||||
import { LegendLogHits, 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[];
|
||||
@@ -57,6 +58,29 @@ 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);
|
||||
@@ -121,6 +145,7 @@ const BarHitsChart: FC<Props> = ({ logHits, data: _data, period, setPeriod, onAp
|
||||
<BarHitsLegend
|
||||
uPlotInst={uPlotInst}
|
||||
onApplyFilter={onApplyFilter}
|
||||
legendDetails={legendDetails}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,83 +1,53 @@
|
||||
import React, { FC, useCallback, useEffect, useState } from "preact/compat";
|
||||
import React, { FC, useEffect, useState } from "preact/compat";
|
||||
import uPlot, { Series } from "uplot";
|
||||
import "./style.scss";
|
||||
import "../../Line/Legend/style.scss";
|
||||
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";
|
||||
import BarHitsLegendItem from "./BarHitsLegendItem";
|
||||
import { LegendLogHits } from "../../../../api/types";
|
||||
|
||||
interface Props {
|
||||
uPlotInst: uPlot;
|
||||
legendDetails: LegendLogHits[];
|
||||
onApplyFilter: (value: string) => void;
|
||||
}
|
||||
|
||||
const BarHitsLegend: FC<Props> = ({ uPlotInst, onApplyFilter }) => {
|
||||
const BarHitsLegend: FC<Props> = ({ uPlotInst, legendDetails, onApplyFilter }) => {
|
||||
const [series, setSeries] = useState<Series[]>([]);
|
||||
const [pairs, setPairs] = useState<string[][]>([]);
|
||||
const totalHits = legendDetails[0]?.totalHits || 0;
|
||||
|
||||
const updateSeries = useCallback(() => {
|
||||
const series = uPlotInst.series.filter(s => s.scale !== "x");
|
||||
setSeries(series);
|
||||
setPairs(series.map(s => getStreamPairs(s.label || "")));
|
||||
const getSeries = () => {
|
||||
return uPlotInst.series.filter(s => s.scale !== "x");
|
||||
};
|
||||
|
||||
const handleRedrawGraph = () => {
|
||||
uPlotInst.redraw();
|
||||
setSeries(getSeries());
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setSeries(getSeries());
|
||||
}, [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">
|
||||
{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>
|
||||
{legendDetails.map((legend) => (
|
||||
<BarHitsLegendItem
|
||||
key={legend.label}
|
||||
legend={legend}
|
||||
series={series}
|
||||
onRedrawGraph={handleRedrawGraph}
|
||||
onApplyFilter={onApplyFilter}
|
||||
/>
|
||||
))}
|
||||
<div className="vm-bar-hits-legend-info">
|
||||
<div>
|
||||
Total hits: <b>{totalHits.toLocaleString("en-US")}</b>
|
||||
</div>
|
||||
<div>
|
||||
<code>L-Click</code> toggles visibility.
|
||||
<code>R-Click</code> opens menu.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
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;
|
||||
@@ -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 {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
max-width: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $padding-small;
|
||||
font-size: 12px;
|
||||
padding: 0 $padding-small;
|
||||
font-size: $font-size-small;
|
||||
padding: $padding-small $padding-global;
|
||||
border-radius: $border-radius-small;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
@@ -27,34 +27,44 @@
|
||||
}
|
||||
|
||||
&__marker {
|
||||
width: 14px;
|
||||
min-width: 14px;
|
||||
max-width: 14px;
|
||||
height: 14px;
|
||||
border: $color-background-block;
|
||||
}
|
||||
|
||||
&-pairs {
|
||||
display: flex;
|
||||
gap: $padding-small;
|
||||
&__label {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&__value {
|
||||
padding: $padding-small 0;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: ",";
|
||||
}
|
||||
|
||||
&:last-child:after {
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
&__total {
|
||||
color: $color-text-secondary;
|
||||
font-style: italic;
|
||||
grid-column: 2;
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
list-style-position: inside;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ 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";
|
||||
@@ -24,27 +23,20 @@ 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(false, "fill");
|
||||
const [fill, setFill] = useStateSearchParams("true", "fill");
|
||||
const [hideChart, setHideChart] = useStateSearchParams(false, "hide_chart");
|
||||
|
||||
const options: GraphOptions = useMemo(() => ({
|
||||
graphStyle,
|
||||
graphStyle: GRAPH_STYLES.BAR,
|
||||
stacked,
|
||||
fill,
|
||||
fill: fill === "true",
|
||||
hideChart,
|
||||
}), [graphStyle, stacked, fill, hideChart]);
|
||||
|
||||
const handleChangeGraphStyle = (val: string) => () => {
|
||||
setGraphStyle(val as GRAPH_STYLES);
|
||||
searchParams.set("graph", val);
|
||||
setSearchParams(searchParams);
|
||||
};
|
||||
}), [stacked, fill, hideChart]);
|
||||
|
||||
const handleChangeFill = (val: boolean) => {
|
||||
setFill(val);
|
||||
val ? searchParams.set("fill", "true") : searchParams.delete("fill");
|
||||
setFill(`${val}`);
|
||||
searchParams.set("fill", `${val}`);
|
||||
setSearchParams(searchParams);
|
||||
};
|
||||
|
||||
@@ -97,21 +89,6 @@ 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"}
|
||||
@@ -122,7 +99,7 @@ const BarHitsOptions: FC<Props> = ({ onChange }) => {
|
||||
<div className="vm-bar-hits-options-settings-item">
|
||||
<Switch
|
||||
label={"Fill"}
|
||||
value={fill}
|
||||
value={fill === "true"}
|
||||
onChange={handleChangeFill}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
&-settings {
|
||||
display: grid;
|
||||
align-items: flex-start;
|
||||
gap: $padding-global;
|
||||
min-width: 200px;
|
||||
gap: $padding-global;
|
||||
padding-bottom: $padding-global;
|
||||
|
||||
&-item {
|
||||
border-bottom: $border-divider;
|
||||
padding: 0 $padding-global $padding-global;
|
||||
padding: 0 $padding-global;
|
||||
|
||||
&_list {
|
||||
padding: 0;
|
||||
|
||||
@@ -5,6 +5,7 @@ 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;
|
||||
@@ -26,7 +27,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 || "other";
|
||||
const label = targetSeries?.label;
|
||||
const show = targetSeries?.show;
|
||||
return {
|
||||
label,
|
||||
@@ -34,7 +35,7 @@ const BarHitsTooltip: FC<Props> = ({ data, focusDataIdx, uPlotInst }) => {
|
||||
value,
|
||||
show
|
||||
};
|
||||
}).filter(item => item.value > 0 && item.show).sort((a, b) => b.value - a.value);
|
||||
}).filter(item => item.value > 0 && item.show).sort(sortLogHits("value"));
|
||||
|
||||
const point = {
|
||||
top: tooltipItems[0] ? uPlotInst?.valToPos?.(tooltipItems[0].value, "y") || 0 : 0,
|
||||
@@ -104,16 +105,19 @@ const BarHitsTooltip: FC<Props> = ({ data, focusDataIdx, uPlotInst }) => {
|
||||
className="vm-chart-tooltip-data__marker"
|
||||
style={{ background: item.stroke }}
|
||||
/>
|
||||
<p>
|
||||
{item.label}: <b>{item.value}</b>
|
||||
<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>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{tooltipData.values.length > 1 && (
|
||||
<div className="vm-chart-tooltip-data">
|
||||
<p>
|
||||
Total records: <b>{tooltipData.total}</b>
|
||||
<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>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -9,4 +9,19 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
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;
|
||||
@@ -0,0 +1,64 @@
|
||||
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;
|
||||
@@ -0,0 +1,74 @@
|
||||
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;
|
||||
@@ -0,0 +1,116 @@
|
||||
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;
|
||||
@@ -0,0 +1,23 @@
|
||||
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;
|
||||
@@ -0,0 +1,178 @@
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,14 @@ 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,
|
||||
@@ -59,12 +67,12 @@ const useBarHitsOptions = ({
|
||||
let colorN = 0;
|
||||
return data.map((_d, i) => {
|
||||
if (i === 0) return {}; // 0 index is xAxis(timestamps)
|
||||
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++;
|
||||
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++;
|
||||
return {
|
||||
label: label || "other",
|
||||
label,
|
||||
width: strokeWidth[graphOptions.graphStyle],
|
||||
spanGaps: true,
|
||||
stroke: color,
|
||||
|
||||
@@ -32,6 +32,11 @@ $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;
|
||||
@@ -90,6 +95,8 @@ $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);
|
||||
|
||||
@@ -124,7 +124,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setOpenAutocomplete(!!AutocompleteEl);
|
||||
setOpenAutocomplete(!!AutocompleteEl && autocompleteQuick);
|
||||
}, [autocompleteQuick]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
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 "+N more" badge for extra fields.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GroupLogsConfigurators;
|
||||
@@ -0,0 +1,48 @@
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,10 @@ const Accordion: FC<AccordionProps> = ({
|
||||
onChange && onChange(isOpen);
|
||||
}, [isOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsOpen(defaultExpanded);
|
||||
}, [defaultExpanded]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<header
|
||||
|
||||
@@ -581,3 +581,45 @@ 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>
|
||||
);
|
||||
|
||||
@@ -67,11 +67,11 @@ const Modal: FC<ModalProps> = ({
|
||||
})}
|
||||
onMouseDown={onClose}
|
||||
>
|
||||
<div className="vm-modal-content">
|
||||
<div
|
||||
className="vm-modal-content-header"
|
||||
onMouseDown={handleMouseDown}
|
||||
>
|
||||
<div
|
||||
className="vm-modal-content"
|
||||
onMouseDown={handleMouseDown}
|
||||
>
|
||||
<div className="vm-modal-content-header">
|
||||
{title && (
|
||||
<div className="vm-modal-content-header__title">
|
||||
{title}
|
||||
@@ -91,7 +91,6 @@ const Modal: FC<ModalProps> = ({
|
||||
{/* tabIndex to fix Ctrl-A */}
|
||||
<div
|
||||
className="vm-modal-content-body"
|
||||
onMouseDown={handleMouseDown}
|
||||
tabIndex={0}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -15,9 +15,10 @@ interface PopperProps {
|
||||
open: boolean
|
||||
onClose: () => void
|
||||
buttonRef: React.RefObject<HTMLElement>
|
||||
placement?: "bottom-right" | "bottom-left" | "top-left" | "top-right"
|
||||
placement?: "bottom-right" | "bottom-left" | "top-left" | "top-right" | "fixed"
|
||||
placementPosition?: { top: number, left: number } | null
|
||||
animation?: string
|
||||
offset?: {top: number, left: number}
|
||||
offset?: { top: number, left: number }
|
||||
clickOutside?: boolean,
|
||||
fullWidth?: boolean
|
||||
title?: string
|
||||
@@ -29,6 +30,7 @@ const Popper: FC<PopperProps> = ({
|
||||
children,
|
||||
buttonRef,
|
||||
placement = "bottom-left",
|
||||
placementPosition,
|
||||
open = false,
|
||||
onClose,
|
||||
offset = { top: 6, left: 0 },
|
||||
@@ -92,13 +94,18 @@ const Popper: FC<PopperProps> = ({
|
||||
if (needAlignRight) position.left = buttonPos.right - popperSize.width;
|
||||
if (needAlignTop) position.top = buttonPos.top - popperSize.height - offsetTop;
|
||||
|
||||
const { innerWidth, innerHeight } = window;
|
||||
const margin = 20;
|
||||
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 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;
|
||||
const { innerWidth, innerHeight } = window;
|
||||
|
||||
const isOverflowBottom = (position.top + popperSize.height) > innerHeight;
|
||||
const isOverflowTop = (position.top) < 0;
|
||||
const isOverflowRight = (position.left + popperSize.width) > innerWidth;
|
||||
const isOverflowLeft = (position.left) < 0;
|
||||
|
||||
if (isOverflowBottom) position.top = buttonPos.top - popperSize.height - offsetTop;
|
||||
if (isOverflowTop) position.top = buttonPos.height + buttonPos.top + offsetTop;
|
||||
@@ -106,11 +113,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 = 20;
|
||||
if (position.left < 0) position.left = 20;
|
||||
if (position.top < 0) position.top = 0;
|
||||
if (position.left < 0) position.left = 0;
|
||||
|
||||
return position;
|
||||
},[buttonRef, placement, isOpen, children, fullWidth]);
|
||||
}, [buttonRef, placement, isOpen, children, fullWidth]);
|
||||
|
||||
const handleClickClose = (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
e.stopPropagation();
|
||||
@@ -131,10 +138,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 - 20 - width;
|
||||
popperRef.current.style.left = left < window.innerWidth ? "0" : `${left}px`;
|
||||
const left = window.innerWidth - width;
|
||||
popperRef.current.style.left = `${left}px`;
|
||||
}
|
||||
}, [isOpen, popperRef]);
|
||||
}, [isOpen, popperRef, placementPosition]);
|
||||
|
||||
const handlePopstate = useCallback(() => {
|
||||
if (isOpen && isMobile && !disabledFullScreen) {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
border-radius: $border-radius-small;
|
||||
|
||||
&_open {
|
||||
z-index: 101;
|
||||
z-index: 100;
|
||||
opacity: 1;
|
||||
transform-origin: top center;
|
||||
animation: vm-slider 150ms cubic-bezier(0.280, 0.840, 0.420, 1.1);
|
||||
|
||||
@@ -33,9 +33,9 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: $color-hover-black;
|
||||
padding: 2px 2px 2px 6px;
|
||||
padding: 2px 2px 2px $padding-small;
|
||||
border-radius: $border-radius-small;
|
||||
font-size: $font-size;
|
||||
font-size: $font-size-small;
|
||||
line-height: $font-size;
|
||||
max-width: 100%;
|
||||
|
||||
|
||||
@@ -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 { getFromStorage, removeFromStorage, saveToStorage } from "../../../utils/storage";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
|
||||
const title = "Table settings";
|
||||
|
||||
@@ -30,6 +30,8 @@ const TableSettings: FC<TableSettingsProps> = ({
|
||||
onChangeColumns,
|
||||
toggleTableCompact
|
||||
}) => {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
const buttonRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const {
|
||||
@@ -38,11 +40,6 @@ 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);
|
||||
|
||||
@@ -60,15 +57,34 @@ 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) => {
|
||||
onChangeColumns(selectedColumns.includes(key) ? selectedColumns.filter(col => col !== key) : [...selectedColumns, key]);
|
||||
const displayColumns = selectedColumns.includes(key)
|
||||
? selectedColumns.filter(col => col !== key)
|
||||
: [...selectedColumns, key];
|
||||
|
||||
handleChangeDisplayColumns(displayColumns);
|
||||
};
|
||||
|
||||
const toggleAllColumns = () => {
|
||||
if (isAllChecked) {
|
||||
onChangeColumns(selectedColumns.filter(col => !filteredColumns.includes(col)));
|
||||
handleChangeDisplayColumns(selectedColumns.filter(col => !filteredColumns.includes(col)));
|
||||
} else {
|
||||
onChangeColumns(filteredColumns);
|
||||
handleChangeDisplayColumns(filteredColumns);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -95,22 +111,16 @@ const TableSettings: FC<TableSettingsProps> = ({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (arrayEquals(columns, selectedColumns) || saveColumns) return;
|
||||
if (arrayEquals(columns, selectedColumns) || searchParams.has("columns")) return;
|
||||
onChangeColumns(columns);
|
||||
}, [columns]);
|
||||
|
||||
useEffect(() => {
|
||||
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(","));
|
||||
const hasColumns = searchParams.has("columns");
|
||||
if (!hasColumns) return;
|
||||
const columnsParam = searchParams.get("columns") || "";
|
||||
const columnsArray = columnsParam.split(",").map(decodeURIComponent).filter(Boolean);
|
||||
onChangeColumns(columnsArray);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@@ -183,19 +193,6 @@ 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">
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
.vm-table-settings {
|
||||
&-modal {
|
||||
.vm-modal-content-body {
|
||||
min-width: clamp(300px, 600px, 90vw);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -83,16 +84,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-preserve {
|
||||
padding: $padding-global;
|
||||
|
||||
&__info {
|
||||
padding-top: $padding-small;
|
||||
font-size: $font-size-small;
|
||||
color: $color-text-secondary;
|
||||
line-height: 130%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,22 @@
|
||||
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",
|
||||
};
|
||||
|
||||
@@ -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("mousedown", listener);
|
||||
useEventListener("mouseup", listener);
|
||||
useEventListener("touchstart", listener);
|
||||
};
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ const ExploreLogs: FC = () => {
|
||||
};
|
||||
|
||||
const handleApplyFilter = (val: string) => {
|
||||
setQuery(prev => `_stream: ${val === "other" ? "{}" : val} AND (${prev})`);
|
||||
setQuery(prev => `${val} AND (${prev})`);
|
||||
setIsUpdatingQuery(true);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
import React, { FC, useCallback, useEffect, useMemo, useRef } from "preact/compat";
|
||||
import { MouseEvent, useState } from "react";
|
||||
import React, { FC, useCallback, useEffect, useMemo } from "preact/compat";
|
||||
import { 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, 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 { CollapseIcon, ExpandIcon } from "../../../components/Main/Icons";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import { getStreamPairs } from "../../../utils/logs";
|
||||
|
||||
const WITHOUT_GROUPING = "No Grouping";
|
||||
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";
|
||||
|
||||
interface Props {
|
||||
logs: Logs[];
|
||||
@@ -26,73 +21,31 @@ interface Props {
|
||||
}
|
||||
|
||||
const GroupLogs: FC<Props> = ({ logs, settingsRef }) => {
|
||||
const { isDarkTheme } = useAppState();
|
||||
const copyToClipboard = useCopyToClipboard();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [searchParams] = 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 {
|
||||
value: openOptions,
|
||||
toggle: toggleOpenOptions,
|
||||
setFalse: handleCloseOptions,
|
||||
} = useBoolean(false);
|
||||
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 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) => a.keysString.localeCompare(b.keysString)); // groups sorting
|
||||
}).sort((a, b) => b.values.length - a.values.length); // 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]);
|
||||
@@ -105,11 +58,6 @@ 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));
|
||||
@@ -124,38 +72,16 @@ const GroupLogs: FC<Props> = ({ logs, settingsRef }) => {
|
||||
key={item.keysString}
|
||||
>
|
||||
<Accordion
|
||||
key={String(expandGroups[i])}
|
||||
defaultExpanded={expandGroups[i]}
|
||||
onChange={handleChangeExpand(i)}
|
||||
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>
|
||||
)}
|
||||
title={groupBy !== WITHOUT_GROUPING && <GroupLogsHeader group={item}/>}
|
||||
>
|
||||
<div className="vm-group-logs-section-rows">
|
||||
{item.values.map((value) => (
|
||||
<GroupLogsItem
|
||||
key={`${value._msg}${value._time}`}
|
||||
log={value}
|
||||
displayFields={displayFields}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -175,47 +101,7 @@ const GroupLogs: FC<Props> = ({ logs, settingsRef }) => {
|
||||
ariaLabel={expandAll ? "Collapse All" : "Expand All"}
|
||||
/>
|
||||
</Tooltip>
|
||||
<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>
|
||||
}
|
||||
<GroupLogsConfigurators logs={logs}/>
|
||||
</div>
|
||||
), settingsRef.current)}
|
||||
</>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
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 } from "../../../components/Main/Icons";
|
||||
import { CopyIcon, StorageIcon, VisibilityIcon } 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;
|
||||
@@ -11,8 +13,17 @@ 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 {
|
||||
@@ -23,6 +34,18 @@ 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);
|
||||
@@ -35,6 +58,7 @@ 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"
|
||||
@@ -43,6 +67,34 @@ 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>
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
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;
|
||||
@@ -0,0 +1,59 @@
|
||||
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;
|
||||
@@ -6,28 +6,34 @@ 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 }) => {
|
||||
const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
|
||||
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(`${DATE_TIME_FORMAT}.SSS`);
|
||||
}, [log._time, timezone]);
|
||||
return dayjs(log._time).tz().format(dateFormat);
|
||||
}, [log._time, timezone, dateFormat]);
|
||||
|
||||
const formattedMarkdown = useMemo(() => {
|
||||
if (!markdownParsing || !log._msg) return "";
|
||||
@@ -38,6 +44,14 @@ const GroupLogsItem: FC<Props> = ({ log }) => {
|
||||
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]) => {
|
||||
@@ -45,7 +59,7 @@ const GroupLogsItem: FC<Props> = ({ log }) => {
|
||||
return obj;
|
||||
}, {});
|
||||
return JSON.stringify(dataObject);
|
||||
}, [log, fields, hasFields]);
|
||||
}, [log, fields, hasFields, displayFields]);
|
||||
|
||||
return (
|
||||
<div className="vm-group-logs-row">
|
||||
@@ -76,7 +90,8 @@ const GroupLogsItem: FC<Props> = ({ log }) => {
|
||||
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_missing": !displayMessage,
|
||||
"vm-group-logs-row-content__msg_single-line": noWrapLines,
|
||||
})}
|
||||
dangerouslySetInnerHTML={(markdownParsing && formattedMarkdown) ? { __html: formattedMarkdown } : undefined}
|
||||
>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
@use "src/styles/variables" as *;
|
||||
|
||||
$font-size-logs: var(--font-size-logs, $font-size-small);
|
||||
|
||||
.vm-group-logs {
|
||||
margin-top: calc(-1 * $padding-medium);
|
||||
|
||||
@@ -19,22 +21,44 @@
|
||||
}
|
||||
|
||||
&-section {
|
||||
border-bottom: $border-divider;
|
||||
|
||||
&-keys {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: $padding-small;
|
||||
border-bottom: $border-divider;
|
||||
padding: $padding-small 0;
|
||||
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;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
|
||||
code {
|
||||
font-family: monospace;
|
||||
|
||||
&:before {
|
||||
content: "\"";
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: "\"";
|
||||
}
|
||||
@@ -42,19 +66,35 @@
|
||||
}
|
||||
|
||||
&__count {
|
||||
position: absolute;
|
||||
top: auto;
|
||||
right: 0;
|
||||
flex-grow: 1;
|
||||
text-align: right;
|
||||
font-size: $font-size-small;
|
||||
font-size: $font-size-logs;
|
||||
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;
|
||||
@@ -84,13 +124,19 @@
|
||||
|
||||
&-row {
|
||||
position: relative;
|
||||
border-bottom: $border-divider;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: $padding-small;
|
||||
}
|
||||
|
||||
&-content {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(180px, max-content) 1fr;
|
||||
padding: $padding-global 0;
|
||||
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;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease-in;
|
||||
|
||||
@@ -116,8 +162,7 @@
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-end;
|
||||
margin-right: $padding-small;
|
||||
line-height: 1;
|
||||
padding: 0 $padding-global 0 $padding-small;
|
||||
white-space: nowrap;
|
||||
|
||||
&_missing {
|
||||
@@ -130,7 +175,12 @@
|
||||
&__msg {
|
||||
font-family: $font-family-monospace;
|
||||
overflow-wrap: anywhere;
|
||||
line-height: 1.1;
|
||||
|
||||
&_single-line {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&_empty-msg {
|
||||
overflow: hidden;
|
||||
@@ -158,7 +208,7 @@
|
||||
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 {
|
||||
@@ -171,7 +221,7 @@
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: $font-size-small;
|
||||
font-size: $font-size-logs;
|
||||
padding: calc($padding-small / 4) calc($padding-small / 2);
|
||||
}
|
||||
|
||||
@@ -194,25 +244,35 @@
|
||||
|
||||
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-bottom: $padding-small;
|
||||
margin: $padding-small 0 $padding-small calc($padding-global * 2);
|
||||
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;
|
||||
@@ -223,19 +283,26 @@
|
||||
}
|
||||
|
||||
&-controls {
|
||||
padding: 0;
|
||||
padding: 0 calc($padding-small / 2);
|
||||
|
||||
&__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;
|
||||
padding: calc($padding-small / 2) $padding-global;
|
||||
line-height: $font-size;
|
||||
padding: calc($padding-small / 2);
|
||||
}
|
||||
|
||||
&__key {
|
||||
|
||||
@@ -4,6 +4,8 @@ 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();
|
||||
@@ -30,46 +32,12 @@ export const useFetchLogHits = (server: string, query: string) => {
|
||||
step: `${step}ms`,
|
||||
start: start.toISOString(),
|
||||
end: end.toISOString(),
|
||||
field: "_stream" // In the future, this field can be made configurable
|
||||
|
||||
fields_limit: `${LOGS_LIMIT_HITS}`,
|
||||
field: LOGS_GROUP_BY,
|
||||
})
|
||||
};
|
||||
};
|
||||
|
||||
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();
|
||||
@@ -98,7 +66,7 @@ export const useFetchLogHits = (server: string, query: string) => {
|
||||
setError(error);
|
||||
}
|
||||
|
||||
setLogHits(!hits ? [] : getHitsWithTop(hits));
|
||||
setLogHits(hits.map(hit => ({ ...hit, _isOther: isEmptyObject(hit.fields) })));
|
||||
} catch (e) {
|
||||
if (e instanceof Error && e.name !== "AbortError") {
|
||||
setError(String(e));
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { TimeParams } from "../types";
|
||||
import dayjs from "dayjs";
|
||||
import { LOGS_BARS_VIEW } from "../constants/logs";
|
||||
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";
|
||||
|
||||
export const getStreamPairs = (value: string): string[] => {
|
||||
const pairs = /^{.+}$/.test(value) ? value.slice(1, -1).split(",") : [value];
|
||||
@@ -14,3 +16,27 @@ 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;
|
||||
};
|
||||
|
||||
@@ -57,3 +57,15 @@ 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
|
||||
}
|
||||
};
|
||||
|
||||
@@ -14,3 +14,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ export type StorageKeys = "AUTOCOMPLETE"
|
||||
| "QUERY_TRACING"
|
||||
| "SERIES_LIMITS"
|
||||
| "TABLE_COMPACT"
|
||||
| "TABLE_COLUMNS"
|
||||
| "TIMEZONE"
|
||||
| "DISABLED_DEFAULT_TIMEZONE"
|
||||
| "THEME"
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
// specific files
|
||||
// static content
|
||||
//
|
||||
//go:embed favicon-32x32.png robots.txt index.html manifest.json asset-manifest.json
|
||||
//go:embed favicon.svg robots.txt index.html manifest.json asset-manifest.json
|
||||
//go:embed static
|
||||
var files embed.FS
|
||||
|
||||
|
||||
@@ -171,4 +171,49 @@ 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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
76
apptest/tests/sparse_cache_test.go
Normal file
76
apptest/tests/sparse_cache_test.go
Normal file
@@ -0,0 +1,76 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -117,6 +117,22 @@ 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)
|
||||
|
||||
@@ -24,6 +24,7 @@ type Vmsingle struct {
|
||||
|
||||
// vmstorage URLs.
|
||||
forceFlushURL string
|
||||
forceMergeURL string
|
||||
|
||||
// vminsert URLs.
|
||||
influxLineWriteURL string
|
||||
@@ -65,6 +66,7 @@ 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]),
|
||||
@@ -83,6 +85,13 @@ 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.
|
||||
|
||||
@@ -21,6 +21,7 @@ type Vmstorage struct {
|
||||
vmselectAddr string
|
||||
|
||||
forceFlushURL string
|
||||
forceMergeURL string
|
||||
}
|
||||
|
||||
// StartVmstorage starts an instance of vmstorage with the given flags. It also
|
||||
@@ -57,6 +58,7 @@ 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
|
||||
}
|
||||
|
||||
@@ -80,6 +82,12 @@ 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{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
dashboard-copy:
|
||||
echo "" > dashboards/vm/${SRC}
|
||||
cat dashboards/${SRC} >> dashboards/vm/${SRC}
|
||||
sed -i='.tmp' 's/prometheus/victoriametrics-datasource/g' dashboards/vm/${SRC}
|
||||
sed -i='.tmp' 's/prometheus/victoriametrics-metrics-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}
|
||||
|
||||
@@ -1686,7 +1686,7 @@
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"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)",
|
||||
"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)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
|
||||
@@ -1933,7 +1933,7 @@
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": true,
|
||||
"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)",
|
||||
"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)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
|
||||
@@ -1981,7 +1981,7 @@
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"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)",
|
||||
"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)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "victoriametrics-datasource",
|
||||
"id": "victoriametrics-metrics-datasource",
|
||||
"name": "VictoriaMetrics",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
@@ -85,7 +85,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -133,7 +133,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -150,7 +150,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Status of last backup operation.",
|
||||
@@ -210,7 +210,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -225,7 +225,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Number of backups stored in remote storage.",
|
||||
@@ -275,7 +275,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -290,7 +290,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Space used in remote storage.",
|
||||
@@ -341,7 +341,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -356,7 +356,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "",
|
||||
@@ -420,7 +420,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -435,7 +435,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -510,7 +510,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -573,7 +573,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -588,7 +588,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -674,7 +674,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -715,7 +715,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -801,7 +801,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -852,7 +852,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -946,7 +946,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1020,7 +1020,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1035,7 +1035,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1110,7 +1110,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1125,7 +1125,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1184,7 +1184,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1227,7 +1227,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1298,7 +1298,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1313,7 +1313,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1387,7 +1387,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1416,7 +1416,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1500,7 +1500,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1574,7 +1574,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1603,7 +1603,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1705,7 +1705,7 @@
|
||||
"multi": false,
|
||||
"name": "ds",
|
||||
"options": [],
|
||||
"query": "victoriametrics-datasource",
|
||||
"query": "victoriametrics-metrics-datasource",
|
||||
"queryValue": "",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
@@ -1764,7 +1764,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"filters": [],
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "victoriametrics-datasource",
|
||||
"id": "victoriametrics-metrics-datasource",
|
||||
"name": "VictoriaMetrics",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
@@ -80,7 +80,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -184,7 +184,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Request rate accepted by vmselect nodes per tenant",
|
||||
@@ -272,7 +272,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -290,7 +290,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -403,7 +403,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Time spent on query execution per tenant per second",
|
||||
@@ -491,7 +491,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -509,7 +509,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -614,7 +614,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Number of new series created over last 24h.",
|
||||
@@ -702,7 +702,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -731,7 +731,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -785,7 +785,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -800,7 +800,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -853,7 +853,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -868,7 +868,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -921,7 +921,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -936,7 +936,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -991,7 +991,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1006,7 +1006,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1059,7 +1059,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1074,7 +1074,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1127,7 +1127,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1142,7 +1142,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1242,7 +1242,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1260,7 +1260,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1360,7 +1360,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1378,7 +1378,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1478,7 +1478,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1496,7 +1496,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1596,7 +1596,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1614,7 +1614,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1714,7 +1714,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1732,7 +1732,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1832,7 +1832,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1868,7 +1868,7 @@
|
||||
"multi": false,
|
||||
"name": "ds",
|
||||
"options": [],
|
||||
"query": "victoriametrics-datasource",
|
||||
"query": "victoriametrics-metrics-datasource",
|
||||
"queryValue": "",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
@@ -1879,7 +1879,7 @@
|
||||
"allValue": ".*",
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vm_tenant_active_timeseries, accountID)",
|
||||
@@ -1905,7 +1905,7 @@
|
||||
"allValue": ".*",
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vm_tenant_active_timeseries{accountID=~\"$accountID\"},projectID)",
|
||||
@@ -1929,7 +1929,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "PE8D8DB4BEE4E4B22"
|
||||
},
|
||||
"filters": [],
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
{
|
||||
"collapsed": false,
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"gridPos": {
|
||||
@@ -47,7 +47,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"refId": "A"
|
||||
@@ -58,7 +58,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"gridPos": {
|
||||
@@ -81,7 +81,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"refId": "A"
|
||||
@@ -92,7 +92,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Number of objects at kubernetes cluster per each controller",
|
||||
@@ -147,7 +147,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -162,7 +162,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -215,7 +215,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -234,7 +234,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": " Shows per namespace watchers for VictoriaMetrics Operator objects (ServiceMonitors, PodMonitors, etc) ",
|
||||
@@ -288,11 +288,11 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(operator_victoriametrics-datasource_converter_active_watchers)",
|
||||
"expr": "sum(operator_victoriametrics-metrics-datasource_converter_active_watchers)",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
@@ -304,7 +304,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -374,7 +374,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": " Shows number of active reconcile workers",
|
||||
@@ -428,7 +428,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -444,7 +444,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": " Shows amount of VictoriaMetrics Operator objects processed by Operator.",
|
||||
@@ -527,11 +527,11 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate(operator_victoriametrics-datasource_converter_watch_events_total{job=~\"$job\"}[$__interval])) by (event_type,object_type_name)",
|
||||
"expr": "sum(rate(operator_victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -627,7 +627,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -642,7 +642,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -743,7 +743,7 @@
|
||||
{
|
||||
"collapsed": false,
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"gridPos": {
|
||||
@@ -757,7 +757,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"refId": "A"
|
||||
@@ -768,7 +768,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -865,7 +865,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -881,7 +881,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -980,7 +980,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1079,7 +1079,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1180,7 +1180,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1278,7 +1278,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1389,7 +1389,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1406,7 +1406,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1502,7 +1502,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": " Requests latency to the Kubernetes API server.",
|
||||
@@ -1585,7 +1585,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1602,7 +1602,7 @@
|
||||
{
|
||||
"collapsed": true,
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"gridPos": {
|
||||
@@ -1615,7 +1615,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1699,7 +1699,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1710,7 +1710,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1722,7 +1722,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1734,7 +1734,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1750,7 +1750,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1830,7 +1830,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1845,7 +1845,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1925,7 +1925,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1940,7 +1940,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -2023,7 +2023,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2040,7 +2040,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"refId": "A"
|
||||
@@ -2065,7 +2065,7 @@
|
||||
"multi": false,
|
||||
"name": "ds",
|
||||
"options": [],
|
||||
"query": "victoriametrics-datasource",
|
||||
"query": "victoriametrics-metrics-datasource",
|
||||
"queryValue": "te",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
@@ -2075,7 +2075,7 @@
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(operator_log_messages_total,job)",
|
||||
@@ -2097,7 +2097,7 @@
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(operator_log_messages_total{job=~\"$job\"},instance)",
|
||||
@@ -2119,7 +2119,7 @@
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vm_app_version{job=\"$job\", instance=\"$instance\"}, version)",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "victoriametrics-datasource",
|
||||
"id": "victoriametrics-metrics-datasource",
|
||||
"name": "VictoriaMetrics",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
@@ -50,7 +50,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"enable": true,
|
||||
@@ -63,7 +63,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"enable": true,
|
||||
@@ -97,7 +97,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "How many log entries are in storage",
|
||||
@@ -149,7 +149,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -168,7 +168,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows the logs ingestion rate.",
|
||||
@@ -220,7 +220,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -239,7 +239,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "The ratio of original data size and compressed data stored on disk",
|
||||
@@ -291,7 +291,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -310,7 +310,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Total number of available CPUs for VM process",
|
||||
@@ -366,7 +366,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -385,7 +385,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -439,7 +439,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -456,7 +456,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Total amount of used disk space",
|
||||
@@ -508,7 +508,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -527,7 +527,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows the rate of HTTP read requests.",
|
||||
@@ -579,7 +579,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -598,7 +598,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Total size of available memory for VM process",
|
||||
@@ -680,7 +680,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "How many logs are inserted into storage per second",
|
||||
@@ -769,7 +769,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -787,7 +787,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -895,7 +895,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1003,7 +1003,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "The number of the new log streams created over the last 24h",
|
||||
@@ -1093,7 +1093,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1111,7 +1111,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1226,7 +1226,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1332,7 +1332,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "",
|
||||
@@ -1421,7 +1421,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"expr": "sum(go_memstats_stack_inuse_bytes{job=~\"$job\", instance=~\"$instance\"})",
|
||||
@@ -1457,7 +1457,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"expr": "sum(process_resident_memory_bytes{job=~\"$job\", instance=~\"$instance\"})",
|
||||
@@ -1470,7 +1470,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"exemplar": false,
|
||||
@@ -1488,7 +1488,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1594,7 +1594,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1682,12 +1682,12 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"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)",
|
||||
"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)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
@@ -1701,7 +1701,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1826,7 +1826,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "",
|
||||
@@ -1931,7 +1931,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1945,7 +1945,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"exemplar": false,
|
||||
@@ -1963,7 +1963,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -2052,7 +2052,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2069,7 +2069,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows the number of bytes read/write from the storage layer.",
|
||||
@@ -2170,7 +2170,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -2289,7 +2289,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2306,7 +2306,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2422,7 +2422,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2441,7 +2441,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "",
|
||||
@@ -2530,7 +2530,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2548,7 +2548,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "",
|
||||
@@ -2637,7 +2637,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2655,7 +2655,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2780,7 +2780,7 @@
|
||||
"multi": false,
|
||||
"name": "ds",
|
||||
"options": [],
|
||||
"query": "victoriametrics-datasource",
|
||||
"query": "victoriametrics-metrics-datasource",
|
||||
"queryValue": "",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
@@ -2790,7 +2790,7 @@
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vm_app_version{version=~\"victoria-logs-.*\"}, job)",
|
||||
@@ -2812,7 +2812,7 @@
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vm_app_version{job=~\"$job\"}, instance)",
|
||||
@@ -2833,7 +2833,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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
@@ -11,7 +11,7 @@
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "victoriametrics-datasource",
|
||||
"id": "victoriametrics-metrics-datasource",
|
||||
"name": "VictoriaMetrics",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
@@ -56,7 +56,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"enable": true,
|
||||
@@ -69,7 +69,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"enable": true,
|
||||
@@ -140,7 +140,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"exemplar": false,
|
||||
@@ -225,7 +225,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"exemplar": false,
|
||||
@@ -288,7 +288,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"exemplar": false,
|
||||
@@ -351,7 +351,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"exemplar": false,
|
||||
@@ -418,7 +418,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -487,7 +487,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -568,7 +568,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -584,7 +584,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -672,7 +672,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -716,7 +716,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows the number of fired alerts by job.",
|
||||
@@ -804,7 +804,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -821,7 +821,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -926,7 +926,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1028,7 +1028,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1144,7 +1144,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1258,7 +1258,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1371,7 +1371,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"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)",
|
||||
"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)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
@@ -1487,7 +1487,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1599,7 +1599,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1619,7 +1619,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1728,7 +1728,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1817,7 +1817,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1835,7 +1835,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1943,7 +1943,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2072,7 +2072,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -2157,7 +2157,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2202,7 +2202,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2304,7 +2304,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2426,7 +2426,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2528,7 +2528,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2630,7 +2630,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2732,7 +2732,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"exemplar": false,
|
||||
@@ -2831,7 +2831,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2959,7 +2959,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -3061,7 +3061,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -3163,7 +3163,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -3245,7 +3245,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -3285,7 +3285,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -3361,7 +3361,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -3376,7 +3376,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -3468,7 +3468,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows current number of established connections to remote write endpoints.\n\n",
|
||||
@@ -3554,7 +3554,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -3571,7 +3571,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -3696,7 +3696,7 @@
|
||||
"multi": false,
|
||||
"name": "ds",
|
||||
"options": [],
|
||||
"query": "victoriametrics-datasource",
|
||||
"query": "victoriametrics-metrics-datasource",
|
||||
"queryValue": "",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
@@ -3706,7 +3706,7 @@
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vm_app_version{version=~\"^vmalert.*\"}, job)",
|
||||
@@ -3729,7 +3729,7 @@
|
||||
"allValue": ".*",
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vm_app_version{job=~\"$job\"}, instance)",
|
||||
@@ -3752,7 +3752,7 @@
|
||||
"allValue": ".*",
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vmalert_iteration_total{job=~\"$job\", instance=~\"$instance\"},file)",
|
||||
@@ -3775,7 +3775,7 @@
|
||||
"allValue": ".*",
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vmalert_iteration_total{job=~\"$job\", instance=~\"$instance\"}, group)",
|
||||
@@ -3843,7 +3843,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"filters": [],
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "victoriametrics-datasource",
|
||||
"id": "victoriametrics-metrics-datasource",
|
||||
"name": "VictoriaMetrics",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
@@ -116,7 +116,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -204,7 +204,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -222,7 +222,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"exemplar": false,
|
||||
@@ -307,7 +307,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows the rate of requests.",
|
||||
@@ -356,7 +356,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -372,7 +372,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows the total number of users defined at configuration file.",
|
||||
@@ -420,7 +420,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -437,7 +437,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows the rate of request errors.",
|
||||
@@ -486,7 +486,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -502,7 +502,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -581,7 +581,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -611,7 +611,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -690,7 +690,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -702,7 +702,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -718,7 +718,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows percent utilization of per concurrent requests capacity.",
|
||||
@@ -805,7 +805,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -822,7 +822,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows the rate of rejected requests by a reason.",
|
||||
@@ -902,7 +902,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -918,7 +918,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1010,7 +1010,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1022,7 +1022,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1038,7 +1038,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows duration in seconds of user requests by quantile.",
|
||||
@@ -1124,7 +1124,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1136,7 +1136,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1162,7 +1162,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1268,7 +1268,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -1356,12 +1356,12 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"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)",
|
||||
"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)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
@@ -1375,7 +1375,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "",
|
||||
@@ -1464,7 +1464,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"expr": "sum(go_memstats_stack_inuse_bytes{job=~\"$job\", instance=~\"$instance\"})",
|
||||
@@ -1500,7 +1500,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"expr": "sum(process_resident_memory_bytes{job=~\"$job\", instance=~\"$instance\"})",
|
||||
@@ -1513,7 +1513,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"exemplar": false,
|
||||
@@ -1531,7 +1531,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "",
|
||||
@@ -1636,7 +1636,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"expr": "rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])",
|
||||
@@ -1648,7 +1648,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"exemplar": false,
|
||||
@@ -1666,7 +1666,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "",
|
||||
@@ -1755,7 +1755,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"expr": "sum(vm_tcplistener_conns{job=~\"$job\", instance=~\"$instance\"})",
|
||||
@@ -1771,7 +1771,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "",
|
||||
@@ -1860,7 +1860,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -1878,7 +1878,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2003,7 +2003,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -2092,7 +2092,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"expr": "sum(go_goroutines{job=~\"$job\", instance=~\"$instance\"})",
|
||||
@@ -2107,7 +2107,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -2196,7 +2196,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"expr": "sum(process_num_threads{job=~\"$job\", instance=~\"$instance\"})",
|
||||
@@ -2225,7 +2225,7 @@
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
@@ -2311,7 +2311,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2352,7 +2352,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2448,7 +2448,7 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-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-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
@@ -2573,7 +2573,7 @@
|
||||
"multi": false,
|
||||
"name": "ds",
|
||||
"options": [],
|
||||
"query": "victoriametrics-datasource",
|
||||
"query": "victoriametrics-metrics-datasource",
|
||||
"queryValue": "",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
@@ -2583,7 +2583,7 @@
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vm_app_version{version=~\"^vmauth.*\"}, job)",
|
||||
@@ -2606,7 +2606,7 @@
|
||||
"allValue": ".*",
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vm_app_version{job=~\"$job\"}, instance)",
|
||||
@@ -2628,7 +2628,7 @@
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "victoriametrics-datasource",
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"definition": "label_values(vmauth_user_requests_total{job=~\"$job\", instance=~\"$instance\"}, username)",
|
||||
|
||||
@@ -1665,7 +1665,7 @@
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": true,
|
||||
"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)",
|
||||
"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)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
|
||||
@@ -1472,7 +1472,7 @@
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"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)",
|
||||
"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)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
|
||||
@@ -1360,7 +1360,7 @@
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"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)",
|
||||
"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)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
|
||||
@@ -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.4-alpine
|
||||
GO_BUILDER_IMAGE := golang:1.23.5-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
|
||||
|
||||
@@ -4,7 +4,7 @@ services:
|
||||
# And forward them to --remoteWrite.url
|
||||
vmagent:
|
||||
container_name: vmagent
|
||||
image: victoriametrics/vmagent:v1.109.0
|
||||
image: victoriametrics/vmagent:v1.110.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.109.0-cluster
|
||||
image: victoriametrics/vmstorage:v1.110.0-cluster
|
||||
ports:
|
||||
- 8482
|
||||
- 8400
|
||||
@@ -51,7 +51,7 @@ services:
|
||||
restart: always
|
||||
vmstorage-2:
|
||||
container_name: vmstorage-2
|
||||
image: victoriametrics/vmstorage:v1.109.0-cluster
|
||||
image: victoriametrics/vmstorage:v1.110.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.109.0-cluster
|
||||
image: victoriametrics/vminsert:v1.110.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.109.0-cluster
|
||||
image: victoriametrics/vmselect:v1.110.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.109.0-cluster
|
||||
image: victoriametrics/vmselect:v1.110.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.109.0
|
||||
image: victoriametrics/vmauth:v1.110.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.109.0
|
||||
image: victoriametrics/vmalert:v1.110.0
|
||||
depends_on:
|
||||
- "vmauth"
|
||||
ports:
|
||||
|
||||
@@ -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.0/victoriametrics-logs-datasource-v0.13.0.zip;victoriametrics-logs-datasource"
|
||||
- "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_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.6.0-victorialogs
|
||||
image: victoriametrics/victoria-logs:v1.8.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.109.0
|
||||
image: victoriametrics/victoria-metrics:v1.110.0
|
||||
ports:
|
||||
- 8428:8428
|
||||
volumes:
|
||||
@@ -79,7 +79,7 @@ services:
|
||||
# depending on the requested path.
|
||||
vmauth:
|
||||
container_name: vmauth
|
||||
image: victoriametrics/vmauth:v1.109.0
|
||||
image: victoriametrics/vmauth:v1.110.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.109.0
|
||||
image: victoriametrics/vmalert:v1.110.0
|
||||
depends_on:
|
||||
- "vmauth"
|
||||
- "alertmanager"
|
||||
|
||||
@@ -4,7 +4,7 @@ services:
|
||||
# And forward them to --remoteWrite.url
|
||||
vmagent:
|
||||
container_name: vmagent
|
||||
image: victoriametrics/vmagent:v1.109.0
|
||||
image: victoriametrics/vmagent:v1.110.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.109.0
|
||||
image: victoriametrics/victoria-metrics:v1.110.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.109.0
|
||||
image: victoriametrics/vmalert:v1.110.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
- "alertmanager"
|
||||
|
||||
@@ -2,7 +2,7 @@ apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: VictoriaMetrics - cluster
|
||||
type: victoriametrics-datasource
|
||||
type: victoriametrics-metrics-datasource
|
||||
access: proxy
|
||||
url: http://vmauth:8427/select/0/prometheus
|
||||
isDefault: true
|
||||
|
||||
@@ -2,7 +2,7 @@ apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: VictoriaMetrics
|
||||
type: victoriametrics-datasource
|
||||
type: victoriametrics-metrics-datasource
|
||||
access: proxy
|
||||
url: http://victoriametrics:8428
|
||||
isDefault: true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
services:
|
||||
# meta service will be ignored by compose
|
||||
.victorialogs:
|
||||
image: docker.io/victoriametrics/victoria-logs:v1.6.0-victorialogs
|
||||
image: docker.io/victoriametrics/victoria-logs:v1.8.0-victorialogs
|
||||
command:
|
||||
- -storageDataPath=/vlogs
|
||||
- -loggerFormat=json
|
||||
@@ -19,7 +19,7 @@ services:
|
||||
retries: 10
|
||||
|
||||
dd-proxy:
|
||||
image: docker.io/victoriametrics/vmauth:v1.109.0
|
||||
image: docker.io/victoriametrics/vmauth:v1.110.0
|
||||
restart: on-failure
|
||||
volumes:
|
||||
- ./:/etc/vmauth
|
||||
@@ -45,7 +45,7 @@ services:
|
||||
replicas: 0
|
||||
|
||||
victoriametrics:
|
||||
image: victoriametrics/victoria-metrics:latest
|
||||
image: victoriametrics/victoria-metrics:v1.110.0
|
||||
ports:
|
||||
- '8428:8428'
|
||||
command:
|
||||
|
||||
@@ -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.10.3/victoriametrics-datasource-v0.10.3.zip;victoriametrics-datasource"
|
||||
- "GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=victoriametrics-datasource"
|
||||
- "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"
|
||||
restart: always
|
||||
|
||||
@@ -15,8 +15,8 @@ services:
|
||||
- ./../../dashboards/vm/vmagent.json:/var/lib/grafana/dashboards/vmagent.json
|
||||
- ./../../dashboards/vm/vmalert.json:/var/lib/grafana/dashboards/vmalert.json
|
||||
environment:
|
||||
- "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"
|
||||
- "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"
|
||||
networks:
|
||||
- vm_net
|
||||
restart: always
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user