mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-06-08 11:23:53 +03:00
Compare commits
17 Commits
issue-8229
...
v1.110.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ed31b9180 | ||
|
|
00fb218269 | ||
|
|
aa0ac1d0ed | ||
|
|
81d359507d | ||
|
|
ebac07bcf6 | ||
|
|
92bfb7ba15 | ||
|
|
6a8fa799c6 | ||
|
|
5e7866c3a0 | ||
|
|
c26cbf57dd | ||
|
|
ee8f852a83 | ||
|
|
80a5f6863b | ||
|
|
8e576854b3 | ||
|
|
5dbca072bb | ||
|
|
375548ca4b | ||
|
|
f0424facf7 | ||
|
|
48602a1ae8 | ||
|
|
0a6f6d0bba |
@@ -2,20 +2,19 @@ package insertutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage"
|
||||
)
|
||||
|
||||
// ExtractTimestampRFC3339NanoFromFields extracts RFC3339 timestamp in nanoseconds from the field with the name timeField at fields.
|
||||
// ExtractTimestampFromFields extracts timestamp in nanoseconds from the field with the name timeField at fields.
|
||||
//
|
||||
// The value for the timeField is set to empty string after returning from the function,
|
||||
// so it could be ignored during data ingestion.
|
||||
//
|
||||
// The current timestamp is returned if fields do not contain a field with timeField name or if the timeField value is empty.
|
||||
func ExtractTimestampRFC3339NanoFromFields(timeField string, fields []logstorage.Field) (int64, error) {
|
||||
func ExtractTimestampFromFields(timeField string, fields []logstorage.Field) (int64, error) {
|
||||
for i := range fields {
|
||||
f := &fields[i]
|
||||
if f.Name != timeField {
|
||||
@@ -48,22 +47,24 @@ func parseTimestamp(s string) (int64, error) {
|
||||
return nsecs, nil
|
||||
}
|
||||
|
||||
// ParseUnixTimestamp parses s as unix timestamp in either seconds or milliseconds and returns the parsed timestamp in nanoseconds.
|
||||
// ParseUnixTimestamp parses s as unix timestamp in seconds, milliseconds, microseconds or nanoseconds and returns the parsed timestamp in nanoseconds.
|
||||
func ParseUnixTimestamp(s string) (int64, error) {
|
||||
n, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("cannot parse unix timestamp from %q: %w", s, err)
|
||||
}
|
||||
if n < (1<<31) && n >= (-1<<31) {
|
||||
// The timestamp is in seconds. Convert it to milliseconds
|
||||
n *= 1e3
|
||||
// The timestamp is in seconds.
|
||||
return n * 1e9, nil
|
||||
}
|
||||
if n > int64(math.MaxInt64)/1e6 {
|
||||
return 0, fmt.Errorf("too big timestamp in milliseconds: %d; mustn't exceed %d", n, int64(math.MaxInt64)/1e6)
|
||||
if n < 1e3*(1<<31) && n >= 1e3*(-1<<31) {
|
||||
// The timestamp is in milliseconds.
|
||||
return n * 1e6, nil
|
||||
}
|
||||
if n < int64(math.MinInt64)/1e6 {
|
||||
return 0, fmt.Errorf("too small timestamp in milliseconds: %d; must be bigger than %d", n, int64(math.MinInt64)/1e6)
|
||||
if n < 1e6*(1<<31) && n >= 1e6*(-1<<31) {
|
||||
// The timestamp is in microseconds.
|
||||
return n * 1e3, nil
|
||||
}
|
||||
n *= 1e6
|
||||
// The timestamp is in nanoseconds
|
||||
return n, nil
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage"
|
||||
)
|
||||
|
||||
func TestExtractTimestampRFC3339NanoFromFields_Success(t *testing.T) {
|
||||
func TestExtractTimestampFromFields_Success(t *testing.T) {
|
||||
f := func(timeField string, fields []logstorage.Field, nsecsExpected int64) {
|
||||
t.Helper()
|
||||
|
||||
nsecs, err := ExtractTimestampRFC3339NanoFromFields(timeField, fields)
|
||||
nsecs, err := ExtractTimestampFromFields(timeField, fields)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
@@ -51,6 +51,18 @@ func TestExtractTimestampRFC3339NanoFromFields_Success(t *testing.T) {
|
||||
{Name: "foo", Value: "bar"},
|
||||
}, 1718773640123456789)
|
||||
|
||||
// Unix timestamp in nanoseconds
|
||||
f("time", []logstorage.Field{
|
||||
{Name: "foo", Value: "bar"},
|
||||
{Name: "time", Value: "1718773640123456789"},
|
||||
}, 1718773640123456789)
|
||||
|
||||
// Unix timestamp in microseconds
|
||||
f("time", []logstorage.Field{
|
||||
{Name: "foo", Value: "bar"},
|
||||
{Name: "time", Value: "1718773640123456"},
|
||||
}, 1718773640123456000)
|
||||
|
||||
// Unix timestamp in milliseconds
|
||||
f("time", []logstorage.Field{
|
||||
{Name: "foo", Value: "bar"},
|
||||
@@ -64,14 +76,14 @@ func TestExtractTimestampRFC3339NanoFromFields_Success(t *testing.T) {
|
||||
}, 1718773640000000000)
|
||||
}
|
||||
|
||||
func TestExtractTimestampRFC3339NanoFromFields_Error(t *testing.T) {
|
||||
func TestExtractTimestampFromFields_Error(t *testing.T) {
|
||||
f := func(s string) {
|
||||
t.Helper()
|
||||
|
||||
fields := []logstorage.Field{
|
||||
{Name: "time", Value: s},
|
||||
}
|
||||
nsecs, err := ExtractTimestampRFC3339NanoFromFields("time", fields)
|
||||
nsecs, err := ExtractTimestampFromFields("time", fields)
|
||||
if err == nil {
|
||||
t.Fatalf("expecting non-nil error")
|
||||
}
|
||||
@@ -80,6 +92,7 @@ func TestExtractTimestampRFC3339NanoFromFields_Error(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// invalid time
|
||||
f("foobar")
|
||||
|
||||
// incomplete time
|
||||
|
||||
@@ -51,20 +51,13 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
lmp := cp.NewLogMessageProcessor("jsonline")
|
||||
streamName := fmt.Sprintf("remoteAddr=%s, requestURI=%q", httpserver.GetQuotedRemoteAddr(r), r.RequestURI)
|
||||
err = processStreamInternal(streamName, reader, cp.TimeField, cp.MsgFields, lmp)
|
||||
processStreamInternal(streamName, reader, cp.TimeField, cp.MsgFields, lmp)
|
||||
lmp.MustClose()
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("jsonline: %s", err)
|
||||
} else {
|
||||
// update requestDuration only for successfully parsed requests.
|
||||
// There is no need in updating requestDuration for request errors,
|
||||
// since their timings are usually much smaller than the timing for successful request parsing.
|
||||
requestDuration.UpdateDuration(startTime)
|
||||
}
|
||||
requestDuration.UpdateDuration(startTime)
|
||||
}
|
||||
|
||||
func processStreamInternal(streamName string, r io.Reader, timeField string, msgFields []string, lmp insertutils.LogMessageProcessor) error {
|
||||
func processStreamInternal(streamName string, r io.Reader, timeField string, msgFields []string, lmp insertutils.LogMessageProcessor) {
|
||||
wcr := writeconcurrencylimiter.GetReader(r)
|
||||
defer writeconcurrencylimiter.PutReader(wcr)
|
||||
|
||||
@@ -76,10 +69,10 @@ func processStreamInternal(streamName string, r io.Reader, timeField string, msg
|
||||
wcr.DecConcurrency()
|
||||
if err != nil {
|
||||
errorsTotal.Inc()
|
||||
return fmt.Errorf("cannot read line #%d in /jsonline request: %s", n, err)
|
||||
logger.Warnf("jsonline: cannot read line #%d in /jsonline request: %s", n, err)
|
||||
}
|
||||
if !ok {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
n++
|
||||
}
|
||||
@@ -96,16 +89,17 @@ func readLine(lr *insertutils.LineReader, timeField string, msgFields []string,
|
||||
}
|
||||
|
||||
p := logstorage.GetJSONParser()
|
||||
defer logstorage.PutJSONParser(p)
|
||||
|
||||
if err := p.ParseLogMessage(line); err != nil {
|
||||
return false, fmt.Errorf("cannot parse json-encoded log entry: %w", err)
|
||||
return true, fmt.Errorf("cannot parse json-encoded line: %w; line contents: %q", err, line)
|
||||
}
|
||||
ts, err := insertutils.ExtractTimestampRFC3339NanoFromFields(timeField, p.Fields)
|
||||
ts, err := insertutils.ExtractTimestampFromFields(timeField, p.Fields)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cannot get timestamp: %w", err)
|
||||
return true, fmt.Errorf("cannot get timestamp from json-encoded line: %w; line contents: %q", err, line)
|
||||
}
|
||||
logstorage.RenameField(p.Fields, msgFields, "_msg")
|
||||
lmp.AddRow(ts, p.Fields, nil)
|
||||
logstorage.PutJSONParser(p)
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -7,16 +7,14 @@ import (
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vlinsert/insertutils"
|
||||
)
|
||||
|
||||
func TestProcessStreamInternal_Success(t *testing.T) {
|
||||
func TestProcessStreamInternal(t *testing.T) {
|
||||
f := func(data, timeField, msgField string, timestampsExpected []int64, resultExpected string) {
|
||||
t.Helper()
|
||||
|
||||
msgFields := []string{msgField}
|
||||
tlp := &insertutils.TestLogMessageProcessor{}
|
||||
r := bytes.NewBufferString(data)
|
||||
if err := processStreamInternal("test", r, timeField, msgFields, tlp); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
processStreamInternal("test", r, timeField, msgFields, tlp)
|
||||
|
||||
if err := tlp.Verify(timestampsExpected, resultExpected); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -45,22 +43,37 @@ func TestProcessStreamInternal_Success(t *testing.T) {
|
||||
resultExpected = `{"log.offset":"71770","log.file.path":"/var/log/auth.log","message":"foobar"}
|
||||
{"message":"baz"}`
|
||||
f(data, timeField, msgField, timestampsExpected, resultExpected)
|
||||
}
|
||||
|
||||
func TestProcessStreamInternal_Failure(t *testing.T) {
|
||||
f := func(data string) {
|
||||
t.Helper()
|
||||
|
||||
tlp := &insertutils.TestLogMessageProcessor{}
|
||||
r := bytes.NewBufferString(data)
|
||||
if err := processStreamInternal("test", r, "time", nil, tlp); err == nil {
|
||||
t.Fatalf("expecting non-nil error")
|
||||
}
|
||||
}
|
||||
|
||||
// invalid json
|
||||
f("foobar")
|
||||
data = "foobar"
|
||||
timeField = "@timestamp"
|
||||
msgField = "aaa"
|
||||
timestampsExpected = nil
|
||||
resultExpected = ``
|
||||
f(data, timeField, msgField, timestampsExpected, resultExpected)
|
||||
|
||||
// invalid timestamp field
|
||||
f(`{"time":"foobar"}`)
|
||||
data = `{"time":"foobar"}`
|
||||
timeField = "time"
|
||||
msgField = "abc"
|
||||
timestampsExpected = nil
|
||||
resultExpected = ``
|
||||
f(data, timeField, msgField, timestampsExpected, resultExpected)
|
||||
|
||||
// invalid lines among valid lines
|
||||
data = `
|
||||
dsfodmasd
|
||||
|
||||
{"time":"2023-06-06T04:48:11.735Z","log":{"offset":71770,"file":{"path":"/var/log/auth.log"}},"message":"foobar"}
|
||||
invalid line
|
||||
{"time":"2023-06-06T04:48:12.735+01:00","message":"baz"}
|
||||
asbsdf
|
||||
|
||||
`
|
||||
timeField = "time"
|
||||
msgField = "message"
|
||||
timestampsExpected = []int64{1686026891735000000, 1686023292735000000}
|
||||
resultExpected = `{"log.offset":"71770","log.file.path":"/var/log/auth.log","_msg":"foobar"}
|
||||
{"_msg":"baz"}`
|
||||
f(data, timeField, msgField, timestampsExpected, resultExpected)
|
||||
}
|
||||
|
||||
@@ -560,7 +560,7 @@ func processLine(line []byte, currentYear int, timezone *time.Location, useLocal
|
||||
if useLocalTimestamp {
|
||||
ts = time.Now().UnixNano()
|
||||
} else {
|
||||
nsecs, err := insertutils.ExtractTimestampRFC3339NanoFromFields("timestamp", p.Fields)
|
||||
nsecs, err := insertutils.ExtractTimestampFromFields("timestamp", p.Fields)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot get timestamp from syslog line %q: %w", line, err)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package notifier
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -28,12 +27,10 @@ func TestBlackHoleNotifier_Send(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBlackHoleNotifier_Close(t *testing.T) {
|
||||
addr := "blackhole-close"
|
||||
bh := newBlackHoleNotifier()
|
||||
bh.addr = addr
|
||||
if err := bh.Send(context.Background(), []Alert{{
|
||||
GroupID: 0,
|
||||
Name: "alert1",
|
||||
Name: "alert0",
|
||||
Start: time.Now().UTC(),
|
||||
End: time.Now().UTC(),
|
||||
Annotations: map[string]string{"a": "b", "c": "d", "e": "f"},
|
||||
@@ -44,10 +41,10 @@ func TestBlackHoleNotifier_Close(t *testing.T) {
|
||||
bh.Close()
|
||||
|
||||
defaultMetrics := metricset.GetDefaultSet()
|
||||
alertMetricName := fmt.Sprintf("vmalert_alerts_sent_total{addr=%q}", addr)
|
||||
alertMetricName := "vmalert_alerts_sent_total{addr=\"blackhole\"}"
|
||||
for _, name := range defaultMetrics.ListMetricNames() {
|
||||
if name == alertMetricName {
|
||||
t.Fatalf("Metric name should have unregistered. But still present")
|
||||
t.Fatalf("Metric name should have unregistered.But still present")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +1,14 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||
)
|
||||
import "github.com/VictoriaMetrics/metrics"
|
||||
|
||||
type namedMetric struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
var usedMetrics map[string]*atomic.Int64
|
||||
var usedMetricMu sync.Mutex
|
||||
|
||||
func trackUsedMetric(name string) {
|
||||
usedMetricMu.Lock()
|
||||
defer usedMetricMu.Unlock()
|
||||
|
||||
if usedMetrics == nil {
|
||||
usedMetrics = make(map[string]*atomic.Int64)
|
||||
}
|
||||
if _, ok := usedMetrics[name]; !ok {
|
||||
usedMetrics[name] = &atomic.Int64{}
|
||||
}
|
||||
usedMetrics[name].Add(1)
|
||||
}
|
||||
|
||||
// Unregister removes the metric by name from default registry
|
||||
func (nm namedMetric) Unregister() {
|
||||
if usedMetrics == nil {
|
||||
logger.Fatalf("BUG: unregistered metric %q before registering", nm.Name)
|
||||
}
|
||||
|
||||
usedMetricMu.Lock()
|
||||
counter, ok := usedMetrics[nm.Name]
|
||||
if !ok {
|
||||
logger.Fatalf("BUG: unregistered metric %q before registering", nm.Name)
|
||||
}
|
||||
current := counter.Add(-1)
|
||||
usedMetricMu.Unlock()
|
||||
|
||||
if current < 0 {
|
||||
logger.Fatalf("BUG: negative metric counter for %q", nm.Name)
|
||||
}
|
||||
|
||||
if current == 0 {
|
||||
metrics.UnregisterMetric(nm.Name)
|
||||
}
|
||||
|
||||
metrics.UnregisterMetric(nm.Name)
|
||||
}
|
||||
|
||||
// Gauge is a metrics.Gauge with Name
|
||||
@@ -61,7 +19,6 @@ type Gauge struct {
|
||||
|
||||
// GetOrCreateGauge creates a new Gauge with the given name
|
||||
func GetOrCreateGauge(name string, f func() float64) *Gauge {
|
||||
trackUsedMetric(name)
|
||||
return &Gauge{
|
||||
namedMetric: namedMetric{Name: name},
|
||||
Gauge: metrics.GetOrCreateGauge(name, f),
|
||||
@@ -76,7 +33,6 @@ type Counter struct {
|
||||
|
||||
// GetOrCreateCounter creates a new Counter with the given name
|
||||
func GetOrCreateCounter(name string) *Counter {
|
||||
trackUsedMetric(name)
|
||||
return &Counter{
|
||||
namedMetric: namedMetric{Name: name},
|
||||
Counter: metrics.GetOrCreateCounter(name),
|
||||
@@ -91,7 +47,6 @@ type Summary struct {
|
||||
|
||||
// GetOrCreateSummary creates a new Summary with the given name
|
||||
func GetOrCreateSummary(name string) *Summary {
|
||||
trackUsedMetric(name)
|
||||
return &Summary{
|
||||
namedMetric: namedMetric{Name: name},
|
||||
Summary: metrics.GetOrCreateSummary(name),
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
)
|
||||
|
||||
func isMetricRegistered(name string) bool {
|
||||
metricNames := metrics.GetDefaultSet().ListMetricNames()
|
||||
for _, mn := range metricNames {
|
||||
if mn == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func TestMetricIsUnregistered(t *testing.T) {
|
||||
metricName := "example_runs_total"
|
||||
c := GetOrCreateCounter(metricName)
|
||||
if !isMetricRegistered(metricName) {
|
||||
t.Errorf("Expected metric %s to be present", metricName)
|
||||
}
|
||||
|
||||
c.Unregister()
|
||||
if isMetricRegistered(metricName) {
|
||||
t.Errorf("Expected metric %s to be unregistered", metricName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetricIsRemovedIfNoUses(t *testing.T) {
|
||||
metricName := "example_runs_total"
|
||||
c := GetOrCreateCounter(metricName)
|
||||
c2 := GetOrCreateCounter(metricName)
|
||||
|
||||
if !isMetricRegistered(metricName) {
|
||||
t.Errorf("Expected metric %s to be present", metricName)
|
||||
}
|
||||
|
||||
c.Unregister()
|
||||
// metric should still be registered since c2 is using it
|
||||
if !isMetricRegistered(metricName) {
|
||||
t.Errorf("Expected metric %s to be present", metricName)
|
||||
}
|
||||
|
||||
c2.Unregister()
|
||||
if isMetricRegistered(metricName) {
|
||||
t.Errorf("Expected metric %s to be unregistered", metricName)
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
@@ -1002,9 +1001,7 @@ func ExportBlocks(qt *querytracer.Tracer, sq *storage.SearchQuery, deadline sear
|
||||
|
||||
sr := getStorageSearch()
|
||||
defer putStorageSearch(sr)
|
||||
startTime := time.Now()
|
||||
sr.Init(qt, vmstorage.Storage, tfss, tr, sq.MaxMetrics, deadline.Deadline())
|
||||
indexSearchDuration.UpdateDuration(startTime)
|
||||
|
||||
// Start workers that call f in parallel on available CPU cores.
|
||||
workCh := make(chan *exportWork, gomaxprocs*8)
|
||||
@@ -1142,9 +1139,7 @@ func ProcessSearchQuery(qt *querytracer.Tracer, sq *storage.SearchQuery, deadlin
|
||||
defer vmstorage.WG.Done()
|
||||
|
||||
sr := getStorageSearch()
|
||||
startTime := time.Now()
|
||||
maxSeriesCount := sr.Init(qt, vmstorage.Storage, tfss, tr, sq.MaxMetrics, deadline.Deadline())
|
||||
indexSearchDuration.UpdateDuration(startTime)
|
||||
type blockRefs struct {
|
||||
brs []blockRef
|
||||
}
|
||||
@@ -1296,8 +1291,6 @@ func ProcessSearchQuery(qt *querytracer.Tracer, sq *storage.SearchQuery, deadlin
|
||||
return &rss, nil
|
||||
}
|
||||
|
||||
var indexSearchDuration = metrics.NewHistogram(`vm_index_search_duration_seconds`)
|
||||
|
||||
type blockRef struct {
|
||||
partRef storage.PartRef
|
||||
addr tmpBlockAddr
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.af583aad.css",
|
||||
"main.js": "./static/js/main.1413b18d.js",
|
||||
"main.css": "./static/css/main.7fa18e1b.css",
|
||||
"main.js": "./static/js/main.ba08300f.js",
|
||||
"static/js/685.f772060c.chunk.js": "./static/js/685.f772060c.chunk.js",
|
||||
"static/media/MetricsQL.md": "./static/media/MetricsQL.a00044c91d9781cf8557.md",
|
||||
"index.html": "./index.html"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.af583aad.css",
|
||||
"static/js/main.1413b18d.js"
|
||||
"static/css/main.7fa18e1b.css",
|
||||
"static/js/main.ba08300f.js"
|
||||
]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.svg"/><link rel="apple-touch-icon" href="./favicon.svg"/><link rel="mask-icon" href="./favicon.svg" color="#000000"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=5"/><meta name="theme-color" content="#000000"/><meta name="description" content="Explore and troubleshoot your VictoriaMetrics data"/><link rel="manifest" href="./manifest.json"/><title>vmui</title><script src="./dashboards/index.js" type="module"></script><meta name="twitter:card" content="summary"><meta name="twitter:title" content="UI for VictoriaMetrics"><meta name="twitter:site" content="@https://victoriametrics.com/"><meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta name="twitter:image" content="./preview.jpg"><meta property="og:type" content="website"><meta property="og:title" content="UI for VictoriaMetrics"><meta property="og:url" content="https://victoriametrics.com/"><meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data"><script defer="defer" src="./static/js/main.1413b18d.js"></script><link href="./static/css/main.af583aad.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.svg"/><link rel="apple-touch-icon" href="./favicon.svg"/><link rel="mask-icon" href="./favicon.svg" color="#000000"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=5"/><meta name="theme-color" content="#000000"/><meta name="description" content="Explore and troubleshoot your VictoriaMetrics data"/><link rel="manifest" href="./manifest.json"/><title>vmui</title><script src="./dashboards/index.js" type="module"></script><meta name="twitter:card" content="summary"><meta name="twitter:title" content="UI for VictoriaMetrics"><meta name="twitter:site" content="@https://victoriametrics.com/"><meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta name="twitter:image" content="./preview.jpg"><meta property="og:type" content="website"><meta property="og:title" content="UI for VictoriaMetrics"><meta property="og:url" content="https://victoriametrics.com/"><meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data"><script defer="defer" src="./static/js/main.ba08300f.js"></script><link href="./static/css/main.7fa18e1b.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
1
app/vmselect/vmui/static/css/main.7fa18e1b.css
Normal file
1
app/vmselect/vmui/static/css/main.7fa18e1b.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
File diff suppressed because one or more lines are too long
2
app/vmselect/vmui/static/js/main.ba08300f.js
Normal file
2
app/vmselect/vmui/static/js/main.ba08300f.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.23.5 AS build-web-stage
|
||||
FROM golang:1.23.6 AS build-web-stage
|
||||
COPY build /build
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
@@ -1 +1 @@
|
||||
FAST_REFRESH=false
|
||||
VITE_APP_TYPE=victoriametrics
|
||||
|
||||
1
app/vmui/packages/vmui/.env.victorialogs
Normal file
1
app/vmui/packages/vmui/.env.victorialogs
Normal file
@@ -0,0 +1 @@
|
||||
VITE_APP_TYPE=victorialogs
|
||||
1
app/vmui/packages/vmui/.env.vmanomaly
Normal file
1
app/vmui/packages/vmui/.env.vmanomaly
Normal file
@@ -0,0 +1 @@
|
||||
VITE_APP_TYPE=vmanomaly
|
||||
@@ -1,48 +0,0 @@
|
||||
// eslint-disable-next-line no-undef
|
||||
module.exports = {
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": { "jsx": true },
|
||||
"ecmaVersion": 12,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"react",
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": ["warn", { "varsIgnorePattern": "^_" }],
|
||||
"react/jsx-closing-bracket-location": [1, "line-aligned"],
|
||||
"react/jsx-max-props-per-line":[1, { "maximum": 1 }],
|
||||
"react/jsx-first-prop-new-line": [1, "multiline"],
|
||||
"object-curly-spacing": [2, "always"],
|
||||
"indent": ["error", 2, { "SwitchCase": 1 }],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"quotes": ["error", "double"],
|
||||
"semi": ["error", "always"],
|
||||
"react/prop-types": 0
|
||||
},
|
||||
"settings": {
|
||||
"react": {
|
||||
"pragma": "React", // Pragma to use, default to "React"
|
||||
"version": "detect"
|
||||
},
|
||||
"linkComponents": [
|
||||
// Components used as alternatives to <a> for linking, eg. <Link to={ url } />
|
||||
"Hyperlink",
|
||||
{
|
||||
"name": "Link", "linkAttribute": "to"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/* eslint-disable */
|
||||
const { override, addExternalBabelPlugin, addWebpackAlias, addWebpackPlugin } = require("customize-cra");
|
||||
const webpack = require("webpack");
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// This will replace the default check
|
||||
const pathIndexHTML = (() => {
|
||||
switch (process.env.REACT_APP_TYPE) {
|
||||
case 'logs':
|
||||
return 'src/html/victorialogs.html';
|
||||
case 'anomaly':
|
||||
return 'src/html/vmanomaly.html';
|
||||
default:
|
||||
return 'src/html/victoriametrics.html';
|
||||
}
|
||||
})();
|
||||
const fileContent = fs.readFileSync(path.resolve(__dirname, pathIndexHTML), 'utf8');
|
||||
fs.writeFileSync(path.resolve(__dirname, 'public/index.html'), fileContent);
|
||||
|
||||
module.exports = override(
|
||||
addExternalBabelPlugin("@babel/plugin-proposal-nullish-coalescing-operator"),
|
||||
addWebpackAlias({
|
||||
"react": "preact/compat",
|
||||
"react-dom/test-utils": "preact/test-utils",
|
||||
"react-dom": "preact/compat", // Must be below test-utils
|
||||
"react/jsx-runtime": "preact/jsx-runtime"
|
||||
}),
|
||||
addWebpackPlugin(
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/\.\/App/,
|
||||
function (resource) {
|
||||
if (process.env.REACT_APP_TYPE === "logs") {
|
||||
resource.request = "./AppLogs";
|
||||
}
|
||||
if (process.env.REACT_APP_TYPE === "anomaly") {
|
||||
resource.request = "./AppAnomaly";
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
23
app/vmui/packages/vmui/config/plugins/dynamicIndexHtml.ts
Normal file
23
app/vmui/packages/vmui/config/plugins/dynamicIndexHtml.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { readFile } from "fs/promises";
|
||||
import { IndexHtmlTransform } from "vite";
|
||||
|
||||
/**
|
||||
* Vite plugin to dynamically load index.html based on the current mode.
|
||||
* If a specific mode-based index file (e.g., index.victorialogs.html) exists, it is used.
|
||||
* Otherwise, the default index.html is loaded.
|
||||
*/
|
||||
export default function dynamicIndexHtmlPlugin({ mode }) {
|
||||
return {
|
||||
name: "vm-dynamic-index-html",
|
||||
transformIndexHtml: {
|
||||
order: "pre",
|
||||
handler: async () => {
|
||||
try {
|
||||
return await readFile(`./index.${mode}.html`, "utf8");
|
||||
} catch (error) {
|
||||
return await readFile("./index.html", "utf8");
|
||||
}
|
||||
}
|
||||
} as IndexHtmlTransform
|
||||
};
|
||||
}
|
||||
90
app/vmui/packages/vmui/eslint.config.js
Normal file
90
app/vmui/packages/vmui/eslint.config.js
Normal file
@@ -0,0 +1,90 @@
|
||||
import react from "eslint-plugin-react";
|
||||
import typescriptEslint from "@typescript-eslint/eslint-plugin";
|
||||
import globals from "globals";
|
||||
import tsParser from "@typescript-eslint/parser";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import js from "@eslint/js";
|
||||
import { FlatCompat } from "@eslint/eslintrc";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
recommendedConfig: js.configs.recommended,
|
||||
allConfig: js.configs.all
|
||||
});
|
||||
|
||||
export default [...compat.extends(
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
), {
|
||||
plugins: {
|
||||
react,
|
||||
"@typescript-eslint": typescriptEslint,
|
||||
},
|
||||
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
},
|
||||
|
||||
parser: tsParser,
|
||||
ecmaVersion: 12,
|
||||
sourceType: "module",
|
||||
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
settings: {
|
||||
react: {
|
||||
pragma: "React",
|
||||
version: "detect",
|
||||
},
|
||||
|
||||
linkComponents: ["Hyperlink", {
|
||||
name: "Link",
|
||||
linkAttribute: "to",
|
||||
}],
|
||||
},
|
||||
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-expressions": ["error", {
|
||||
allowShortCircuit: true,
|
||||
allowTernary: true
|
||||
}],
|
||||
|
||||
"@typescript-eslint/no-unused-vars": ["warn", {
|
||||
"argsIgnorePattern": "^_",
|
||||
"caughtErrors": "none",
|
||||
"caughtErrorsIgnorePattern": "^_",
|
||||
"destructuredArrayIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
"ignoreRestSiblings": true
|
||||
}],
|
||||
|
||||
"react/jsx-closing-bracket-location": [1, "line-aligned"],
|
||||
|
||||
"react/jsx-max-props-per-line": [1, {
|
||||
maximum: 1,
|
||||
}],
|
||||
|
||||
"react/jsx-first-prop-new-line": [1, "multiline"],
|
||||
"object-curly-spacing": [2, "always"],
|
||||
|
||||
indent: ["error", 2, {
|
||||
SwitchCase: 1,
|
||||
}],
|
||||
|
||||
"linebreak-style": ["error", "unix"],
|
||||
quotes: ["error", "double"],
|
||||
semi: ["error", "always"],
|
||||
"react/prop-types": 0,
|
||||
|
||||
},
|
||||
}];
|
||||
@@ -2,9 +2,9 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.svg" />
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/favicon.svg" />
|
||||
<link rel="mask-icon" href="%PUBLIC_URL%/favicon.svg" color="#000000">
|
||||
<link rel="icon" href="/favicon.svg"/>
|
||||
<link rel="apple-touch-icon" href="/favicon.svg"/>
|
||||
<link rel="mask-icon" href="/favicon.svg" color="#000000">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5"/>
|
||||
<meta name="theme-color" content="#000000"/>
|
||||
@@ -13,24 +13,24 @@
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
|
||||
<link rel="manifest" href="/manifest.json"/>
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
Notice the use of in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
Unlike "/favicon.ico" or "favicon.ico", "/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>vmui</title>
|
||||
<script src="%PUBLIC_URL%/dashboards/index.js" type="module"></script>
|
||||
<script src="/dashboards/index.js" type="module"></script>
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="UI for VictoriaMetrics">
|
||||
<meta name="twitter:site" content="@https://victoriametrics.com/">
|
||||
<meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data">
|
||||
<meta name="twitter:image" content="%PUBLIC_URL%/preview.jpg">
|
||||
<meta name="twitter:image" content="/preview.jpg">
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="UI for VictoriaMetrics">
|
||||
@@ -50,5 +50,6 @@
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,9 +2,9 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.svg" />
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/favicon.svg" />
|
||||
<link rel="mask-icon" href="%PUBLIC_URL%/favicon.svg" color="#000000">
|
||||
<link rel="icon" href="/favicon.svg" />
|
||||
<link rel="apple-touch-icon" href="/favicon.svg" />
|
||||
<link rel="mask-icon" href="/favicon.svg" color="#000000">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5"/>
|
||||
<meta name="theme-color" content="#000000"/>
|
||||
@@ -13,13 +13,13 @@
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
|
||||
<link rel="manifest" href="/manifest.json"/>
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
Notice the use of in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
Unlike "/favicon.ico" or "favicon.ico", "/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
@@ -29,7 +29,7 @@
|
||||
<meta name="twitter:title" content="UI for VictoriaLogs">
|
||||
<meta name="twitter:site" content="@https://victoriametrics.com/products/victorialogs/">
|
||||
<meta name="twitter:description" content="Explore your log data with VictoriaLogs UI">
|
||||
<meta name="twitter:image" content="%PUBLIC_URL%/preview.jpg">
|
||||
<meta name="twitter:image" content="/preview.jpg">
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="UI for VictoriaLogs">
|
||||
@@ -49,5 +49,6 @@
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,9 +2,9 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.svg" />
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/favicon.svg" />
|
||||
<link rel="mask-icon" href="%PUBLIC_URL%/favicon.svg" color="#000000">
|
||||
<link rel="icon" href="/favicon.svg" />
|
||||
<link rel="apple-touch-icon" href="/favicon.svg" />
|
||||
<link rel="mask-icon" href="/favicon.svg" color="#000000">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5"/>
|
||||
<meta name="theme-color" content="#000000"/>
|
||||
@@ -13,13 +13,13 @@
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
|
||||
<link rel="manifest" href="/manifest.json"/>
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
Notice the use of in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
Unlike "/favicon.ico" or "favicon.ico", "/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
@@ -29,7 +29,7 @@
|
||||
<meta name="twitter:title" content="UI for VictoriaMetrics Anomaly Detection">
|
||||
<meta name="twitter:site" content="@https://victoriametrics.com/products/enterprise/anomaly-detection/">
|
||||
<meta name="twitter:description" content="Detect anomalies in your metrics with VictoriaMetrics Anomaly Detection UI">
|
||||
<meta name="twitter:image" content="%PUBLIC_URL%/preview.jpg">
|
||||
<meta name="twitter:image" content="/preview.jpg">
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="UI for VictoriaMetrics Anomaly Detection">
|
||||
@@ -49,5 +49,6 @@
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
19985
app/vmui/packages/vmui/package-lock.json
generated
19985
app/vmui/packages/vmui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,50 +3,40 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"homepage": "./",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@types/lodash.debounce": "^4.0.9",
|
||||
"@types/lodash.get": "^4.4.9",
|
||||
"@types/lodash.throttle": "^4.1.9",
|
||||
"@types/node": "^22.5.4",
|
||||
"@types/qs": "^6.9.15",
|
||||
"@types/react-input-mask": "^3.0.5",
|
||||
"@types/qs": "^6.9.18",
|
||||
"@types/react": "^19.0.8",
|
||||
"@types/react-input-mask": "^3.0.6",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/webpack-env": "^1.18.5",
|
||||
"classnames": "^2.5.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"marked": "^14.1.2",
|
||||
"marked-emoji": "^1.4.2",
|
||||
"preact": "^10.23.2",
|
||||
"qs": "^6.13.0",
|
||||
"marked": "^15.0.6",
|
||||
"marked-emoji": "^1.4.3",
|
||||
"preact": "^10.25.4",
|
||||
"qs": "^6.14.0",
|
||||
"react-input-mask": "^2.0.4",
|
||||
"react-router-dom": "^6.26.2",
|
||||
"sass": "^1.78.0",
|
||||
"source-map-explorer": "^2.5.3",
|
||||
"typescript": "~4.6.2",
|
||||
"uplot": "^1.6.30",
|
||||
"web-vitals": "^4.2.3"
|
||||
"react-router-dom": "^7.1.5",
|
||||
"uplot": "^1.6.31",
|
||||
"vite": "^6.0.11",
|
||||
"web-vitals": "^4.2.4"
|
||||
},
|
||||
"scripts": {
|
||||
"prestart": "npm run copy-metricsql-docs",
|
||||
"start": "react-app-rewired start",
|
||||
"start:logs": "cross-env REACT_APP_TYPE=logs npm run start",
|
||||
"start:anomaly": "cross-env REACT_APP_TYPE=anomaly npm run start",
|
||||
"build": "GENERATE_SOURCEMAP=false react-app-rewired build",
|
||||
"build:logs": "cross-env REACT_APP_TYPE=logs npm run build",
|
||||
"build:anomaly": "cross-env REACT_APP_TYPE=anomaly npm run build",
|
||||
"lint": "eslint src --ext tsx,ts",
|
||||
"lint:fix": "eslint src --ext tsx,ts --fix",
|
||||
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
||||
"copy-metricsql-docs": "cp ../../../../docs/MetricsQL.md src/assets/MetricsQL.md || true"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
"start": "vite",
|
||||
"start:logs": "vite --mode victorialogs",
|
||||
"start:anomaly": "vite --mode vmanomaly",
|
||||
"build": "vite build",
|
||||
"build:logs": "vite build --mode victorialogs",
|
||||
"build:anomaly": "vite build --mode vmanomaly",
|
||||
"lint": "eslint 'src/**/*.{ts,tsx}'",
|
||||
"lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix",
|
||||
"copy-metricsql-docs": "cp ../../../../docs/MetricsQL.md src/assets/MetricsQL.md || true",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
@@ -61,26 +51,24 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.15.0",
|
||||
"@typescript-eslint/parser": "^5.15.0",
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.19.0",
|
||||
"@preact/preset-vite": "^2.10.1",
|
||||
"@types/node": "^22.13.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.22.0",
|
||||
"@typescript-eslint/parser": "^8.22.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"customize-cra": "^1.0.0",
|
||||
"eslint": "^8.44.0",
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"eslint-plugin-react": "^7.36.1",
|
||||
"http-proxy-middleware": "^3.0.2",
|
||||
"react-app-rewired": "^2.2.1",
|
||||
"webpack": "^5.94.0"
|
||||
},
|
||||
"overrides": {
|
||||
"react-app-rewired": {
|
||||
"nth-check": "^2.0.1"
|
||||
},
|
||||
"css-select": {
|
||||
"nth-check": "^2.0.1"
|
||||
}
|
||||
"eslint": "^9.19.0",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"globals": "^15.14.0",
|
||||
"http-proxy-middleware": "^3.0.3",
|
||||
"postcss": "^8.5.1",
|
||||
"rollup-plugin-visualizer": "^5.14.0",
|
||||
"sass": "^1.83.4",
|
||||
"sass-embedded": "^1.83.4",
|
||||
"typescript": "^5.7.3",
|
||||
"webpack": "^5.97.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,4 +38,4 @@ const AppAnomaly: FC = () => {
|
||||
</>;
|
||||
};
|
||||
|
||||
export default AppAnomaly;
|
||||
export default AppAnomaly;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { FC, useCallback, useEffect, useRef, useState } from "preact/compat";
|
||||
import React, { FC, useCallback, useEffect, useRef, useState, createPortal } from "preact/compat";
|
||||
import { MouseEvent as ReactMouseEvent } from "react";
|
||||
import useEventListener from "../../../hooks/useEventListener";
|
||||
import ReactDOM from "react-dom";
|
||||
import classNames from "classnames";
|
||||
import uPlot from "uplot";
|
||||
import Button from "../../Main/Button/Button";
|
||||
@@ -49,7 +48,7 @@ const ChartTooltip: FC<ChartTooltipProps> = ({
|
||||
onClose && onClose(id);
|
||||
};
|
||||
|
||||
const handleMouseDown = (e: ReactMouseEvent) => {
|
||||
const handleMouseDown = (e: ReactMouseEvent<HTMLButtonElement>) => {
|
||||
setMoved(true);
|
||||
setMoving(true);
|
||||
const { clientX, clientY } = e;
|
||||
@@ -107,7 +106,7 @@ const ChartTooltip: FC<ChartTooltipProps> = ({
|
||||
|
||||
if (!u) return null;
|
||||
|
||||
return ReactDOM.createPortal((
|
||||
return createPortal((
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-chart-tooltip": true,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@use "src/styles/variables" as *;
|
||||
@use 'sass:color';
|
||||
|
||||
$color-bar: #33BB55;
|
||||
$color-bar-highest: #F79420;
|
||||
@@ -7,7 +8,7 @@ $color-bar-highest: #F79420;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
height: 100%;
|
||||
padding-bottom: calc($font-size-small/2);
|
||||
padding-bottom: calc($font-size-small / 2);
|
||||
overflow: hidden;
|
||||
|
||||
&-y-axis {
|
||||
@@ -54,19 +55,19 @@ $color-bar-highest: #F79420;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
min-width: 1px;
|
||||
height: calc(100% - ($font-size-small*4));
|
||||
height: calc(100% - ($font-size-small * 4));
|
||||
background-color: $color-bar;
|
||||
transition: background-color 200ms ease-in;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten($color-bar, 10%);
|
||||
background-color: color.scale($color-bar, $lightness: 40%);
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
background-color: $color-bar-highest;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten($color-bar-highest, 10%);
|
||||
background-color: color.scale($color-bar-highest, $lightness: 40%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,14 +12,11 @@ import Timezones from "./Timezones/Timezones";
|
||||
import ThemeControl from "../ThemeControl/ThemeControl";
|
||||
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
import useBoolean from "../../../hooks/useBoolean";
|
||||
import { AppType } from "../../../types/appType";
|
||||
import SwitchMarkdownParsing from "../LogsSettings/MarkdownParsing/SwitchMarkdownParsing";
|
||||
import { APP_TYPE_LOGS } from "../../../constants/appType";
|
||||
|
||||
const title = "Settings";
|
||||
|
||||
const { REACT_APP_TYPE } = process.env;
|
||||
const isLogsApp = REACT_APP_TYPE === AppType.logs;
|
||||
|
||||
export interface ChildComponentHandle {
|
||||
handleApply: () => void;
|
||||
}
|
||||
@@ -48,21 +45,21 @@ const GlobalSettings: FC = () => {
|
||||
|
||||
const controls = [
|
||||
{
|
||||
show: !appModeEnable && !isLogsApp,
|
||||
show: !appModeEnable && !APP_TYPE_LOGS,
|
||||
component: <ServerConfigurator
|
||||
ref={serverSettingRef}
|
||||
onClose={handleClose}
|
||||
/>
|
||||
},
|
||||
{
|
||||
show: !isLogsApp,
|
||||
show: !APP_TYPE_LOGS,
|
||||
component: <LimitsConfigurator
|
||||
ref={limitsSettingRef}
|
||||
onClose={handleClose}
|
||||
/>
|
||||
},
|
||||
{
|
||||
show: isLogsApp,
|
||||
show: APP_TYPE_LOGS,
|
||||
component: <SwitchMarkdownParsing/>
|
||||
},
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ export class QueryAutocompleteCache {
|
||||
put(key: QueryAutocompleteCacheItem, value: string[]) {
|
||||
if (this.map.size >= this.maxSize) {
|
||||
const firstKey = this.map.keys().next().value;
|
||||
this.map.delete(firstKey);
|
||||
firstKey && this.map.delete(firstKey);
|
||||
}
|
||||
this.map.set(JSON.stringify(key), value);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { FC, useEffect, useRef, useState } from "preact/compat";
|
||||
import { KeyboardEvent } from "react";
|
||||
import { ErrorTypes } from "../../../types";
|
||||
import TextField from "../../Main/TextField/TextField";
|
||||
import TextField, { TextFieldKeyboardEvent } from "../../Main/TextField/TextField";
|
||||
import "./style.scss";
|
||||
import { QueryStats } from "../../../api/types";
|
||||
import { partialWarning, seriesFetchedWarning } from "./warningText";
|
||||
@@ -81,7 +80,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
|
||||
setCaretPositionInput([caretPosition, caretPosition]);
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
const handleKeyDown = (e: TextFieldKeyboardEvent) => {
|
||||
const { key, ctrlKey, metaKey, shiftKey } = e;
|
||||
|
||||
const value = (e.target as HTMLTextAreaElement).value || "";
|
||||
|
||||
@@ -137,12 +137,7 @@ const StepConfigurator: FC = () => {
|
||||
startIcon={<TimelineIcon/>}
|
||||
onClick={toggleOpenOptions}
|
||||
>
|
||||
<p>
|
||||
STEP
|
||||
<p className="vm-step-control__value">
|
||||
{customStep}
|
||||
</p>
|
||||
</p>
|
||||
STEP {customStep}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
&__value {
|
||||
display: inline;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
&-popper {
|
||||
display: grid;
|
||||
gap: $padding-small;
|
||||
|
||||
@@ -14,8 +14,8 @@ interface ButtonProps {
|
||||
disabled?: boolean
|
||||
children?: ReactNode
|
||||
className?: string
|
||||
onClick?: (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => void
|
||||
onMouseDown?: (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => void
|
||||
onClick?: (e: ReactMouseEvent<HTMLButtonElement>) => void
|
||||
onMouseDown?: (e: ReactMouseEvent<HTMLButtonElement>) => void
|
||||
}
|
||||
|
||||
const Button: FC<ButtonProps> = ({
|
||||
|
||||
@@ -46,7 +46,7 @@ const DateTimeInput: FC<DateTimeInputProps> = ({
|
||||
onChange(maskedValue);
|
||||
};
|
||||
|
||||
const handleKeyUp = (e: KeyboardEvent) => {
|
||||
const handleKeyUp = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Enter") {
|
||||
onChange(maskedValue);
|
||||
setAwaitChangeForEnter(true);
|
||||
|
||||
@@ -89,7 +89,8 @@ const TimePicker: FC<CalendarTimepickerProps>= ({ selectDate, onChangeTime, onCl
|
||||
};
|
||||
|
||||
const handleFocusInput = (unit: TimeUnits, e: FocusEvent<HTMLInputElement>) => {
|
||||
e.target.select();
|
||||
const target = e.target as HTMLInputElement;
|
||||
target && target.select();
|
||||
setActiveField(unit);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { FC, useCallback, useEffect } from "preact/compat";
|
||||
import ReactDOM from "react-dom";
|
||||
import React, { FC, useCallback, useEffect, createPortal } from "preact/compat";
|
||||
import { CloseIcon } from "../Icons";
|
||||
import Button from "../Button/Button";
|
||||
import { ReactNode, MouseEvent } from "react";
|
||||
@@ -58,7 +57,7 @@ const Modal: FC<ModalProps> = ({
|
||||
useEventListener("popstate", handlePopstate);
|
||||
useEventListener("keyup", handleKeyUp);
|
||||
|
||||
return ReactDOM.createPortal((
|
||||
return createPortal((
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-modal": true,
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import React, { FC, MouseEvent as ReactMouseEvent, ReactNode, useEffect, useMemo, useRef, useState } from "react";
|
||||
import React, {
|
||||
FC,
|
||||
MouseEvent as ReactMouseEvent,
|
||||
ReactNode,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
useCallback,
|
||||
createPortal
|
||||
} from "react";
|
||||
import classNames from "classnames";
|
||||
import ReactDOM from "react-dom";
|
||||
import "./style.scss";
|
||||
import useClickOutside from "../../../hooks/useClickOutside";
|
||||
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
@@ -8,7 +17,6 @@ import Button from "../Button/Button";
|
||||
import { CloseIcon } from "../Icons";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import useEventListener from "../../../hooks/useEventListener";
|
||||
import { useCallback } from "preact/compat";
|
||||
|
||||
interface PopperProps {
|
||||
children: ReactNode
|
||||
@@ -119,7 +127,7 @@ const Popper: FC<PopperProps> = ({
|
||||
return position;
|
||||
}, [buttonRef, placement, isOpen, children, fullWidth]);
|
||||
|
||||
const handleClickClose = (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
const handleClickClose = (e: ReactMouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
onClose();
|
||||
};
|
||||
@@ -156,7 +164,7 @@ const Popper: FC<PopperProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{(isOpen || !popperSize.width) && ReactDOM.createPortal((
|
||||
{(isOpen || !popperSize.width) && createPortal((
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-popper": true,
|
||||
|
||||
@@ -11,7 +11,7 @@ interface MultipleSelectedValueProps {
|
||||
const MultipleSelectedValue: FC<MultipleSelectedValueProps> = ({ values, onRemoveItem }) => {
|
||||
const { isMobile } = useDeviceDetect();
|
||||
|
||||
const createHandleClick = (value: string) => (e: MouseEvent) => {
|
||||
const createHandleClick = (value: string) => (e: MouseEvent<HTMLDivElement>) => {
|
||||
onRemoveItem(value);
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
@@ -92,7 +92,7 @@ const Select: FC<SelectProps> = ({
|
||||
setSearch((e.target as HTMLInputElement).value);
|
||||
};
|
||||
|
||||
const createHandleClick = (value: string) => (e: MouseEvent) => {
|
||||
const createHandleClick = (value: string) => (e: MouseEvent<HTMLDivElement>) => {
|
||||
handleSelected(value);
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
@@ -15,6 +15,8 @@ import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
import TextFieldMessage from "./TextFieldMessage";
|
||||
import "./style.scss";
|
||||
|
||||
export type TextFieldKeyboardEvent = KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>;
|
||||
|
||||
interface TextFieldProps {
|
||||
label?: string,
|
||||
value?: string | number
|
||||
@@ -31,7 +33,7 @@ interface TextFieldProps {
|
||||
caretPosition?: [number, number]
|
||||
onChange?: (value: string) => void
|
||||
onEnter?: () => void
|
||||
onKeyDown?: (e: KeyboardEvent) => void
|
||||
onKeyDown?: (e: TextFieldKeyboardEvent) => void
|
||||
onFocus?: () => void
|
||||
onBlur?: () => void
|
||||
onChangeCaret?: (position: [number, number]) => void
|
||||
@@ -84,7 +86,7 @@ const TextField: FC<TextFieldProps> = ({
|
||||
updateCaretPosition(e.currentTarget);
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
const handleKeyDown = (e: TextFieldKeyboardEvent) => {
|
||||
onKeyDown && onKeyDown(e);
|
||||
const { key, ctrlKey, metaKey } = e;
|
||||
const isEnter = key === "Enter";
|
||||
@@ -95,7 +97,7 @@ const TextField: FC<TextFieldProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyUp = (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
const handleKeyUp = (e: TextFieldKeyboardEvent) => {
|
||||
updateCaretPosition(e.currentTarget);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import React, { FC, useEffect, useMemo, useRef, useState, Fragment } from "preact/compat";
|
||||
import ReactDOM from "react-dom";
|
||||
import React, { FC, useEffect, useMemo, useRef, useState, Fragment, createPortal } from "preact/compat";
|
||||
import "./style.scss";
|
||||
import { ReactNode } from "react";
|
||||
import { ExoticComponent } from "react";
|
||||
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
|
||||
interface TooltipProps {
|
||||
@@ -25,7 +23,7 @@ const Tooltip: FC<TooltipProps> = ({
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [popperSize, setPopperSize] = useState({ width: 0, height: 0 });
|
||||
|
||||
const buttonRef = useRef<ExoticComponent>(null);
|
||||
const buttonRef = useRef<ReactNode>(null);
|
||||
const popperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const onScrollWindow = () => setIsOpen(false);
|
||||
@@ -120,7 +118,7 @@ const Tooltip: FC<TooltipProps> = ({
|
||||
{children}
|
||||
</Fragment>
|
||||
|
||||
{!isMobile && isOpen && ReactDOM.createPortal((
|
||||
{!isMobile && isOpen && createPortal((
|
||||
<div
|
||||
className="vm-tooltip"
|
||||
ref={popperRef}
|
||||
|
||||
@@ -8,8 +8,8 @@ import Switch from "../../Main/Switch/Switch";
|
||||
import { arrayEquals } from "../../../utils/array";
|
||||
import classNames from "classnames";
|
||||
import useBoolean from "../../../hooks/useBoolean";
|
||||
import TextField from "../../Main/TextField/TextField";
|
||||
import { KeyboardEvent, useState } from "react";
|
||||
import TextField, { TextFieldKeyboardEvent } from "../../Main/TextField/TextField";
|
||||
import { useState } from "react";
|
||||
import Modal from "../../Main/Modal/Modal";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
|
||||
@@ -96,7 +96,7 @@ const TableSettings: FC<TableSettingsProps> = ({
|
||||
setIndexFocusItem(-1);
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
const handleKeyDown = (e: TextFieldKeyboardEvent) => {
|
||||
const arrowUp = e.key === "ArrowUp";
|
||||
const arrowDown = e.key === "ArrowDown";
|
||||
const enter = e.key === "Enter";
|
||||
|
||||
@@ -6,8 +6,8 @@ const dateColumns = ["date", "timestamp", "time"];
|
||||
export function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
||||
const valueA = a[orderBy];
|
||||
const valueB = b[orderBy];
|
||||
const parsedValueA = dateColumns.includes(`${orderBy}`) ? dayjs(`${valueA}`).unix() : valueA;
|
||||
const parsedValueB = dateColumns.includes(`${orderBy}`) ? dayjs(`${valueB}`).unix() : valueB;
|
||||
const parsedValueA = dateColumns.includes(String(orderBy)) ? dayjs(`${valueA}`).unix() : valueA;
|
||||
const parsedValueB = dateColumns.includes(String(orderBy)) ? dayjs(`${valueB}`).unix() : valueB;
|
||||
if (parsedValueB < parsedValueA) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
12
app/vmui/packages/vmui/src/constants/appType.ts
Normal file
12
app/vmui/packages/vmui/src/constants/appType.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export enum AppType {
|
||||
victoriametrics = "victoriametrics",
|
||||
victorialogs = "victorialogs",
|
||||
vmanomaly = "vmanomaly",
|
||||
}
|
||||
|
||||
export const APP_TYPE = import.meta.env.VITE_APP_TYPE;
|
||||
export const APP_TYPE_VM = APP_TYPE === AppType.victoriametrics;
|
||||
export const APP_TYPE_LOGS = APP_TYPE === AppType.victorialogs;
|
||||
export const APP_TYPE_ANOMALY = APP_TYPE === AppType.vmanomaly;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useAppDispatch } from "../state/common/StateContext";
|
||||
import { useEffect, useState } from "preact/compat";
|
||||
import { ErrorTypes } from "../types";
|
||||
import { APP_TYPE_VM } from "../constants/appType";
|
||||
|
||||
const useFetchFlags = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -10,7 +11,7 @@ const useFetchFlags = () => {
|
||||
|
||||
useEffect(() => {
|
||||
const fetchAppConfig = async () => {
|
||||
if (process.env.REACT_APP_TYPE) return;
|
||||
if (!APP_TYPE_VM) return;
|
||||
setError("");
|
||||
setIsLoading(true);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useTimeDispatch } from "../state/time/TimeStateContext";
|
||||
import { getFromStorage } from "../utils/storage";
|
||||
import dayjs from "dayjs";
|
||||
import { getBrowserTimezone } from "../utils/time";
|
||||
import { APP_TYPE_VM } from "../constants/appType";
|
||||
|
||||
const disabledDefaultTimezone = Boolean(getFromStorage("DISABLED_DEFAULT_TIMEZONE"));
|
||||
|
||||
@@ -28,7 +29,7 @@ const useFetchDefaultTimezone = () => {
|
||||
};
|
||||
|
||||
const fetchDefaultTimezone = async () => {
|
||||
if (!serverUrl || process.env.REACT_APP_TYPE) return;
|
||||
if (!serverUrl || !APP_TYPE_VM) return;
|
||||
setError("");
|
||||
setIsLoading(true);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useAppDispatch, useAppState } from "../state/common/StateContext";
|
||||
import { useEffect, useState } from "preact/compat";
|
||||
import { ErrorTypes } from "../types";
|
||||
import { APP_TYPE_VM } from "../constants/appType";
|
||||
|
||||
const useFetchFlags = () => {
|
||||
const { serverUrl } = useAppState();
|
||||
@@ -11,7 +12,7 @@ const useFetchFlags = () => {
|
||||
|
||||
useEffect(() => {
|
||||
const fetchFlags = async () => {
|
||||
if (!serverUrl || process.env.REACT_APP_TYPE) return;
|
||||
if (!serverUrl || !APP_TYPE_VM) return;
|
||||
setError("");
|
||||
setIsLoading(true);
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ import { useCustomPanelState } from "../state/customPanel/CustomPanelStateContex
|
||||
import { isHistogramData } from "../utils/metric";
|
||||
import { useGraphState } from "../state/graph/GraphStateContext";
|
||||
import { getStepFromDuration } from "../utils/time";
|
||||
import { AppType } from "../types/appType";
|
||||
import { getQueryStringValue } from "../utils/query-string";
|
||||
import { APP_TYPE_ANOMALY } from "../constants/appType";
|
||||
|
||||
interface FetchQueryParams {
|
||||
predefinedQuery?: string[]
|
||||
@@ -49,8 +49,6 @@ interface FetchDataParams {
|
||||
hideQuery?: number[]
|
||||
}
|
||||
|
||||
const isAnomalyUI = AppType.anomaly === process.env.REACT_APP_TYPE;
|
||||
|
||||
export const useFetchQuery = ({
|
||||
predefinedQuery,
|
||||
visible,
|
||||
@@ -134,7 +132,7 @@ export const useFetchQuery = ({
|
||||
}
|
||||
|
||||
const preventChangeType = !!getQueryStringValue("display_mode", null);
|
||||
isHistogramResult = !isAnomalyUI && isDisplayChart && !preventChangeType && isHistogramData(resp.data.result);
|
||||
isHistogramResult = !APP_TYPE_ANOMALY && isDisplayChart && !preventChangeType && isHistogramData(resp.data.result);
|
||||
seriesLimit = isHistogramResult ? Infinity : defaultLimit;
|
||||
const freeTempSize = seriesLimit - tempData.length;
|
||||
resp.data.result.slice(0, freeTempSize).forEach((d: MetricBase) => {
|
||||
|
||||
@@ -3,9 +3,23 @@ import "./constants/dayjsPlugins";
|
||||
import App from "./App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import "./styles/style.scss";
|
||||
import { APP_TYPE, AppType } from "./constants/appType";
|
||||
import AppLogs from "./AppLogs";
|
||||
import AppAnomaly from "./AppAnomaly";
|
||||
|
||||
const getAppComponent = () => {
|
||||
switch (APP_TYPE) {
|
||||
case AppType.victorialogs:
|
||||
return <AppLogs/>;
|
||||
case AppType.vmanomaly:
|
||||
return <AppAnomaly/>;
|
||||
default:
|
||||
return <App/>;
|
||||
}
|
||||
};
|
||||
|
||||
const root = document.getElementById("root");
|
||||
if (root) render(<App />, root);
|
||||
if (root) render(getAppComponent(), root);
|
||||
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
|
||||
@@ -13,19 +13,16 @@ import HeaderControls, { ControlsProps } from "./HeaderControls/HeaderControls";
|
||||
import useDeviceDetect from "../../hooks/useDeviceDetect";
|
||||
import useWindowSize from "../../hooks/useWindowSize";
|
||||
import { ComponentType } from "react";
|
||||
import { AppType } from "../../types/appType";
|
||||
import { APP_TYPE, AppType } from "../../constants/appType";
|
||||
|
||||
export interface HeaderProps {
|
||||
controlsComponent: ComponentType<ControlsProps>
|
||||
}
|
||||
const { REACT_APP_TYPE } = process.env;
|
||||
const isCustomApp = REACT_APP_TYPE === AppType.logs || REACT_APP_TYPE === AppType.anomaly;
|
||||
|
||||
const Logo = () => {
|
||||
switch (REACT_APP_TYPE) {
|
||||
case AppType.logs:
|
||||
switch (APP_TYPE) {
|
||||
case AppType.victorialogs:
|
||||
return <LogoLogsIcon/>;
|
||||
case AppType.anomaly:
|
||||
case AppType.vmanomaly:
|
||||
return <LogoAnomalyIcon/>;
|
||||
default:
|
||||
return <LogoIcon/>;
|
||||
@@ -81,10 +78,7 @@ const Header: FC<HeaderProps> = ({ controlsComponent }) => {
|
||||
<>
|
||||
{!appModeEnable && (
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-header-logo": true,
|
||||
"vm-header-logo_logs": isCustomApp
|
||||
})}
|
||||
className="vm-header-logo"
|
||||
onClick={onClickLogo}
|
||||
style={{ color }}
|
||||
>
|
||||
@@ -102,7 +96,6 @@ const Header: FC<HeaderProps> = ({ controlsComponent }) => {
|
||||
className={classNames({
|
||||
"vm-header-logo": true,
|
||||
"vm-header-logo_mobile": true,
|
||||
"vm-header-logo_logs": isCustomApp
|
||||
})}
|
||||
onClick={onClickLogo}
|
||||
style={{ color }}
|
||||
|
||||
@@ -8,16 +8,13 @@ import MenuBurger from "../../../components/Main/MenuBurger/MenuBurger";
|
||||
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
import "./style.scss";
|
||||
import useBoolean from "../../../hooks/useBoolean";
|
||||
import { AppType } from "../../../types/appType";
|
||||
import { APP_TYPE_LOGS } from "../../../constants/appType";
|
||||
|
||||
interface SidebarHeaderProps {
|
||||
background: string
|
||||
color: string
|
||||
}
|
||||
|
||||
const { REACT_APP_TYPE } = process.env;
|
||||
const isLogsApp = REACT_APP_TYPE === AppType.logs;
|
||||
|
||||
const SidebarHeader: FC<SidebarHeaderProps> = ({
|
||||
background,
|
||||
color,
|
||||
@@ -64,7 +61,7 @@ const SidebarHeader: FC<SidebarHeaderProps> = ({
|
||||
/>
|
||||
</div>
|
||||
<div className="vm-header-sidebar-menu-settings">
|
||||
{!isMobile && !isLogsApp && <ShortcutKeys showTitle={true}/>}
|
||||
{!isMobile && !APP_TYPE_LOGS && <ShortcutKeys showTitle={true}/>}
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
|
||||
@@ -47,14 +47,14 @@
|
||||
justify-content: flex-start;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
max-width: 65px;
|
||||
min-width: 65px;
|
||||
max-width: 75px;
|
||||
min-width: 75px;
|
||||
margin-bottom: 2px;
|
||||
overflow: hidden;
|
||||
|
||||
svg {
|
||||
max-width: 65px;
|
||||
min-width: 65px;
|
||||
max-width: 75px;
|
||||
min-width: 75px;
|
||||
}
|
||||
|
||||
&_mobile {
|
||||
@@ -62,10 +62,5 @@
|
||||
min-width: 65px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
&_logs, &_logs svg {
|
||||
max-width: 75px;
|
||||
min-width: 75px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ const EnhancedTable: FC<TableProps> = ({
|
||||
const [orderBy, setOrderBy] = useState<keyof Data>(defaultSortColumn);
|
||||
|
||||
const handleRequestSort = (
|
||||
event: MouseEvent<unknown>,
|
||||
event: MouseEvent<HTMLTableCellElement>,
|
||||
property: keyof Data,
|
||||
) => {
|
||||
const isAsc = orderBy === property && order === "asc";
|
||||
|
||||
@@ -7,7 +7,7 @@ import Tooltip from "../../../components/Main/Tooltip/Tooltip";
|
||||
|
||||
export function EnhancedTableHead(props: EnhancedHeaderTableProps) {
|
||||
const { order, orderBy, onRequestSort, headerCells } = props;
|
||||
const createSortHandler = (property: keyof Data) => (event: MouseEvent<unknown>) => {
|
||||
const createSortHandler = (property: keyof Data) => (event: MouseEvent<HTMLTableCellElement>) => {
|
||||
onRequestSort(event, property);
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ export interface HeadCell {
|
||||
}
|
||||
|
||||
export interface EnhancedHeaderTableProps {
|
||||
onRequestSort: (event: MouseEvent<unknown>, property: keyof Data) => void;
|
||||
onRequestSort: (event: MouseEvent<HTMLTableCellElement>, property: keyof Data) => void;
|
||||
order: Order;
|
||||
orderBy: string;
|
||||
rowCount: number;
|
||||
|
||||
@@ -3,10 +3,11 @@ import { useCustomPanelDispatch, useCustomPanelState } from "../../state/customP
|
||||
import { ChartIcon, CodeIcon, TableIcon } from "../../components/Main/Icons";
|
||||
import Tabs from "../../components/Main/Tabs/Tabs";
|
||||
import { DisplayType } from "../../types";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
type DisplayTab = {
|
||||
value: DisplayType
|
||||
icon: JSX.Element
|
||||
icon: ReactNode
|
||||
label: string
|
||||
prometheusCode: number
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
|
||||
setStateQuery(prev => prev.filter((q, i) => i !== index));
|
||||
};
|
||||
|
||||
const handleToggleHideQuery = (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>, index: number) => {
|
||||
const handleToggleHideQuery = (e: ReactMouseEvent<HTMLButtonElement>, index: number) => {
|
||||
const { ctrlKey, metaKey } = e;
|
||||
const ctrlMetaKey = ctrlKey || metaKey;
|
||||
|
||||
@@ -160,7 +160,7 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
|
||||
setHideQuery(prev => prev.includes(i) ? prev.filter(n => n !== i) : prev.map(n => n > i ? n - 1 : n));
|
||||
};
|
||||
|
||||
const createHandlerHideQuery = (i: number) => (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
const createHandlerHideQuery = (i: number) => (e: ReactMouseEvent<HTMLButtonElement>) => {
|
||||
handleToggleHideQuery(e, i);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@use "src/styles/variables" as *;
|
||||
@use 'sass:color';
|
||||
|
||||
$font-size-logs: var(--font-size-logs, $font-size-small);
|
||||
|
||||
@@ -79,8 +80,8 @@ $font-size-logs: var(--font-size-logs, $font-size-small);
|
||||
&__pair {
|
||||
order: 0;
|
||||
padding: calc($padding-global / 2) $padding-global;
|
||||
background-color: lighten($color-tropical-blue, 6%);
|
||||
color: darken($color-dodger-blue, 20%);
|
||||
background-color: color.scale($color-tropical-blue, $lightness: 60%);
|
||||
color: color.scale($color-tropical-blue, $lightness: -60%);
|
||||
border-radius: $border-radius-medium;
|
||||
transition: background-color 0.3s ease-in, transform 0.1s ease-in, opacity 0.3s ease-in;
|
||||
white-space: nowrap;
|
||||
@@ -105,7 +106,7 @@ $font-size-logs: var(--font-size-logs, $font-size-small);
|
||||
}
|
||||
|
||||
&_dark {
|
||||
color: lighten($color-dodger-blue, 20%);
|
||||
color: color.scale($color-dodger-blue, $lightness: 40%);
|
||||
background-color: $color-background-body;
|
||||
opacity: 0.8;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ const PredefinedDashboard: FC<PredefinedDashboardProps> = ({
|
||||
setPanelsWidth(width);
|
||||
}, [resize, sizeSection]);
|
||||
|
||||
const handleMouseDown = (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>, i: number) => {
|
||||
const handleMouseDown = (e: ReactMouseEvent<HTMLButtonElement>, i: number) => {
|
||||
setResize({
|
||||
start: e.clientX,
|
||||
target: i,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { DashboardSettings, ErrorTypes } from "../../../types";
|
||||
import { useAppState } from "../../../state/common/StateContext";
|
||||
import { useDashboardsDispatch } from "../../../state/dashboards/DashboardsStateContext";
|
||||
import { getAppModeEnable } from "../../../utils/app-mode";
|
||||
import { APP_TYPE_VM } from "../../../constants/appType";
|
||||
|
||||
const importModule = async (filename: string) => {
|
||||
const data = await fetch(`./dashboards/${filename}`);
|
||||
@@ -34,7 +35,7 @@ export const useFetchDashboards = (): {
|
||||
};
|
||||
|
||||
const fetchRemoteDashboards = async () => {
|
||||
if (!serverUrl || process.env.REACT_APP_TYPE) return;
|
||||
if (!serverUrl || !APP_TYPE_VM) return;
|
||||
setError("");
|
||||
setIsLoading(true);
|
||||
|
||||
|
||||
@@ -108,10 +108,12 @@ const QueryAnalyzer: FC = () => {
|
||||
};
|
||||
|
||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!e.target) return;
|
||||
const target = e.target as HTMLInputElement;
|
||||
setError("");
|
||||
const files = Array.from(e.target.files || []);
|
||||
const files = Array.from(target.files || []);
|
||||
handleReadFiles(files);
|
||||
e.target.value = "";
|
||||
target.value = "";
|
||||
};
|
||||
|
||||
const handleCloseError = () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { FC, useEffect, useMemo, KeyboardEvent } from "react";
|
||||
import React, { FC, useEffect, useMemo } from "react";
|
||||
import { useFetchTopQueries } from "./hooks/useFetchTopQueries";
|
||||
import Spinner from "../../components/Main/Spinner/Spinner";
|
||||
import TopQueryPanel from "./TopQueryPanel/TopQueryPanel";
|
||||
@@ -8,7 +8,7 @@ import dayjs from "dayjs";
|
||||
import { TopQueryStats } from "../../types";
|
||||
import Button from "../../components/Main/Button/Button";
|
||||
import { PlayIcon } from "../../components/Main/Icons";
|
||||
import TextField from "../../components/Main/TextField/TextField";
|
||||
import TextField, { TextFieldKeyboardEvent } from "../../components/Main/TextField/TextField";
|
||||
import Alert from "../../components/Main/Alert/Alert";
|
||||
import Tooltip from "../../components/Main/Tooltip/Tooltip";
|
||||
import "./style.scss";
|
||||
@@ -55,7 +55,7 @@ const TopQueries: FC = () => {
|
||||
setMaxLifetime(value);
|
||||
};
|
||||
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
const onKeyDown = (e: TextFieldKeyboardEvent) => {
|
||||
if (e.key === "Enter") fetch();
|
||||
};
|
||||
|
||||
|
||||
@@ -56,10 +56,12 @@ const TracePage: FC = () => {
|
||||
};
|
||||
|
||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!e.target) return;
|
||||
const target = e.target as HTMLInputElement;
|
||||
setErrors([]);
|
||||
const files = Array.from(e.target.files || []);
|
||||
const files = Array.from(target.files || []);
|
||||
handleReadFiles(files);
|
||||
e.target.value = "";
|
||||
target.value = "";
|
||||
};
|
||||
|
||||
const handleTraceDelete = (trace: Trace) => {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/// <reference types="react-scripts" />
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AppType } from "../types/appType";
|
||||
import { APP_TYPE_LOGS } from "../constants/appType";
|
||||
|
||||
const router = {
|
||||
home: "/",
|
||||
@@ -34,15 +34,12 @@ export interface RouterOptions {
|
||||
header: RouterOptionsHeader
|
||||
}
|
||||
|
||||
const { REACT_APP_TYPE } = process.env;
|
||||
const isLogsApp = REACT_APP_TYPE === AppType.logs;
|
||||
|
||||
const routerOptionsDefault = {
|
||||
header: {
|
||||
tenant: true,
|
||||
stepControl: !isLogsApp,
|
||||
timeSelector: !isLogsApp,
|
||||
executionControls: !isLogsApp,
|
||||
stepControl: !APP_TYPE_LOGS,
|
||||
timeSelector: !APP_TYPE_LOGS,
|
||||
executionControls: !APP_TYPE_LOGS,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,11 +2,9 @@ import { getAppModeEnable } from "../utils/app-mode";
|
||||
import { useDashboardsState } from "../state/dashboards/DashboardsStateContext";
|
||||
import { useAppState } from "../state/common/StateContext";
|
||||
import { useMemo } from "preact/compat";
|
||||
import { AppType } from "../types/appType";
|
||||
import { processNavigationItems } from "./utils";
|
||||
import { getAnomalyNavigation, getDefaultNavigation, getLogsNavigation } from "./navigation";
|
||||
|
||||
const appType = process.env.REACT_APP_TYPE;
|
||||
import { APP_TYPE, AppType } from "../constants/appType";
|
||||
|
||||
const useNavigationMenu = () => {
|
||||
const appModeEnable = getAppModeEnable();
|
||||
@@ -25,10 +23,10 @@ const useNavigationMenu = () => {
|
||||
|
||||
|
||||
const menu = useMemo(() => {
|
||||
switch (appType) {
|
||||
case AppType.logs:
|
||||
switch (APP_TYPE) {
|
||||
case AppType.victorialogs:
|
||||
return getLogsNavigation();
|
||||
case AppType.anomaly:
|
||||
case AppType.vmanomaly:
|
||||
return getAnomalyNavigation();
|
||||
default:
|
||||
return getDefaultNavigation(navigationConfig);
|
||||
|
||||
@@ -28,7 +28,7 @@ export function reducer(state: LogsState, action: LogsAction): LogsState {
|
||||
case "SET_AUTOCOMPLETE_CACHE": {
|
||||
if (state.autocompleteCache.size >= AUTOCOMPLETE_LIMITS.cacheLimit) {
|
||||
const firstKey = state.autocompleteCache.keys().next().value;
|
||||
state.autocompleteCache.delete(firstKey);
|
||||
firstKey && state.autocompleteCache.delete(firstKey);
|
||||
}
|
||||
state.autocompleteCache.set(action.payload.key, action.payload.value);
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export enum AppType {
|
||||
logs = "logs",
|
||||
anomaly = "anomaly",
|
||||
}
|
||||
@@ -4,7 +4,7 @@ export const arrayEquals = (a: (string|number)[], b: (string|number)[]) => {
|
||||
|
||||
export function groupByMultipleKeys<T>(items: T[], keys: (keyof T)[]): { keys: string[], values: T[] }[] {
|
||||
const groups = items.reduce((result, item) => {
|
||||
const compositeKey = keys.map(key => `${key}: ${item[key] || "-"}`).join("|");
|
||||
const compositeKey = keys.map(key => `${String(key)}: ${item[key] || "-"}`).join("|");
|
||||
|
||||
(result[compositeKey] = result[compositeKey] || []).push(item);
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { ComponentProps, FC } from "react";
|
||||
import React, { ComponentProps, FC, ReactNode } from "react";
|
||||
|
||||
type Props = { children: JSX.Element };
|
||||
type Props = { children: ReactNode };
|
||||
|
||||
export const combineComponents = (...components: FC<Props>[]): FC<Props> => {
|
||||
return components.reduce(
|
||||
(AccumulatedComponents, CurrentComponent) => {
|
||||
// eslint-disable-next-line react/display-name
|
||||
return ({ children }: ComponentProps<FC<Props>>): JSX.Element => (
|
||||
return ({ children }: ComponentProps<FC<Props>>): ReactNode => (
|
||||
<AccumulatedComponents>
|
||||
<CurrentComponent>{children}</CurrentComponent>
|
||||
</AccumulatedComponents>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { getAppModeParams } from "./app-mode";
|
||||
import { replaceTenantId } from "./tenants";
|
||||
import { AppType } from "../types/appType";
|
||||
import { APP_TYPE, AppType } from "../constants/appType";
|
||||
import { getFromStorage } from "./storage";
|
||||
const { REACT_APP_TYPE } = process.env;
|
||||
|
||||
export const getDefaultServer = (tenantId?: string): string => {
|
||||
const { serverURL } = getAppModeParams();
|
||||
@@ -12,10 +11,10 @@ export const getDefaultServer = (tenantId?: string): string => {
|
||||
const defaultURL = window.location.href.replace(/\/(?:prometheus\/)?(?:graph|vmui)\/.*/, "/prometheus");
|
||||
const url = serverURL || storageURL || defaultURL;
|
||||
|
||||
switch (REACT_APP_TYPE) {
|
||||
case AppType.logs:
|
||||
switch (APP_TYPE) {
|
||||
case AppType.victorialogs:
|
||||
return logsURL;
|
||||
case AppType.anomaly:
|
||||
case AppType.vmanomaly:
|
||||
return storageURL || anomalyURL;
|
||||
default:
|
||||
return tenantId ? replaceTenantId(url, tenantId) : url;
|
||||
|
||||
@@ -3,7 +3,7 @@ import dayjs, { UnitTypeShort } from "dayjs";
|
||||
import { getQueryStringValue } from "./query-string";
|
||||
import { DATE_ISO_FORMAT } from "../constants/date";
|
||||
import timezones from "../constants/timezones";
|
||||
import { AppType } from "../types/appType";
|
||||
import { APP_TYPE_LOGS } from "../constants/appType";
|
||||
|
||||
const MAX_ITEMS_PER_CHART = window.innerWidth / 4;
|
||||
const MAX_ITEMS_PER_HISTOGRAM = window.innerWidth / 40;
|
||||
@@ -160,11 +160,10 @@ export const dateFromSeconds = (epochTimeInSeconds: number): Date => {
|
||||
const getYesterday = () => dayjs().tz().subtract(1, "day").endOf("day").toDate();
|
||||
const getToday = () => dayjs().tz().endOf("day").toDate();
|
||||
|
||||
const isLogsApp = process.env.REACT_APP_TYPE === AppType.logs;
|
||||
export const relativeTimeOptions: RelativeTimeOption[] = [
|
||||
{ title: "Last 5 minutes", duration: "5m", isDefault: isLogsApp },
|
||||
{ title: "Last 5 minutes", duration: "5m", isDefault: APP_TYPE_LOGS },
|
||||
{ title: "Last 15 minutes", duration: "15m" },
|
||||
{ title: "Last 30 minutes", duration: "30m", isDefault: !isLogsApp },
|
||||
{ title: "Last 30 minutes", duration: "30m", isDefault: !APP_TYPE_LOGS },
|
||||
{ title: "Last 1 hour", duration: "1h" },
|
||||
{ title: "Last 3 hours", duration: "3h" },
|
||||
{ title: "Last 6 hours", duration: "6h" },
|
||||
|
||||
2
app/vmui/packages/vmui/src/vite-env.d.ts
vendored
Normal file
2
app/vmui/packages/vmui/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference types="vite/types/importMeta.d.ts" />
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"target": "ESNext",
|
||||
"types": ["vite/client"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
@@ -19,7 +20,13 @@
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"downlevelIteration": true
|
||||
"downlevelIteration": true,
|
||||
"paths": {
|
||||
"react": ["./node_modules/preact/compat/"],
|
||||
"react/jsx-runtime": ["./node_modules/preact/jsx-runtime"],
|
||||
"react-dom": ["./node_modules/preact/compat/"],
|
||||
"react-dom/*": ["./node_modules/preact/compat/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
|
||||
39
app/vmui/packages/vmui/vite.config.ts
Normal file
39
app/vmui/packages/vmui/vite.config.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import * as path from "path";
|
||||
|
||||
import { defineConfig } from "vite";
|
||||
import preact from "@preact/preset-vite";
|
||||
import dynamicIndexHtmlPlugin from "./config/plugins/dynamicIndexHtml";
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
return {
|
||||
base: "",
|
||||
plugins: [
|
||||
preact(),
|
||||
dynamicIndexHtmlPlugin({ mode })
|
||||
],
|
||||
assetsInclude: ["**/*.md"],
|
||||
server: {
|
||||
open: true,
|
||||
port: 3000,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"src": path.resolve(__dirname, "src"),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
outDir: "./build",
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks(id) {
|
||||
if (id.includes("node_modules")) {
|
||||
return "vendor";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ ROOT_IMAGE ?= alpine:3.21.2
|
||||
ROOT_IMAGE_SCRATCH ?= scratch
|
||||
CERTS_IMAGE := alpine:3.21.2
|
||||
|
||||
GO_BUILDER_IMAGE := golang:1.23.5-alpine
|
||||
GO_BUILDER_IMAGE := golang:1.23.6-alpine
|
||||
BUILDER_IMAGE := local/builder:2.0.0-$(shell echo $(GO_BUILDER_IMAGE) | tr :/ __)-1
|
||||
BASE_IMAGE := local/base:1.1.4-$(shell echo $(ROOT_IMAGE) | tr :/ __)-$(shell echo $(CERTS_IMAGE) | tr :/ __)
|
||||
DOCKER ?= docker
|
||||
|
||||
@@ -152,7 +152,7 @@ services:
|
||||
# and distributes them according to --config.file.
|
||||
alertmanager:
|
||||
container_name: alertmanager
|
||||
image: prom/alertmanager:v0.27.0
|
||||
image: prom/alertmanager:v0.28.0
|
||||
volumes:
|
||||
- ./alertmanager.yml:/config/alertmanager.yml
|
||||
command:
|
||||
|
||||
@@ -44,7 +44,7 @@ services:
|
||||
# storing logs and serving read queries.
|
||||
victorialogs:
|
||||
container_name: victorialogs
|
||||
image: victoriametrics/victoria-logs:v1.8.0-victorialogs
|
||||
image: victoriametrics/victoria-logs:v1.9.0-victorialogs
|
||||
command:
|
||||
- "--storageDataPath=/vlogs"
|
||||
- "--httpListenAddr=:9428"
|
||||
@@ -126,7 +126,7 @@ services:
|
||||
# and distributes them according to --config.file.
|
||||
alertmanager:
|
||||
container_name: alertmanager
|
||||
image: prom/alertmanager:v0.27.0
|
||||
image: prom/alertmanager:v0.28.0
|
||||
volumes:
|
||||
- ./alertmanager.yml:/config/alertmanager.yml
|
||||
command:
|
||||
|
||||
@@ -93,7 +93,7 @@ services:
|
||||
# and distributes them according to --config.file.
|
||||
alertmanager:
|
||||
container_name: alertmanager
|
||||
image: prom/alertmanager:v0.27.0
|
||||
image: prom/alertmanager:v0.28.0
|
||||
volumes:
|
||||
- ./alertmanager.yml:/config/alertmanager.yml
|
||||
command:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
services:
|
||||
# meta service will be ignored by compose
|
||||
.victorialogs:
|
||||
image: docker.io/victoriametrics/victoria-logs:v1.8.0-victorialogs
|
||||
image: docker.io/victoriametrics/victoria-logs:v1.9.0-victorialogs
|
||||
command:
|
||||
- -storageDataPath=/vlogs
|
||||
- -loggerFormat=json
|
||||
|
||||
@@ -89,7 +89,7 @@ services:
|
||||
- "--licenseFile=/license"
|
||||
alertmanager:
|
||||
container_name: alertmanager
|
||||
image: prom/alertmanager:v0.27.0
|
||||
image: prom/alertmanager:v0.28.0
|
||||
volumes:
|
||||
- ./alertmanager.yml:/config/alertmanager.yml
|
||||
command:
|
||||
|
||||
@@ -18,7 +18,7 @@ services:
|
||||
- vlogs
|
||||
|
||||
generator:
|
||||
image: golang:1.23.5-alpine
|
||||
image: golang:1.23.6-alpine
|
||||
restart: always
|
||||
working_dir: /go/src/app
|
||||
volumes:
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '3'
|
||||
|
||||
services:
|
||||
generator:
|
||||
image: golang:1.23.5-alpine
|
||||
image: golang:1.23.6-alpine
|
||||
restart: always
|
||||
working_dir: /go/src/app
|
||||
volumes:
|
||||
|
||||
@@ -3,7 +3,7 @@ version: "3"
|
||||
services:
|
||||
# Run `make package-victoria-logs` to build victoria-logs image
|
||||
vlogs:
|
||||
image: docker.io/victoriametrics/victoria-logs:v1.8.0-victorialogs
|
||||
image: docker.io/victoriametrics/victoria-logs:v1.9.0-victorialogs
|
||||
volumes:
|
||||
- vlogs:/vlogs
|
||||
ports:
|
||||
@@ -58,7 +58,7 @@ services:
|
||||
- ./vmsingle/promscrape.yml:/promscrape.yml
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:9.2.7
|
||||
image: grafana/grafana:11.5.0
|
||||
depends_on: [vmsingle]
|
||||
ports:
|
||||
- 3000:3000
|
||||
|
||||
@@ -16,11 +16,21 @@ according to [these docs](https://docs.victoriametrics.com/victorialogs/quicksta
|
||||
|
||||
## tip
|
||||
|
||||
## [v1.9.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.9.0-victorialogs)
|
||||
|
||||
Released at 2025-02-10
|
||||
|
||||
* FEATURE: [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/): improve performance for [`stats by (...) ...`](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe) by up to 30% when it is applied to big number of `by (...)` groups.
|
||||
* FEATURE: [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/): improve performance for [`top` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#top-pipe) by up to 30% when it is applied to big number of unique values.
|
||||
* FEATURE: [`stats` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe): improve performance for [`count_uniq`](https://docs.victoriametrics.com/victorialogs/logsql/#count_uniq-stats) and [`count_uniq_hash`](https://docs.victoriametrics.com/victorialogs/logsql/#count_uniq_hash-stats) functions by up to 30% when they are applied to big number of unique values.
|
||||
* FEATURE: [`block_stats` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#block_stats-pipe): return the path to the part where every data block is stored. The path to the part is returned in the `part_path` field. This allows investigating the distribution of data blocks among parts.
|
||||
* FEATURE: reduce VictoriaLogs startup time by multiple times when it opens a large datastore with big [retention](https://docs.victoriametrics.com/victorialogs/#retention).
|
||||
* FEATURE: [data ingestion](https://docs.victoriametrics.com/victorialogs/data-ingestion/): accept timestamps with microsecond and nanosecond precision at [`_time` field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#time-field).
|
||||
* FEATURE: [JSON lines data ingestion](https://docs.victoriametrics.com/victorialogs/data-ingestion/#json-stream-api): continue parsing lines after encountering parse errors for some lines. Previously the input JSON lines' stream was closed after the first parse error.
|
||||
* FEATURE: [web UI](https://docs.victoriametrics.com/victorialogs/querying/#web-ui): add the `_msg` field to the list of fields for the group view, allowing users to select multiple fields, including `_msg`, for log display.
|
||||
|
||||
* BUGFIX: [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/): properly limit [`concurrency` query option](https://docs.victoriametrics.com/victorialogs/logsql/#query-options) for [`stats`](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe), [`uniq`](https://docs.victoriametrics.com/victorialogs/logsql/#uniq-pipe) and [`top`](https://docs.victoriametrics.com/victorialogs/logsql/#top-pipe). This prevents from `runtime error: index out of range` panic. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8201).
|
||||
* BUGFIX: [`sort` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#sort-pipe): properly sort [RFC3339 timestamps](https://www.rfc-editor.org/rfc/rfc3339) with variable sub-second precision. Previosuly such timestamps were sorted using [natural sorting](https://en.wikipedia.org/wiki/Natural_sort_order), and this could lead to unexpected results. For example, `2025-02-21T10:20:30.9Z` was incorrectly considered smaller than `2025-02-21T10:20:30.012Z`, since the last one had higher decimal value after the last dot.
|
||||
* BUGFIX: [data ingestion](https://docs.victoriametrics.com/victorialogs/data-ingestion/): drop log entries with too long field names and log the dropped log entries with the `ignoring log entry with too long field name` message, so human operators could notice and fix the ingestion of incorrect logs ASAP. Previously too long field names were silently truncated to shorter values. This isn't what most users expect. See [why VictoriaLogs has a limit on the field name length](https://docs.victoriametrics.com/victorialogs/faq/#what-is-the-maximum-supported-field-name-length).
|
||||
* BUGFIX: [web UI](https://docs.victoriametrics.com/victorialogs/querying/#web-ui): fix transparency for bars in the hits bar chart to improve visibility. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8152).
|
||||
* BUGFIX: [web UI](https://docs.victoriametrics.com/victorialogs/querying/#web-ui): fix `Group by field` dropdown menu not displaying any options in Group View settings. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8153).
|
||||
|
||||
@@ -33,8 +33,8 @@ Just download archive for the needed Operating system and architecture, unpack i
|
||||
For example, the following commands download VictoriaLogs archive for Linux/amd64, unpack and run it:
|
||||
|
||||
```sh
|
||||
curl -L -O https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.8.0-victorialogs/victoria-logs-linux-amd64-v1.8.0-victorialogs.tar.gz
|
||||
tar xzf victoria-logs-linux-amd64-v1.8.0-victorialogs.tar.gz
|
||||
curl -L -O https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.9.0-victorialogs/victoria-logs-linux-amd64-v1.9.0-victorialogs.tar.gz
|
||||
tar xzf victoria-logs-linux-amd64-v1.9.0-victorialogs.tar.gz
|
||||
./victoria-logs-prod
|
||||
```
|
||||
|
||||
@@ -58,7 +58,7 @@ Here is the command to run VictoriaLogs in a Docker container:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -p 9428:9428 -v ./victoria-logs-data:/victoria-logs-data \
|
||||
docker.io/victoriametrics/victoria-logs:v1.8.0-victorialogs
|
||||
docker.io/victoriametrics/victoria-logs:v1.9.0-victorialogs
|
||||
```
|
||||
|
||||
See also:
|
||||
|
||||
@@ -56,7 +56,8 @@ Otherwise the timestamp field must be in one of the following formats:
|
||||
If timezone information is missing (for example, `2023-06-20 15:32:10`),
|
||||
then the time is parsed in the local timezone of the host where VictoriaLogs runs.
|
||||
|
||||
- Unix timestamp in seconds or in milliseconds. For example, `1686026893` (seconds) or `1686026893735` (milliseconds).
|
||||
- Unix timestamp in seconds, milliseconds, microseconds or nanoseconds. For example, `1686026893` (seconds), `1686026893735` (milliseconds),
|
||||
`1686026893735321` (microseconds) or `1686026893735321098` (nanoseconds).
|
||||
|
||||
See [these docs](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) for details on fields,
|
||||
which must be present in the ingested log messages.
|
||||
@@ -111,7 +112,8 @@ Otherwise the timestamp field must be in one of the following formats:
|
||||
If timezone information is missing (for example, `2023-06-20 15:32:10`),
|
||||
then the time is parsed in the local timezone of the host where VictoriaLogs runs.
|
||||
|
||||
- Unix timestamp in seconds or in milliseconds. For example, `1686026893` (seconds) or `1686026893735` (milliseconds).
|
||||
- Unix timestamp in seconds, milliseconds, microseconds or nanoseconds. For example, `1686026893` (seconds), `1686026893735` (milliseconds),
|
||||
`1686026893735321` (microseconds) or `1686026893735321098` (nanoseconds).
|
||||
|
||||
See [these docs](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) for details on fields,
|
||||
which must be present in the ingested log messages.
|
||||
|
||||
@@ -146,7 +146,8 @@ The timestamp field must be in one of the following formats:
|
||||
If timezone information is missing (for example, `2023-06-20 15:32:10`),
|
||||
then the time is parsed in the local timezone of the host where VictoriaLogs runs.
|
||||
|
||||
- Unix timestamp in seconds or in milliseconds. For example, `1686026893` (seconds) or `1686026893735` (milliseconds).
|
||||
- Unix timestamp in seconds, milliseconds, microseconds or nanoseconds. For example, `1686026893` (seconds), `1686026893735` (milliseconds),
|
||||
`1686026893735321` (microseconds) or `1686026893735321098` (nanoseconds).
|
||||
|
||||
For example, the following [log entry](#data-model) contains valid timestamp with millisecond precision in the `_time` field:
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ or from [docker images](https://hub.docker.com/r/victoriametrics/vlogscli/tags).
|
||||
### Running `vlogscli` from release binary
|
||||
|
||||
```sh
|
||||
curl -L -O https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.8.0-victorialogs/vlogscli-linux-amd64-v1.8.0-victorialogs.tar.gz
|
||||
tar xzf vlogscli-linux-amd64-v1.8.0-victorialogs.tar.gz
|
||||
curl -L -O https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.9.0-victorialogs/vlogscli-linux-amd64-v1.9.0-victorialogs.tar.gz
|
||||
tar xzf vlogscli-linux-amd64-v1.9.0-victorialogs.tar.gz
|
||||
./vlogscli-prod
|
||||
```
|
||||
|
||||
|
||||
@@ -18,6 +18,14 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
|
||||
|
||||
## tip
|
||||
|
||||
* SECURITY: upgrade Go builder from Go1.23.5 to Go1.23.6. See the list of issues addressed in [Go1.23.6](https://github.com/golang/go/issues?q=milestone%3AGo1.23.6+label%3ACherryPickApproved).
|
||||
|
||||
## [v1.111.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.111.0)
|
||||
|
||||
Released at 2025-02-10
|
||||
|
||||
**Update note 1: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and [vmstorage](https://docs.victoriametrics.com/victoriametrics/) stop exposing `vm_index_search_duration_seconds` histogram metric. This metric records time spent on search operations in the index. It was introduced in [v1.56.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.56.0). However, this metric was used neither in dashboards nor in alerting rules. It also has high cardinality because index search operations latency can differ by 3 orders of magnitude. Hence, dropping it as unused.**
|
||||
|
||||
* FEATURE: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and [vmstorage](https://docs.victoriametrics.com/cluster-victoriametrics/): improve startup times when opening a storage with the [retention](https://docs.victoriametrics.com/#retention) exceeding a few months.
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add the ability to switch the heatmap to a line chart. Now, vmui would suggest to switch to line graph display if heatmap can't be properly rendered. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8057).
|
||||
* FEATURE: [vmauth](https://docs.victoriametrics.com/vmauth/): add `-httpInternalListenAddr` cmd-line flag to serve internal HTTP routes `/metrics`, `/flags`, etc. It allows properly route requests to backends with the same service routes as vmauth. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6468) and [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7345) for details.
|
||||
@@ -29,7 +37,33 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui) for [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise.html) components: properly display enterprise features when the enterprise version is used.
|
||||
* BUGFIX: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and [vmselect](https://docs.victoriametrics.com/cluster-victoriametrics/): fix discrepancies when using `or` binary operator. See [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7759) and [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7640) issues for details.
|
||||
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/) and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): properly update number of unique series for [cardinality limiter](https://docs.victoriametrics.com/#cardinality-limiter) on ingestion. Previously, limit could undercount the real number of the ingested unique series.
|
||||
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert/): do not unregister group metrics if the group is still in use. Previously, this could lead to group metrics being absent even though rules group is still running. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8229) for details.
|
||||
|
||||
## [v1.110.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.110.1)
|
||||
|
||||
Released at 2025-02-10
|
||||
|
||||
**v1.110.x is a line of [LTS releases](https://docs.victoriametrics.com/lts-releases/). It contains important up-to-date bugfixes for [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise.html).
|
||||
All these fixes are also included in [the latest community release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest).
|
||||
The v1.110.x line will be supported for at least 12 months since [v1.110.0](https://docs.victoriametrics.com/changelog/#v11100) release**
|
||||
|
||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent/): properly perform graceful shutdown for kafka client.
|
||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent/): properly add message metadata headers for kafka remoteWrite target.
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): improve clipboard error handling in tables and code snippets by showing detailed messages with possible reasons. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7778).
|
||||
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/) and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): properly update number of unique series for [cardinality limiter](https://docs.victoriametrics.com/#cardinality-limiter) on ingestion. Previously, limit could undercount the real number of the ingested unique series.
|
||||
* BUGFIX: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and [vmselect](https://docs.victoriametrics.com/cluster-victoriametrics/): fix discrepancies when using `or` binary operator. See [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7759) and [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7640) issues for details.
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui) for [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise.html) components: properly display enterprise features when the enterprise version is used.
|
||||
|
||||
## [v1.102.13](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.102.13)
|
||||
|
||||
Released at 2025-02-10
|
||||
|
||||
**v1.102.x is a line of [LTS releases](https://docs.victoriametrics.com/lts-releases/). It contains important up-to-date bugfixes for [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise.html).
|
||||
All these fixes are also included in [the latest community release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest).
|
||||
The v1.102.x line will be supported for at least 12 months since [v1.102.0](https://docs.victoriametrics.com/changelog/#v11020) release**
|
||||
|
||||
* BUGFIX: [export API](https://docs.victoriametrics.com/#how-to-export-time-series): cancel export process on client connection close. Previously client connection close was ignored and VictoriaMetrics started to hog CPU by exporting metrics to nowhere until it export all of them.
|
||||
* BUGFIX: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and [vmselect](https://docs.victoriametrics.com/cluster-victoriametrics/): fix discrepancies when using `or` binary operator. See [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7759) and [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7640) issues for details.
|
||||
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/) and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): properly update number of unique series for [cardinality limiter](https://docs.victoriametrics.com/#cardinality-limiter) on ingestion. Previously, limit could undercount the real number of the ingested unique series.
|
||||
|
||||
## [v1.102.12](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.102.12)
|
||||
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
## Next release
|
||||
|
||||
- TODO
|
||||
|
||||
## 0.8.16
|
||||
|
||||
**Release date:** 07 Feb 2025
|
||||
|
||||
 
|
||||
|
||||
- add `.Values.server.vmServiceScrape` for [VMOperator](https://docs.victoriametrics.com/operator/) [VMServiceScrape](https://docs.victoriametrics.com/operator/api/#vmservicescrape) resource
|
||||
- update victorialogs version to [v1.8.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.8.0-victorialogs)
|
||||
|
||||
## 0.8.15
|
||||
|
||||
**Release date:** 06 Feb 2025
|
||||
|
||||
 
|
||||
|
||||
- added ability to override default headless service .Values.server.service.clusterIP with empty value
|
||||
- vector chart 0.37.x -> 0.40.x
|
||||
- updated common dependency 0.0.37 -> 0.0.39
|
||||
|
||||
## 0.8.14
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
@@ -910,7 +910,7 @@ readOnlyRootFilesystem: true
|
||||
<td>server.service.clusterIP</td>
|
||||
<td>string</td>
|
||||
<td><pre class="helm-vars-default-value language-yaml" lang="">
|
||||
<code class="language-yaml">""
|
||||
<code class="language-yaml">None
|
||||
</code>
|
||||
</pre>
|
||||
</td>
|
||||
@@ -1179,6 +1179,69 @@ readOnlyRootFilesystem: true
|
||||
</pre>
|
||||
</td>
|
||||
<td><p>Pod topologySpreadConstraints</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>server.vmServiceScrape.annotations</td>
|
||||
<td>object</td>
|
||||
<td><pre class="helm-vars-default-value language-yaml" lang="plaintext">
|
||||
<code class="language-yaml">{}
|
||||
</code>
|
||||
</pre>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>server.vmServiceScrape.enabled</td>
|
||||
<td>bool</td>
|
||||
<td><pre class="helm-vars-default-value language-yaml" lang="">
|
||||
<code class="language-yaml">false
|
||||
</code>
|
||||
</pre>
|
||||
</td>
|
||||
<td><p>Enable deployment of VMServiceScrape for server component. This is Victoria Metrics operator object</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>server.vmServiceScrape.extraLabels</td>
|
||||
<td>object</td>
|
||||
<td><pre class="helm-vars-default-value language-yaml" lang="plaintext">
|
||||
<code class="language-yaml">{}
|
||||
</code>
|
||||
</pre>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>server.vmServiceScrape.metricRelabelings</td>
|
||||
<td>list</td>
|
||||
<td><pre class="helm-vars-default-value language-yaml" lang="plaintext">
|
||||
<code class="language-yaml">[]
|
||||
</code>
|
||||
</pre>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>server.vmServiceScrape.relabelings</td>
|
||||
<td>list</td>
|
||||
<td><pre class="helm-vars-default-value language-yaml" lang="plaintext">
|
||||
<code class="language-yaml">[]
|
||||
</code>
|
||||
</pre>
|
||||
</td>
|
||||
<td><p>Commented. TLS configuration to use when scraping the endpoint tlsConfig: insecureSkipVerify: true</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>server.vmServiceScrape.targetPort</td>
|
||||
<td>string</td>
|
||||
<td><pre class="helm-vars-default-value language-yaml" lang="">
|
||||
<code class="language-yaml">http
|
||||
</code>
|
||||
</pre>
|
||||
</td>
|
||||
<td><p>target port</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
## Next release
|
||||
|
||||
- TODO
|
||||
- updated common dependency 0.0.37 -> 0.0.39
|
||||
|
||||
## 0.15.7
|
||||
|
||||
**Release date:** 05 Feb 2025
|
||||
|
||||
 
|
||||
|
||||
- added `.Values.allowedMetricsEndpoints` to set allowed scrape endpoints. See [this issue](https://github.com/VictoriaMetrics/helm-charts/issues/1970) for details.
|
||||
|
||||
## 0.15.6
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user