mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-05-29 14:51:27 +03:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35bd7f37b1 | ||
|
|
f5ffbb4e00 | ||
|
|
13d2b0b558 | ||
|
|
b83b2bae3b | ||
|
|
ef84c16f37 | ||
|
|
47391fea3b | ||
|
|
afce8bc320 | ||
|
|
5d18cd3416 | ||
|
|
65e0b3b86f | ||
|
|
aa3171cf4b | ||
|
|
1754ac53cd | ||
|
|
5c6af65e48 | ||
|
|
d8871f56ba | ||
|
|
4d6bc3b5df | ||
|
|
60e253b387 | ||
|
|
127d6972ac | ||
|
|
6d7d22f3e6 | ||
|
|
6a4757ad06 | ||
|
|
ff0632c01e | ||
|
|
134501bf99 | ||
|
|
faa3943a25 | ||
|
|
b30f4ca12a | ||
|
|
208515dc38 | ||
|
|
9de3e80a4f | ||
|
|
63d8d0c5ac | ||
|
|
6b485c4e46 | ||
|
|
723e56ac50 | ||
|
|
0a4f7e0958 | ||
|
|
9eb6796bad | ||
|
|
1916f5be4b | ||
|
|
4207cb8450 | ||
|
|
231bfcf4cf | ||
|
|
03ceeb7211 | ||
|
|
118a322aa4 | ||
|
|
454ad7a1b4 | ||
|
|
266bceaffd | ||
|
|
60322ed491 | ||
|
|
18f4c1f646 | ||
|
|
45e6491a8e | ||
|
|
0108d5777c | ||
|
|
4fabb459aa | ||
|
|
75623173d4 |
2
Makefile
2
Makefile
@@ -526,7 +526,7 @@ test-full:
|
||||
test-full-386:
|
||||
GOEXPERIMENT=synctest GOARCH=386 go test -coverprofile=coverage.txt -covermode=atomic ./lib/... ./app/...
|
||||
|
||||
integration-test: victoria-metrics vmagent vmalert vmauth
|
||||
integration-test: victoria-metrics vmagent vmalert vmauth vmctl
|
||||
go test ./apptest/... -skip="^TestCluster.*"
|
||||
|
||||
benchmark:
|
||||
|
||||
@@ -95,6 +95,7 @@ func datadogLogsIngestion(w http.ResponseWriter, r *http.Request) bool {
|
||||
// There is no need in updating v2LogsRequestDuration for request errors,
|
||||
// since their timings are usually much smaller than the timing for successful request parsing.
|
||||
v2LogsRequestDuration.UpdateDuration(startTime)
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
fmt.Fprintf(w, `{}`)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -514,6 +514,11 @@ func ProcessLiveTailRequest(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
if !ok {
|
||||
logger.Panicf("BUG: it is expected that http.ResponseWriter (%T) supports http.Flusher interface", w)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/x-ndjson")
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
flusher.Flush()
|
||||
|
||||
qOrig := q
|
||||
for {
|
||||
q = qOrig.CloneWithTimeFilter(end, start, end)
|
||||
|
||||
File diff suppressed because one or more lines are too long
1
app/vlselect/vmui/assets/index-C85_NB5q.css
Normal file
1
app/vlselect/vmui/assets/index-C85_NB5q.css
Normal file
File diff suppressed because one or more lines are too long
208
app/vlselect/vmui/assets/index-DLp5TlUn.js
Normal file
208
app/vlselect/vmui/assets/index-DLp5TlUn.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
File diff suppressed because one or more lines are too long
67
app/vlselect/vmui/assets/vendor-D8IJGiEn.js
Normal file
67
app/vlselect/vmui/assets/vendor-D8IJGiEn.js
Normal file
File diff suppressed because one or more lines are too long
@@ -35,10 +35,10 @@
|
||||
<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 type="module" crossorigin src="./assets/index-DfcWONVQ.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-C-vZmbyg.js">
|
||||
<script type="module" crossorigin src="./assets/index-DLp5TlUn.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-D8IJGiEn.js">
|
||||
<link rel="stylesheet" crossorigin href="./assets/vendor-D1GxaB_c.css">
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-Brup_hCI.css">
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-C85_NB5q.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
@@ -22,10 +22,10 @@ var (
|
||||
relabelConfigPathGlobal = flag.String("remoteWrite.relabelConfig", "", "Optional path to file with relabeling configs, which are applied "+
|
||||
"to all the metrics before sending them to -remoteWrite.url. See also -remoteWrite.urlRelabelConfig. "+
|
||||
"The path can point either to local file or to http url. "+
|
||||
"See https://docs.victoriametrics.com/victoriametrics/vmagent/#relabeling")
|
||||
"See https://docs.victoriametrics.com/victoriametrics/relabeling/")
|
||||
relabelConfigPaths = flagutil.NewArrayString("remoteWrite.urlRelabelConfig", "Optional path to relabel configs for the corresponding -remoteWrite.url. "+
|
||||
"See also -remoteWrite.relabelConfig. The path can point either to local file or to http url. "+
|
||||
"See https://docs.victoriametrics.com/victoriametrics/vmagent/#relabeling")
|
||||
"See https://docs.victoriametrics.com/victoriametrics/relabeling/")
|
||||
|
||||
usePromCompatibleNaming = flag.Bool("usePromCompatibleNaming", false, "Whether to replace characters unsupported by Prometheus with underscores "+
|
||||
"in the ingested metric names and label names. For example, foo.bar{a.b='c'} is transformed into foo_bar{a_b='c'} during data ingestion if this flag is set. "+
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -99,8 +98,11 @@ func UnitTest(files []string, disableGroupLabel bool, externalLabels []string, e
|
||||
}()
|
||||
}
|
||||
|
||||
// adding time.Now().UnixNano() to avoid possible file conflict when multiple processes run on a single host
|
||||
storagePath = filepath.Join(os.TempDir(), testStoragePath, strconv.FormatInt(time.Now().UnixNano(), 10))
|
||||
tmpFolder, err := os.MkdirTemp(os.TempDir(), testStoragePath)
|
||||
if err != nil {
|
||||
logger.Fatalf("failed to create tmp dir for tests: %v", err)
|
||||
}
|
||||
storagePath = tmpFolder
|
||||
processFlags()
|
||||
vminsert.Init()
|
||||
vmselect.Init()
|
||||
|
||||
@@ -258,12 +258,18 @@ func (rr *RecordingRule) toTimeSeries(m datasource.Metric) prompbmarshal.TimeSer
|
||||
Value: rr.Name,
|
||||
})
|
||||
}
|
||||
// add extra labels configured by user
|
||||
for k := range rr.Labels {
|
||||
prevLabel := promrelabel.GetLabelByName(m.Labels, k)
|
||||
if prevLabel != nil && prevLabel.Value != rr.Labels[k] {
|
||||
// Rename the prevLabel to "exported_" + label.Name
|
||||
prevLabel.Name = fmt.Sprintf("exported_%s", prevLabel.Name)
|
||||
existingLabel := promrelabel.GetLabelByName(m.Labels, k)
|
||||
if existingLabel != nil { // there is a conflict between extra and existing label
|
||||
if existingLabel.Value == rr.Labels[k] {
|
||||
// extra and existing labels are identical - do nothing
|
||||
continue
|
||||
}
|
||||
// preserve existing label by adding "exported_" prefix
|
||||
existingLabel.Name = fmt.Sprintf("exported_%s", existingLabel.Name)
|
||||
}
|
||||
// add extra label
|
||||
m.Labels = append(m.Labels, prompbmarshal.Label{
|
||||
Name: k,
|
||||
Value: rr.Labels[k],
|
||||
|
||||
@@ -168,6 +168,7 @@ func TestRecordingRule_Exec(t *testing.T) {
|
||||
}, [][]datasource.Metric{{
|
||||
metricWithValueAndLabels(t, 2, "__name__", "foo", "job", "foo"),
|
||||
metricWithValueAndLabels(t, 1, "__name__", "bar", "job", "bar", "source", "origin"),
|
||||
metricWithValueAndLabels(t, 1, "__name__", "baz", "job", "baz", "source", "test"),
|
||||
}}, [][]prompbmarshal.TimeSeries{{
|
||||
newTimeSeries([]float64{2}, []int64{ts.UnixNano()}, []prompbmarshal.Label{
|
||||
{
|
||||
@@ -202,6 +203,21 @@ func TestRecordingRule_Exec(t *testing.T) {
|
||||
Value: "origin",
|
||||
},
|
||||
}),
|
||||
newTimeSeries([]float64{1}, []int64{ts.UnixNano()},
|
||||
[]prompbmarshal.Label{
|
||||
{
|
||||
Name: "__name__",
|
||||
Value: "job:foo",
|
||||
},
|
||||
{
|
||||
Name: "job",
|
||||
Value: "baz",
|
||||
},
|
||||
{
|
||||
Name: "source",
|
||||
Value: "test",
|
||||
},
|
||||
}),
|
||||
}})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,215 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/storage"
|
||||
"github.com/prometheus/prometheus/tsdb"
|
||||
"github.com/prometheus/prometheus/tsdb/chunkenc"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/backoff"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/barpool"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/prometheus"
|
||||
remote_read_integration "github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/testdata/servers_integration_test"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/vm"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/promql"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage"
|
||||
)
|
||||
|
||||
const (
|
||||
testSnapshot = "./testdata/snapshots/20250118T124506Z-59d1b952d7eaf547"
|
||||
blockData = "./testdata/snapshots/20250118T124506Z-59d1b952d7eaf547/01JHWQ445Y2P1TDYB05AEKD6MC"
|
||||
)
|
||||
|
||||
// This test simulates close process if user abort it
|
||||
func TestPrometheusProcessorRun(t *testing.T) {
|
||||
|
||||
f := func(startStr, endStr string, numOfSeries int, resultExpected []vm.TimeSeries) {
|
||||
t.Helper()
|
||||
|
||||
dst := remote_read_integration.NewRemoteWriteServer(t)
|
||||
|
||||
defer func() {
|
||||
dst.Close()
|
||||
}()
|
||||
|
||||
dst.Series(resultExpected)
|
||||
dst.ExpectedSeries(resultExpected)
|
||||
|
||||
if err := fillStorage(resultExpected); err != nil {
|
||||
t.Fatalf("cannot fill storage: %s", err)
|
||||
}
|
||||
|
||||
isSilent = true
|
||||
defer func() { isSilent = false }()
|
||||
|
||||
bf, err := backoff.New(1, 1.8, time.Second*2)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot create backoff: %s", err)
|
||||
}
|
||||
|
||||
importerCfg := vm.Config{
|
||||
Addr: dst.URL(),
|
||||
Transport: nil,
|
||||
Concurrency: 1,
|
||||
Backoff: bf,
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
importer, err := vm.NewImporter(ctx, importerCfg)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot create importer: %s", err)
|
||||
}
|
||||
defer importer.Close()
|
||||
|
||||
matchName := "__name__"
|
||||
matchValue := ".*"
|
||||
filter := prometheus.Filter{
|
||||
TimeMin: startStr,
|
||||
TimeMax: endStr,
|
||||
Label: matchName,
|
||||
LabelValue: matchValue,
|
||||
}
|
||||
|
||||
runner, err := prometheus.NewClient(prometheus.Config{
|
||||
Snapshot: testSnapshot,
|
||||
Filter: filter,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("cannot create prometheus client: %s", err)
|
||||
}
|
||||
p := &prometheusProcessor{
|
||||
cl: runner,
|
||||
im: importer,
|
||||
cc: 1,
|
||||
}
|
||||
|
||||
if err := p.run(); err != nil {
|
||||
t.Fatalf("run() error: %s", err)
|
||||
}
|
||||
|
||||
collectedTs := dst.GetCollectedTimeSeries()
|
||||
t.Logf("collected timeseries: %d; expected timeseries: %d", len(collectedTs), len(resultExpected))
|
||||
if len(collectedTs) != len(resultExpected) {
|
||||
t.Fatalf("unexpected number of collected time series; got %d; want %d", len(collectedTs), numOfSeries)
|
||||
}
|
||||
|
||||
deleted, err := deleteSeries(matchName, matchValue)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot delete series: %s", err)
|
||||
}
|
||||
if deleted != numOfSeries {
|
||||
t.Fatalf("unexpected number of deleted series; got %d; want %d", deleted, numOfSeries)
|
||||
}
|
||||
}
|
||||
|
||||
processFlags()
|
||||
vmstorage.Init(promql.ResetRollupResultCacheIfNeeded)
|
||||
defer func() {
|
||||
vmstorage.Stop()
|
||||
if err := os.RemoveAll(storagePath); err != nil {
|
||||
log.Fatalf("cannot remove %q: %s", storagePath, err)
|
||||
}
|
||||
}()
|
||||
|
||||
barpool.Disable(true)
|
||||
defer func() {
|
||||
barpool.Disable(false)
|
||||
}()
|
||||
|
||||
b, err := tsdb.OpenBlock(nil, blockData, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot open block: %s", err)
|
||||
}
|
||||
// timestamp is equal to minTime and maxTime from meta.json
|
||||
ss, err := readBlock(b, 1737204082361, 1737204302539)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot read block: %s", err)
|
||||
}
|
||||
|
||||
resultExpected, err := prepareExpectedData(ss)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot prepare expected data: %s", err)
|
||||
}
|
||||
|
||||
f("2025-01-18T12:40:00Z", "2025-01-18T12:46:00Z", 2792, resultExpected)
|
||||
}
|
||||
|
||||
func readBlock(b tsdb.BlockReader, timeMin int64, timeMax int64) (storage.SeriesSet, error) {
|
||||
minTime, maxTime := b.Meta().MinTime, b.Meta().MaxTime
|
||||
|
||||
if timeMin != 0 {
|
||||
minTime = timeMin
|
||||
}
|
||||
if timeMax != 0 {
|
||||
maxTime = timeMax
|
||||
}
|
||||
|
||||
q, err := tsdb.NewBlockQuerier(b, minTime, maxTime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
matchName := "__name__"
|
||||
matchValue := ".*"
|
||||
ctx := context.Background()
|
||||
ss := q.Select(ctx, false, nil, labels.MustNewMatcher(labels.MatchRegexp, matchName, matchValue))
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
func prepareExpectedData(ss storage.SeriesSet) ([]vm.TimeSeries, error) {
|
||||
var expectedSeriesSet []vm.TimeSeries
|
||||
var it chunkenc.Iterator
|
||||
for ss.Next() {
|
||||
var name string
|
||||
var labelPairs []vm.LabelPair
|
||||
series := ss.At()
|
||||
|
||||
for _, label := range series.Labels() {
|
||||
if label.Name == "__name__" {
|
||||
name = label.Value
|
||||
continue
|
||||
}
|
||||
labelPairs = append(labelPairs, vm.LabelPair{
|
||||
Name: label.Name,
|
||||
Value: label.Value,
|
||||
})
|
||||
}
|
||||
if name == "" {
|
||||
return nil, fmt.Errorf("failed to find `__name__` label in labelset for block")
|
||||
}
|
||||
|
||||
var timestamps []int64
|
||||
var values []float64
|
||||
it = series.Iterator(it)
|
||||
for {
|
||||
typ := it.Next()
|
||||
if typ == chunkenc.ValNone {
|
||||
break
|
||||
}
|
||||
if typ != chunkenc.ValFloat {
|
||||
// Skip unsupported values
|
||||
continue
|
||||
}
|
||||
t, v := it.At()
|
||||
timestamps = append(timestamps, t)
|
||||
values = append(values, v)
|
||||
}
|
||||
if err := it.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts := vm.TimeSeries{
|
||||
Name: name,
|
||||
LabelPairs: labelPairs,
|
||||
Timestamps: timestamps,
|
||||
Values: values,
|
||||
}
|
||||
expectedSeriesSet = append(expectedSeriesSet, ts)
|
||||
}
|
||||
return expectedSeriesSet, nil
|
||||
}
|
||||
@@ -32,9 +32,13 @@ See https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries
|
||||
{% code
|
||||
// seriesFetched is string instead of int because of historical reasons.
|
||||
// It cannot be converted to int without breaking backwards compatibility at vmalert :(
|
||||
executionDuration := int64(0)
|
||||
if ed := qs.ExecutionDuration.Load(); ed != nil {
|
||||
executionDuration = ed.Milliseconds()
|
||||
}
|
||||
%}
|
||||
"seriesFetched": "{%dl qs.SeriesFetched.Load() %}",
|
||||
"executionTimeMsec": {%dl qs.ExecutionDuration.Load().Milliseconds() %}
|
||||
"executionTimeMsec": {%dl executionDuration %}
|
||||
}
|
||||
{% code
|
||||
qt.Printf("generate /api/v1/query_range response for series=%d, points=%d", seriesCount, pointsCount)
|
||||
|
||||
@@ -64,91 +64,95 @@ func StreamQueryRangeResponse(qw422016 *qt422016.Writer, rs []netstorage.Result,
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:33
|
||||
// seriesFetched is string instead of int because of historical reasons.
|
||||
// It cannot be converted to int without breaking backwards compatibility at vmalert :(
|
||||
executionDuration := int64(0)
|
||||
if ed := qs.ExecutionDuration.Load(); ed != nil {
|
||||
executionDuration = ed.Milliseconds()
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:35
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:39
|
||||
qw422016.N().S(`"seriesFetched": "`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:36
|
||||
qw422016.N().DL(qs.SeriesFetched.Load())
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:36
|
||||
qw422016.N().S(`","executionTimeMsec":`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:37
|
||||
qw422016.N().DL(qs.ExecutionDuration.Load().Milliseconds())
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:37
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:40
|
||||
qw422016.N().DL(qs.SeriesFetched.Load())
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:40
|
||||
qw422016.N().S(`","executionTimeMsec":`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
qw422016.N().DL(executionDuration)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:44
|
||||
qt.Printf("generate /api/v1/query_range response for series=%d, points=%d", seriesCount, pointsCount)
|
||||
qtDone()
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:47
|
||||
streamdumpQueryTrace(qw422016, qt)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:47
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
func WriteQueryRangeResponse(qq422016 qtio422016.Writer, rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) {
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
StreamQueryRangeResponse(qw422016, rs, qt, qtDone, qs)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
func QueryRangeResponse(rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) string {
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
WriteQueryRangeResponse(qb422016, rs, qt, qtDone, qs)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
qs422016 := string(qb422016.B)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
return qs422016
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:51
|
||||
func streamqueryRangeLine(qw422016 *qt422016.Writer, r *netstorage.Result) {
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:51
|
||||
qw422016.N().S(`{"metric":`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:53
|
||||
streammetricNameObject(qw422016, &r.MetricName)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:53
|
||||
qw422016.N().S(`,"values":`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:50
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:54
|
||||
streamvaluesWithTimestamps(qw422016, r.Values, r.Timestamps)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:50
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:54
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
func writequeryRangeLine(qq422016 qtio422016.Writer, r *netstorage.Result) {
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
streamqueryRangeLine(qw422016, r)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
func queryRangeLine(r *netstorage.Result) string {
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
writequeryRangeLine(qb422016, r)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
qs422016 := string(qb422016.B)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
return qs422016
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:52
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:56
|
||||
}
|
||||
|
||||
@@ -34,9 +34,13 @@ See https://prometheus.io/docs/prometheus/latest/querying/api/#instant-queries
|
||||
{% code
|
||||
// seriesFetched is string instead of int because of historical reasons.
|
||||
// It cannot be converted to int without breaking backwards compatibility at vmalert :(
|
||||
executionDuration := int64(0)
|
||||
if ed := qs.ExecutionDuration.Load(); ed != nil {
|
||||
executionDuration = ed.Milliseconds()
|
||||
}
|
||||
%}
|
||||
"seriesFetched": "{%dl qs.SeriesFetched.Load() %}",
|
||||
"executionTimeMsec": {%dl qs.ExecutionDuration.Load().Milliseconds() %}
|
||||
"executionTimeMsec": {%dl executionDuration %}
|
||||
}
|
||||
{% code
|
||||
qt.Printf("generate /api/v1/query response for series=%d", seriesCount)
|
||||
|
||||
@@ -74,50 +74,54 @@ func StreamQueryResponse(qw422016 *qt422016.Writer, rs []netstorage.Result, qt *
|
||||
//line app/vmselect/prometheus/query_response.qtpl:35
|
||||
// seriesFetched is string instead of int because of historical reasons.
|
||||
// It cannot be converted to int without breaking backwards compatibility at vmalert :(
|
||||
executionDuration := int64(0)
|
||||
if ed := qs.ExecutionDuration.Load(); ed != nil {
|
||||
executionDuration = ed.Milliseconds()
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_response.qtpl:37
|
||||
//line app/vmselect/prometheus/query_response.qtpl:41
|
||||
qw422016.N().S(`"seriesFetched": "`)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:38
|
||||
qw422016.N().DL(qs.SeriesFetched.Load())
|
||||
//line app/vmselect/prometheus/query_response.qtpl:38
|
||||
qw422016.N().S(`","executionTimeMsec":`)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:39
|
||||
qw422016.N().DL(qs.ExecutionDuration.Load().Milliseconds())
|
||||
//line app/vmselect/prometheus/query_response.qtpl:39
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:42
|
||||
qw422016.N().DL(qs.SeriesFetched.Load())
|
||||
//line app/vmselect/prometheus/query_response.qtpl:42
|
||||
qw422016.N().S(`","executionTimeMsec":`)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
qw422016.N().DL(executionDuration)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:46
|
||||
qt.Printf("generate /api/v1/query response for series=%d", seriesCount)
|
||||
qtDone()
|
||||
|
||||
//line app/vmselect/prometheus/query_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_response.qtpl:49
|
||||
streamdumpQueryTrace(qw422016, qt)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_response.qtpl:49
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
func WriteQueryResponse(qq422016 qtio422016.Writer, rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) {
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
StreamQueryResponse(qw422016, rs, qt, qtDone, qs)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
func QueryResponse(rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) string {
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
WriteQueryResponse(qb422016, rs, qt, qtDone, qs)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
qs422016 := string(qb422016.B)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
return qs422016
|
||||
//line app/vmselect/prometheus/query_response.qtpl:47
|
||||
//line app/vmselect/prometheus/query_response.qtpl:51
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
1
app/vmselect/vmui/assets/index-C85_NB5q.css
Normal file
1
app/vmselect/vmui/assets/index-C85_NB5q.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
209
app/vmselect/vmui/assets/index-xmjGcv4-.js
Normal file
209
app/vmselect/vmui/assets/index-xmjGcv4-.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
67
app/vmselect/vmui/assets/vendor-D8IJGiEn.js
Normal file
67
app/vmselect/vmui/assets/vendor-D8IJGiEn.js
Normal file
File diff suppressed because one or more lines are too long
@@ -36,10 +36,10 @@
|
||||
<meta property="og:title" content="UI for VictoriaMetrics">
|
||||
<meta property="og:url" content="https://victoriametrics.com/">
|
||||
<meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data">
|
||||
<script type="module" crossorigin src="./assets/index-C_-w5pCZ.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-C-vZmbyg.js">
|
||||
<script type="module" crossorigin src="./assets/index-xmjGcv4-.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="./assets/vendor-D8IJGiEn.js">
|
||||
<link rel="stylesheet" crossorigin href="./assets/vendor-D1GxaB_c.css">
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-Brup_hCI.css">
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-C85_NB5q.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
@@ -6,6 +6,7 @@ import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import js from "@eslint/js";
|
||||
import { FlatCompat } from "@eslint/eslintrc";
|
||||
import unusedImports from "eslint-plugin-unused-imports";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -23,6 +24,7 @@ export default [...compat.extends(
|
||||
plugins: {
|
||||
react,
|
||||
"@typescript-eslint": typescriptEslint,
|
||||
"unused-imports": unusedImports,
|
||||
},
|
||||
|
||||
languageOptions: {
|
||||
@@ -59,7 +61,7 @@ export default [...compat.extends(
|
||||
allowTernary: true
|
||||
}],
|
||||
|
||||
"@typescript-eslint/no-unused-vars": ["warn", {
|
||||
"@typescript-eslint/no-unused-vars": ["error", {
|
||||
"argsIgnorePattern": "^_",
|
||||
"caughtErrors": "none",
|
||||
"caughtErrorsIgnorePattern": "^_",
|
||||
@@ -67,6 +69,8 @@ export default [...compat.extends(
|
||||
"varsIgnorePattern": "^_",
|
||||
"ignoreRestSiblings": true
|
||||
}],
|
||||
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
|
||||
"react/jsx-closing-bracket-location": [1, "line-aligned"],
|
||||
|
||||
@@ -85,6 +89,7 @@ export default [...compat.extends(
|
||||
quotes: ["error", "double"],
|
||||
semi: ["error", "always"],
|
||||
"react/prop-types": 0,
|
||||
"react/react-in-jsx-scope": "off",
|
||||
|
||||
},
|
||||
}];
|
||||
|
||||
57
app/vmui/packages/vmui/package-lock.json
generated
57
app/vmui/packages/vmui/package-lock.json
generated
@@ -23,9 +23,9 @@
|
||||
"preact": "^10.26.5",
|
||||
"qs": "^6.14.0",
|
||||
"react-input-mask": "^2.0.4",
|
||||
"react-router-dom": "^7.5.0",
|
||||
"react-router-dom": "^7.6.0",
|
||||
"uplot": "^1.6.32",
|
||||
"vite": "^6.2.6",
|
||||
"vite": "^6.2.7",
|
||||
"web-vitals": "^4.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -42,6 +42,7 @@
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.24.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"globals": "^16.0.0",
|
||||
"http-proxy-middleware": "^3.0.5",
|
||||
"jsdom": "^26.1.0",
|
||||
@@ -2115,12 +2116,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/cookie": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "9.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
|
||||
@@ -4199,6 +4194,22 @@
|
||||
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unused-imports": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz",
|
||||
"integrity": "sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0",
|
||||
"eslint": "^9.0.0 || ^8.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
|
||||
@@ -6476,15 +6487,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.5.0.tgz",
|
||||
"integrity": "sha512-estOHrRlDMKdlQa6Mj32gIks4J+AxNsYoE0DbTTxiMy2mPzZuWSDU+N85/r1IlNR7kGfznF3VCUlvc5IUO+B9g==",
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz",
|
||||
"integrity": "sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.6.0",
|
||||
"cookie": "^1.0.1",
|
||||
"set-cookie-parser": "^2.6.0",
|
||||
"turbo-stream": "2.4.0"
|
||||
"set-cookie-parser": "^2.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
@@ -6500,12 +6509,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.5.0.tgz",
|
||||
"integrity": "sha512-fFhGFCULy4vIseTtH5PNcY/VvDJK5gvOWcwJVHQp8JQcWVr85ENhJ3UpuF/zP1tQOIFYNRJHzXtyhU1Bdgw0RA==",
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.0.tgz",
|
||||
"integrity": "sha512-DYgm6RDEuKdopSyGOWZGtDfSm7Aofb8CCzgkliTjtu/eDuB0gcsv6qdFhhi8HdtmA+KHkt5MfZ5K2PdzjugYsA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-router": "7.5.0"
|
||||
"react-router": "7.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
@@ -8012,12 +8021,6 @@
|
||||
"devOptional": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/turbo-stream": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
|
||||
"integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
@@ -8204,9 +8207,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.2.6",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.6.tgz",
|
||||
"integrity": "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==",
|
||||
"version": "6.2.7",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.7.tgz",
|
||||
"integrity": "sha512-qg3LkeuinTrZoJHHF94coSaTfIPyBYoywp+ys4qu20oSJFbKMYoIJo0FWJT9q6Vp49l6z9IsJRbHdcGtiKbGoQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
|
||||
@@ -20,14 +20,15 @@
|
||||
"preact": "^10.26.5",
|
||||
"qs": "^6.14.0",
|
||||
"react-input-mask": "^2.0.4",
|
||||
"react-router-dom": "^7.5.0",
|
||||
"react-router-dom": "^7.6.0",
|
||||
"uplot": "^1.6.32",
|
||||
"vite": "^6.2.6",
|
||||
"vite": "^6.2.7",
|
||||
"web-vitals": "^4.2.4"
|
||||
},
|
||||
"scripts": {
|
||||
"prestart": "npm run copy-metricsql-docs",
|
||||
"start": "vite",
|
||||
"start:playground": "cross-env PLAYGROUND=METRICS npm run start",
|
||||
"start:logs": "vite --mode victorialogs",
|
||||
"start:logs:playground": "cross-env PLAYGROUND=LOGS npm run start:logs",
|
||||
"start:anomaly": "vite --mode vmanomaly",
|
||||
@@ -66,6 +67,7 @@
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.24.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"globals": "^16.0.0",
|
||||
"http-proxy-middleware": "^3.0.5",
|
||||
"jsdom": "^26.1.0",
|
||||
|
||||
@@ -69,7 +69,7 @@ const LogsQueryEditorAutocomplete: FC<QueryEditorAutocompleteProps> = ({
|
||||
if (insertType === ContextType.FilterName) {
|
||||
modifiedInsert += ":";
|
||||
} else if (contextType === ContextType.FilterValue) {
|
||||
const insertWithQuotes = value.startsWith("_stream:") ? modifiedInsert : `"${modifiedInsert}"`;
|
||||
const insertWithQuotes = value.startsWith("_stream:") ? modifiedInsert : `${JSON.stringify(modifiedInsert)}`;
|
||||
modifiedInsert = `${contextData?.filterName || ""}:${insertWithQuotes}`;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
import React, { FC, useMemo, useRef } from "preact/compat";
|
||||
import { FC, useMemo, useRef } from "preact/compat";
|
||||
import { ArrowDropDownIcon } from "../../Icons";
|
||||
import useBoolean from "../../../../hooks/useBoolean";
|
||||
import Popper from "../../Popper/Popper";
|
||||
@@ -10,11 +10,12 @@ interface SelectLimitProps {
|
||||
limit: number | string;
|
||||
allowUnlimited?: boolean;
|
||||
onChange: (val: number) => void;
|
||||
onOpenSelect?: () => void;
|
||||
}
|
||||
|
||||
const defaultLimits = [10, 25, 50, 100, 250, 500, 1000];
|
||||
|
||||
const SelectLimit: FC<SelectLimitProps> = ({ limit, allowUnlimited, onChange }) => {
|
||||
const SelectLimit: FC<SelectLimitProps> = ({ limit, allowUnlimited, onChange, onOpenSelect }) => {
|
||||
const { isMobile } = useDeviceDetect();
|
||||
const buttonRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -28,6 +29,11 @@ const SelectLimit: FC<SelectLimitProps> = ({ limit, allowUnlimited, onChange })
|
||||
setFalse: handleClose,
|
||||
} = useBoolean(false);
|
||||
|
||||
const handleClickSelect = () => {
|
||||
toggleOpenList();
|
||||
if(!openList) onOpenSelect?.();
|
||||
};
|
||||
|
||||
const handleChangeLimit = (n: number) => () => {
|
||||
onChange(n);
|
||||
handleClose();
|
||||
@@ -37,7 +43,7 @@ const SelectLimit: FC<SelectLimitProps> = ({ limit, allowUnlimited, onChange })
|
||||
<>
|
||||
<div
|
||||
className="vm-select-limits-button"
|
||||
onClick={toggleOpenList}
|
||||
onClick={handleClickSelect}
|
||||
ref={buttonRef}
|
||||
>
|
||||
<div>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
&_sidebar {
|
||||
display: grid;
|
||||
grid-template-columns: 40px auto 1fr;
|
||||
box-shadow: $color-background-body 0 1px 1px 0px;
|
||||
}
|
||||
|
||||
&_mobile {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { FC, useMemo } from "preact/compat";
|
||||
import { FC, useMemo } from "preact/compat";
|
||||
import { useCallback } from "react";
|
||||
import dayjs from "dayjs";
|
||||
import DownloadButton from "../../../components/DownloadButton/DownloadButton";
|
||||
@@ -7,10 +7,11 @@ import { downloadCSV, downloadJSON } from "../../../utils/file";
|
||||
import { Logs } from "../../../api/types";
|
||||
|
||||
interface DownloadLogsButtonProps {
|
||||
logs: Logs[];
|
||||
/** Callback to get logs to download */
|
||||
getLogs: () => Logs[];
|
||||
}
|
||||
|
||||
const DownloadLogsButton: FC<DownloadLogsButtonProps> = ({ logs }) => {
|
||||
const DownloadLogsButton: FC<DownloadLogsButtonProps> = ({ getLogs }) => {
|
||||
const { fileExtensions, getDownloaderByExtension } = useMemo(() => {
|
||||
const downloadFileOptions: {
|
||||
extension: string;
|
||||
@@ -39,12 +40,13 @@ const DownloadLogsButton: FC<DownloadLogsButtonProps> = ({ logs }) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const logs = getLogs();
|
||||
const downloader = getDownloaderByExtension(fileExtension);
|
||||
if (downloader){
|
||||
const timestamp = dayjs().utc().format(DATE_FILENAME_FORMAT);
|
||||
downloader(logs, `vmui_logs_${timestamp}.${fileExtension}`);
|
||||
}
|
||||
}, [logs]);
|
||||
}, [getLogs]);
|
||||
|
||||
return <DownloadButton
|
||||
title={"Download logs"}
|
||||
@@ -53,4 +55,4 @@ const DownloadLogsButton: FC<DownloadLogsButtonProps> = ({ logs }) => {
|
||||
/>;
|
||||
};
|
||||
|
||||
export default DownloadLogsButton;
|
||||
export default DownloadLogsButton;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { FC, useState, useMemo, useRef } from "preact/compat";
|
||||
import { CodeIcon, ListIcon, TableIcon } from "../../../components/Main/Icons";
|
||||
import { FC, useRef } from "preact/compat";
|
||||
import { CodeIcon, ListIcon, TableIcon, PlayIcon } from "../../../components/Main/Icons";
|
||||
import Tabs from "../../../components/Main/Tabs/Tabs";
|
||||
import "./style.scss";
|
||||
import classNames from "classnames";
|
||||
@@ -7,18 +7,11 @@ import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
import { Logs } from "../../../api/types";
|
||||
import useStateSearchParams from "../../../hooks/useStateSearchParams";
|
||||
import useSearchParamsFromObject from "../../../hooks/useSearchParamsFromObject";
|
||||
import TableSettings from "../../../components/Table/TableSettings/TableSettings";
|
||||
import useBoolean from "../../../hooks/useBoolean";
|
||||
import TableLogs from "./TableLogs";
|
||||
import GroupLogs from "../GroupLogs/GroupLogs";
|
||||
import JsonView from "../../../components/Views/JsonView/JsonView";
|
||||
import LineLoader from "../../../components/Main/LineLoader/LineLoader";
|
||||
import SelectLimit from "../../../components/Main/Pagination/SelectLimit/SelectLimit";
|
||||
import DownloadLogsButton from "../DownloadLogsButton/DownloadLogsButton";
|
||||
|
||||
const MemoizedTableLogs = React.memo(TableLogs);
|
||||
const MemoizedGroupLogs = React.memo(GroupLogs);
|
||||
const MemoizedJsonView = React.memo(JsonView);
|
||||
import GroupView from "./views/GroupView/GroupView";
|
||||
import TableView from "./views/TableView/TableView";
|
||||
import JsonView from "./views/JsonView/JsonView";
|
||||
import LiveTailingView from "./views/LiveTailingView/LiveTailingView";
|
||||
|
||||
export interface ExploreLogBodyProps {
|
||||
data: Logs[];
|
||||
@@ -29,44 +22,28 @@ enum DisplayType {
|
||||
group = "group",
|
||||
table = "table",
|
||||
json = "json",
|
||||
liveTailing = "liveTailing",
|
||||
}
|
||||
|
||||
const tabs = [
|
||||
{ label: "Group", value: DisplayType.group, icon: <ListIcon/> },
|
||||
{ label: "Table", value: DisplayType.table, icon: <TableIcon/> },
|
||||
{ label: "JSON", value: DisplayType.json, icon: <CodeIcon/> },
|
||||
{ label: "Group", value: DisplayType.group, icon: <ListIcon/>, Component: GroupView },
|
||||
{ label: "Table", value: DisplayType.table, icon: <TableIcon/>, Component: TableView },
|
||||
{ label: "JSON", value: DisplayType.json, icon: <CodeIcon/>, Component: JsonView },
|
||||
{ label: "Live", value: DisplayType.liveTailing, icon: <PlayIcon/>, Component: LiveTailingView },
|
||||
];
|
||||
|
||||
const ExploreLogsBody: FC<ExploreLogBodyProps> = ({ data, isLoading }) => {
|
||||
const { isMobile } = useDeviceDetect();
|
||||
const { setSearchParamsFromKeys } = useSearchParamsFromObject();
|
||||
const groupSettingsRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [activeTab, setActiveTab] = useStateSearchParams(DisplayType.group, "view");
|
||||
const [displayColumns, setDisplayColumns] = useState<string[]>([]);
|
||||
const [rowsPerPage, setRowsPerPage] = useStateSearchParams(1000, "rows_per_page");
|
||||
const { value: tableCompact, toggle: toggleTableCompact } = useBoolean(false);
|
||||
|
||||
const columns = useMemo(() => {
|
||||
if (!data?.length || activeTab !== DisplayType.table) return [];
|
||||
const keys = new Set<string>();
|
||||
for (const item of data) {
|
||||
for (const key in item) {
|
||||
keys.add(key);
|
||||
}
|
||||
}
|
||||
return Array.from(keys);
|
||||
}, [data, activeTab]);
|
||||
const settingsRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const handleChangeTab = (view: string) => {
|
||||
setActiveTab(view as DisplayType);
|
||||
setSearchParamsFromKeys({ view });
|
||||
};
|
||||
|
||||
const handleSetRowsPerPage = (limit: number) => {
|
||||
setRowsPerPage(limit);
|
||||
setSearchParamsFromKeys({ rows_per_page: limit });
|
||||
};
|
||||
const ActiveTabComponent = tabs.find(tab => tab.value === activeTab)?.Component;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -95,39 +72,16 @@ const ExploreLogsBody: FC<ExploreLogBodyProps> = ({ data, isLoading }) => {
|
||||
items={tabs}
|
||||
onChange={handleChangeTab}
|
||||
/>
|
||||
<div className="vm-explore-logs-body-header__log-info">
|
||||
Total logs returned: <b>{data.length}</b>
|
||||
</div>
|
||||
</div>
|
||||
{activeTab === DisplayType.table && (
|
||||
<div className="vm-explore-logs-body-header__settings">
|
||||
<SelectLimit
|
||||
limit={rowsPerPage}
|
||||
onChange={handleSetRowsPerPage}
|
||||
/>
|
||||
<div className="vm-explore-logs-body-header__table-settings">
|
||||
{data.length > 0 && <DownloadLogsButton logs={data} />}
|
||||
<TableSettings
|
||||
columns={columns}
|
||||
selectedColumns={displayColumns}
|
||||
onChangeColumns={setDisplayColumns}
|
||||
tableCompact={tableCompact}
|
||||
toggleTableCompact={toggleTableCompact}
|
||||
/>
|
||||
{activeTab !== DisplayType.liveTailing && (
|
||||
<div className="vm-explore-logs-body-header__log-info">
|
||||
Total logs returned: <b>{data.length}</b>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{activeTab === DisplayType.group && (
|
||||
<>
|
||||
<div
|
||||
className="vm-explore-logs-body-header__settings"
|
||||
ref={groupSettingsRef}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{activeTab === DisplayType.json && data.length > 0 && (
|
||||
<DownloadLogsButton logs={data} />
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="vm-explore-logs-body-header__settings"
|
||||
ref={settingsRef}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -136,29 +90,12 @@ const ExploreLogsBody: FC<ExploreLogBodyProps> = ({ data, isLoading }) => {
|
||||
"vm-explore-logs-body__table_mobile": isMobile,
|
||||
})}
|
||||
>
|
||||
{!data.length && <div className="vm-explore-logs-body__empty">No logs found</div>}
|
||||
{!!data.length && (
|
||||
<>
|
||||
{activeTab === DisplayType.table && (
|
||||
<MemoizedTableLogs
|
||||
logs={data}
|
||||
displayColumns={displayColumns}
|
||||
tableCompact={tableCompact}
|
||||
columns={columns}
|
||||
rowsPerPage={Number(rowsPerPage)}
|
||||
/>
|
||||
)}
|
||||
{activeTab === DisplayType.group && (
|
||||
<MemoizedGroupLogs
|
||||
logs={data}
|
||||
settingsRef={groupSettingsRef}
|
||||
/>
|
||||
)}
|
||||
{activeTab === DisplayType.json && (
|
||||
<MemoizedJsonView data={data}/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{ActiveTabComponent &&
|
||||
<ActiveTabComponent
|
||||
data={data}
|
||||
settingsRef={settingsRef}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,15 @@
|
||||
position: relative;
|
||||
|
||||
&-header {
|
||||
background-color: $color-background-block;
|
||||
z-index: 1;
|
||||
margin: -$padding-medium 0-$padding-medium 0;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
@media (max-width:1000px) {
|
||||
top: 51px;
|
||||
}
|
||||
|
||||
&_mobile {
|
||||
margin: -$padding-global 0-$padding-global 0;
|
||||
@@ -19,11 +27,6 @@
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
&__table-settings {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
&__log-info {
|
||||
flex-grow: 1;
|
||||
text-align: right;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { Logs } from "../../../api/types";
|
||||
|
||||
export interface ViewProps {
|
||||
data: Logs[];
|
||||
settingsRef: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React, { FC } from "preact/compat";
|
||||
import GroupLogs from "../../../GroupLogs/GroupLogs";
|
||||
import { ViewProps } from "../../types";
|
||||
import EmptyLogs from "../components/EmptyLogs/EmptyLogs";
|
||||
|
||||
const MemoizedGroupLogs = React.memo(GroupLogs);
|
||||
|
||||
const GroupView: FC<ViewProps> = ({ data, settingsRef }) => {
|
||||
if (!data.length) return <EmptyLogs />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<MemoizedGroupLogs
|
||||
logs={data}
|
||||
settingsRef={settingsRef}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GroupView;
|
||||
@@ -0,0 +1,33 @@
|
||||
import React, { FC } from "preact/compat";
|
||||
import DownloadLogsButton from "../../../DownloadLogsButton/DownloadLogsButton";
|
||||
import { createPortal } from "preact/compat";
|
||||
import JsonViewComponent from "../../../../../components/Views/JsonView/JsonView";
|
||||
import { ViewProps } from "../../types";
|
||||
import EmptyLogs from "../components/EmptyLogs/EmptyLogs";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const MemoizedJsonView = React.memo(JsonViewComponent);
|
||||
|
||||
const JsonView: FC<ViewProps> = ({ data, settingsRef }) => {
|
||||
const getLogs = useCallback(() => data, [data]);
|
||||
|
||||
const renderSettings = () => {
|
||||
if (!settingsRef.current) return null;
|
||||
|
||||
return createPortal(
|
||||
data.length > 0 && <DownloadLogsButton getLogs={getLogs} />,
|
||||
settingsRef.current
|
||||
);
|
||||
};
|
||||
|
||||
if (!data.length) return <EmptyLogs />;
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderSettings()}
|
||||
<MemoizedJsonView data={data} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default JsonView;
|
||||
@@ -0,0 +1,125 @@
|
||||
import { FC, RefObject, useCallback, useRef } from "preact/compat";
|
||||
import { createPortal } from "preact/compat";
|
||||
import DownloadLogsButton from "../../../DownloadLogsButton/DownloadLogsButton";
|
||||
import Button from "../../../../../components/Main/Button/Button";
|
||||
import SelectLimit from "../../../../../components/Main/Pagination/SelectLimit/SelectLimit";
|
||||
import { DeleteIcon, PauseIcon, PlayCircleOutlineIcon, SettingsIcon } from "../../../../../components/Main/Icons";
|
||||
import Tooltip from "../../../../../components/Main/Tooltip/Tooltip";
|
||||
import Modal from "../../../../../components/Main/Modal/Modal";
|
||||
import Switch from "../../../../../components/Main/Switch/Switch";
|
||||
import useBoolean from "../../../../../hooks/useBoolean";
|
||||
import { Logs } from "../../../../../api/types";
|
||||
|
||||
interface LiveTailingSettingsProps {
|
||||
settingsRef: RefObject<HTMLDivElement>;
|
||||
rowsPerPage: number;
|
||||
handleSetRowsPerPage: (limit: number) => void;
|
||||
logs: Logs[];
|
||||
isPaused: boolean;
|
||||
handleResumeLiveTailing: () => void;
|
||||
pauseLiveTailing: () => void;
|
||||
clearLogs: () => void;
|
||||
isCompactTailingNumber: boolean;
|
||||
handleSetCompactTailing: (value: boolean) => void;
|
||||
}
|
||||
|
||||
const LiveTailingSettings: FC<LiveTailingSettingsProps> = ({
|
||||
settingsRef,
|
||||
rowsPerPage,
|
||||
handleSetRowsPerPage,
|
||||
logs,
|
||||
isPaused,
|
||||
handleResumeLiveTailing,
|
||||
pauseLiveTailing,
|
||||
clearLogs,
|
||||
isCompactTailingNumber,
|
||||
handleSetCompactTailing
|
||||
}) => {
|
||||
const settingButtonRef = useRef<HTMLDivElement>(null);
|
||||
const { value: isSettingsOpen, setFalse: closeSettings, setTrue: openSettings } = useBoolean(false);
|
||||
|
||||
const getLogs = useCallback(() => logs.map(({ _log_id, ...log }) => log), [logs]);
|
||||
|
||||
if (!settingsRef.current) return null;
|
||||
|
||||
return createPortal(
|
||||
<div className="vm-live-tailing-view__settings">
|
||||
<SelectLimit
|
||||
limit={rowsPerPage}
|
||||
onChange={handleSetRowsPerPage}
|
||||
onOpenSelect={pauseLiveTailing}
|
||||
/>
|
||||
<div className="vm-live-tailing-view__settings-buttons">
|
||||
{logs.length > 0 && <DownloadLogsButton getLogs={getLogs}/>}
|
||||
{isPaused ? (
|
||||
<Tooltip
|
||||
title={"Resume live tailing"}
|
||||
>
|
||||
<Button
|
||||
variant="text"
|
||||
color="primary"
|
||||
onClick={handleResumeLiveTailing}
|
||||
startIcon={<PlayCircleOutlineIcon/>}
|
||||
ariaLabel={"Resume live tailing"}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip
|
||||
title={"Pause live tailing"}
|
||||
>
|
||||
<Button
|
||||
variant="text"
|
||||
color="primary"
|
||||
onClick={pauseLiveTailing}
|
||||
startIcon={<PauseIcon/>}
|
||||
ariaLabel={"Pause live tailing"}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip
|
||||
title={"Clear logs"}
|
||||
>
|
||||
<Button
|
||||
variant="text"
|
||||
color="secondary"
|
||||
onClick={clearLogs}
|
||||
startIcon={<DeleteIcon/>}
|
||||
ariaLabel={"Clear logs"}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={"Settings"}
|
||||
>
|
||||
<Button
|
||||
ref={settingButtonRef}
|
||||
variant="text"
|
||||
color="secondary"
|
||||
onClick={openSettings}
|
||||
startIcon={<SettingsIcon/>}
|
||||
ariaLabel={"Settings"}
|
||||
/>
|
||||
</Tooltip>
|
||||
{isSettingsOpen && <Modal
|
||||
onClose={closeSettings}
|
||||
title={"Live tailing settings"}
|
||||
>
|
||||
<div className="vm-live-tailing-view__settings-modal">
|
||||
<div className={"vm-live-tailing-view__settings-modal-item"}>
|
||||
<Switch
|
||||
label={"Expandable Properties View"}
|
||||
value={isCompactTailingNumber}
|
||||
onChange={handleSetCompactTailing}
|
||||
/>
|
||||
<span className="vm-group-logs-configurator-item__info">
|
||||
Switches log display to expandable properties view with additional visualization settings. Please note: when processing large volumes of data, it may increase system response time.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>}
|
||||
</div>
|
||||
</div>,
|
||||
settingsRef.current
|
||||
);
|
||||
};
|
||||
|
||||
export default LiveTailingSettings;
|
||||
@@ -0,0 +1,145 @@
|
||||
import { FC, useCallback, useEffect, useRef, useState } from "preact/compat";
|
||||
import { ViewProps } from "../../types";
|
||||
import useStateSearchParams from "../../../../../hooks/useStateSearchParams";
|
||||
import useSearchParamsFromObject from "../../../../../hooks/useSearchParamsFromObject";
|
||||
import "./style.scss";
|
||||
import { useLiveTailingLogs } from "./useLiveTailingLogs";
|
||||
import { LOGS_DISPLAY_FIELDS, LOGS_URL_PARAMS } from "../../../../../constants/logs";
|
||||
import { useMemo } from "react";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import throttle from "lodash/throttle";
|
||||
import GroupLogsItem from "../../../GroupLogs/GroupLogsItem";
|
||||
import LiveTailingSettings from "./LiveTailingSettings";
|
||||
|
||||
const SCROLL_THRESHOLD = 100;
|
||||
const scrollToBottom = () => window.scrollTo({
|
||||
top: document.documentElement.scrollHeight,
|
||||
behavior: "instant"
|
||||
});
|
||||
const throttledScrollToBottom = throttle(scrollToBottom, 200);
|
||||
|
||||
const LiveTailingView: FC<ViewProps> = ({ settingsRef }) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [isAtBottom, setIsAtBottom] = useState(true);
|
||||
const [searchParams] = useSearchParams();
|
||||
const { setSearchParamsFromKeys } = useSearchParamsFromObject();
|
||||
const [rowsPerPage, setRowsPerPage] = useStateSearchParams(100, "rows_per_page");
|
||||
const [query, _setQuery] = useStateSearchParams("*", "query");
|
||||
const [isCompactTailingStr] = useStateSearchParams(0, "compact_tailing");
|
||||
const isCompactTailingNumber = Boolean(Number(isCompactTailingStr));
|
||||
const {
|
||||
logs,
|
||||
isPaused,
|
||||
error,
|
||||
startLiveTailing,
|
||||
stopLiveTailing,
|
||||
pauseLiveTailing,
|
||||
resumeLiveTailing,
|
||||
clearLogs
|
||||
} = useLiveTailingLogs(query, rowsPerPage);
|
||||
|
||||
const displayFieldsString = searchParams.get(LOGS_URL_PARAMS.DISPLAY_FIELDS) || LOGS_DISPLAY_FIELDS;
|
||||
const displayFields = useMemo(() => displayFieldsString.split(","), [displayFieldsString]);
|
||||
|
||||
const handleResumeLiveTailing = useCallback(() => {
|
||||
throttledScrollToBottom();
|
||||
resumeLiveTailing();
|
||||
}, [resumeLiveTailing]);
|
||||
|
||||
const handleSetRowsPerPage = useCallback((limit: number) => {
|
||||
setSearchParamsFromKeys({ rows_per_page: limit });
|
||||
}, [setRowsPerPage, setSearchParamsFromKeys]);
|
||||
|
||||
const handleSetCompactTailing = useCallback((value: boolean) => {
|
||||
setSearchParamsFromKeys({ compact_tailing: Number(value) });
|
||||
}, [setSearchParamsFromKeys]);
|
||||
|
||||
useEffect(() => {
|
||||
startLiveTailing();
|
||||
return () => stopLiveTailing();
|
||||
}, [startLiveTailing, stopLiveTailing]);
|
||||
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
if (!container) return;
|
||||
|
||||
const handleScroll = () => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
|
||||
const isBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < SCROLL_THRESHOLD;
|
||||
|
||||
setIsAtBottom(isBottom);
|
||||
|
||||
if (!isBottom && !isPaused) {
|
||||
pauseLiveTailing();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("scroll", handleScroll);
|
||||
return () => document.removeEventListener("scroll", handleScroll);
|
||||
}, [isPaused, pauseLiveTailing, resumeLiveTailing]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAtBottom && !isPaused) {
|
||||
throttledScrollToBottom();
|
||||
}
|
||||
}, [logs, isAtBottom]);
|
||||
|
||||
useEffect(() => {
|
||||
handleResumeLiveTailing();
|
||||
}, [rowsPerPage]);
|
||||
|
||||
|
||||
|
||||
if (error) {
|
||||
return <div className="vm-live-tailing-view__error">{error}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<LiveTailingSettings
|
||||
settingsRef={settingsRef}
|
||||
rowsPerPage={rowsPerPage}
|
||||
handleSetRowsPerPage={handleSetRowsPerPage}
|
||||
logs={logs}
|
||||
isPaused={isPaused}
|
||||
handleResumeLiveTailing={handleResumeLiveTailing}
|
||||
pauseLiveTailing={pauseLiveTailing}
|
||||
clearLogs={clearLogs}
|
||||
isCompactTailingNumber={isCompactTailingNumber}
|
||||
handleSetCompactTailing={handleSetCompactTailing}
|
||||
/>
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="vm-live-tailing-view__container"
|
||||
>
|
||||
{logs.length === 0
|
||||
? (<div className="vm-live-tailing-view__empty">Waiting for logs...</div>)
|
||||
: (<div className="vm-live-tailing-view__logs">
|
||||
{logs.map(({ _log_id, ...log }, idx) =>
|
||||
isCompactTailingNumber
|
||||
? (
|
||||
<GroupLogsItem
|
||||
key={_log_id}
|
||||
log={log}
|
||||
onItemClick={pauseLiveTailing}
|
||||
hideGroupButton={true}
|
||||
displayFields={displayFields}
|
||||
/>
|
||||
) : (
|
||||
<pre
|
||||
key={idx}
|
||||
className="vm-live-tailing-view__log-row"
|
||||
>
|
||||
{JSON.stringify(log)}
|
||||
</pre>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LiveTailingView;
|
||||
@@ -0,0 +1,76 @@
|
||||
@use "src/styles/variables" as *;
|
||||
|
||||
.vm-live-tailing-view {
|
||||
&__settings {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__settings-modal {
|
||||
max-width: 500px;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
&__settings-modal-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $padding-small;
|
||||
}
|
||||
|
||||
&__settings-modal-item-info {
|
||||
font-size: $font-size-small;
|
||||
color: $color-text-secondary;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
&__settings-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: $padding-global;
|
||||
min-height: 200px;
|
||||
font-family: $font-family-monospace;
|
||||
}
|
||||
|
||||
&__empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: $color-text-secondary;
|
||||
}
|
||||
|
||||
&__error {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: $color-error;
|
||||
}
|
||||
|
||||
&__logs {
|
||||
.vm-group-logs-row {
|
||||
animation: highlight-fade 1s ease-out forwards;
|
||||
}
|
||||
}
|
||||
|
||||
&__log-row {
|
||||
margin-top: $padding-small;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes highlight-fade {
|
||||
0% {
|
||||
background-color: $color-tropical-blue;
|
||||
}
|
||||
100% {
|
||||
background-color: $color-background-block;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "preact/compat";
|
||||
import { ErrorTypes } from "../../../../../types";
|
||||
import { Logs } from "../../../../../api/types";
|
||||
import { useAppState } from "../../../../../state/common/StateContext";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import useBoolean from "../../../../../hooks/useBoolean";
|
||||
|
||||
export const useLiveTailingLogs = (query: string, limit: number) => {
|
||||
const { serverUrl } = useAppState();
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const [logs, setLogs] = useState<Logs[]>([]);
|
||||
const { value: isPaused, setTrue: pauseLiveTailing, setFalse: resumeLiveTailing } = useBoolean(false);
|
||||
const [error, setError] = useState<ErrorTypes | string>();
|
||||
|
||||
const counterRef = useRef<bigint>(0n);
|
||||
const abortControllerRef = useRef(new AbortController());
|
||||
const readerRef = useRef<ReadableStreamDefaultReader<Uint8Array> | null>(null);
|
||||
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
const bufferRef = useRef<string>("");
|
||||
|
||||
const stopLiveTailing = useCallback(() => {
|
||||
if (readerRef.current) {
|
||||
readerRef.current.cancel();
|
||||
readerRef.current = null;
|
||||
}
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
if (bufferRef.current) {
|
||||
bufferRef.current = "";
|
||||
}
|
||||
abortControllerRef.current.abort();
|
||||
}, []);
|
||||
|
||||
const startLiveTailing = useCallback(async () => {
|
||||
stopLiveTailing();
|
||||
|
||||
abortControllerRef.current = new AbortController();
|
||||
const { signal } = abortControllerRef.current;
|
||||
|
||||
setError(undefined);
|
||||
setLogs([]);
|
||||
|
||||
try {
|
||||
const tenant = {
|
||||
AccountID: searchParams.get("accountID") || "0",
|
||||
ProjectID: searchParams.get("projectID") || "0"
|
||||
};
|
||||
const response = await fetch(`${serverUrl}/select/logsql/tail`, {
|
||||
signal,
|
||||
method: "POST",
|
||||
headers: {
|
||||
...tenant,
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
query: query.trim(),
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok || !response.body) {
|
||||
const text = await response.text();
|
||||
setError(text);
|
||||
setLogs([]);
|
||||
return false;
|
||||
}
|
||||
|
||||
const reader = response.body.getReader();
|
||||
readerRef.current = reader;
|
||||
|
||||
const processStream = async () => {
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
// Convert the Uint8Array to a string
|
||||
const chunk = new TextDecoder().decode(value);
|
||||
bufferRef.current += chunk;
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof Error && e.name !== "AbortError") {
|
||||
console.error("Stream processing error:", e);
|
||||
setError(String(e));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
processStream();
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e instanceof Error && e.name !== "AbortError") {
|
||||
setError(String(e));
|
||||
console.error(e);
|
||||
setLogs([]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}, [query, stopLiveTailing]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (isPaused) return;
|
||||
|
||||
/**
|
||||
* Process incoming log data at a throttled rate (every 1s)
|
||||
* This interval-based approach prevents CPU overload by:
|
||||
* 1. Batching log processing instead of processing each chunk immediately
|
||||
* 2. Limiting UI updates to a reasonable frequency (1/sec) even when data streams in rapidly
|
||||
* 3. Reducing performance impact when handling large volumes of incoming logs
|
||||
* 4. Allowing efficient garbage collection between processing cycles
|
||||
*/
|
||||
const timerId = setInterval(() => {
|
||||
const lines = bufferRef.current.split("\n");
|
||||
bufferRef.current = lines.pop() || "";
|
||||
|
||||
const newLogs = lines
|
||||
.map(line => {
|
||||
try {
|
||||
const parsedLine = line && JSON.parse(line);
|
||||
parsedLine._log_id = counterRef.current++;
|
||||
return parsedLine;
|
||||
} catch (e) {
|
||||
console.error(`Failed to parse "${line}" to JSON\n`, e);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Boolean) as Logs[];
|
||||
|
||||
setLogs(prevLogs => {
|
||||
const combinedLogs = [...prevLogs, ...newLogs];
|
||||
return combinedLogs.length > limit ? combinedLogs.slice(-limit) : combinedLogs;
|
||||
});
|
||||
}, 1000);
|
||||
return () => clearInterval(timerId);
|
||||
}, [limit, isPaused]);
|
||||
|
||||
const clearLogs = useCallback(() => {
|
||||
setLogs([]);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
logs,
|
||||
isPaused,
|
||||
error,
|
||||
startLiveTailing,
|
||||
stopLiveTailing,
|
||||
pauseLiveTailing,
|
||||
resumeLiveTailing,
|
||||
clearLogs
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
import React, { FC, useMemo, useState } from "preact/compat";
|
||||
import DownloadLogsButton from "../../../DownloadLogsButton/DownloadLogsButton";
|
||||
import { createPortal } from "preact/compat";
|
||||
import "./style.scss";
|
||||
import { ViewProps } from "../../types";
|
||||
import useBoolean from "../../../../../hooks/useBoolean";
|
||||
import useStateSearchParams from "../../../../../hooks/useStateSearchParams";
|
||||
import TableLogs from "../../TableLogs";
|
||||
import SelectLimit from "../../../../../components/Main/Pagination/SelectLimit/SelectLimit";
|
||||
import TableSettings from "../../../../../components/Table/TableSettings/TableSettings";
|
||||
import useSearchParamsFromObject from "../../../../../hooks/useSearchParamsFromObject";
|
||||
import EmptyLogs from "../components/EmptyLogs/EmptyLogs";
|
||||
import { useCallback } from "react";
|
||||
|
||||
const MemoizedTableView = React.memo(TableLogs);
|
||||
|
||||
const TableView: FC<ViewProps> = ({ data, settingsRef }) => {
|
||||
const { setSearchParamsFromKeys } = useSearchParamsFromObject();
|
||||
const [displayColumns, setDisplayColumns] = useState<string[]>([]);
|
||||
const [rowsPerPage, setRowsPerPage] = useStateSearchParams(100, "rows_per_page");
|
||||
const { value: tableCompact, toggle: toggleTableCompact } = useBoolean(false);
|
||||
|
||||
const columns = useMemo(() => {
|
||||
const keys = new Set<string>();
|
||||
for (const item of data) {
|
||||
for (const key in item) {
|
||||
keys.add(key);
|
||||
}
|
||||
}
|
||||
return Array.from(keys);
|
||||
}, [data]);
|
||||
|
||||
const handleSetRowsPerPage = (limit: number) => {
|
||||
setRowsPerPage(limit);
|
||||
setSearchParamsFromKeys({ rows_per_page: limit });
|
||||
};
|
||||
|
||||
const getLogs = useCallback(() => data, [data]);
|
||||
|
||||
const renderSettings = () => {
|
||||
if (!settingsRef.current) return null;
|
||||
|
||||
return createPortal(
|
||||
<div className="vm-table-view__settings">
|
||||
<SelectLimit
|
||||
limit={rowsPerPage}
|
||||
onChange={handleSetRowsPerPage}
|
||||
/>
|
||||
<div className="vm-table-view__settings-buttons">
|
||||
{data.length > 0 && <DownloadLogsButton getLogs={getLogs} />}
|
||||
<TableSettings
|
||||
columns={columns}
|
||||
selectedColumns={displayColumns}
|
||||
onChangeColumns={setDisplayColumns}
|
||||
tableCompact={tableCompact}
|
||||
toggleTableCompact={toggleTableCompact}
|
||||
/>
|
||||
</div>
|
||||
</div>,
|
||||
settingsRef.current
|
||||
);
|
||||
};
|
||||
|
||||
if (!data.length) return <EmptyLogs />;
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderSettings()}
|
||||
<MemoizedTableView
|
||||
logs={data}
|
||||
displayColumns={displayColumns}
|
||||
tableCompact={tableCompact}
|
||||
columns={columns}
|
||||
rowsPerPage={Number(rowsPerPage)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableView;
|
||||
@@ -0,0 +1,10 @@
|
||||
@use "src/styles/variables" as *;
|
||||
|
||||
.vm-table-view {
|
||||
&__settings,
|
||||
&__settings-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $padding-small;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { FC } from "preact/compat";
|
||||
import "./style.scss";
|
||||
|
||||
const EmptyLogs: FC = () => {
|
||||
return (
|
||||
<div className="vm-explore-logs-body__empty">No logs found</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmptyLogs;
|
||||
@@ -0,0 +1,12 @@
|
||||
@use "src/styles/variables" as *;
|
||||
|
||||
.vm-explore-logs-body {
|
||||
&__empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 120px;
|
||||
color: $color-text-disabled;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
@@ -96,6 +96,8 @@ const GroupLogs: FC<Props> = ({ logs, settingsRef }) => {
|
||||
window.scrollTo({ top: 0 });
|
||||
};
|
||||
|
||||
const getLogs = useCallback(() => logs, [logs]);
|
||||
|
||||
useEffect(() => {
|
||||
setExpandGroups(new Array(groupData.length).fill(!isMobile));
|
||||
}, [groupData]);
|
||||
@@ -162,7 +164,7 @@ const GroupLogs: FC<Props> = ({ logs, settingsRef }) => {
|
||||
ariaLabel={expandAll ? "Collapse All" : "Expand All"}
|
||||
/>
|
||||
</Tooltip>
|
||||
<DownloadLogsButton logs={logs} />
|
||||
<DownloadLogsButton getLogs={getLogs} />
|
||||
<GroupLogsConfigurators logs={logs}/>
|
||||
</div>
|
||||
), settingsRef.current)}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { FC, memo, useCallback, useEffect, useState } from "preact/compat";
|
||||
import { FC, memo, useCallback, useEffect, useState } from "preact/compat";
|
||||
import Tooltip from "../../../components/Main/Tooltip/Tooltip";
|
||||
import Button from "../../../components/Main/Button/Button";
|
||||
import { CopyIcon, StorageIcon, VisibilityIcon } from "../../../components/Main/Icons";
|
||||
@@ -9,9 +9,10 @@ import { LOGS_GROUP_BY, LOGS_URL_PARAMS } from "../../../constants/logs";
|
||||
interface Props {
|
||||
field: string;
|
||||
value: string;
|
||||
hideGroupButton?: boolean;
|
||||
}
|
||||
|
||||
const GroupLogsFieldRow: FC<Props> = ({ field, value }) => {
|
||||
const GroupLogsFieldRow: FC<Props> = ({ field, value, hideGroupButton }) => {
|
||||
const copyToClipboard = useCopyToClipboard();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
@@ -75,20 +76,22 @@ const GroupLogsFieldRow: FC<Props> = ({ field, value }) => {
|
||||
size="small"
|
||||
startIcon={isSelectedField ? <VisibilityIcon/> : <VisibilityIcon/>}
|
||||
onClick={handleSelectDisplayField}
|
||||
ariaLabel="copy to clipboard"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip 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"
|
||||
ariaLabel={isSelectedField ? "Hide this field" : "Show this field instead of the message"}
|
||||
/>
|
||||
</Tooltip>
|
||||
{!hideGroupButton && (
|
||||
<Tooltip 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={isGroupByField ? "Ungroup this field" : "Group by this field"}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="vm-group-logs-row-fields-item__key">{field}</td>
|
||||
|
||||
@@ -8,9 +8,10 @@ import { getFromStorage } from "../../../utils/storage";
|
||||
|
||||
interface Props {
|
||||
log: Logs;
|
||||
hideGroupButton?: boolean;
|
||||
}
|
||||
|
||||
const GroupLogsFields: FC<Props> = ({ log }) => {
|
||||
const GroupLogsFields: FC<Props> = ({ log, hideGroupButton }) => {
|
||||
const sortedFields = useMemo(() => {
|
||||
return Object.entries(log)
|
||||
.sort(([aKey], [bKey]) => aKey.localeCompare(bKey));
|
||||
@@ -41,6 +42,7 @@ const GroupLogsFields: FC<Props> = ({ log }) => {
|
||||
key={key}
|
||||
field={key}
|
||||
value={value}
|
||||
hideGroupButton={hideGroupButton}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
|
||||
@@ -18,9 +18,11 @@ import GroupLogsFields from "./GroupLogsFields";
|
||||
interface Props {
|
||||
log: Logs;
|
||||
displayFields?: string[];
|
||||
hideGroupButton?: boolean;
|
||||
onItemClick?: (log: Logs) => void;
|
||||
}
|
||||
|
||||
const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
|
||||
const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"], onItemClick, hideGroupButton }) => {
|
||||
const {
|
||||
value: isOpenFields,
|
||||
toggle: toggleOpenFields,
|
||||
@@ -75,6 +77,11 @@ const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
toggleOpenFields();
|
||||
onItemClick?.(log);
|
||||
};
|
||||
|
||||
useEventListener("storage", handleUpdateStage);
|
||||
|
||||
return (
|
||||
@@ -84,7 +91,7 @@ const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
|
||||
"vm-group-logs-row-content": true,
|
||||
"vm-group-logs-row-content_interactive": !disabledHovers,
|
||||
})}
|
||||
onClick={toggleOpenFields}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{hasFields && (
|
||||
<div
|
||||
@@ -123,7 +130,10 @@ const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{hasFields && isOpenFields && <GroupLogsFields log={log}/>}
|
||||
{hasFields && isOpenFields && <GroupLogsFields
|
||||
hideGroupButton={hideGroupButton}
|
||||
log={log}
|
||||
/>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -101,7 +101,7 @@ const Relabel: FC = () => {
|
||||
<a
|
||||
className="vm-link vm-link_with-icon"
|
||||
target="_blank"
|
||||
href="https://docs.victoriametrics.com/victoriametrics/vmagent/#relabeling"
|
||||
href="https://docs.victoriametrics.com/victoriametrics/relabeling/"
|
||||
rel="help noreferrer"
|
||||
>
|
||||
<WikiIcon/>
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "preact",
|
||||
"downlevelIteration": true,
|
||||
"noUnusedLocals": true,
|
||||
"paths": {
|
||||
"react": ["./node_modules/preact/compat/"],
|
||||
"react/jsx-runtime": ["./node_modules/preact/jsx-runtime"],
|
||||
|
||||
@@ -8,6 +8,28 @@ const getProxy = (): Record<string, ProxyOptions> | undefined => {
|
||||
const playground = process.env.PLAYGROUND;
|
||||
|
||||
switch (playground) {
|
||||
case "METRICS": {
|
||||
return {
|
||||
"^/vmalert/.*": {
|
||||
target: "https://play.victoriametrics.com",
|
||||
changeOrigin: true,
|
||||
configure: (proxy) => {
|
||||
proxy.on("error", (err) => {
|
||||
console.error("[proxy error]", err.message);
|
||||
});
|
||||
}
|
||||
},
|
||||
"^/api/.*": {
|
||||
target: "https://play.victoriametrics.com/select/0/prometheus/",
|
||||
changeOrigin: true,
|
||||
configure: (proxy) => {
|
||||
proxy.on("error", (err) => {
|
||||
console.error("[proxy error]", err.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
case "LOGS": {
|
||||
return {
|
||||
"^/select/.*": {
|
||||
|
||||
@@ -31,6 +31,7 @@ type app struct {
|
||||
binary string
|
||||
flags []string
|
||||
process *os.Process
|
||||
wait bool
|
||||
}
|
||||
|
||||
// appOptions holds the optional configuration of an app, such as default flags
|
||||
@@ -38,6 +39,7 @@ type app struct {
|
||||
type appOptions struct {
|
||||
defaultFlags map[string]string
|
||||
extractREs []*regexp.Regexp
|
||||
wait bool
|
||||
}
|
||||
|
||||
// startApp starts an instance of an app using the app binary file path and
|
||||
@@ -73,6 +75,7 @@ func startApp(instance string, binary string, flags []string, opts *appOptions)
|
||||
binary: binary,
|
||||
flags: flags,
|
||||
process: cmd.Process,
|
||||
wait: opts.wait,
|
||||
}
|
||||
|
||||
go app.processOutput("stdout", stdout, app.writeToStderr)
|
||||
@@ -92,7 +95,11 @@ func startApp(instance string, binary string, flags []string, opts *appOptions)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return app, extracts, nil
|
||||
if app.wait {
|
||||
err = cmd.Wait()
|
||||
}
|
||||
|
||||
return app, extracts, err
|
||||
}
|
||||
|
||||
// setDefaultFlags adds flags with default values to `flags` if it does not
|
||||
@@ -112,9 +119,12 @@ func setDefaultFlags(flags []string, defaultFlags map[string]string) []string {
|
||||
return flags
|
||||
}
|
||||
|
||||
// stop sends the app process a SIGINT signal and waits until it terminates
|
||||
// Stop sends the app process a SIGINT signal and waits until it terminates
|
||||
// gracefully.
|
||||
func (app *app) Stop() {
|
||||
if app.wait {
|
||||
return
|
||||
}
|
||||
if err := app.process.Signal(os.Interrupt); err != nil {
|
||||
log.Fatalf("Could not send SIGINT signal to %s process: %v", app.instance, err)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
|
||||
)
|
||||
|
||||
// TestCase holds the state and defines clean-up procedure common for all test
|
||||
@@ -251,6 +252,18 @@ func (tc *TestCase) MustStartCluster(opts *ClusterOptions) PrometheusWriteQuerie
|
||||
return &Vmcluster{vminsert, vmselect, []*Vmstorage{vmstorage1, vmstorage2}}
|
||||
}
|
||||
|
||||
// MustStartVmctl is a test helper function that starts an instance of vmctl
|
||||
func (tc *TestCase) MustStartVmctl(instance string, flags []string) *Vmctl {
|
||||
tc.t.Helper()
|
||||
|
||||
app, err := StartVmctl(instance, flags)
|
||||
if err != nil {
|
||||
tc.t.Fatalf("Could not start %s: %v", instance, err)
|
||||
}
|
||||
tc.addApp(instance, app)
|
||||
return app
|
||||
}
|
||||
|
||||
func (tc *TestCase) addApp(instance string, app Stopper) {
|
||||
if _, alreadyStarted := tc.startedApps[instance]; alreadyStarted {
|
||||
tc.t.Fatalf("%s has already been started", instance)
|
||||
|
||||
270769
apptest/tests/testdata/prometheus/expected_response.json
vendored
Normal file
270769
apptest/tests/testdata/prometheus/expected_response.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
80
apptest/tests/vmctl_prometheus_migration_test.go
Normal file
80
apptest/tests/vmctl_prometheus_migration_test.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/apptest"
|
||||
)
|
||||
|
||||
func TestVmctlPrometheusProtocolToVMSingle(t *testing.T) {
|
||||
os.RemoveAll(t.Name())
|
||||
|
||||
tc := apptest.NewTestCase(t)
|
||||
defer tc.Stop()
|
||||
|
||||
cmpOpt := cmpopts.IgnoreFields(apptest.PrometheusAPIV1QueryResponse{}, "Status", "Data.ResultType")
|
||||
|
||||
vmsingleDst := tc.MustStartVmsingle("vmsingle", []string{
|
||||
"-storageDataPath=" + tc.Dir() + "/vmsingle",
|
||||
"-retentionPeriod=100y",
|
||||
})
|
||||
|
||||
// test for empty data request
|
||||
got := vmsingleDst.PrometheusAPIV1Query(t, `{__name__=~".*"}`, apptest.QueryOpts{
|
||||
Step: "5m",
|
||||
Time: "2025-01-18T12:45:00Z",
|
||||
})
|
||||
|
||||
want := apptest.NewPrometheusAPIV1QueryResponse(t, `{"data":{"result":[]}}`)
|
||||
if diff := cmp.Diff(want, got, cmpOpt); diff != "" {
|
||||
t.Errorf("unexpected response (-want, +got):\n%s", diff)
|
||||
}
|
||||
|
||||
vmAddr := fmt.Sprintf("http://%s/", vmsingleDst.HTTPAddr())
|
||||
testSnapshot := "./testdata/prometheus/snapshots/20250118T124506Z-59d1b952d7eaf547"
|
||||
_ = tc.MustStartVmctl("vmctl", []string{
|
||||
`prometheus`,
|
||||
`--prom-snapshot=` + testSnapshot,
|
||||
`--vm-addr=` + vmAddr,
|
||||
`--disable-progress-bar=true`,
|
||||
})
|
||||
|
||||
vmsingleDst.ForceFlush(t)
|
||||
|
||||
// open the expected series response file
|
||||
file, err := os.Open("./testdata/prometheus/expected_response.json")
|
||||
if err != nil {
|
||||
t.Fatalf("cannot open expected series response file: %s", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
bytes, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot read expected series response file: %s", err)
|
||||
}
|
||||
|
||||
wantResponse := apptest.NewPrometheusAPIV1QueryResponse(t, string(bytes))
|
||||
wantResponse.Sort()
|
||||
|
||||
tc.Assert(&apptest.AssertOptions{
|
||||
Msg: `unexpected metrics stored on vmsingle via the prometheus protocol`,
|
||||
Got: func() any {
|
||||
exported := vmsingleDst.PrometheusAPIV1Export(t, `{__name__=~".*"}`, apptest.QueryOpts{
|
||||
Start: "2025-01-18T00:45:00Z",
|
||||
End: "2025-01-18T23:46:00Z",
|
||||
})
|
||||
exported.Sort()
|
||||
return exported
|
||||
},
|
||||
Want: &apptest.PrometheusAPIV1QueryResponse{Data: wantResponse.Data},
|
||||
CmpOpts: []cmp.Option{
|
||||
cmpopts.IgnoreFields(apptest.PrometheusAPIV1QueryResponse{}, "Status", "Data.ResultType"),
|
||||
},
|
||||
})
|
||||
}
|
||||
18
apptest/vmctl.go
Normal file
18
apptest/vmctl.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package apptest
|
||||
|
||||
// Vmctl holds the state of a vmctl app and provides vmctl-specific functions
|
||||
type Vmctl struct {
|
||||
*app
|
||||
}
|
||||
|
||||
// StartVmctl starts an instance of vmctl cli with the given flags
|
||||
func StartVmctl(instance string, flags []string) (*Vmctl, error) {
|
||||
app, _, err := startApp(instance, "../../bin/vmctl", flags, &appOptions{wait: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Vmctl{
|
||||
app: app,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,50 +1,4 @@
|
||||
{
|
||||
"__inputs": [],
|
||||
"__elements": {},
|
||||
"__requires": [
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "11.5.0"
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "prometheus",
|
||||
"name": "Prometheus",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "stat",
|
||||
"name": "Stat",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "table",
|
||||
"name": "Table",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "text",
|
||||
"name": "Text",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "timeseries",
|
||||
"name": "Time series",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "victoriametrics-logs-datasource",
|
||||
"name": "VictoriaLogs",
|
||||
"version": "0.16.3"
|
||||
}
|
||||
],
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
@@ -92,11 +46,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Overview for cluster version of VictoriaLogs v1.18.0 or higher",
|
||||
"description": "Overview for cluster version of VictoriaLogs v1.22.0 or higher",
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"id": 1,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
@@ -478,6 +432,10 @@
|
||||
},
|
||||
{
|
||||
"description": "See [latest releases](https://docs.victoriametrics.com/victorialogs/changelog/).",
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 2,
|
||||
"w": 4,
|
||||
@@ -886,6 +844,7 @@
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "",
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
@@ -1540,7 +1499,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -1647,7 +1607,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -1780,7 +1741,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 341
|
||||
"y": 543
|
||||
},
|
||||
"id": 62,
|
||||
"options": {
|
||||
@@ -1885,7 +1846,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 341
|
||||
"y": 543
|
||||
},
|
||||
"id": 26,
|
||||
"options": {
|
||||
@@ -2002,7 +1963,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 405
|
||||
"y": 607
|
||||
},
|
||||
"id": 70,
|
||||
"options": {
|
||||
@@ -2102,7 +2063,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 405
|
||||
"y": 607
|
||||
},
|
||||
"id": 71,
|
||||
"options": {
|
||||
@@ -2209,7 +2170,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2225,7 +2187,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 342
|
||||
"y": 150
|
||||
},
|
||||
"id": 38,
|
||||
"options": {
|
||||
@@ -2266,6 +2228,116 @@
|
||||
"title": "RSS memory % usage ($instance)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 150
|
||||
},
|
||||
"id": 44,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"mean",
|
||||
"lastNotNull",
|
||||
"max"
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true,
|
||||
"sortBy": "Last *",
|
||||
"sortDesc": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "CPU % usage ($instance)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
@@ -2317,7 +2389,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2332,8 +2405,8 @@
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 342
|
||||
"x": 0,
|
||||
"y": 158
|
||||
},
|
||||
"id": 42,
|
||||
"options": {
|
||||
@@ -2379,6 +2452,7 @@
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows CPU pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
@@ -2414,9 +2488,10 @@
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
"mode": "line"
|
||||
}
|
||||
},
|
||||
"decimals": 0,
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
@@ -2424,25 +2499,22 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 350
|
||||
"x": 12,
|
||||
"y": 158
|
||||
},
|
||||
"id": 44,
|
||||
"id": 76,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
@@ -2459,7 +2531,7 @@
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
@@ -2470,17 +2542,153 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
|
||||
"expr": "max(rate(process_pressure_cpu_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
"legendFormat": "__auto",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - waiting",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(rate(process_pressure_cpu_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - stalled",
|
||||
"range": true,
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "CPU % usage ($instance)",
|
||||
"title": "CPU pressure",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "line"
|
||||
}
|
||||
},
|
||||
"decimals": 0,
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 166
|
||||
},
|
||||
"id": 77,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"mean",
|
||||
"lastNotNull",
|
||||
"max"
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true,
|
||||
"sortBy": "Last *",
|
||||
"sortDesc": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(rate(process_pressure_memory_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - waiting",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(rate(process_pressure_memory_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - stalled",
|
||||
"range": true,
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "Memory pressure",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -2533,7 +2741,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2562,7 +2771,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 350
|
||||
"y": 166
|
||||
},
|
||||
"id": 52,
|
||||
"options": {
|
||||
@@ -2672,7 +2881,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2704,7 +2914,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 358
|
||||
"y": 174
|
||||
},
|
||||
"id": 46,
|
||||
"options": {
|
||||
@@ -2797,7 +3007,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2826,7 +3037,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 358
|
||||
"y": 174
|
||||
},
|
||||
"id": 56,
|
||||
"options": {
|
||||
@@ -2935,7 +3146,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2951,7 +3163,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 366
|
||||
"y": 182
|
||||
},
|
||||
"id": 50,
|
||||
"options": {
|
||||
@@ -2997,7 +3209,7 @@
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "",
|
||||
"description": "Shows IO pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
@@ -3033,9 +3245,10 @@
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
"mode": "line"
|
||||
}
|
||||
},
|
||||
"decimals": 0,
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
@@ -3043,15 +3256,12 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
@@ -3059,9 +3269,9 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 366
|
||||
"y": 182
|
||||
},
|
||||
"id": 60,
|
||||
"id": 78,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
@@ -3078,7 +3288,7 @@
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
@@ -3089,16 +3299,31 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(max_over_time(vm_tcplistener_conns{job=~\"$job\", instance=~\"$instance\"}[$__interval])) by(job)",
|
||||
"expr": "max(rate(process_pressure_io_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"intervalFactor": 1,
|
||||
"legendFormat": "__auto",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - waiting",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(rate(process_pressure_io_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - stalled",
|
||||
"range": true,
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "TCP connections ($instance)",
|
||||
"title": "IO pressure",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -3152,7 +3377,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3168,7 +3394,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 374
|
||||
"y": 190
|
||||
},
|
||||
"id": 54,
|
||||
"options": {
|
||||
@@ -3260,7 +3486,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3276,9 +3503,9 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 374
|
||||
"y": 190
|
||||
},
|
||||
"id": 58,
|
||||
"id": 60,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
@@ -3306,7 +3533,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate(vm_tcplistener_accepts_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by(job)",
|
||||
"expr": "sum(max_over_time(vm_tcplistener_conns{job=~\"$job\", instance=~\"$instance\"}[$__interval])) by(job)",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"intervalFactor": 1,
|
||||
@@ -3315,7 +3542,7 @@
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "TCP connections rate ($instance)",
|
||||
"title": "TCP connections ($instance)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -3370,7 +3597,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3386,7 +3614,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 382
|
||||
"y": 198
|
||||
},
|
||||
"id": 74,
|
||||
"options": {
|
||||
@@ -3431,7 +3659,7 @@
|
||||
"type": "prometheus",
|
||||
"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.",
|
||||
"description": "",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
@@ -3467,10 +3695,9 @@
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "line"
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"decimals": 0,
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
@@ -3478,15 +3705,16 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 0.1
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
@@ -3494,9 +3722,9 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 382
|
||||
"y": 198
|
||||
},
|
||||
"id": 61,
|
||||
"id": 58,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
@@ -3506,12 +3734,14 @@
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
"showLegend": true,
|
||||
"sortBy": "Last *",
|
||||
"sortDesc": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "desc"
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
@@ -3522,16 +3752,16 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(histogram_quantile(0.99, sum(rate(go_sched_latencies_seconds_bucket{job=~\"$job\"}[$__rate_interval])) by (job, instance, le))) by(job)",
|
||||
"expr": "sum(rate(vm_tcplistener_accepts_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by(job)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"hide": false,
|
||||
"intervalFactor": 1,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Go scheduling latency",
|
||||
"title": "TCP connections rate ($instance)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -3586,7 +3816,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -3598,7 +3829,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 390
|
||||
"y": 206
|
||||
},
|
||||
"id": 75,
|
||||
"options": {
|
||||
@@ -3637,12 +3868,122 @@
|
||||
],
|
||||
"title": "Memory allocations rate",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"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.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "line"
|
||||
}
|
||||
},
|
||||
"decimals": 0,
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 0.1
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 206
|
||||
},
|
||||
"id": 61,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"mean",
|
||||
"lastNotNull",
|
||||
"max"
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(histogram_quantile(0.99, sum(rate(go_sched_latencies_seconds_bucket{job=~\"$job\"}[$__rate_interval])) by (job, instance, le))) by(job)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Go scheduling latency",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"title": "Resource usage",
|
||||
"type": "row"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"refresh": "",
|
||||
"schemaVersion": 40,
|
||||
"tags": [
|
||||
@@ -3740,4 +4081,4 @@
|
||||
"uid": "XqCOFEX4z",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
}
|
||||
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
@@ -1,51 +1,5 @@
|
||||
|
||||
{
|
||||
"__inputs": [],
|
||||
"__elements": {},
|
||||
"__requires": [
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "11.5.0"
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "victoriametrics-metrics-datasource",
|
||||
"name": "VictoriaMetrics",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "stat",
|
||||
"name": "Stat",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "table",
|
||||
"name": "Table",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "text",
|
||||
"name": "Text",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "timeseries",
|
||||
"name": "Time series",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "victoriametrics-logs-datasource",
|
||||
"name": "VictoriaLogs",
|
||||
"version": "0.16.3"
|
||||
}
|
||||
],
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
@@ -93,11 +47,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Overview for cluster version of VictoriaLogs v1.18.0 or higher",
|
||||
"description": "Overview for cluster version of VictoriaLogs v1.22.0 or higher",
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"id": 1,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
@@ -479,6 +433,10 @@
|
||||
},
|
||||
{
|
||||
"description": "See [latest releases](https://docs.victoriametrics.com/victorialogs/changelog/).",
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 2,
|
||||
"w": 4,
|
||||
@@ -887,6 +845,7 @@
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "",
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
@@ -1541,7 +1500,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -1648,7 +1608,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -1781,7 +1742,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 341
|
||||
"y": 543
|
||||
},
|
||||
"id": 62,
|
||||
"options": {
|
||||
@@ -1886,7 +1847,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 341
|
||||
"y": 543
|
||||
},
|
||||
"id": 26,
|
||||
"options": {
|
||||
@@ -2003,7 +1964,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 405
|
||||
"y": 607
|
||||
},
|
||||
"id": 70,
|
||||
"options": {
|
||||
@@ -2103,7 +2064,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 405
|
||||
"y": 607
|
||||
},
|
||||
"id": 71,
|
||||
"options": {
|
||||
@@ -2210,7 +2171,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2226,7 +2188,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 342
|
||||
"y": 150
|
||||
},
|
||||
"id": 38,
|
||||
"options": {
|
||||
@@ -2267,6 +2229,116 @@
|
||||
"title": "RSS memory % usage ($instance)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 150
|
||||
},
|
||||
"id": 44,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"mean",
|
||||
"lastNotNull",
|
||||
"max"
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true,
|
||||
"sortBy": "Last *",
|
||||
"sortDesc": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"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 process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "CPU % usage ($instance)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
@@ -2318,7 +2390,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2333,8 +2406,8 @@
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 342
|
||||
"x": 0,
|
||||
"y": 158
|
||||
},
|
||||
"id": 42,
|
||||
"options": {
|
||||
@@ -2380,6 +2453,7 @@
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows CPU pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
@@ -2415,9 +2489,10 @@
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
"mode": "line"
|
||||
}
|
||||
},
|
||||
"decimals": 0,
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
@@ -2425,25 +2500,22 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 350
|
||||
"x": 12,
|
||||
"y": 158
|
||||
},
|
||||
"id": 44,
|
||||
"id": 76,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
@@ -2460,7 +2532,7 @@
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
@@ -2471,17 +2543,153 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
|
||||
"expr": "max(rate(process_pressure_cpu_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
"legendFormat": "__auto",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - waiting",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(rate(process_pressure_cpu_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - stalled",
|
||||
"range": true,
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "CPU % usage ($instance)",
|
||||
"title": "CPU pressure",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "line"
|
||||
}
|
||||
},
|
||||
"decimals": 0,
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 166
|
||||
},
|
||||
"id": 77,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"mean",
|
||||
"lastNotNull",
|
||||
"max"
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true,
|
||||
"sortBy": "Last *",
|
||||
"sortDesc": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(rate(process_pressure_memory_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - waiting",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(rate(process_pressure_memory_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - stalled",
|
||||
"range": true,
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "Memory pressure",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -2534,7 +2742,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2563,7 +2772,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 350
|
||||
"y": 166
|
||||
},
|
||||
"id": 52,
|
||||
"options": {
|
||||
@@ -2673,7 +2882,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2705,7 +2915,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 358
|
||||
"y": 174
|
||||
},
|
||||
"id": 46,
|
||||
"options": {
|
||||
@@ -2798,7 +3008,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2827,7 +3038,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 358
|
||||
"y": 174
|
||||
},
|
||||
"id": 56,
|
||||
"options": {
|
||||
@@ -2936,7 +3147,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -2952,7 +3164,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 366
|
||||
"y": 182
|
||||
},
|
||||
"id": 50,
|
||||
"options": {
|
||||
@@ -2998,7 +3210,7 @@
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "",
|
||||
"description": "Shows IO pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
@@ -3034,9 +3246,10 @@
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
"mode": "line"
|
||||
}
|
||||
},
|
||||
"decimals": 0,
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
@@ -3044,15 +3257,12 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
@@ -3060,9 +3270,9 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 366
|
||||
"y": 182
|
||||
},
|
||||
"id": 60,
|
||||
"id": 78,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
@@ -3079,7 +3289,7 @@
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
@@ -3090,16 +3300,31 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(max_over_time(vm_tcplistener_conns{job=~\"$job\", instance=~\"$instance\"}[$__interval])) by(job)",
|
||||
"expr": "max(rate(process_pressure_io_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"intervalFactor": 1,
|
||||
"legendFormat": "__auto",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - waiting",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(rate(process_pressure_io_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{job}} - stalled",
|
||||
"range": true,
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "TCP connections ($instance)",
|
||||
"title": "IO pressure",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -3153,7 +3378,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3169,7 +3395,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 374
|
||||
"y": 190
|
||||
},
|
||||
"id": 54,
|
||||
"options": {
|
||||
@@ -3261,7 +3487,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3277,9 +3504,9 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 374
|
||||
"y": 190
|
||||
},
|
||||
"id": 58,
|
||||
"id": 60,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
@@ -3307,7 +3534,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate(vm_tcplistener_accepts_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by(job)",
|
||||
"expr": "sum(max_over_time(vm_tcplistener_conns{job=~\"$job\", instance=~\"$instance\"}[$__interval])) by(job)",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"intervalFactor": 1,
|
||||
@@ -3316,7 +3543,7 @@
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "TCP connections rate ($instance)",
|
||||
"title": "TCP connections ($instance)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -3371,7 +3598,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -3387,7 +3615,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 382
|
||||
"y": 198
|
||||
},
|
||||
"id": 74,
|
||||
"options": {
|
||||
@@ -3432,7 +3660,7 @@
|
||||
"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.",
|
||||
"description": "",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
@@ -3468,10 +3696,9 @@
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "line"
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"decimals": 0,
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
@@ -3479,15 +3706,16 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 0.1
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
@@ -3495,9 +3723,9 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 382
|
||||
"y": 198
|
||||
},
|
||||
"id": 61,
|
||||
"id": 58,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
@@ -3507,12 +3735,14 @@
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
"showLegend": true,
|
||||
"sortBy": "Last *",
|
||||
"sortDesc": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "desc"
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
@@ -3523,16 +3753,16 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(histogram_quantile(0.99, sum(rate(go_sched_latencies_seconds_bucket{job=~\"$job\"}[$__rate_interval])) by (job, instance, le))) by(job)",
|
||||
"expr": "sum(rate(vm_tcplistener_accepts_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by(job)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"hide": false,
|
||||
"intervalFactor": 1,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Go scheduling latency",
|
||||
"title": "TCP connections rate ($instance)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
@@ -3587,7 +3817,8 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -3599,7 +3830,7 @@
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 390
|
||||
"y": 206
|
||||
},
|
||||
"id": 75,
|
||||
"options": {
|
||||
@@ -3638,12 +3869,122 @@
|
||||
],
|
||||
"title": "Memory allocations rate",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"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.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "line"
|
||||
}
|
||||
},
|
||||
"decimals": 0,
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 0.1
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 206
|
||||
},
|
||||
"id": 61,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"mean",
|
||||
"lastNotNull",
|
||||
"max"
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "desc"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "max(histogram_quantile(0.99, sum(rate(go_sched_latencies_seconds_bucket{job=~\"$job\"}[$__rate_interval])) by (job, instance, le))) by(job)",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Go scheduling latency",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"title": "Resource usage",
|
||||
"type": "row"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"refresh": "",
|
||||
"schemaVersion": 40,
|
||||
"tags": [
|
||||
@@ -3741,4 +4082,4 @@
|
||||
"uid": "XqCOFEX4z_vm",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
}
|
||||
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
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
File diff suppressed because it is too large
Load Diff
@@ -68,7 +68,7 @@ services:
|
||||
# VictoriaMetrics instance, a single process responsible for
|
||||
# scraping, storing metrics and serve read requests.
|
||||
victoriametrics:
|
||||
image: victoriametrics/victoria-metrics:v1.117.0
|
||||
image: victoriametrics/victoria-metrics:v1.118.0
|
||||
volumes:
|
||||
- vmdata:/storage
|
||||
- ./prometheus-vl-cluster.yml:/etc/prometheus/prometheus.yml
|
||||
@@ -81,7 +81,7 @@ services:
|
||||
# It proxies query requests from vmalert to either VictoriaMetrics or VictoriaLogs,
|
||||
# depending on the requested path.
|
||||
vmauth:
|
||||
image: victoriametrics/vmauth:v1.117.0
|
||||
image: victoriametrics/vmauth:v1.118.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
- "vlselect-1"
|
||||
@@ -97,7 +97,7 @@ services:
|
||||
|
||||
# vmalert executes alerting and recording rules according to given rule type.
|
||||
vmalert:
|
||||
image: victoriametrics/vmalert:v1.117.0
|
||||
image: victoriametrics/vmalert:v1.118.0
|
||||
depends_on:
|
||||
- "vmauth"
|
||||
- "alertmanager"
|
||||
|
||||
@@ -49,7 +49,7 @@ services:
|
||||
# VictoriaMetrics instance, a single process responsible for
|
||||
# scraping, storing metrics and serve read requests.
|
||||
victoriametrics:
|
||||
image: victoriametrics/victoria-metrics:v1.117.0
|
||||
image: victoriametrics/victoria-metrics:v1.118.0
|
||||
ports:
|
||||
- "8428:8428"
|
||||
volumes:
|
||||
@@ -64,7 +64,7 @@ services:
|
||||
# It proxies query requests from vmalert to either VictoriaMetrics or VictoriaLogs,
|
||||
# depending on the requested path.
|
||||
vmauth:
|
||||
image: victoriametrics/vmauth:v1.117.0
|
||||
image: victoriametrics/vmauth:v1.118.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
- "victorialogs"
|
||||
@@ -78,7 +78,7 @@ services:
|
||||
|
||||
# vmalert executes alerting and recording rules according to the given rule type.
|
||||
vmalert:
|
||||
image: victoriametrics/vmalert:v1.117.0
|
||||
image: victoriametrics/vmalert:v1.118.0
|
||||
depends_on:
|
||||
- "vmauth"
|
||||
- "alertmanager"
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
# It scrapes targets defined in --promscrape.config
|
||||
# And forward them to --remoteWrite.url
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.117.0
|
||||
image: victoriametrics/vmagent:v1.118.0
|
||||
depends_on:
|
||||
- "vmauth"
|
||||
ports:
|
||||
@@ -35,14 +35,14 @@ services:
|
||||
# vmstorage shards. Each shard receives 1/N of all metrics sent to vminserts,
|
||||
# where N is number of vmstorages (2 in this case).
|
||||
vmstorage-1:
|
||||
image: victoriametrics/vmstorage:v1.117.0-cluster
|
||||
image: victoriametrics/vmstorage:v1.118.0-cluster
|
||||
volumes:
|
||||
- strgdata-1:/storage
|
||||
command:
|
||||
- "--storageDataPath=/storage"
|
||||
restart: always
|
||||
vmstorage-2:
|
||||
image: victoriametrics/vmstorage:v1.117.0-cluster
|
||||
image: victoriametrics/vmstorage:v1.118.0-cluster
|
||||
volumes:
|
||||
- strgdata-2:/storage
|
||||
command:
|
||||
@@ -52,7 +52,7 @@ services:
|
||||
# vminsert is ingestion frontend. It receives metrics pushed by vmagent,
|
||||
# pre-process them and distributes across configured vmstorage shards.
|
||||
vminsert-1:
|
||||
image: victoriametrics/vminsert:v1.117.0-cluster
|
||||
image: victoriametrics/vminsert:v1.118.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -61,7 +61,7 @@ services:
|
||||
- "--storageNode=vmstorage-2:8400"
|
||||
restart: always
|
||||
vminsert-2:
|
||||
image: victoriametrics/vminsert:v1.117.0-cluster
|
||||
image: victoriametrics/vminsert:v1.118.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -73,7 +73,7 @@ services:
|
||||
# vmselect is a query fronted. It serves read queries in MetricsQL or PromQL.
|
||||
# vmselect collects results from configured `--storageNode` shards.
|
||||
vmselect-1:
|
||||
image: victoriametrics/vmselect:v1.117.0-cluster
|
||||
image: victoriametrics/vmselect:v1.118.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -83,7 +83,7 @@ services:
|
||||
- "--vmalert.proxyURL=http://vmalert:8880"
|
||||
restart: always
|
||||
vmselect-2:
|
||||
image: victoriametrics/vmselect:v1.117.0-cluster
|
||||
image: victoriametrics/vmselect:v1.118.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -98,7 +98,7 @@ services:
|
||||
# read requests from Grafana, vmui, vmalert among vmselects.
|
||||
# It can be used as an authentication proxy.
|
||||
vmauth:
|
||||
image: victoriametrics/vmauth:v1.117.0
|
||||
image: victoriametrics/vmauth:v1.118.0
|
||||
depends_on:
|
||||
- "vmselect-1"
|
||||
- "vmselect-2"
|
||||
@@ -112,7 +112,7 @@ services:
|
||||
|
||||
# vmalert executes alerting and recording rules
|
||||
vmalert:
|
||||
image: victoriametrics/vmalert:v1.117.0
|
||||
image: victoriametrics/vmalert:v1.118.0
|
||||
depends_on:
|
||||
- "vmauth"
|
||||
ports:
|
||||
@@ -125,7 +125,7 @@ services:
|
||||
command:
|
||||
- "--datasource.url=http://vmauth:8427/select/0/prometheus"
|
||||
- "--remoteRead.url=http://vmauth:8427/select/0/prometheus"
|
||||
- "--remoteWrite.url=http://vmauth:8427/insert/0/prometheus/api/v1/write"
|
||||
- "--remoteWrite.url=http://vmauth:8427/insert/0/prometheus"
|
||||
- "--notifier.url=http://alertmanager:9093/"
|
||||
- "--rule=/etc/alerts/*.yml"
|
||||
# display source of alerts in grafana
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
# It scrapes targets defined in --promscrape.config
|
||||
# And forward them to --remoteWrite.url
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.117.0
|
||||
image: victoriametrics/vmagent:v1.118.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
@@ -18,7 +18,7 @@ services:
|
||||
# VictoriaMetrics instance, a single process responsible for
|
||||
# storing metrics and serve read requests.
|
||||
victoriametrics:
|
||||
image: victoriametrics/victoria-metrics:v1.117.0
|
||||
image: victoriametrics/victoria-metrics:v1.118.0
|
||||
ports:
|
||||
- 8428:8428
|
||||
- 8089:8089
|
||||
@@ -54,7 +54,7 @@ services:
|
||||
|
||||
# vmalert executes alerting and recording rules
|
||||
vmalert:
|
||||
image: victoriametrics/vmalert:v1.117.0
|
||||
image: victoriametrics/vmalert:v1.118.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
- "alertmanager"
|
||||
|
||||
@@ -11,13 +11,18 @@ groups:
|
||||
rules:
|
||||
- alert: DiskRunsOutOfSpaceIn3Days
|
||||
expr: |
|
||||
sum(vm_free_disk_space_bytes) without(path) /
|
||||
(
|
||||
rate(vm_rows_added_to_storage_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
) < 3 * 24 * 3600 > 0
|
||||
sum(vm_free_disk_space_bytes) without(path) /
|
||||
(
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
+
|
||||
rate(vm_new_timeseries_created_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) /
|
||||
sum(vm_rows{type="indexdb/file"})
|
||||
)
|
||||
) < 3 * 24 * 3600 > 0
|
||||
for: 30m
|
||||
labels:
|
||||
severity: critical
|
||||
@@ -32,10 +37,15 @@ groups:
|
||||
expr: |
|
||||
sum(vm_free_disk_space_bytes - vm_free_disk_space_limit_bytes) without(path) /
|
||||
(
|
||||
rate(vm_rows_added_to_storage_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
+
|
||||
rate(vm_new_timeseries_created_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) /
|
||||
sum(vm_rows{type="indexdb/file"})
|
||||
)
|
||||
) < 3 * 24 * 3600 > 0
|
||||
for: 30m
|
||||
labels:
|
||||
|
||||
@@ -11,13 +11,18 @@ groups:
|
||||
rules:
|
||||
- alert: DiskRunsOutOfSpaceIn3Days
|
||||
expr: |
|
||||
sum(vm_free_disk_space_bytes) without(path) /
|
||||
(
|
||||
rate(vm_rows_added_to_storage_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
) < 3 * 24 * 3600 > 0
|
||||
sum(vm_free_disk_space_bytes) without(path) /
|
||||
(
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
+
|
||||
rate(vm_new_timeseries_created_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) /
|
||||
sum(vm_rows{type="indexdb/file"})
|
||||
)
|
||||
) < 3 * 24 * 3600 > 0
|
||||
for: 30m
|
||||
labels:
|
||||
severity: critical
|
||||
@@ -32,10 +37,15 @@ groups:
|
||||
expr: |
|
||||
sum(vm_free_disk_space_bytes - vm_free_disk_space_limit_bytes) without(path) /
|
||||
(
|
||||
rate(vm_rows_added_to_storage_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
|
||||
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
|
||||
sum(vm_rows{type!~"indexdb.*"}) without(type)
|
||||
)
|
||||
+
|
||||
rate(vm_new_timeseries_created_total[1d]) * (
|
||||
sum(vm_data_size_bytes{type="indexdb/file"}) /
|
||||
sum(vm_rows{type="indexdb/file"})
|
||||
)
|
||||
) < 3 * 24 * 3600 > 0
|
||||
for: 30m
|
||||
labels:
|
||||
|
||||
@@ -19,11 +19,11 @@ services:
|
||||
retries: 10
|
||||
|
||||
dd-proxy:
|
||||
image: docker.io/victoriametrics/vmauth:v1.117.0
|
||||
image: docker.io/victoriametrics/vmauth:v1.118.0
|
||||
restart: on-failure
|
||||
volumes:
|
||||
- ./:/etc/vmauth
|
||||
command: -auth.config=/etc/vmauth/vmauth.yaml
|
||||
command: -auth.config=/etc/vmauth/vmauth.yml
|
||||
|
||||
victorialogs:
|
||||
extends: .victorialogs
|
||||
@@ -34,7 +34,7 @@ services:
|
||||
deploy:
|
||||
replicas: 1
|
||||
|
||||
# second replica is needed for HA setup and its replica count is set to 1 in compose-ha.yaml file
|
||||
# second replica is needed for HA setup and its replica count is set to 1 in compose-ha.yml file
|
||||
victorialogs-2:
|
||||
extends: .victorialogs
|
||||
ports:
|
||||
|
||||
@@ -4,26 +4,27 @@ The folder contains examples of [DataDog agent](https://docs.datadoghq.com/agent
|
||||
|
||||
* [datadog](./datadog)
|
||||
|
||||
## Quick start
|
||||
|
||||
To spin-up environment `cd` to any of listed above directories run the following command:
|
||||
```
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
To shut down the docker-compose environment run the following command:
|
||||
```
|
||||
docker compose down
|
||||
docker compose rm -f
|
||||
```sh
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
The docker compose file contains the following components:
|
||||
|
||||
* datadog - Datadog logs collection agent, which is configured to collect and write data to `victorialogs`
|
||||
* victorialogs - VictoriaLogs log database, which accepts the data from `datadog`
|
||||
* victoriametrics - VictoriaMetrics metrics database, which collects metrics from `victorialogs` and `datadog`
|
||||
* victoriametrics - VictoriaMetrics metrics database, collects metrics from `victorialogs` and `datadog`
|
||||
|
||||
Querying the data
|
||||
## Querying
|
||||
|
||||
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
|
||||
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
|
||||
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
|
||||
@@ -5,15 +5,16 @@ The folder contains examples of [DataDog serverless](https://docs.datadoghq.com/
|
||||
* [AWS Lambda](./aws)
|
||||
* [GCP Cloud Run](./gcp)
|
||||
|
||||
## Quick start
|
||||
|
||||
To spin-up environment `cd` to any of listed above directories run the following command:
|
||||
```
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
To shut down the docker-compose environment run the following command:
|
||||
```
|
||||
docker compose down
|
||||
docker compose rm -f
|
||||
```sh
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
The docker compose file contains the following components:
|
||||
@@ -21,11 +22,11 @@ The docker compose file contains the following components:
|
||||
* dd-proxy - VMAuth proxy, with path-based routing to `victoriametrics` and `victorialogs`
|
||||
* lambda - Serverless application with Datadog logs collection extension, which is configured to collect and write data to `victorialogs` and `victoriametrics` via `dd-proxy`
|
||||
* victorialogs - VictoriaLogs log database, which accepts the data from `datadog`
|
||||
* victoriametrics - VictoriaMetrics metrics database, which collects metrics from `victorialogs` and `datadog`
|
||||
* victoriametrics - VictoriaMetrics metrics database, collects metrics from `victorialogs` and `datadog`
|
||||
|
||||
Querying the data
|
||||
## Querying
|
||||
|
||||
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
|
||||
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
|
||||
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.23-bullseye as aws-lambda-rie
|
||||
FROM golang:1.24-bullseye as aws-lambda-rie
|
||||
|
||||
# Install custom aws-lambda-rie till Telemetry API support is not merged
|
||||
# https://github.com/aws/aws-lambda-runtime-interface-emulator/pull/137
|
||||
@@ -26,7 +26,7 @@ RUN \
|
||||
WORKDIR /var/task
|
||||
COPY --from=aws-lambda-rie /aws-lambda-rie /var/task/aws-lambda-rie
|
||||
COPY main.py /var/task/
|
||||
COPY --from=public.ecr.aws/datadog/lambda-extension:73 /opt/. /opt/
|
||||
COPY --from=public.ecr.aws/datadog/lambda-extension:78 /opt/. /opt/
|
||||
|
||||
ENTRYPOINT ["/var/task/aws-lambda-rie"]
|
||||
CMD ["/usr/local/bin/python", "-m", "awslambdaric", "main.lambda_handler"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3.12-bullseye
|
||||
FROM python:3.13-bullseye
|
||||
|
||||
COPY --from=datadog/serverless-init:1 /datadog-init /app/datadog-init
|
||||
ENV DD_SERVICE=datadog-demo-run-go
|
||||
|
||||
@@ -5,30 +5,31 @@ The folder contains examples of [Filebeat](https://www.elastic.co/guide/en/beats
|
||||
* [syslog](./syslog)
|
||||
* [elasticsearch](./elasticsearch)
|
||||
|
||||
## Quick start
|
||||
|
||||
To spin-up environment `cd` to any of listed above directories run the following command:
|
||||
```
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
To shut down the docker-compose environment run the following command:
|
||||
```
|
||||
```sh
|
||||
docker compose down
|
||||
docker compose rm -f
|
||||
```
|
||||
|
||||
The docker compose file contains the following components:
|
||||
|
||||
* filebeat - logs collection agent configured to collect and write data to `victorialogs`
|
||||
* victorialogs - logs database, receives data from `filebeat` agent
|
||||
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `filebeat` for observability purposes
|
||||
* victoriametrics - metrics database, collects metrics from `victorialogs` and `filebeat` for observability purposes
|
||||
|
||||
Querying the data
|
||||
## Querying
|
||||
|
||||
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
|
||||
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
|
||||
Filebeat configuration example can be found below:
|
||||
- [syslog](./syslog/filebeat.yml)
|
||||
- [elasticsearch](./elasticsearch/filebeat.yml)
|
||||
|
||||
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
|
||||
@@ -8,27 +8,28 @@ The folder contains examples of [FluentBit](https://docs.fluentbit.io/manual) in
|
||||
* [jsonline HA setup](./jsonline-ha)
|
||||
* [otlp](./otlp)
|
||||
|
||||
## Quick start
|
||||
|
||||
To spin-up environment `cd` to any of listed above directories run the following command:
|
||||
```
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
To shut down the docker-compose environment run the following command:
|
||||
```
|
||||
docker compose down
|
||||
docker compose rm -f
|
||||
```sh
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
The docker compose file contains the following components:
|
||||
|
||||
* fluentbit - logs collection agent configured to collect and write data to `victorialogs`
|
||||
* victorialogs - logs database, receives data from `fluentbit` agent
|
||||
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `fluentbit` for observability purposes
|
||||
* victoriametrics - metrics database, collects metrics from `victorialogs` and `fluentbit` for observability purposes
|
||||
|
||||
Querying the data
|
||||
## Querying
|
||||
|
||||
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
|
||||
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
|
||||
FluentBit configuration example can be found below:
|
||||
* [datadog](./datadog/fluent-bit.conf)
|
||||
@@ -37,4 +38,4 @@ FluentBit configuration example can be found below:
|
||||
* [jsonline HA setup](./jsonline-ha/fluent-bit.conf)
|
||||
* [otlp](./otlp/fluent-bit.conf)
|
||||
|
||||
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
include:
|
||||
- ../compose.yml
|
||||
- ../compose-base.yml
|
||||
name: fluentbit-loki
|
||||
|
||||
@@ -9,31 +9,32 @@ The folder contains examples of [Fluentd](https://www.fluentd.org/) integration
|
||||
|
||||
All required plugins, that should be installed in order to support protocols listed above can be found in a [Dockerfile](./Dockerfile)
|
||||
|
||||
## Quick start
|
||||
|
||||
To spin-up environment `cd` to any of listed above directories run the following command:
|
||||
```
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
To shut down the docker-compose environment run the following command:
|
||||
```
|
||||
docker compose down
|
||||
docker compose rm -f
|
||||
```sh
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
The docker compose file contains the following components:
|
||||
|
||||
* fluentd - logs collection agent configured to collect and write data to `victorialogs`
|
||||
* victorialogs - logs database, receives data from `fluentd` agent
|
||||
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `fluentd` for observability purposes
|
||||
* victoriametrics - metrics database, collects metrics from `victorialogs` and `fluentd` for observability purposes
|
||||
|
||||
Querying the data
|
||||
## Querying
|
||||
|
||||
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
|
||||
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
|
||||
Fluentd configuration example can be found below:
|
||||
* [loki](./loki/fluent.conf)
|
||||
* [jsonline](./jsonline/fluent.conf)
|
||||
* [elasticsearch](./elasticsearch/fluent.conf)
|
||||
|
||||
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
|
||||
34
deployment/docker/victorialogs/grafana-alloy/README.md
Normal file
34
deployment/docker/victorialogs/grafana-alloy/README.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Docker compose Grafana Alloy integration with VictoriaLogs
|
||||
|
||||
The folder contains examples of [Grafana Alloy](https://grafana.com/docs/alloy/latest/) integration with VictoriaLogs using protocols:
|
||||
|
||||
* [loki](./loki)
|
||||
* [otlp](./otlp)
|
||||
|
||||
## Quick start
|
||||
|
||||
To spin-up environment `cd` to any of listed above directories run the following command:
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
To shut down the docker-compose environment run the following command:
|
||||
```sh
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
The docker compose file contains the following components:
|
||||
* alloy - logs collection agent configured to collect and write data to `victorialogs`
|
||||
* victorialogs - logs database, receives data from `alloy` agent
|
||||
* victoriametrics - metrics database, collects metrics from `victorialogs` and `alloy` for observability purposes
|
||||
|
||||
## Querying
|
||||
|
||||
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
|
||||
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
|
||||
Grafana Alloy configuration example can be found below:
|
||||
* [loki](./loki/config.alloy)
|
||||
* [otlp](./otlp/config.alloy)
|
||||
|
||||
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
@@ -0,0 +1,16 @@
|
||||
include:
|
||||
- ../compose-base.yml
|
||||
services:
|
||||
alloy:
|
||||
image: docker.io/grafana/alloy:latest
|
||||
restart: on-failure
|
||||
user: 0:0
|
||||
volumes:
|
||||
- ${PWD}/config.alloy:/etc/alloy/config.alloy
|
||||
- /var/lib/docker/containers:/var/lib/docker/containers
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
depends_on:
|
||||
victorialogs:
|
||||
condition: service_healthy
|
||||
victoriametrics:
|
||||
condition: service_healthy
|
||||
@@ -0,0 +1,3 @@
|
||||
include:
|
||||
- ../compose-base.yml
|
||||
name: alloy-loki
|
||||
@@ -0,0 +1,38 @@
|
||||
discovery.docker "default" {
|
||||
host = "unix:///var/run/docker.sock"
|
||||
refresh_interval = "5s"
|
||||
}
|
||||
|
||||
discovery.relabel "default" {
|
||||
targets = discovery.docker.default.targets
|
||||
rule {
|
||||
source_labels = ["__meta_docker_container_name"]
|
||||
target_label = "container_name"
|
||||
}
|
||||
}
|
||||
|
||||
prometheus.exporter.self "default" {}
|
||||
|
||||
prometheus.scrape "default" {
|
||||
targets = prometheus.exporter.self.default.targets
|
||||
forward_to = [prometheus.remote_write.default.receiver]
|
||||
}
|
||||
|
||||
prometheus.remote_write "default" {
|
||||
endpoint {
|
||||
url = "http://victoriametrics:8428/api/v1/write"
|
||||
}
|
||||
}
|
||||
|
||||
loki.write "default" {
|
||||
endpoint {
|
||||
headers = { "VL-Msg-Field" = "msg", "VL-Stream-Fields" = "container_name" }
|
||||
url = "http://victorialogs:9428/insert/loki/api/v1/push"
|
||||
}
|
||||
}
|
||||
|
||||
loki.source.docker "default" {
|
||||
host = "unix:///var/run/docker.sock"
|
||||
targets = discovery.relabel.default.output
|
||||
forward_to = [loki.write.default.receiver]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
include:
|
||||
- ../compose-base.yml
|
||||
name: alloy-otlp
|
||||
@@ -0,0 +1,47 @@
|
||||
discovery.docker "default" {
|
||||
host = "unix:///var/run/docker.sock"
|
||||
refresh_interval = "5s"
|
||||
}
|
||||
|
||||
discovery.relabel "default" {
|
||||
targets = discovery.docker.default.targets
|
||||
rule {
|
||||
source_labels = ["__meta_docker_container_name"]
|
||||
target_label = "container_name"
|
||||
}
|
||||
}
|
||||
|
||||
prometheus.exporter.self "default" {}
|
||||
|
||||
prometheus.scrape "default" {
|
||||
targets = prometheus.exporter.self.default.targets
|
||||
forward_to = [otelcol.receiver.prometheus.default.receiver]
|
||||
}
|
||||
|
||||
otelcol.receiver.prometheus "default" {
|
||||
output {
|
||||
metrics = [otelcol.exporter.otlphttp.default.input]
|
||||
}
|
||||
}
|
||||
|
||||
otelcol.exporter.otlphttp "default" {
|
||||
client {
|
||||
endpoint = "http://victorialogs:9428/insert/opentelemetry"
|
||||
headers = { "VL-Stream-Fields" = "container_name" }
|
||||
}
|
||||
metrics_endpoint = "http://victoriametrics:8428/opentelemetry/v1/metrics"
|
||||
}
|
||||
|
||||
otelcol.receiver.loki "default" {
|
||||
output {
|
||||
metrics = [otelcol.exporter.otlphttp.default.input]
|
||||
logs = [otelcol.exporter.otlphttp.default.input]
|
||||
traces = [otelcol.exporter.otlphttp.default.input]
|
||||
}
|
||||
}
|
||||
|
||||
loki.source.docker "default" {
|
||||
host = "unix:///var/run/docker.sock"
|
||||
targets = discovery.relabel.default.output
|
||||
forward_to = [otelcol.receiver.loki.default.receiver]
|
||||
}
|
||||
@@ -4,26 +4,27 @@ The folder contains examples of Journald integration with VictoriaLogs using pro
|
||||
|
||||
* [journald](./journald)
|
||||
|
||||
## Quick start
|
||||
|
||||
To spin-up environment `cd` to any of listed above directories run the following command:
|
||||
```
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
To shut down the docker-compose environment run the following command:
|
||||
```
|
||||
docker compose down
|
||||
docker compose rm -f
|
||||
```sh
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
The docker compose file contains the following components:
|
||||
|
||||
* journald - Journald logs collection agent, which is configured to collect and write data to `victorialogs`
|
||||
* victorialogs - VictoriaLogs log database, which accepts the data from `journald`
|
||||
* victoriametrics - VictoriaMetrics metrics database, which collects metrics from `victorialogs` and `journald`
|
||||
* journald - Journald logs collection agent, configured to collect and write data to `victorialogs`
|
||||
* victorialogs - VictoriaLogs log database, accepts the data from `journald`
|
||||
* victoriametrics - VictoriaMetrics metrics database, collects metrics from `victorialogs` and `journald`
|
||||
|
||||
Querying the data
|
||||
## Querying
|
||||
|
||||
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
|
||||
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
|
||||
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
|
||||
@@ -9,27 +9,28 @@ The folder contains examples of [Logstash](https://www.elastic.co/logstash) inte
|
||||
|
||||
All required plugins, that should be installed in order to support protocols listed above can be found in a [Dockerfile](./Dockerfile)
|
||||
|
||||
## Quick start
|
||||
|
||||
To spin-up environment `cd` to any of listed above directories run the following command:
|
||||
```
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
To shut down the docker-compose environment run the following command:
|
||||
```
|
||||
docker compose down
|
||||
docker compose rm -f
|
||||
```sh
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
The docker compose file contains the following components:
|
||||
|
||||
* logstash - logs collection agent configured to collect and write data to `victorialogs`
|
||||
* victorialogs - logs database, receives data from `logstash` agent
|
||||
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `logstash` for observability purposes
|
||||
* victoriametrics - metrics database, collects metrics from `victorialogs` and `logstash` for observability purposes
|
||||
|
||||
Querying the data
|
||||
## Querying
|
||||
|
||||
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
|
||||
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
|
||||
Logstash configuration example can be found below:
|
||||
* [loki](./loki/pipeline.conf)
|
||||
@@ -37,4 +38,4 @@ Logstash configuration example can be found below:
|
||||
* [jsonline HA setup](./jsonline-ha/pipeline.conf)
|
||||
* [elasticsearch](./elasticsearch/pipeline.conf)
|
||||
|
||||
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
|
||||
@@ -8,27 +8,28 @@ The folder contains examples of [OpenTelemetry collector](https://opentelemetry.
|
||||
* [elasticsearch single node](./elasticsearch)
|
||||
* [elasticsearch HA mode](./elasticsearch-ha/)
|
||||
|
||||
## Quick start
|
||||
|
||||
To spin-up environment `cd` to any of listed above directories run the following command:
|
||||
```
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
To shut down the docker-compose environment run the following command:
|
||||
```
|
||||
docker compose down
|
||||
docker compose rm -f
|
||||
```sh
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
The docker compose file contains the following components:
|
||||
|
||||
* collector - logs collection agent configured to collect and write data to `victorialogs`
|
||||
* victorialogs - logs database, receives data from `collector` agent
|
||||
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `collector` for observability purposes
|
||||
* victoriametrics - metrics database, collects metrics from `victorialogs` and `collector` for observability purposes
|
||||
|
||||
Querying the data
|
||||
## Querying
|
||||
|
||||
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
|
||||
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
|
||||
OpenTelemetry collector configuration example can be found below:
|
||||
* [loki](./loki/config.yml)
|
||||
@@ -37,4 +38,4 @@ OpenTelemetry collector configuration example can be found below:
|
||||
* [elasticsearch single node](./elasticsearch/config.yml)
|
||||
* [elasticsearch HA mode](./elasticsearch-ha/config.yml)
|
||||
|
||||
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
|
||||
@@ -4,15 +4,16 @@ The folder contains the example of integration of [Promtail agent](https://grafa
|
||||
|
||||
* [loki](./loki)
|
||||
|
||||
## Quick start
|
||||
|
||||
To spin-up environment `cd` to any of listed above directories run the following command:
|
||||
```
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
To shut down the docker-compose environment run the following command:
|
||||
```
|
||||
docker compose down
|
||||
docker compose rm -f
|
||||
```sh
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
The docker compose file contains the following components:
|
||||
@@ -21,12 +22,12 @@ The docker compose file contains the following components:
|
||||
* victorialogs - logs database, receives data from `promtail` agent
|
||||
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `promtail` for observability purposes
|
||||
|
||||
Querying the data
|
||||
## Querying
|
||||
|
||||
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
|
||||
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
|
||||
|
||||
Promtail agent configuration example can be found below:
|
||||
* [loki](./loki/config.yml)
|
||||
|
||||
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user