mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-05-30 07:10:55 +03:00
Compare commits
151 Commits
docs/vmano
...
v1.93.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bdaaea6820 | ||
|
|
87eeac43cc | ||
|
|
9c22c87f18 | ||
|
|
b0a254bec9 | ||
|
|
a9ad7f45d4 | ||
|
|
236404eb1f | ||
|
|
86fd89e524 | ||
|
|
83dd5e4e72 | ||
|
|
25cf57910d | ||
|
|
eea354f5bb | ||
|
|
2e4165f551 | ||
|
|
76e34b5ac3 | ||
|
|
6177975aa7 | ||
|
|
5b4381ac14 | ||
|
|
04a6324162 | ||
|
|
5e826af497 | ||
|
|
13f40cac61 | ||
|
|
1c83e2c28c | ||
|
|
67284377f3 | ||
|
|
3362774ab2 | ||
|
|
c25fe07cd1 | ||
|
|
8be5ebe809 | ||
|
|
27a2e119cf | ||
|
|
5d726b07ae | ||
|
|
a1063a5ef3 | ||
|
|
445e4b1c73 | ||
|
|
e61b3cd612 | ||
|
|
80862282ca | ||
|
|
3acd660678 | ||
|
|
c56c2df117 | ||
|
|
84b4e6344b | ||
|
|
93bb28edb8 | ||
|
|
65a37c0113 | ||
|
|
05103d91da | ||
|
|
50ebc3a749 | ||
|
|
77f7518981 | ||
|
|
fb02fb696d | ||
|
|
aaf9c8891d | ||
|
|
a99a05ea23 | ||
|
|
919593a163 | ||
|
|
f1367236cb | ||
|
|
7385766805 | ||
|
|
be88c2c85b | ||
|
|
ecd523662f | ||
|
|
9979f6796e | ||
|
|
3efbb0af2b | ||
|
|
a14198ba97 | ||
|
|
bfbd0b478e | ||
|
|
15f9e77e4c | ||
|
|
1dd4c72e27 | ||
|
|
c9f1a573e6 | ||
|
|
88e385e273 | ||
|
|
63384291eb | ||
|
|
f36d20de08 | ||
|
|
b11d312a6b | ||
|
|
081f9e8e1c | ||
|
|
9b4b77975b | ||
|
|
db57fbc5d6 | ||
|
|
3045ba01f5 | ||
|
|
77756c7acc | ||
|
|
51e4fd652d | ||
|
|
63ca7b62e5 | ||
|
|
cad2c28c6d | ||
|
|
ca3513bdb3 | ||
|
|
ed2484ecfa | ||
|
|
1e689800c4 | ||
|
|
e8a11780ef | ||
|
|
cd5300555e | ||
|
|
15d49169fb | ||
|
|
c1f0a2b5fa | ||
|
|
b3050356eb | ||
|
|
7cd79e0eba | ||
|
|
c72570179e | ||
|
|
9133a5acb1 | ||
|
|
aabc4dc492 | ||
|
|
761510c054 | ||
|
|
c607a6126d | ||
|
|
e1dd49b739 | ||
|
|
4a6a3a1506 | ||
|
|
3665c16444 | ||
|
|
28cc553cac | ||
|
|
73d33bc96b | ||
|
|
b2019a5fac | ||
|
|
cc874daa1d | ||
|
|
e5d14ef682 | ||
|
|
6489dc387c | ||
|
|
3f33f9ce6f | ||
|
|
9fa5a07887 | ||
|
|
f9604bcf3a | ||
|
|
3d8dec3e4c | ||
|
|
7002c8d74b | ||
|
|
0459aaf8f9 | ||
|
|
f0849ff7fa | ||
|
|
7f6ae70bac | ||
|
|
c8c20b7f7a | ||
|
|
35263983a6 | ||
|
|
a2c901423b | ||
|
|
382721a3ac | ||
|
|
d688f9a744 | ||
|
|
c060c6d839 | ||
|
|
927ded6c3b | ||
|
|
d4123e135f | ||
|
|
4b86a18105 | ||
|
|
c6154f8f52 | ||
|
|
b4c79fc606 | ||
|
|
b4529df08d | ||
|
|
a63fb21ab2 | ||
|
|
7a19b2a14c | ||
|
|
e06d855636 | ||
|
|
11329c3d16 | ||
|
|
fae59146ad | ||
|
|
1a57815769 | ||
|
|
f96804658b | ||
|
|
59f7d810c9 | ||
|
|
e1235267a0 | ||
|
|
05f109ad58 | ||
|
|
d144e39592 | ||
|
|
8faa17493b | ||
|
|
f111ddb862 | ||
|
|
072d891ed9 | ||
|
|
d7067c46d0 | ||
|
|
e8bcb17c8a | ||
|
|
acbe327fdf | ||
|
|
b007f78a2e | ||
|
|
1bd7637fe1 | ||
|
|
e0017b4d47 | ||
|
|
a19a65b3a5 | ||
|
|
4c4bcdf0b1 | ||
|
|
271743f892 | ||
|
|
be5c4818f5 | ||
|
|
ac0b7e0421 | ||
|
|
2328e4cabc | ||
|
|
38e72ea344 | ||
|
|
7ec4ccc005 | ||
|
|
b50ed5ddd1 | ||
|
|
6d0163cca9 | ||
|
|
efb81185a7 | ||
|
|
e49e4f372b | ||
|
|
f2df8ad480 | ||
|
|
7602b95bcb | ||
|
|
6411191158 | ||
|
|
c36259fca5 | ||
|
|
a4a1884237 | ||
|
|
252643d100 | ||
|
|
86f1459ca6 | ||
|
|
cc7bfaca6c | ||
|
|
0a93abfeed | ||
|
|
bd8ecfb551 | ||
|
|
835c03fb47 | ||
|
|
bc5065fd14 | ||
|
|
262c888d4b |
2
.github/workflows/check-licenses.yml
vendored
2
.github/workflows/check-licenses.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@main
|
||||
with:
|
||||
go-version: 1.20.7
|
||||
go-version: 1.21.4
|
||||
id: go
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@master
|
||||
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.20.7
|
||||
go-version: 1.21.4
|
||||
check-latest: true
|
||||
cache: true
|
||||
if: ${{ matrix.language == 'go' }}
|
||||
|
||||
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.20.7
|
||||
go-version: 1.21.4
|
||||
check-latest: true
|
||||
cache: true
|
||||
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.20.7
|
||||
go-version: 1.21.4
|
||||
check-latest: true
|
||||
cache: true
|
||||
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
id: go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.20.7
|
||||
go-version: 1.21.4
|
||||
check-latest: true
|
||||
cache: true
|
||||
|
||||
|
||||
7
Makefile
7
Makefile
@@ -34,7 +34,6 @@ clean:
|
||||
|
||||
publish: package-base \
|
||||
publish-victoria-metrics \
|
||||
publish-victoria-logs \
|
||||
publish-vmagent \
|
||||
publish-vmalert \
|
||||
publish-vmauth \
|
||||
@@ -174,6 +173,7 @@ vmutils-crossbuild: \
|
||||
vmutils-windows-amd64
|
||||
|
||||
publish-release:
|
||||
rm -rf bin/*
|
||||
git checkout $(TAG) && LATEST_TAG=stable $(MAKE) release publish && \
|
||||
git checkout $(TAG)-cluster && LATEST_TAG=cluster-stable $(MAKE) release publish && \
|
||||
git checkout $(TAG)-enterprise && LATEST_TAG=enterprise-stable $(MAKE) release publish && \
|
||||
@@ -181,7 +181,6 @@ publish-release:
|
||||
|
||||
release: \
|
||||
release-victoria-metrics \
|
||||
release-victoria-logs \
|
||||
release-vmutils
|
||||
|
||||
release-victoria-metrics: \
|
||||
@@ -437,7 +436,7 @@ benchmark-pure:
|
||||
vendor-update:
|
||||
go get -u -d ./lib/...
|
||||
go get -u -d ./app/...
|
||||
go mod tidy -compat=1.19
|
||||
go mod tidy -compat=1.20
|
||||
go mod vendor
|
||||
|
||||
app-local:
|
||||
@@ -463,7 +462,7 @@ golangci-lint: install-golangci-lint
|
||||
golangci-lint run
|
||||
|
||||
install-golangci-lint:
|
||||
which golangci-lint || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.51.2
|
||||
which golangci-lint || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.54.2
|
||||
|
||||
govulncheck: install-govulncheck
|
||||
govulncheck ./...
|
||||
|
||||
38
README.md
38
README.md
@@ -173,7 +173,8 @@ VictoriaMetrics is developed at a fast pace, so it is recommended periodically c
|
||||
|
||||
### Environment variables
|
||||
|
||||
All the VictoriaMetrics components allow referring environment variables in command-line flags via `%{ENV_VAR}` syntax.
|
||||
All the VictoriaMetrics components allow referring environment variables in `yaml` configuration files (such as `-promscrape.config`)
|
||||
and in command-line flags via `%{ENV_VAR}` syntax.
|
||||
For example, `-metricsAuthKey=%{METRICS_AUTH_KEY}` is automatically expanded to `-metricsAuthKey=top-secret`
|
||||
if `METRICS_AUTH_KEY=top-secret` environment variable exists at VictoriaMetrics startup.
|
||||
This expansion is performed by VictoriaMetrics itself.
|
||||
@@ -914,7 +915,7 @@ to your needs or when testing bugfixes.
|
||||
|
||||
### Development build
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make victoria-metrics` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds `victoria-metrics` binary and puts it into the `bin` folder.
|
||||
|
||||
@@ -930,7 +931,7 @@ ARM build may run on Raspberry Pi or on [energy-efficient ARM servers](https://b
|
||||
|
||||
### Development ARM build
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make victoria-metrics-linux-arm` or `make victoria-metrics-linux-arm64` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds `victoria-metrics-linux-arm` or `victoria-metrics-linux-arm64` binary respectively and puts it into the `bin` folder.
|
||||
|
||||
@@ -944,7 +945,7 @@ ARM build may run on Raspberry Pi or on [energy-efficient ARM servers](https://b
|
||||
|
||||
`Pure Go` mode builds only Go code without [cgo](https://golang.org/cmd/cgo/) dependencies.
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make victoria-metrics-pure` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds `victoria-metrics-pure` binary and puts it into the `bin` folder.
|
||||
|
||||
@@ -1936,6 +1937,11 @@ and [cardinality explorer docs](#cardinality-explorer).
|
||||
if background merge cannot be initiated due to free disk space shortage. The value shows the number of per-month partitions,
|
||||
which would start background merge if they had more free disk space.
|
||||
|
||||
* If you run VictoriaMetrics on a host with 16 or more CPU cores, then it may be needed to tune the `-search.maxWorkersPerQuery` command-line flag
|
||||
in order to improve query performance. If VictoriaMetrics serves big number of concurrent `select` queries, then try reducing the value for this flag.
|
||||
If VcitoriaMetrics serves heavy queries, which select `>10K` of [time series](https://docs.victoriametrics.com/keyConcepts.html#time-series) and/or process `>100M`
|
||||
of [raw samples](https://docs.victoriametrics.com/keyConcepts.html#raw-samples) per query, then try setting the value for this flag to the number of available CPU cores.
|
||||
|
||||
* VictoriaMetrics buffers incoming data in memory for up to a few seconds before flushing it to persistent storage.
|
||||
This may lead to the following "issues":
|
||||
* Data becomes available for querying in a few seconds after inserting. It is possible to flush in-memory buffers to searchable parts
|
||||
@@ -1972,15 +1978,19 @@ and [cardinality explorer docs](#cardinality-explorer).
|
||||
This suppresses default gap filling algorithm used by VictoriaMetrics - by default it assumes
|
||||
each time series is continuous instead of discrete, so it fills gaps between real samples with regular intervals.
|
||||
|
||||
* Metrics and labels leading to [high cardinality](https://docs.victoriametrics.com/FAQ.html#what-is-high-cardinality) or [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate) can be determined via [cardinality explorer](#cardinality-explorer) and via [/api/v1/status/tsdb](#tsdb-stats) endpoint.
|
||||
* Metrics and labels leading to [high cardinality](https://docs.victoriametrics.com/FAQ.html#what-is-high-cardinality)
|
||||
or [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate) can be determined
|
||||
via [cardinality explorer](#cardinality-explorer) and via [/api/v1/status/tsdb](#tsdb-stats) endpoint.
|
||||
|
||||
* New time series can be logged if `-logNewSeries` command-line flag is passed to VictoriaMetrics.
|
||||
|
||||
* VictoriaMetrics limits the number of labels per each metric with `-maxLabelsPerTimeseries` command-line flag.
|
||||
This prevents from ingesting metrics with too many labels. It is recommended [monitoring](#monitoring) `vm_metrics_with_dropped_labels_total`
|
||||
* VictoriaMetrics limits the number of labels per each metric with `-maxLabelsPerTimeseries` command-line flag
|
||||
and drops superflouos labels. This prevents from ingesting metrics with too many labels.
|
||||
It is recommended [monitoring](#monitoring) `vm_metrics_with_dropped_labels_total`
|
||||
metric in order to determine whether `-maxLabelsPerTimeseries` must be adjusted for your workload.
|
||||
|
||||
* If you store Graphite metrics like `foo.bar.baz` in VictoriaMetrics, then `{__graphite__="foo.*.baz"}` filter can be used for selecting such metrics. See [these docs](#selecting-graphite-metrics) for details.
|
||||
* If you store Graphite metrics like `foo.bar.baz` in VictoriaMetrics, then `{__graphite__="foo.*.baz"}` filter can be used for selecting such metrics.
|
||||
See [these docs](#selecting-graphite-metrics) for details. You can also query Graphite metrics with [Graphite querying API](#graphite-render-api-usage).
|
||||
|
||||
* VictoriaMetrics ignores `NaN` values during data ingestion.
|
||||
|
||||
@@ -2293,7 +2303,7 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
|
||||
-envflag.prefix string
|
||||
Prefix for environment variables if -envflag.enable is set
|
||||
-eula
|
||||
By specifying this flag, you confirm that you have an enterprise license and accept the EULA https://victoriametrics.com/assets/VM_EULA.pdf . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Deprecated, please use -license or -licenseFile flags instead. By specifying this flag, you confirm that you have an enterprise license and accept the ESA https://victoriametrics.com/legal/esa/ . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-finalMergeDelay duration
|
||||
The delay before starting final merge for per-month partition after no new data is ingested into it. Final merge may require additional disk IO and CPU resources. Final merge may increase query speed and reduce disk space usage in some cases. Zero value disables final merge
|
||||
-flagsAuthKey string
|
||||
@@ -2363,6 +2373,12 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
|
||||
Whether to disable caches for interned strings. This may reduce memory usage at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringCacheExpireDuration and -internStringMaxLen
|
||||
-internStringMaxLen int
|
||||
The maximum length for strings to intern. A lower limit may save memory at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringDisableCache and -internStringCacheExpireDuration (default 500)
|
||||
-license string
|
||||
Lisense key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed via file specified by -licenseFile command-line flag
|
||||
-license.forceOffline
|
||||
Whether to enable offline verification for VictoriaMetrics Enterprise license key, which has been passed either via -license or via -licenseFile command-line flag. The issued license key must support offline verification feature. Contact info@victoriametrics.com if you need offline license verification. This flag is avilable only in Enterprise binaries
|
||||
-licenseFile string
|
||||
Path to file with license key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed inline via -license command-line flag
|
||||
-logNewSeries
|
||||
Whether to log new series. This option is for debug purposes only. It can lead to performance issues when big number of new series are ingested into VictoriaMetrics
|
||||
-loggerDisableTimestamps
|
||||
@@ -2382,7 +2398,7 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
|
||||
-loggerWarnsPerSecondLimit int
|
||||
Per-second limit on the number of WARN messages. If more than the given number of warns are emitted per second, then the remaining warns are suppressed. Zero values disable the rate limit
|
||||
-maxConcurrentInserts int
|
||||
The maximum number of concurrent insert requests. The default value should work for most cases, since it minimizes memory usage. The default value can be increased when clients send data over slow networks. See also -insert.maxQueueDuration (default 8)
|
||||
The maximum number of concurrent insert requests. Default value should work for most cases, since it minimizes the memory usage. The default value can be increased when clients send data over slow networks. See also -insert.maxQueueDuration (default 8)
|
||||
-maxInsertRequestSize size
|
||||
The maximum size in bytes of a single Prometheus remote_write API request
|
||||
Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 33554432)
|
||||
@@ -2596,6 +2612,8 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
|
||||
The maximum number of tag values returned from /api/v1/label/<label_name>/values (default 100000)
|
||||
-search.maxUniqueTimeseries int
|
||||
The maximum number of unique time series, which can be selected during /api/v1/query and /api/v1/query_range queries. This option allows limiting memory usage (default 300000)
|
||||
-search.maxWorkersPerQuery int
|
||||
The maximum number of CPU cores a single query can use. The default value should work good for most cases. The flag can be set to lower values for improving performance of big number of concurrently executed queries. The flag can be set to bigger values for improving performance of heavy queries, which scan big number of time series (>10K) and/or big number of samples (>100M). There is no sense in setting this flag to values bigger than the number of CPU cores available on the system (default 4)
|
||||
-search.minStalenessInterval duration
|
||||
The minimum interval for staleness calculations. This flag could be useful for removing gaps on graphs generated from time series with irregular intervals between samples. See also '-search.maxStalenessInterval'
|
||||
-search.noStaleMarkers
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
| Version | Supported |
|
||||
|---------|--------------------|
|
||||
| [latest release](https://docs.victoriametrics.com/CHANGELOG.html) | :white_check_mark: |
|
||||
| v1.93.x LTS release | :white_check_mark: |
|
||||
| v1.87.x LTS release | :white_check_mark: |
|
||||
| v1.79.x LTS release | :white_check_mark: |
|
||||
| other releases | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
@@ -3,6 +3,7 @@ package elasticsearch
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@@ -24,6 +25,10 @@ import (
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
)
|
||||
|
||||
var (
|
||||
elasticsearchVersion = flag.String("elasticsearch.version", "8.9.0", "Elasticsearch version to report to client")
|
||||
)
|
||||
|
||||
// RequestHandler processes Elasticsearch insert requests
|
||||
func RequestHandler(path string, w http.ResponseWriter, r *http.Request) bool {
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
@@ -60,9 +65,9 @@ func RequestHandler(path string, w http.ResponseWriter, r *http.Request) bool {
|
||||
// See the latest available version for Elasticsearch at https://github.com/elastic/elasticsearch/releases
|
||||
fmt.Fprintf(w, `{
|
||||
"version": {
|
||||
"number": "8.8.0"
|
||||
"number": %q
|
||||
}
|
||||
}`)
|
||||
}`, *elasticsearchVersion)
|
||||
case http.MethodHead:
|
||||
// Return empty response for Logstash ping request.
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.5f461a27.css",
|
||||
"main.js": "./static/js/main.7566144a.js",
|
||||
"main.css": "./static/css/main.5f91b1c5.css",
|
||||
"main.js": "./static/js/main.7226aaff.js",
|
||||
"static/js/522.b5ae4365.chunk.js": "./static/js/522.b5ae4365.chunk.js",
|
||||
"static/media/Lato-Regular.ttf": "./static/media/Lato-Regular.d714fec1633b69a9c2e9.ttf",
|
||||
"static/media/Lato-Bold.ttf": "./static/media/Lato-Bold.32360ba4b57802daa4d6.ttf",
|
||||
"index.html": "./index.html"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.5f461a27.css",
|
||||
"static/js/main.7566144a.js"
|
||||
"static/css/main.5f91b1c5.css",
|
||||
"static/js/main.7226aaff.js"
|
||||
]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"/><meta name="theme-color" content="#000000"/><meta name="description" content="UI for VictoriaMetrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><script src="./dashboards/index.js" type="module"></script><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="./preview.jpg"><meta name="twitter:title" content="UI for VictoriaMetrics"><meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta name="twitter:site" content="@VictoriaMetrics"><meta property="og:title" content="Metric explorer for VictoriaMetrics"><meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta property="og:image" content="./preview.jpg"><meta property="og:type" content="website"><script defer="defer" src="./static/js/main.7566144a.js"></script><link href="./static/css/main.5f461a27.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.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"/><meta name="theme-color" content="#000000"/><meta name="description" content="UI for VictoriaMetrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><script src="./dashboards/index.js" type="module"></script><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="./preview.jpg"><meta name="twitter:title" content="UI for VictoriaMetrics"><meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta name="twitter:site" content="@VictoriaMetrics"><meta property="og:title" content="Metric explorer for VictoriaMetrics"><meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta property="og:image" content="./preview.jpg"><meta property="og:type" content="website"><script defer="defer" src="./static/js/main.7226aaff.js"></script><link href="./static/css/main.5f91b1c5.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
File diff suppressed because one or more lines are too long
1
app/vlselect/vmui/static/css/main.5f91b1c5.css
Normal file
1
app/vlselect/vmui/static/css/main.5f91b1c5.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
@@ -1130,7 +1130,7 @@ It may be needed to build `vmagent` from source code when developing or testing
|
||||
|
||||
### Development build
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make vmagent` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds the `vmagent` binary and puts it into the `bin` folder.
|
||||
|
||||
@@ -1159,7 +1159,7 @@ ARM build may run on Raspberry Pi or on [energy-efficient ARM servers](https://b
|
||||
|
||||
### Development ARM build
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make vmagent-linux-arm` or `make vmagent-linux-arm64` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics)
|
||||
It builds `vmagent-linux-arm` or `vmagent-linux-arm64` binary respectively and puts it into the `bin` folder.
|
||||
|
||||
@@ -1236,7 +1236,7 @@ See the docs at https://docs.victoriametrics.com/vmagent.html .
|
||||
-envflag.prefix string
|
||||
Prefix for environment variables if -envflag.enable is set
|
||||
-eula
|
||||
By specifying this flag, you confirm that you have an enterprise license and accept the EULA https://victoriametrics.com/assets/VM_EULA.pdf . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Deprecated, please use -license or -licenseFile flags instead. By specifying this flag, you confirm that you have an enterprise license and accept the ESA https://victoriametrics.com/legal/esa/ . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-flagsAuthKey string
|
||||
Auth key for /flags endpoint. It must be passed via authKey query arg. It overrides httpAuth.* settings
|
||||
-fs.disableMmap
|
||||
@@ -1299,34 +1299,40 @@ See the docs at https://docs.victoriametrics.com/vmagent.html .
|
||||
-internStringMaxLen int
|
||||
The maximum length for strings to intern. A lower limit may save memory at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringDisableCache and -internStringCacheExpireDuration (default 500)
|
||||
-kafka.consumer.topic array
|
||||
Kafka topic names for data consumption. This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Kafka topic names for data consumption. This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-kafka.consumer.topic.basicAuth.password array
|
||||
Optional basic auth password for -kafka.consumer.topic. Must be used in conjunction with any supported auth methods for kafka client, specified by flag -kafka.consumer.topic.options='security.protocol=SASL_SSL;sasl.mechanisms=PLAIN' . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Optional basic auth password for -kafka.consumer.topic. Must be used in conjunction with any supported auth methods for kafka client, specified by flag -kafka.consumer.topic.options='security.protocol=SASL_SSL;sasl.mechanisms=PLAIN' . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-kafka.consumer.topic.basicAuth.username array
|
||||
Optional basic auth username for -kafka.consumer.topic. Must be used in conjunction with any supported auth methods for kafka client, specified by flag -kafka.consumer.topic.options='security.protocol=SASL_SSL;sasl.mechanisms=PLAIN' . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Optional basic auth username for -kafka.consumer.topic. Must be used in conjunction with any supported auth methods for kafka client, specified by flag -kafka.consumer.topic.options='security.protocol=SASL_SSL;sasl.mechanisms=PLAIN' . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-kafka.consumer.topic.brokers array
|
||||
List of brokers to connect for given topic, e.g. -kafka.consumer.topic.broker=host-1:9092;host-2:9092 . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
List of brokers to connect for given topic, e.g. -kafka.consumer.topic.broker=host-1:9092;host-2:9092 . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-kafka.consumer.topic.concurrency array
|
||||
Configures consumer concurrency for topic specified via -kafka.consumer.topic flag.This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Configures consumer concurrency for topic specified via -kafka.consumer.topic flag.This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html (default 1)
|
||||
Supports array of values separated by comma or specified via multiple flags.
|
||||
-kafka.consumer.topic.defaultFormat string
|
||||
Expected data format in the topic if -kafka.consumer.topic.format is skipped. This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html (default "promremotewrite")
|
||||
Expected data format in the topic if -kafka.consumer.topic.format is skipped. This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html (default "promremotewrite")
|
||||
-kafka.consumer.topic.format array
|
||||
data format for corresponding kafka topic. Valid formats: influx, prometheus, promremotewrite, graphite, jsonline . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
data format for corresponding kafka topic. Valid formats: influx, prometheus, promremotewrite, graphite, jsonline . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-kafka.consumer.topic.groupID array
|
||||
Defines group.id for topic. This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Defines group.id for topic. This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-kafka.consumer.topic.isGzipped array
|
||||
Enables gzip setting for topic messages payload. Only prometheus, jsonline and influx formats accept gzipped messages.This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Enables gzip setting for topic messages payload. Only prometheus, jsonline and influx formats accept gzipped messages.This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
Supports array of values separated by comma or specified via multiple flags.
|
||||
-kafka.consumer.topic.options array
|
||||
Optional key=value;key1=value2 settings for topic consumer. See full configuration options at https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Optional key=value;key1=value2 settings for topic consumer. See full configuration options at https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-license string
|
||||
Lisense key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed via file specified by -licenseFile command-line flag
|
||||
-license.forceOffline
|
||||
Whether to enable offline verification for VictoriaMetrics Enterprise license key, which has been passed either via -license or via -licenseFile command-line flag. The issued license key must support offline verification feature. Contact info@victoriametrics.com if you need offline license verification. This flag is avilable only in Enterprise binaries
|
||||
-licenseFile string
|
||||
Path to file with license key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed inline via -license command-line flag
|
||||
-loggerDisableTimestamps
|
||||
Whether to disable writing timestamps in logs
|
||||
-loggerErrorsPerSecondLimit int
|
||||
@@ -1344,7 +1350,7 @@ See the docs at https://docs.victoriametrics.com/vmagent.html .
|
||||
-loggerWarnsPerSecondLimit int
|
||||
Per-second limit on the number of WARN messages. If more than the given number of warns are emitted per second, then the remaining warns are suppressed. Zero values disable the rate limit
|
||||
-maxConcurrentInserts int
|
||||
The maximum number of concurrent insert requests. The default value should work for most cases, since it minimizes memory usage. The default value can be increased when clients send data over slow networks. See also -insert.maxQueueDuration (default 8)
|
||||
The maximum number of concurrent insert requests. Default value should work for most cases, since it minimizes the memory usage. The default value can be increased when clients send data over slow networks. See also -insert.maxQueueDuration (default 8)
|
||||
-maxInsertRequestSize size
|
||||
The maximum size in bytes of a single Prometheus remote_write API request
|
||||
Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 33554432)
|
||||
@@ -1533,7 +1539,7 @@ See the docs at https://docs.victoriametrics.com/vmagent.html .
|
||||
The maximum number of unique series vmagent can send to remote storage systems during the last 24 hours. Excess series are logged and dropped. This can be useful for limiting series churn rate. See https://docs.victoriametrics.com/vmagent.html#cardinality-limiter
|
||||
-remoteWrite.maxDiskUsagePerURL array
|
||||
The maximum file-based buffer size in bytes at -remoteWrite.tmpDataPath for each -remoteWrite.url. When buffer size reaches the configured maximum, then old data is dropped when adding new data to the buffer. Buffered data is stored in ~500MB chunks. It is recommended to set the value for this flag to a multiple of the block size 500MB. Disk usage is unlimited if the value is set to 0
|
||||
Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB.
|
||||
Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB. (default 0)
|
||||
Supports array of values separated by comma or specified via multiple flags.
|
||||
-remoteWrite.maxHourlySeries int
|
||||
The maximum number of unique series vmagent can send to remote storage systems during the last hour. Excess series are logged and dropped. This can be useful for limiting series cardinality. See https://docs.victoriametrics.com/vmagent.html#cardinality-limiter
|
||||
@@ -1563,28 +1569,28 @@ See the docs at https://docs.victoriametrics.com/vmagent.html .
|
||||
-remoteWrite.queues int
|
||||
The number of concurrent queues to each -remoteWrite.url. Set more queues if default number of queues isn't enough for sending high volume of collected data to remote storage. Default value is 2 * numberOfAvailableCPUs (default 8)
|
||||
-remoteWrite.rateLimit array
|
||||
Optional rate limit in bytes per second for data sent to the corresponding -remoteWrite.url. By default, the rate limit is disabled. It can be useful for limiting load on remote storage when big amounts of buffered data is sent after temporary unavailability of the remote storage
|
||||
Optional rate limit in bytes per second for data sent to the corresponding -remoteWrite.url. By default, the rate limit is disabled. It can be useful for limiting load on remote storage when big amounts of buffered data is sent after temporary unavailability of the remote storage (default 0)
|
||||
Supports array of values separated by comma or specified via multiple flags.
|
||||
-remoteWrite.relabelConfig string
|
||||
Optional path to file with relabeling configs, which are applied to all the metrics before sending them to -remoteWrite.url. See also -remoteWrite.urlRelabelConfig. The path can point either to local file or to http url. See https://docs.victoriametrics.com/vmagent.html#relabeling
|
||||
-remoteWrite.roundDigits array
|
||||
Round metric values to this number of decimal digits after the point before writing them to remote storage. Examples: -remoteWrite.roundDigits=2 would round 1.236 to 1.24, while -remoteWrite.roundDigits=-1 would round 126.78 to 130. By default, digits rounding is disabled. Set it to 100 for disabling it for a particular remote storage. This option may be used for improving data compression for the stored metrics
|
||||
Round metric values to this number of decimal digits after the point before writing them to remote storage. Examples: -remoteWrite.roundDigits=2 would round 1.236 to 1.24, while -remoteWrite.roundDigits=-1 would round 126.78 to 130. By default, digits rounding is disabled. Set it to 100 for disabling it for a particular remote storage. This option may be used for improving data compression for the stored metrics (default 100)
|
||||
Supports array of values separated by comma or specified via multiple flags.
|
||||
-remoteWrite.sendTimeout array
|
||||
Timeout for sending a single block of data to the corresponding -remoteWrite.url (default 1m)
|
||||
Timeout for sending a single block of data to the corresponding -remoteWrite.url (default 1m0s)
|
||||
Supports array of values separated by comma or specified via multiple flags.
|
||||
-remoteWrite.shardByURL
|
||||
Whether to shard outgoing series across all the remote storage systems enumerated via -remoteWrite.url . By default the data is replicated across all the -remoteWrite.url . See https://docs.victoriametrics.com/vmagent.html#sharding-among-remote-storages
|
||||
-remoteWrite.showURL
|
||||
Whether to show -remoteWrite.url in the exported metrics. It is hidden by default, since it can contain sensitive info such as auth key
|
||||
-remoteWrite.significantFigures array
|
||||
The number of significant figures to leave in metric values before writing them to remote storage. See https://en.wikipedia.org/wiki/Significant_figures . Zero value saves all the significant figures. This option may be used for improving data compression for the stored metrics. See also -remoteWrite.roundDigits
|
||||
The number of significant figures to leave in metric values before writing them to remote storage. See https://en.wikipedia.org/wiki/Significant_figures . Zero value saves all the significant figures. This option may be used for improving data compression for the stored metrics. See also -remoteWrite.roundDigits (default 0)
|
||||
Supports array of values separated by comma or specified via multiple flags.
|
||||
-remoteWrite.streamAggr.config array
|
||||
Optional path to file with stream aggregation config. See https://docs.victoriametrics.com/stream-aggregation.html . See also -remoteWrite.streamAggr.keepInput, -remoteWrite.streamAggr.dropInput and -remoteWrite.streamAggr.dedupInterval
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-remoteWrite.streamAggr.dedupInterval array
|
||||
Input samples are de-duplicated with this interval before being aggregated. Only the last sample per each time series per each interval is aggregated if the interval is greater than zero
|
||||
Input samples are de-duplicated with this interval before being aggregated. Only the last sample per each time series per each interval is aggregated if the interval is greater than zero (default 0s)
|
||||
Supports array of values separated by comma or specified via multiple flags.
|
||||
-remoteWrite.streamAggr.dropInput array
|
||||
Whether to drop all the input samples after the aggregation with -remoteWrite.streamAggr.config. By default, only aggregates samples are dropped, while the remaining samples are written to the corresponding -remoteWrite.url . See also -remoteWrite.streamAggr.keepInput and https://docs.victoriametrics.com/stream-aggregation.html
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/csvimport"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/datadog"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/graphite"
|
||||
@@ -39,7 +41,6 @@ import (
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/common"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/pushmetrics"
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -208,7 +209,7 @@ func getAuthTokenFromPath(path string) (*auth.Token, error) {
|
||||
if p.Suffix != "opentsdb/api/put" {
|
||||
return nil, fmt.Errorf("unsupported path requested: %q; expecting 'opentsdb/api/put'", p.Suffix)
|
||||
}
|
||||
return auth.NewToken(p.AuthToken)
|
||||
return auth.NewTokenPossibleMultitenant(p.AuthToken)
|
||||
}
|
||||
|
||||
func requestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||
@@ -251,7 +252,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||
w.WriteHeader(statusCode)
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(path, "datadog/") {
|
||||
if strings.HasPrefix(path, "/datadog/") {
|
||||
// Trim suffix from paths starting from /datadog/ in order to support legacy DataDog agent.
|
||||
// See https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2670
|
||||
path = strings.TrimSuffix(path, "/")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package opentelemetry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/common"
|
||||
@@ -26,6 +27,9 @@ func InsertHandler(at *auth.Token, req *http.Request) error {
|
||||
return err
|
||||
}
|
||||
isGzipped := req.Header.Get("Content-Encoding") == "gzip"
|
||||
if req.Header.Get("Content-Type") == "application/json" {
|
||||
return fmt.Errorf("json encoding isn't supported for opentelemetry format. Use protobuf encoding")
|
||||
}
|
||||
return stream.ParseStream(req.Body, isGzipped, func(tss []prompbmarshal.TimeSeries) error {
|
||||
return insertRows(at, tss, extraLabels)
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@ package remotewrite
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -26,10 +27,10 @@ var (
|
||||
forceVMProto = flagutil.NewArrayBool("remoteWrite.forceVMProto", "Whether to force VictoriaMetrics remote write protocol for sending data "+
|
||||
"to the corresponding -remoteWrite.url . See https://docs.victoriametrics.com/vmagent.html#victoriametrics-remote-write-protocol")
|
||||
|
||||
rateLimit = flagutil.NewArrayInt("remoteWrite.rateLimit", "Optional rate limit in bytes per second for data sent to the corresponding -remoteWrite.url. "+
|
||||
rateLimit = flagutil.NewArrayInt("remoteWrite.rateLimit", 0, "Optional rate limit in bytes per second for data sent to the corresponding -remoteWrite.url. "+
|
||||
"By default, the rate limit is disabled. It can be useful for limiting load on remote storage when big amounts of buffered data "+
|
||||
"is sent after temporary unavailability of the remote storage")
|
||||
sendTimeout = flagutil.NewArrayDuration("remoteWrite.sendTimeout", "Timeout for sending a single block of data to the corresponding -remoteWrite.url (default 1m)")
|
||||
sendTimeout = flagutil.NewArrayDuration("remoteWrite.sendTimeout", time.Minute, "Timeout for sending a single block of data to the corresponding -remoteWrite.url")
|
||||
proxyURL = flagutil.NewArrayString("remoteWrite.proxyURL", "Optional proxy URL for writing data to the corresponding -remoteWrite.url. "+
|
||||
"Supported proxies: http, https, socks5. Example: -remoteWrite.proxyURL=socks5://proxy:1234")
|
||||
|
||||
@@ -134,7 +135,7 @@ func newHTTPClient(argIdx int, remoteWriteURL, sanitizedURL string, fq *persiste
|
||||
}
|
||||
hc := &http.Client{
|
||||
Transport: tr,
|
||||
Timeout: sendTimeout.GetOptionalArgOrDefault(argIdx, time.Minute),
|
||||
Timeout: sendTimeout.GetOptionalArg(argIdx),
|
||||
}
|
||||
c := &client{
|
||||
sanitizedURL: sanitizedURL,
|
||||
@@ -169,7 +170,7 @@ func newHTTPClient(argIdx int, remoteWriteURL, sanitizedURL string, fq *persiste
|
||||
}
|
||||
|
||||
func (c *client) init(argIdx, concurrency int, sanitizedURL string) {
|
||||
if bytesPerSec := rateLimit.GetOptionalArgOrDefault(argIdx, 0); bytesPerSec > 0 {
|
||||
if bytesPerSec := rateLimit.GetOptionalArg(argIdx); bytesPerSec > 0 {
|
||||
logger.Infof("applying %d bytes per second rate limit for -remoteWrite.url=%q", bytesPerSec, sanitizedURL)
|
||||
c.rl.perSecondLimit = int64(bytesPerSec)
|
||||
}
|
||||
@@ -178,7 +179,7 @@ func (c *client) init(argIdx, concurrency int, sanitizedURL string) {
|
||||
c.bytesSent = metrics.GetOrCreateCounter(fmt.Sprintf(`vmagent_remotewrite_bytes_sent_total{url=%q}`, c.sanitizedURL))
|
||||
c.blocksSent = metrics.GetOrCreateCounter(fmt.Sprintf(`vmagent_remotewrite_blocks_sent_total{url=%q}`, c.sanitizedURL))
|
||||
c.rateLimit = metrics.GetOrCreateGauge(fmt.Sprintf(`vmagent_remotewrite_rate_limit{url=%q}`, c.sanitizedURL), func() float64 {
|
||||
return float64(rateLimit.GetOptionalArgOrDefault(argIdx, 0))
|
||||
return float64(rateLimit.GetOptionalArg(argIdx))
|
||||
})
|
||||
c.requestDuration = metrics.GetOrCreateHistogram(fmt.Sprintf(`vmagent_remotewrite_duration_seconds{url=%q}`, c.sanitizedURL))
|
||||
c.requestsOKCount = metrics.GetOrCreateCounter(fmt.Sprintf(`vmagent_remotewrite_requests_total{url=%q, status_code="2XX"}`, c.sanitizedURL))
|
||||
@@ -322,6 +323,20 @@ func (c *client) runWorker() {
|
||||
}
|
||||
|
||||
func (c *client) doRequest(url string, body []byte) (*http.Response, error) {
|
||||
req := c.newRequest(url, body)
|
||||
resp, err := c.hc.Do(req)
|
||||
if err != nil && errors.Is(err, io.EOF) {
|
||||
// it is likely connection became stale.
|
||||
// So we do one more attempt in hope request will succeed.
|
||||
// If not, the error should be handled by the caller as usual.
|
||||
// This should help with https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4139
|
||||
req = c.newRequest(url, body)
|
||||
resp, err = c.hc.Do(req)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (c *client) newRequest(url string, body []byte) *http.Request {
|
||||
reqBody := bytes.NewBuffer(body)
|
||||
req, err := http.NewRequest(http.MethodPost, url, reqBody)
|
||||
if err != nil {
|
||||
@@ -345,7 +360,7 @@ func (c *client) doRequest(url string, body []byte) (*http.Response, error) {
|
||||
logger.Warnf("cannot sign remoteWrite request with AWS sigv4: %s", err)
|
||||
}
|
||||
}
|
||||
return c.hc.Do(req)
|
||||
return req
|
||||
}
|
||||
|
||||
// sendBlockHTTP sends the given block to c.remoteWriteURL.
|
||||
|
||||
@@ -87,8 +87,8 @@ func initLabelsGlobal() {
|
||||
}
|
||||
}
|
||||
|
||||
func (rctx *relabelCtx) applyRelabeling(tss []prompbmarshal.TimeSeries, extraLabels []prompbmarshal.Label, pcs *promrelabel.ParsedConfigs) []prompbmarshal.TimeSeries {
|
||||
if len(extraLabels) == 0 && pcs.Len() == 0 && !*usePromCompatibleNaming {
|
||||
func (rctx *relabelCtx) applyRelabeling(tss []prompbmarshal.TimeSeries, pcs *promrelabel.ParsedConfigs) []prompbmarshal.TimeSeries {
|
||||
if pcs.Len() == 0 && !*usePromCompatibleNaming {
|
||||
// Nothing to change.
|
||||
return tss
|
||||
}
|
||||
@@ -98,34 +98,15 @@ func (rctx *relabelCtx) applyRelabeling(tss []prompbmarshal.TimeSeries, extraLab
|
||||
ts := &tss[i]
|
||||
labelsLen := len(labels)
|
||||
labels = append(labels, ts.Labels...)
|
||||
// extraLabels must be added before applying relabeling according to https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write
|
||||
for j := range extraLabels {
|
||||
extraLabel := &extraLabels[j]
|
||||
tmp := promrelabel.GetLabelByName(labels[labelsLen:], extraLabel.Name)
|
||||
if tmp != nil {
|
||||
tmp.Value = extraLabel.Value
|
||||
} else {
|
||||
labels = append(labels, *extraLabel)
|
||||
}
|
||||
}
|
||||
if *usePromCompatibleNaming {
|
||||
// Replace unsupported Prometheus chars in label names and metric names with underscores.
|
||||
tmpLabels := labels[labelsLen:]
|
||||
for j := range tmpLabels {
|
||||
label := &tmpLabels[j]
|
||||
if label.Name == "__name__" {
|
||||
label.Value = promrelabel.SanitizeName(label.Value)
|
||||
} else {
|
||||
label.Name = promrelabel.SanitizeName(label.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
labels = pcs.Apply(labels, labelsLen)
|
||||
labels = promrelabel.FinalizeLabels(labels[:labelsLen], labels[labelsLen:])
|
||||
if len(labels) == labelsLen {
|
||||
// Drop the current time series, since relabeling removed all the labels.
|
||||
continue
|
||||
}
|
||||
if *usePromCompatibleNaming {
|
||||
fixPromCompatibleNaming(labels[labelsLen:])
|
||||
}
|
||||
tssDst = append(tssDst, prompbmarshal.TimeSeries{
|
||||
Labels: labels[labelsLen:],
|
||||
Samples: ts.Samples,
|
||||
@@ -135,6 +116,29 @@ func (rctx *relabelCtx) applyRelabeling(tss []prompbmarshal.TimeSeries, extraLab
|
||||
return tssDst
|
||||
}
|
||||
|
||||
func (rctx *relabelCtx) appendExtraLabels(tss []prompbmarshal.TimeSeries, extraLabels []prompbmarshal.Label) {
|
||||
if len(extraLabels) == 0 {
|
||||
return
|
||||
}
|
||||
labels := rctx.labels[:0]
|
||||
for i := range tss {
|
||||
ts := &tss[i]
|
||||
labelsLen := len(labels)
|
||||
labels = append(labels, ts.Labels...)
|
||||
for j := range extraLabels {
|
||||
extraLabel := extraLabels[j]
|
||||
tmp := promrelabel.GetLabelByName(labels[labelsLen:], extraLabel.Name)
|
||||
if tmp != nil {
|
||||
tmp.Value = extraLabel.Value
|
||||
} else {
|
||||
labels = append(labels, extraLabel)
|
||||
}
|
||||
}
|
||||
ts.Labels = labels[labelsLen:]
|
||||
}
|
||||
rctx.labels = labels
|
||||
}
|
||||
|
||||
type relabelCtx struct {
|
||||
// pool for labels, which are used during the relabeling.
|
||||
labels []prompbmarshal.Label
|
||||
@@ -159,3 +163,15 @@ func putRelabelCtx(rctx *relabelCtx) {
|
||||
rctx.labels = rctx.labels[:0]
|
||||
relabelCtxPool.Put(rctx)
|
||||
}
|
||||
|
||||
func fixPromCompatibleNaming(labels []prompbmarshal.Label) {
|
||||
// Replace unsupported Prometheus chars in label names and metric names with underscores.
|
||||
for i := range labels {
|
||||
label := &labels[i]
|
||||
if label.Name == "__name__" {
|
||||
label.Value = promrelabel.SanitizeMetricName(label.Value)
|
||||
} else {
|
||||
label.Name = promrelabel.SanitizeLabelName(label.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,18 +10,16 @@ import (
|
||||
)
|
||||
|
||||
func TestApplyRelabeling(t *testing.T) {
|
||||
f := func(extraLabels []prompbmarshal.Label, pcs *promrelabel.ParsedConfigs, sTss, sExpTss string) {
|
||||
f := func(pcs *promrelabel.ParsedConfigs, sTss, sExpTss string) {
|
||||
rctx := &relabelCtx{}
|
||||
tss, expTss := parseSeries(sTss), parseSeries(sExpTss)
|
||||
gotTss := rctx.applyRelabeling(tss, extraLabels, pcs)
|
||||
gotTss := rctx.applyRelabeling(tss, pcs)
|
||||
if !reflect.DeepEqual(gotTss, expTss) {
|
||||
t.Fatalf("expected to have: \n%v;\ngot: \n%v", expTss, gotTss)
|
||||
}
|
||||
}
|
||||
|
||||
f(nil, nil, "up", "up")
|
||||
f([]prompbmarshal.Label{{Name: "foo", Value: "bar"}}, nil, "up", `up{foo="bar"}`)
|
||||
f([]prompbmarshal.Label{{Name: "foo", Value: "bar"}}, nil, `up{foo="baz"}`, `up{foo="bar"}`)
|
||||
f(nil, "up", "up")
|
||||
|
||||
pcs, err := promrelabel.ParseRelabelConfigsData([]byte(`
|
||||
- target_label: "foo"
|
||||
@@ -32,11 +30,33 @@ func TestApplyRelabeling(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
f(nil, pcs, `up{foo="baz", env="prod"}`, `up{foo="aaa"}`)
|
||||
f(pcs, `up{foo="baz", env="prod"}`, `up{foo="aaa"}`)
|
||||
|
||||
oldVal := *usePromCompatibleNaming
|
||||
*usePromCompatibleNaming = true
|
||||
f(nil, nil, `foo.bar`, `foo_bar`)
|
||||
f(nil, `foo.bar`, `foo_bar`)
|
||||
*usePromCompatibleNaming = oldVal
|
||||
}
|
||||
|
||||
func TestAppendExtraLabels(t *testing.T) {
|
||||
f := func(extraLabels []prompbmarshal.Label, sTss, sExpTss string) {
|
||||
t.Helper()
|
||||
rctx := &relabelCtx{}
|
||||
tss, expTss := parseSeries(sTss), parseSeries(sExpTss)
|
||||
rctx.appendExtraLabels(tss, extraLabels)
|
||||
if !reflect.DeepEqual(tss, expTss) {
|
||||
t.Fatalf("expected to have: \n%v;\ngot: \n%v", expTss, tss)
|
||||
}
|
||||
}
|
||||
|
||||
f(nil, "up", "up")
|
||||
f([]prompbmarshal.Label{{Name: "foo", Value: "bar"}}, "up", `up{foo="bar"}`)
|
||||
f([]prompbmarshal.Label{{Name: "foo", Value: "bar"}}, `up{foo="baz"}`, `up{foo="bar"}`)
|
||||
f([]prompbmarshal.Label{{Name: "baz", Value: "qux"}}, `up{foo="baz"}`, `up{foo="baz",baz="qux"}`)
|
||||
|
||||
oldVal := *usePromCompatibleNaming
|
||||
*usePromCompatibleNaming = true
|
||||
f([]prompbmarshal.Label{{Name: "foo.bar", Value: "baz"}}, "up", `up{foo.bar="baz"}`)
|
||||
*usePromCompatibleNaming = oldVal
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/cespare/xxhash/v2"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/auth"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bloomfilter"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
|
||||
@@ -28,6 +26,7 @@ import (
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/streamaggr"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/tenantmetrics"
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
"github.com/cespare/xxhash/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -49,14 +48,15 @@ var (
|
||||
"isn't enough for sending high volume of collected data to remote storage. Default value is 2 * numberOfAvailableCPUs")
|
||||
showRemoteWriteURL = flag.Bool("remoteWrite.showURL", false, "Whether to show -remoteWrite.url in the exported metrics. "+
|
||||
"It is hidden by default, since it can contain sensitive info such as auth key")
|
||||
maxPendingBytesPerURL = flagutil.NewArrayBytes("remoteWrite.maxDiskUsagePerURL", "The maximum file-based buffer size in bytes at -remoteWrite.tmpDataPath "+
|
||||
maxPendingBytesPerURL = flagutil.NewArrayBytes("remoteWrite.maxDiskUsagePerURL", 0, "The maximum file-based buffer size in bytes at -remoteWrite.tmpDataPath "+
|
||||
"for each -remoteWrite.url. When buffer size reaches the configured maximum, then old data is dropped when adding new data to the buffer. "+
|
||||
"Buffered data is stored in ~500MB chunks. It is recommended to set the value for this flag to a multiple of the block size 500MB. "+
|
||||
"Disk usage is unlimited if the value is set to 0")
|
||||
significantFigures = flagutil.NewArrayInt("remoteWrite.significantFigures", "The number of significant figures to leave in metric values before writing them "+
|
||||
significantFigures = flagutil.NewArrayInt("remoteWrite.significantFigures", 0, "The number of significant figures to leave in metric values before writing them "+
|
||||
"to remote storage. See https://en.wikipedia.org/wiki/Significant_figures . Zero value saves all the significant figures. "+
|
||||
"This option may be used for improving data compression for the stored metrics. See also -remoteWrite.roundDigits")
|
||||
roundDigits = flagutil.NewArrayInt("remoteWrite.roundDigits", "Round metric values to this number of decimal digits after the point before writing them to remote storage. "+
|
||||
roundDigits = flagutil.NewArrayInt("remoteWrite.roundDigits", 100, "Round metric values to this number of decimal digits after the point before "+
|
||||
"writing them to remote storage. "+
|
||||
"Examples: -remoteWrite.roundDigits=2 would round 1.236 to 1.24, while -remoteWrite.roundDigits=-1 would round 126.78 to 130. "+
|
||||
"By default, digits rounding is disabled. Set it to 100 for disabling it for a particular remote storage. "+
|
||||
"This option may be used for improving data compression for the stored metrics")
|
||||
@@ -78,7 +78,7 @@ var (
|
||||
streamAggrDropInput = flagutil.NewArrayBool("remoteWrite.streamAggr.dropInput", "Whether to drop all the input samples after the aggregation "+
|
||||
"with -remoteWrite.streamAggr.config. By default, only aggregates samples are dropped, while the remaining samples "+
|
||||
"are written to the corresponding -remoteWrite.url . See also -remoteWrite.streamAggr.keepInput and https://docs.victoriametrics.com/stream-aggregation.html")
|
||||
streamAggrDedupInterval = flagutil.NewArrayDuration("remoteWrite.streamAggr.dedupInterval", "Input samples are de-duplicated with this interval before being aggregated. "+
|
||||
streamAggrDedupInterval = flagutil.NewArrayDuration("remoteWrite.streamAggr.dedupInterval", 0, "Input samples are de-duplicated with this interval before being aggregated. "+
|
||||
"Only the last sample per each time series per each interval is aggregated if the interval is greater than zero")
|
||||
)
|
||||
|
||||
@@ -258,7 +258,7 @@ func newRemoteWriteCtxs(at *auth.Token, urls []string) []*remoteWriteCtx {
|
||||
if *showRemoteWriteURL {
|
||||
sanitizedURL = fmt.Sprintf("%d:%s", i+1, remoteWriteURL)
|
||||
}
|
||||
rwctxs[i] = newRemoteWriteCtx(i, at, remoteWriteURL, maxInmemoryBlocks, sanitizedURL)
|
||||
rwctxs[i] = newRemoteWriteCtx(i, remoteWriteURL, maxInmemoryBlocks, sanitizedURL)
|
||||
}
|
||||
|
||||
if !*keepDanglingQueues {
|
||||
@@ -355,7 +355,7 @@ func Push(at *auth.Token, wr *prompbmarshal.WriteRequest) {
|
||||
var rctx *relabelCtx
|
||||
rcs := allRelabelConfigs.Load()
|
||||
pcsGlobal := rcs.global
|
||||
if pcsGlobal.Len() > 0 || len(labelsGlobal) > 0 {
|
||||
if pcsGlobal.Len() > 0 {
|
||||
rctx = getRelabelCtx()
|
||||
}
|
||||
tss := wr.Timeseries
|
||||
@@ -386,7 +386,7 @@ func Push(at *auth.Token, wr *prompbmarshal.WriteRequest) {
|
||||
}
|
||||
if rctx != nil {
|
||||
rowsCountBeforeRelabel := getRowsCount(tssBlock)
|
||||
tssBlock = rctx.applyRelabeling(tssBlock, labelsGlobal, pcsGlobal)
|
||||
tssBlock = rctx.applyRelabeling(tssBlock, pcsGlobal)
|
||||
rowsCountAfterRelabel := getRowsCount(tssBlock)
|
||||
rowsDroppedByGlobalRelabel.Add(rowsCountBeforeRelabel - rowsCountAfterRelabel)
|
||||
}
|
||||
@@ -559,14 +559,14 @@ type remoteWriteCtx struct {
|
||||
rowsDroppedByRelabel *metrics.Counter
|
||||
}
|
||||
|
||||
func newRemoteWriteCtx(argIdx int, at *auth.Token, remoteWriteURL *url.URL, maxInmemoryBlocks int, sanitizedURL string) *remoteWriteCtx {
|
||||
func newRemoteWriteCtx(argIdx int, remoteWriteURL *url.URL, maxInmemoryBlocks int, sanitizedURL string) *remoteWriteCtx {
|
||||
// strip query params, otherwise changing params resets pq
|
||||
pqURL := *remoteWriteURL
|
||||
pqURL.RawQuery = ""
|
||||
pqURL.Fragment = ""
|
||||
h := xxhash.Sum64([]byte(pqURL.String()))
|
||||
queuePath := filepath.Join(*tmpDataPath, persistentQueueDirname, fmt.Sprintf("%d_%016X", argIdx+1, h))
|
||||
maxPendingBytes := maxPendingBytesPerURL.GetOptionalArgOrDefault(argIdx, 0)
|
||||
maxPendingBytes := maxPendingBytesPerURL.GetOptionalArg(argIdx)
|
||||
if maxPendingBytes != 0 && maxPendingBytes < persistentqueue.DefaultChunkFileSize {
|
||||
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4195
|
||||
logger.Warnf("rounding the -remoteWrite.maxDiskUsagePerURL=%d to the minimum supported value: %d", maxPendingBytes, persistentqueue.DefaultChunkFileSize)
|
||||
@@ -590,8 +590,8 @@ func newRemoteWriteCtx(argIdx int, at *auth.Token, remoteWriteURL *url.URL, maxI
|
||||
c.init(argIdx, *queues, sanitizedURL)
|
||||
|
||||
// Initialize pss
|
||||
sf := significantFigures.GetOptionalArgOrDefault(argIdx, 0)
|
||||
rd := roundDigits.GetOptionalArgOrDefault(argIdx, 100)
|
||||
sf := significantFigures.GetOptionalArg(argIdx)
|
||||
rd := roundDigits.GetOptionalArg(argIdx)
|
||||
pssLen := *queues
|
||||
if n := cgroup.AvailableCPUs(); pssLen > n {
|
||||
// There is no sense in running more than availableCPUs concurrent pendingSeries,
|
||||
@@ -616,7 +616,7 @@ func newRemoteWriteCtx(argIdx int, at *auth.Token, remoteWriteURL *url.URL, maxI
|
||||
// Initialize sas
|
||||
sasFile := streamAggrConfig.GetOptionalArg(argIdx)
|
||||
if sasFile != "" {
|
||||
dedupInterval := streamAggrDedupInterval.GetOptionalArgOrDefault(argIdx, 0)
|
||||
dedupInterval := streamAggrDedupInterval.GetOptionalArg(argIdx)
|
||||
sas, err := streamaggr.LoadFromFile(sasFile, rwctx.pushInternal, dedupInterval)
|
||||
if err != nil {
|
||||
logger.Fatalf("cannot initialize stream aggregators from -remoteWrite.streamAggr.config=%q: %s", sasFile, err)
|
||||
@@ -668,7 +668,7 @@ func (rwctx *remoteWriteCtx) Push(tss []prompbmarshal.TimeSeries) {
|
||||
v = tssPool.Get().(*[]prompbmarshal.TimeSeries)
|
||||
tss = append(*v, tss...)
|
||||
rowsCountBeforeRelabel := getRowsCount(tss)
|
||||
tss = rctx.applyRelabeling(tss, nil, pcs)
|
||||
tss = rctx.applyRelabeling(tss, pcs)
|
||||
rowsCountAfterRelabel := getRowsCount(tss)
|
||||
rwctx.rowsDroppedByRelabel.Add(rowsCountBeforeRelabel - rowsCountAfterRelabel)
|
||||
}
|
||||
@@ -705,11 +705,13 @@ var matchIdxsPool bytesutil.ByteBufferPool
|
||||
|
||||
func dropAggregatedSeries(src []prompbmarshal.TimeSeries, matchIdxs []byte, dropInput bool) []prompbmarshal.TimeSeries {
|
||||
dst := src[:0]
|
||||
for i, match := range matchIdxs {
|
||||
if match == 0 {
|
||||
continue
|
||||
if !dropInput {
|
||||
for i, match := range matchIdxs {
|
||||
if match == 1 {
|
||||
continue
|
||||
}
|
||||
dst = append(dst, src[i])
|
||||
}
|
||||
dst = append(dst, src[i])
|
||||
}
|
||||
tail := src[len(dst):]
|
||||
_ = prompbmarshal.ResetTimeSeries(tail)
|
||||
@@ -717,22 +719,38 @@ func dropAggregatedSeries(src []prompbmarshal.TimeSeries, matchIdxs []byte, drop
|
||||
}
|
||||
|
||||
func (rwctx *remoteWriteCtx) pushInternal(tss []prompbmarshal.TimeSeries) {
|
||||
var rctx *relabelCtx
|
||||
var v *[]prompbmarshal.TimeSeries
|
||||
if len(labelsGlobal) > 0 {
|
||||
// Make a copy of tss before adding extra labels in order to prevent
|
||||
// from affecting time series for other remoteWrite.url configs.
|
||||
rctx = getRelabelCtx()
|
||||
v = tssPool.Get().(*[]prompbmarshal.TimeSeries)
|
||||
tss = append(*v, tss...)
|
||||
rctx.appendExtraLabels(tss, labelsGlobal)
|
||||
}
|
||||
|
||||
pss := rwctx.pss
|
||||
idx := atomic.AddUint64(&rwctx.pssNextIdx, 1) % uint64(len(pss))
|
||||
pss[idx].Push(tss)
|
||||
|
||||
if rctx != nil {
|
||||
*v = prompbmarshal.ResetTimeSeries(tss)
|
||||
tssPool.Put(v)
|
||||
putRelabelCtx(rctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (rwctx *remoteWriteCtx) reinitStreamAggr() {
|
||||
sas := rwctx.sas.Load()
|
||||
if sas == nil {
|
||||
sasFile := streamAggrConfig.GetOptionalArg(rwctx.idx)
|
||||
if sasFile == "" {
|
||||
// There is no stream aggregation for rwctx
|
||||
return
|
||||
}
|
||||
|
||||
sasFile := streamAggrConfig.GetOptionalArg(rwctx.idx)
|
||||
logger.Infof("reloading stream aggregation configs pointed by -remoteWrite.streamAggr.config=%q", sasFile)
|
||||
metrics.GetOrCreateCounter(fmt.Sprintf(`vmagent_streamaggr_config_reloads_total{path=%q}`, sasFile)).Inc()
|
||||
dedupInterval := streamAggrDedupInterval.GetOptionalArgOrDefault(rwctx.idx, 0)
|
||||
dedupInterval := streamAggrDedupInterval.GetOptionalArg(rwctx.idx)
|
||||
sasNew, err := streamaggr.LoadFromFile(sasFile, rwctx.pushInternal, dedupInterval)
|
||||
if err != nil {
|
||||
metrics.GetOrCreateCounter(fmt.Sprintf(`vmagent_streamaggr_config_reloads_errors_total{path=%q}`, sasFile)).Inc()
|
||||
@@ -740,6 +758,7 @@ func (rwctx *remoteWriteCtx) reinitStreamAggr() {
|
||||
logger.Errorf("cannot reload stream aggregation config from -remoteWrite.streamAggr.config=%q; continue using the previously loaded config; error: %s", sasFile, err)
|
||||
return
|
||||
}
|
||||
sas := rwctx.sas.Load()
|
||||
if !sasNew.Equal(sas) {
|
||||
sasOld := rwctx.sas.Swap(sasNew)
|
||||
sasOld.MustStop()
|
||||
@@ -774,7 +793,7 @@ func CheckStreamAggrConfigs() error {
|
||||
if sasFile == "" {
|
||||
continue
|
||||
}
|
||||
dedupInterval := streamAggrDedupInterval.GetOptionalArgOrDefault(idx, 0)
|
||||
dedupInterval := streamAggrDedupInterval.GetOptionalArg(idx)
|
||||
sas, err := streamaggr.LoadFromFile(sasFile, pushNoop, dedupInterval)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load -remoteWrite.streamAggr.config=%q: %w", sasFile, err)
|
||||
|
||||
@@ -27,7 +27,7 @@ var (
|
||||
stdDialerOnce sync.Once
|
||||
)
|
||||
|
||||
func statDial(ctx context.Context, networkUnused, addr string) (conn net.Conn, err error) {
|
||||
func statDial(ctx context.Context, _, addr string) (conn net.Conn, err error) {
|
||||
network := netutil.GetTCPNetwork()
|
||||
d := getStdDialer()
|
||||
conn, err = d.DialContext(ctx, network, addr)
|
||||
|
||||
@@ -117,11 +117,11 @@ name: <string>
|
||||
[ limit: <int> | default = 0 ]
|
||||
|
||||
# How many rules execute at once within a group. Increasing concurrency may speed
|
||||
# up round execution speed.
|
||||
# up group's evaluation duration (exposed via `vmalert_iteration_duration_seconds` metric).
|
||||
[ concurrency: <integer> | default = 1 ]
|
||||
|
||||
# Optional type for expressions inside the rules. Supported values: "graphite" and "prometheus".
|
||||
# By default "prometheus" type is used.
|
||||
# By default, "prometheus" type is used.
|
||||
[ type: <string> ]
|
||||
|
||||
# Optional list of HTTP URL parameters
|
||||
@@ -813,7 +813,8 @@ and check the `Last updates` section:
|
||||
Rows in the section represent ordered rule evaluations and their results. The column `curl` contains an example of
|
||||
HTTP request sent by vmalert to the `-datasource.url` during evaluation. If specific state shows that there were
|
||||
no samples returned and curl command returns data - then it is very likely there was no data in datasource on the
|
||||
moment when rule was evaluated.
|
||||
moment when rule was evaluated. Sensitive info is stripped from the `curl` examples - see [security](#security) section
|
||||
for more details.
|
||||
|
||||
### Debug mode
|
||||
|
||||
@@ -829,6 +830,8 @@ Just set `debug: true` in rule's configuration and vmalert will start printing a
|
||||
2022-09-15T13:36:56.153Z DEBUG rule "TestGroup":"Conns" (2601299393013563564) at 2022-09-15T15:36:56+02:00: alert 10705778000901301787 {alertgroup="TestGroup",alertname="Conns",cluster="east-1",instance="localhost:8429",replica="a"} PENDING => FIRING: 1m0s since becoming active at 2022-09-15 15:35:56.126006 +0200 CEST m=+39.384575417
|
||||
```
|
||||
|
||||
Sensitive info is stripped from the `curl` examples - see [security](#security) section for more details.
|
||||
|
||||
### Never-firing alerts
|
||||
|
||||
vmalert can detect if alert's expression doesn't match any time series in runtime
|
||||
@@ -873,6 +876,20 @@ The same issue can be caused by collision of configured `labels` on [Group](#gro
|
||||
To fix it one should avoid collisions by carefully picking label overrides in configuration.
|
||||
|
||||
|
||||
## Security
|
||||
|
||||
See general recommendations regarding security [here](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#security).
|
||||
|
||||
vmalert [web UI](#web) exposes configuration details such as list of [Groups](#groups), active alerts,
|
||||
[alerts state](#alerts-state), [notifiers](#notifier-configuration-file). Notifier addresses (sanitized) are attached
|
||||
as labels to metrics `vmalert_alerts_sent_.*` on `http://<vmalert>/metrics` page. Consider limiting user's access
|
||||
to the web UI or `/metrics` page if this information is sensitive.
|
||||
|
||||
[Alerts state](#alerts-state) page or [debug mode](#debug-mode) could emit additional information about configured
|
||||
datasource URL, GET params and headers. Sensitive information such as passwords or auth tokens is stripped by default.
|
||||
To disable stripping of such info pass `-datasource.showURL` cmd-line flag to vmalert.
|
||||
|
||||
|
||||
## Profiling
|
||||
|
||||
`vmalert` provides handlers for collecting the following [Go profiles](https://blog.golang.org/profiling-go-programs):
|
||||
@@ -913,7 +930,7 @@ The shortlist of configuration flags is the following:
|
||||
{% raw %}
|
||||
```console
|
||||
-clusterMode
|
||||
If clusterMode is enabled, then vmalert automatically adds the tenant specified in config groups to -datasource.url, -remoteWrite.url and -remoteRead.url. See https://docs.victoriametrics.com/vmalert.html#multitenancy . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
If clusterMode is enabled, then vmalert automatically adds the tenant specified in config groups to -datasource.url, -remoteWrite.url and -remoteRead.url. See https://docs.victoriametrics.com/vmalert.html#multitenancy . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-configCheckInterval duration
|
||||
Interval for checking for changes in '-rule' or '-notifier.config' files. By default, the checking is disabled. Send SIGHUP signal in order to force config check for changes.
|
||||
-datasource.appendTypePrefix
|
||||
@@ -955,7 +972,7 @@ The shortlist of configuration flags is the following:
|
||||
-datasource.roundDigits int
|
||||
Adds "round_digits" GET param to datasource requests. In VM "round_digits" limits the number of digits after the decimal point in response values.
|
||||
-datasource.showURL
|
||||
Whether to show -datasource.url in the exported metrics. It is hidden by default, since it can contain sensitive info such as auth key
|
||||
Whether to avoid stripping sensitive information such as auth headers or passwords from URLs in log messages or UI and exported metrics. It is hidden by default, since it can contain sensitive info such as auth key
|
||||
-datasource.tlsCAFile string
|
||||
Optional path to TLS CA file to use for verifying connections to -datasource.url. By default, system CA is used
|
||||
-datasource.tlsCertFile string
|
||||
@@ -969,9 +986,9 @@ The shortlist of configuration flags is the following:
|
||||
-datasource.url string
|
||||
Datasource compatible with Prometheus HTTP API. It can be single node VictoriaMetrics or vmselect URL. Required parameter. E.g. http://127.0.0.1:8428 . See also -remoteRead.disablePathAppend and -datasource.showURL
|
||||
-defaultTenant.graphite string
|
||||
Default tenant for Graphite alerting groups. See https://docs.victoriametrics.com/vmalert.html#multitenancy .This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Default tenant for Graphite alerting groups. See https://docs.victoriametrics.com/vmalert.html#multitenancy .This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-defaultTenant.prometheus string
|
||||
Default tenant for Prometheus alerting groups. See https://docs.victoriametrics.com/vmalert.html#multitenancy . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Default tenant for Prometheus alerting groups. See https://docs.victoriametrics.com/vmalert.html#multitenancy . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-disableAlertgroupLabel
|
||||
Whether to disable adding group's Name as label to generated alerts and time series.
|
||||
-dryRun
|
||||
@@ -983,7 +1000,7 @@ The shortlist of configuration flags is the following:
|
||||
-envflag.prefix string
|
||||
Prefix for environment variables if -envflag.enable is set
|
||||
-eula
|
||||
By specifying this flag, you confirm that you have an enterprise license and accept the EULA https://victoriametrics.com/assets/VM_EULA.pdf . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Deprecated, please use -license or -licenseFile flags instead. By specifying this flag, you confirm that you have an enterprise license and accept the ESA https://victoriametrics.com/legal/esa/ . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-evaluationInterval duration
|
||||
How often to evaluate the rules (default 1m0s)
|
||||
-external.alert.source string
|
||||
@@ -1023,6 +1040,12 @@ The shortlist of configuration flags is the following:
|
||||
Whether to disable caches for interned strings. This may reduce memory usage at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringCacheExpireDuration and -internStringMaxLen
|
||||
-internStringMaxLen int
|
||||
The maximum length for strings to intern. A lower limit may save memory at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringDisableCache and -internStringCacheExpireDuration (default 500)
|
||||
-license string
|
||||
Lisense key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed via file specified by -licenseFile command-line flag
|
||||
-license.forceOffline
|
||||
Whether to enable offline verification for VictoriaMetrics Enterprise license key, which has been passed either via -license or via -licenseFile command-line flag. The issued license key must support offline verification feature. Contact info@victoriametrics.com if you need offline license verification. This flag is avilable only in Enterprise binaries
|
||||
-licenseFile string
|
||||
Path to file with license key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed inline via -license command-line flag
|
||||
-loggerDisableTimestamps
|
||||
Whether to disable writing timestamps in logs
|
||||
-loggerErrorsPerSecondLimit int
|
||||
@@ -1061,6 +1084,8 @@ The shortlist of configuration flags is the following:
|
||||
-notifier.bearerTokenFile array
|
||||
Optional path to bearer token file for -notifier.url
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-notifier.blackhole -notifier.url
|
||||
Whether to blackhole alerting notifications. Enable this flag if you want vmalert to evaluate alerting rules without sending any notifications to external receivers (eg. alertmanager). -notifier.url, `-notifier.config` and `-notifier.blackhole` are mutually exclusive.
|
||||
-notifier.config string
|
||||
Path to configuration file for notifiers
|
||||
-notifier.oauth2.clientID array
|
||||
@@ -1078,6 +1103,8 @@ The shortlist of configuration flags is the following:
|
||||
-notifier.oauth2.tokenUrl array
|
||||
Optional OAuth2 tokenURL to use for -notifier.url. If multiple args are set, then they are applied independently for the corresponding -notifier.url
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-notifier.showURL
|
||||
Whether to avoid stripping sensitive information such as passwords from URL in log messages or UI for -notifier.url. It is hidden by default, since it can contain sensitive info such as auth key
|
||||
-notifier.suppressDuplicateTargetErrors
|
||||
Whether to suppress 'duplicate target' errors during discovery
|
||||
-notifier.tlsCAFile array
|
||||
@@ -1098,8 +1125,6 @@ The shortlist of configuration flags is the following:
|
||||
-notifier.url array
|
||||
Prometheus Alertmanager URL, e.g. http://127.0.0.1:9093. List all Alertmanager URLs if it runs in the cluster mode to ensure high availability.
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-notifier.blackhole bool
|
||||
Whether to blackhole alerting notifications. Enable this flag if you want vmalert to evaluate alerting rules without sending any notifications to external receivers (eg. alertmanager). `-notifier.url`, `-notifier.config` and `-notifier.blackhole` are mutually exclusive.
|
||||
-pprofAuthKey string
|
||||
Auth key for /debug/pprof/* endpoints. It must be passed via authKey query arg. It overrides httpAuth.* settings
|
||||
-promscrape.consul.waitTime duration
|
||||
@@ -1263,22 +1288,18 @@ The shortlist of configuration flags is the following:
|
||||
Whether to validate rules expressions via MetricsQL engine (default true)
|
||||
-rule.validateTemplates
|
||||
Whether to validate annotation and label templates (default true)
|
||||
-s2a_enable_appengine_dialer
|
||||
If true, opportunistically use AppEngine-specific dialer to call S2A.
|
||||
-s2a_timeout duration
|
||||
Timeout enforced on the connection to the S2A service for handshake. (default 3s)
|
||||
-s3.configFilePath string
|
||||
Path to file with S3 configs. Configs are loaded from default location if not set.
|
||||
See https://docs.aws.amazon.com/general/latest/gr/aws-security-credentials.html . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
See https://docs.aws.amazon.com/general/latest/gr/aws-security-credentials.html . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-s3.configProfile string
|
||||
Profile name for S3 configs. If no set, the value of the environment variable will be loaded (AWS_PROFILE or AWS_DEFAULT_PROFILE), or if both not set, DefaultSharedConfigProfile is used. This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Profile name for S3 configs. If no set, the value of the environment variable will be loaded (AWS_PROFILE or AWS_DEFAULT_PROFILE), or if both not set, DefaultSharedConfigProfile is used. This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-s3.credsFilePath string
|
||||
Path to file with GCS or S3 credentials. Credentials are loaded from default locations if not set.
|
||||
See https://cloud.google.com/iam/docs/creating-managing-service-account-keys and https://docs.aws.amazon.com/general/latest/gr/aws-security-credentials.html . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
See https://cloud.google.com/iam/docs/creating-managing-service-account-keys and https://docs.aws.amazon.com/general/latest/gr/aws-security-credentials.html . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-s3.customEndpoint string
|
||||
Custom S3 endpoint for use with S3-compatible storages (e.g. MinIO). S3 is used if not set. This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Custom S3 endpoint for use with S3-compatible storages (e.g. MinIO). S3 is used if not set. This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-s3.forcePathStyle
|
||||
Prefixing endpoint with bucket name when set false, true by default. This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html (default true)
|
||||
Prefixing endpoint with bucket name when set false, true by default. This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html (default true)
|
||||
-tls
|
||||
Whether to enable TLS for incoming HTTP requests at -httpListenAddr (aka https). -tlsCertFile and -tlsKeyFile must be set if -tls is set
|
||||
-tlsCertFile string
|
||||
@@ -1494,7 +1515,7 @@ spec:
|
||||
|
||||
### Development build
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make vmalert` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds `vmalert` binary and puts it into the `bin` folder.
|
||||
|
||||
@@ -1510,7 +1531,7 @@ ARM build may run on Raspberry Pi or on [energy-efficient ARM servers](https://b
|
||||
|
||||
### Development ARM build
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make vmalert-linux-arm` or `make vmalert-linux-arm64` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds `vmalert-linux-arm` or `vmalert-linux-arm64` binary respectively and puts it into the `bin` folder.
|
||||
|
||||
|
||||
@@ -872,7 +872,6 @@ func TestAlertingRule_Template(t *testing.T) {
|
||||
gotAlert := tc.rule.alerts[hash]
|
||||
if gotAlert == nil {
|
||||
t.Fatalf("alert %d is missing; labels: %v; annotations: %v", hash, expAlert.Labels, expAlert.Annotations)
|
||||
break
|
||||
}
|
||||
if !reflect.DeepEqual(expAlert.Annotations, gotAlert.Annotations) {
|
||||
t.Fatalf("expected to have annotations %#v; got %#v", expAlert.Annotations, gotAlert.Annotations)
|
||||
|
||||
@@ -16,7 +16,7 @@ var (
|
||||
addr = flag.String("datasource.url", "", "Datasource compatible with Prometheus HTTP API. It can be single node VictoriaMetrics or vmselect URL. Required parameter. "+
|
||||
"E.g. http://127.0.0.1:8428 . See also -remoteRead.disablePathAppend and -datasource.showURL")
|
||||
appendTypePrefix = flag.Bool("datasource.appendTypePrefix", false, "Whether to add type prefix to -datasource.url based on the query type. Set to true if sending different query types to the vmselect URL.")
|
||||
showDatasourceURL = flag.Bool("datasource.showURL", false, "Whether to show -datasource.url in the exported metrics. "+
|
||||
showDatasourceURL = flag.Bool("datasource.showURL", false, "Whether to avoid stripping sensitive information such as auth headers or passwords from URLs in log messages or UI and exported metrics. "+
|
||||
"It is hidden by default, since it can contain sensitive info such as auth key")
|
||||
|
||||
headers = flag.String("datasource.headers", "", "Optional HTTP extraHeaders to send with each request to the corresponding -datasource.url. "+
|
||||
@@ -62,6 +62,11 @@ func InitSecretFlags() {
|
||||
}
|
||||
}
|
||||
|
||||
// ShowDatasourceURL whether to show -datasource.url with sensitive information
|
||||
func ShowDatasourceURL() bool {
|
||||
return *showDatasourceURL
|
||||
}
|
||||
|
||||
// Param represents an HTTP GET param
|
||||
type Param struct {
|
||||
Key, Value string
|
||||
|
||||
@@ -91,8 +91,15 @@ func (s *VMStorage) ApplyParams(params QuerierParams) *VMStorage {
|
||||
s.extraParams = url.Values{}
|
||||
}
|
||||
for k, vl := range params.QueryParams {
|
||||
for _, v := range vl { // custom query params are prior to default ones
|
||||
s.extraParams.Set(k, v)
|
||||
// custom query params are prior to default ones
|
||||
if s.extraParams.Has(k) {
|
||||
s.extraParams.Del(k)
|
||||
}
|
||||
for _, v := range vl {
|
||||
// don't use .Set() instead of Del/Add since it is allowed
|
||||
// for GET params to be duplicated
|
||||
// see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4908
|
||||
s.extraParams.Add(k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,21 +134,14 @@ func NewVMStorage(baseURL string, authCfg *promauth.Config, lookBack time.Durati
|
||||
|
||||
// Query executes the given query and returns parsed response
|
||||
func (s *VMStorage) Query(ctx context.Context, query string, ts time.Time) (Result, *http.Request, error) {
|
||||
req, err := s.newRequestPOST()
|
||||
if err != nil {
|
||||
return Result{}, nil, err
|
||||
}
|
||||
|
||||
switch s.dataSourceType {
|
||||
case "", datasourcePrometheus:
|
||||
s.setPrometheusInstantReqParams(req, query, ts)
|
||||
case datasourceGraphite:
|
||||
s.setGraphiteReqParams(req, query, ts)
|
||||
default:
|
||||
return Result{}, nil, fmt.Errorf("engine not found: %q", s.dataSourceType)
|
||||
}
|
||||
|
||||
req := s.newQueryRequest(query, ts)
|
||||
resp, err := s.do(ctx, req)
|
||||
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
// something in the middle between client and datasource might be closing
|
||||
// the connection. So we do a one more attempt in hope request will succeed.
|
||||
req = s.newQueryRequest(query, ts)
|
||||
resp, err = s.do(ctx, req)
|
||||
}
|
||||
if err != nil {
|
||||
return Result{}, req, err
|
||||
}
|
||||
@@ -164,18 +164,20 @@ func (s *VMStorage) QueryRange(ctx context.Context, query string, start, end tim
|
||||
if s.dataSourceType != datasourcePrometheus {
|
||||
return res, fmt.Errorf("%q is not supported for QueryRange", s.dataSourceType)
|
||||
}
|
||||
req, err := s.newRequestPOST()
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
if start.IsZero() {
|
||||
return res, fmt.Errorf("start param is missing")
|
||||
}
|
||||
if end.IsZero() {
|
||||
return res, fmt.Errorf("end param is missing")
|
||||
}
|
||||
s.setPrometheusRangeReqParams(req, query, start, end)
|
||||
req := s.newQueryRangeRequest(query, start, end)
|
||||
resp, err := s.do(ctx, req)
|
||||
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
// something in the middle between client and datasource might be closing
|
||||
// the connection. So we do a one more attempt in hope request will succeed.
|
||||
req = s.newQueryRangeRequest(query, start, end)
|
||||
resp, err = s.do(ctx, req)
|
||||
}
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@@ -186,30 +188,48 @@ func (s *VMStorage) QueryRange(ctx context.Context, query string, start, end tim
|
||||
}
|
||||
|
||||
func (s *VMStorage) do(ctx context.Context, req *http.Request) (*http.Response, error) {
|
||||
ru := req.URL.Redacted()
|
||||
if *showDatasourceURL {
|
||||
ru = req.URL.String()
|
||||
}
|
||||
if s.debug {
|
||||
logger.Infof("DEBUG datasource request: executing %s request with params %q", req.Method, req.URL.RawQuery)
|
||||
logger.Infof("DEBUG datasource request: executing %s request with params %q", req.Method, ru)
|
||||
}
|
||||
resp, err := s.c.Do(req.WithContext(ctx))
|
||||
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
// something in the middle between client and datasource might be closing
|
||||
// the connection. So we do a one more attempt in hope request will succeed.
|
||||
resp, err = s.c.Do(req.WithContext(ctx))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting response from %s: %w", req.URL.Redacted(), err)
|
||||
return nil, fmt.Errorf("error getting response from %s: %w", ru, err)
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
_ = resp.Body.Close()
|
||||
return nil, fmt.Errorf("unexpected response code %d for %s. Response body %s", resp.StatusCode, req.URL.Redacted(), body)
|
||||
return nil, fmt.Errorf("unexpected response code %d for %s. Response body %s", resp.StatusCode, ru, body)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *VMStorage) newRequestPOST() (*http.Request, error) {
|
||||
func (s *VMStorage) newQueryRangeRequest(query string, start, end time.Time) *http.Request {
|
||||
req := s.newRequest()
|
||||
s.setPrometheusRangeReqParams(req, query, start, end)
|
||||
return req
|
||||
}
|
||||
|
||||
func (s *VMStorage) newQueryRequest(query string, ts time.Time) *http.Request {
|
||||
req := s.newRequest()
|
||||
switch s.dataSourceType {
|
||||
case "", datasourcePrometheus:
|
||||
s.setPrometheusInstantReqParams(req, query, ts)
|
||||
case datasourceGraphite:
|
||||
s.setGraphiteReqParams(req, query, ts)
|
||||
default:
|
||||
logger.Panicf("BUG: engine not found: %q", s.dataSourceType)
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
||||
func (s *VMStorage) newRequest() *http.Request {
|
||||
req, err := http.NewRequest(http.MethodPost, s.datasourceURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
logger.Panicf("BUG: unexpected error from http.NewRequest(%q): %s", s.datasourceURL, err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
if s.authCfg != nil {
|
||||
@@ -218,5 +238,5 @@ func (s *VMStorage) newRequestPOST() (*http.Request, error) {
|
||||
for _, h := range s.extraHeaders {
|
||||
req.Header.Set(h.key, h.value)
|
||||
}
|
||||
return req, nil
|
||||
return req
|
||||
}
|
||||
|
||||
@@ -596,6 +596,17 @@ func TestRequestParams(t *testing.T) {
|
||||
checkEqualString(t, exp.Encode(), r.URL.RawQuery)
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow duplicates in query params",
|
||||
false,
|
||||
storage.Clone().ApplyParams(QuerierParams{
|
||||
QueryParams: url.Values{"extra_labels": {"env=dev", "foo=bar"}},
|
||||
}),
|
||||
func(t *testing.T, r *http.Request) {
|
||||
exp := url.Values{"query": {query}, "round_digits": {"10"}, "extra_labels": {"env=dev", "foo=bar"}, "time": {timestamp.Format(time.RFC3339)}}
|
||||
checkEqualString(t, exp.Encode(), r.URL.RawQuery)
|
||||
},
|
||||
},
|
||||
{
|
||||
"graphite extra params",
|
||||
false,
|
||||
@@ -629,10 +640,7 @@ func TestRequestParams(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
req, err := tc.vm.newRequestPOST()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
req := tc.vm.newRequest()
|
||||
switch tc.vm.dataSourceType {
|
||||
case "", datasourcePrometheus:
|
||||
if tc.queryRange {
|
||||
@@ -727,10 +735,7 @@ func TestHeaders(t *testing.T) {
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
vm := tt.vmFn()
|
||||
req, err := vm.newRequestPOST()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
req := vm.newQueryRequest("foo", time.Now())
|
||||
tt.checkFn(t, req)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@ func main() {
|
||||
remoteread.InitSecretFlags()
|
||||
remotewrite.InitSecretFlags()
|
||||
datasource.InitSecretFlags()
|
||||
notifier.InitSecretFlags()
|
||||
buildinfo.Init()
|
||||
logger.Init()
|
||||
pushmetrics.Init()
|
||||
|
||||
@@ -87,10 +87,10 @@ groups:
|
||||
)
|
||||
|
||||
f, err := os.CreateTemp("", "")
|
||||
defer os.Remove(f.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() { _ = os.Remove(f.Name()) }()
|
||||
writeToFile(t, f.Name(), rules1)
|
||||
|
||||
*configCheckInterval = 200 * time.Millisecond
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -17,7 +18,7 @@ import (
|
||||
// AlertManager represents integration provider with Prometheus alert manager
|
||||
// https://github.com/prometheus/alertmanager
|
||||
type AlertManager struct {
|
||||
addr string
|
||||
addr *url.URL
|
||||
argFunc AlertURLGenerator
|
||||
client *http.Client
|
||||
timeout time.Duration
|
||||
@@ -48,7 +49,12 @@ func (am *AlertManager) Close() {
|
||||
}
|
||||
|
||||
// Addr returns address where alerts are sent.
|
||||
func (am AlertManager) Addr() string { return am.addr }
|
||||
func (am AlertManager) Addr() string {
|
||||
if *showNotifierURL {
|
||||
return am.addr.String()
|
||||
}
|
||||
return am.addr.Redacted()
|
||||
}
|
||||
|
||||
// Send an alert or resolve message
|
||||
func (am *AlertManager) Send(ctx context.Context, alerts []Alert, headers map[string]string) error {
|
||||
@@ -64,7 +70,7 @@ func (am *AlertManager) send(ctx context.Context, alerts []Alert, headers map[st
|
||||
b := &bytes.Buffer{}
|
||||
writeamRequest(b, alerts, am.argFunc, am.relabelConfigs)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, am.addr, b)
|
||||
req, err := http.NewRequest(http.MethodPost, am.addr.String(), b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -91,12 +97,16 @@ func (am *AlertManager) send(ctx context.Context, alerts []Alert, headers map[st
|
||||
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
amURL := am.addr.Redacted()
|
||||
if *showNotifierURL {
|
||||
amURL = am.addr.String()
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response from %q: %w", am.addr, err)
|
||||
return fmt.Errorf("failed to read response from %q: %w", amURL, err)
|
||||
}
|
||||
return fmt.Errorf("invalid SC %d from %q; response body: %s", resp.StatusCode, am.addr, string(body))
|
||||
return fmt.Errorf("invalid SC %d from %q; response body: %s", resp.StatusCode, amURL, string(body))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -136,8 +146,15 @@ func NewAlertManager(alertManagerURL string, fn AlertURLGenerator, authCfg proma
|
||||
return nil, fmt.Errorf("failed to configure auth: %w", err)
|
||||
}
|
||||
|
||||
amURL, err := url.Parse(alertManagerURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("provided incorrect notifier url: %w", err)
|
||||
}
|
||||
if !*showNotifierURL {
|
||||
alertManagerURL = amURL.Redacted()
|
||||
}
|
||||
return &AlertManager{
|
||||
addr: alertManagerURL,
|
||||
addr: amURL,
|
||||
argFunc: fn,
|
||||
authCfg: aCfg,
|
||||
relabelConfigs: relabelCfg,
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
|
||||
func TestConfigWatcherReload(t *testing.T) {
|
||||
f, err := os.CreateTemp("", "")
|
||||
defer os.Remove(f.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -37,7 +36,6 @@ static_configs:
|
||||
}
|
||||
|
||||
f2, err := os.CreateTemp("", "")
|
||||
defer os.Remove(f2.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -65,7 +63,6 @@ func TestConfigWatcherStart(t *testing.T) {
|
||||
defer consulSDServer.Close()
|
||||
|
||||
consulSDFile, err := os.CreateTemp("", "")
|
||||
defer os.Remove(consulSDFile.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -112,7 +109,6 @@ func TestConfigWatcherReloadConcurrent(t *testing.T) {
|
||||
defer consulSDServer2.Close()
|
||||
|
||||
consulSDFile, err := os.CreateTemp("", "")
|
||||
defer os.Remove(consulSDFile.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -129,7 +125,6 @@ consul_sd_configs:
|
||||
`, consulSDServer1.URL, consulSDServer2.URL))
|
||||
|
||||
staticAndConsulSDFile, err := os.CreateTemp("", "")
|
||||
defer os.Remove(staticAndConsulSDFile.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ var (
|
||||
|
||||
addrs = flagutil.NewArrayString("notifier.url", "Prometheus Alertmanager URL, e.g. http://127.0.0.1:9093. "+
|
||||
"List all Alertmanager URLs if it runs in the cluster mode to ensure high availability.")
|
||||
showNotifierURL = flag.Bool("notifier.showURL", false, "Whether to avoid stripping sensitive information such as passwords from URL in log messages or UI for -notifier.url. "+
|
||||
"It is hidden by default, since it can contain sensitive info such as auth key")
|
||||
blackHole = flag.Bool("notifier.blackhole", false, "Whether to blackhole alerting notifications. "+
|
||||
"Enable this flag if you want vmalert to evaluate alerting rules without sending any notifications to external receivers (eg. alertmanager). "+
|
||||
"`-notifier.url`, `-notifier.config` and `-notifier.blackhole` are mutually exclusive.")
|
||||
@@ -129,6 +131,13 @@ func Init(gen AlertURLGenerator, extLabels map[string]string, extURL string) (fu
|
||||
return cw.notifiers, nil
|
||||
}
|
||||
|
||||
// InitSecretFlags must be called after flag.Parse and before any logging
|
||||
func InitSecretFlags() {
|
||||
if !*showNotifierURL {
|
||||
flagutil.RegisterSecretFlag("notifier.url")
|
||||
}
|
||||
}
|
||||
|
||||
func notifiersFromFlags(gen AlertURLGenerator) ([]Notifier, error) {
|
||||
var notifiers []Notifier
|
||||
for i, addr := range *addrs {
|
||||
|
||||
@@ -216,7 +216,9 @@ func (c *Client) flush(ctx context.Context, wr *prompbmarshal.WriteRequest) {
|
||||
retryInterval = maxRetryInterval
|
||||
}
|
||||
timeStart := time.Now()
|
||||
defer sendDuration.Add(time.Since(timeStart).Seconds())
|
||||
defer func() {
|
||||
sendDuration.Add(time.Since(timeStart).Seconds())
|
||||
}()
|
||||
L:
|
||||
for attempts := 0; ; attempts++ {
|
||||
err := c.send(ctx, b)
|
||||
|
||||
@@ -79,7 +79,7 @@ func TestRule_state(t *testing.T) {
|
||||
// TestRule_stateConcurrent supposed to test concurrent
|
||||
// execution of state updates.
|
||||
// Should be executed with -race flag
|
||||
func TestRule_stateConcurrent(t *testing.T) {
|
||||
func TestRule_stateConcurrent(_ *testing.T) {
|
||||
state := newRuleState(20)
|
||||
|
||||
const workers = 50
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/datasource"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
|
||||
)
|
||||
|
||||
@@ -80,6 +81,9 @@ func requestToCurl(req *http.Request) string {
|
||||
|
||||
schema := req.URL.Scheme
|
||||
requestURL := req.URL.String()
|
||||
if !datasource.ShowDatasourceURL() {
|
||||
requestURL = req.URL.Redacted()
|
||||
}
|
||||
if schema == "" {
|
||||
schema = "http"
|
||||
if req.TLS != nil {
|
||||
@@ -103,9 +107,25 @@ func requestToCurl(req *http.Request) string {
|
||||
|
||||
for _, k := range keys {
|
||||
cw.add("-H")
|
||||
if !datasource.ShowDatasourceURL() && isSecreteHeader(k) {
|
||||
cw.addWithEsc(fmt.Sprintf("%s: <secret>", k))
|
||||
continue
|
||||
}
|
||||
cw.addWithEsc(fmt.Sprintf("%s: %s", k, strings.Join(req.Header[k], " ")))
|
||||
}
|
||||
|
||||
cw.addWithEsc(requestURL)
|
||||
return cw.string()
|
||||
}
|
||||
|
||||
var secretWords = []string{"auth", "pass", "key", "secret", "token"}
|
||||
|
||||
func isSecreteHeader(str string) bool {
|
||||
s := strings.ToLower(str)
|
||||
for _, secret := range secretWords {
|
||||
if strings.Contains(s, secret) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func TestErrGroup(t *testing.T) {
|
||||
// TestErrGroupConcurrent supposed to test concurrent
|
||||
// use of error group.
|
||||
// Should be executed with -race flag
|
||||
func TestErrGroupConcurrent(t *testing.T) {
|
||||
func TestErrGroupConcurrent(_ *testing.T) {
|
||||
eg := new(ErrGroup)
|
||||
|
||||
const writersN = 4
|
||||
|
||||
@@ -7,41 +7,69 @@ import (
|
||||
|
||||
func TestRequestToCurl(t *testing.T) {
|
||||
f := func(req *http.Request, exp string) {
|
||||
t.Helper()
|
||||
got := requestToCurl(req)
|
||||
if got != exp {
|
||||
t.Fatalf("expected to have %q; got %q instead", exp, got)
|
||||
}
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest(http.MethodPost, "foo.com", nil)
|
||||
newReq := func(url string, queryParams ...string) *http.Request {
|
||||
t.Helper()
|
||||
r, err := http.NewRequest(http.MethodPost, url, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
params := r.URL.Query()
|
||||
for i := 0; i < len(queryParams); i += 2 {
|
||||
params.Add(queryParams[i], queryParams[i+1])
|
||||
}
|
||||
r.URL.RawQuery = params.Encode()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
req := newReq("foo.com")
|
||||
f(req, "curl -X POST 'http://foo.com'")
|
||||
|
||||
req, _ = http.NewRequest(http.MethodGet, "https://foo.com", nil)
|
||||
f(req, "curl -k -X GET 'https://foo.com'")
|
||||
|
||||
req, _ = http.NewRequest(http.MethodPost, "foo.com", nil)
|
||||
req = newReq("foo.com")
|
||||
req.Header.Set("foo", "bar")
|
||||
req.Header.Set("baz", "qux")
|
||||
f(req, "curl -X POST -H 'Baz: qux' -H 'Foo: bar' 'http://foo.com'")
|
||||
|
||||
req, _ = http.NewRequest(http.MethodPost, "foo.com", nil)
|
||||
params := req.URL.Query()
|
||||
params.Add("query", "up")
|
||||
params.Add("step", "10")
|
||||
req.URL.RawQuery = params.Encode()
|
||||
req = newReq("foo.com", "query", "up", "step", "10")
|
||||
f(req, "curl -X POST 'http://foo.com?query=up&step=10'")
|
||||
|
||||
req, _ = http.NewRequest(http.MethodPost, "http://foo.com", nil)
|
||||
params = req.URL.Query()
|
||||
params.Add("query", "up")
|
||||
params.Add("step", "10")
|
||||
req.URL.RawQuery = params.Encode()
|
||||
req = newReq("http://foo.com", "query", "up", "step", "10")
|
||||
f(req, "curl -X POST 'http://foo.com?query=up&step=10'")
|
||||
|
||||
req, _ = http.NewRequest(http.MethodPost, "https://foo.com", nil)
|
||||
params = req.URL.Query()
|
||||
params.Add("query", "up")
|
||||
params.Add("step", "10")
|
||||
req.URL.RawQuery = params.Encode()
|
||||
req = newReq("https://foo.com", "query", "up", "step", "10")
|
||||
f(req, "curl -k -X POST 'https://foo.com?query=up&step=10'")
|
||||
|
||||
req = newReq("https://user:pass@foo.com", "query", "up", "step", "10")
|
||||
f(req, "curl -k -X POST 'https://user:xxxxx@foo.com?query=up&step=10'")
|
||||
|
||||
req = newReq("https://user:pass@foo.com")
|
||||
req.Header.Set("Authorisation", "Bearer 123456")
|
||||
f(req, "curl -k -X POST -H 'Authorisation: <secret>' 'https://user:xxxxx@foo.com'")
|
||||
|
||||
req = newReq("https://user:pass@foo.com")
|
||||
req.Header.Set("Authorisation", "Basic 123456")
|
||||
f(req, "curl -k -X POST -H 'Authorisation: <secret>' 'https://user:xxxxx@foo.com'")
|
||||
|
||||
req = newReq("https://foo.com")
|
||||
req.Header.Set("My-Password", "mypassword")
|
||||
f(req, "curl -k -X POST -H 'My-Password: <secret>' 'https://foo.com'")
|
||||
|
||||
req = newReq("https://foo.com")
|
||||
req.Header.Set("key-for", "my-new-key")
|
||||
f(req, "curl -k -X POST -H 'Key-For: <secret>' 'https://foo.com'")
|
||||
|
||||
req = newReq("https://foo.com")
|
||||
req.Header.Set("My-Secret-Org", "secret-organisation")
|
||||
f(req, "curl -k -X POST -H 'My-Secret-Org: <secret>' 'https://foo.com'")
|
||||
|
||||
req = newReq("https://foo.com")
|
||||
req.Header.Set("Token", "secret-token")
|
||||
f(req, "curl -k -X POST -H 'Token: <secret>' 'https://foo.com'")
|
||||
}
|
||||
|
||||
@@ -181,6 +181,8 @@ users:
|
||||
# For example, request to http://vmauth:8427/non/existing/path are proxied:
|
||||
# - to http://default1:8888/unsupported_url_handler?request_path=/non/existing/path
|
||||
# - or http://default2:8888/unsupported_url_handler?request_path=/non/existing/path
|
||||
#
|
||||
# Regular expressions are allowed in `src_paths` entries.
|
||||
- username: "foobar"
|
||||
url_map:
|
||||
- src_paths:
|
||||
@@ -201,6 +203,11 @@ users:
|
||||
- "http://default2:8888/unsupported_url_handler"
|
||||
|
||||
# Requests without Authorization header are routed according to `unauthorized_user` section.
|
||||
# Requests are routed in round-robin fashion between `url_prefix` backends.
|
||||
# The deny_partial_response query arg is added to all the routed requests.
|
||||
# The requests are re-tried if url_prefix backends send 500 or 503 response status codes.
|
||||
# Note that the unauthorized_user section takes precedence when processing a route without credentials,
|
||||
# even if such a route also exists in the users section (see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5236).
|
||||
unauthorized_user:
|
||||
url_map:
|
||||
- src_paths:
|
||||
@@ -276,7 +283,7 @@ It is recommended using [binary releases](https://github.com/VictoriaMetrics/Vic
|
||||
|
||||
### Development build
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make vmauth` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds `vmauth` binary and puts it into the `bin` folder.
|
||||
|
||||
@@ -350,9 +357,9 @@ See the docs at https://docs.victoriametrics.com/vmauth.html .
|
||||
-envflag.prefix string
|
||||
Prefix for environment variables if -envflag.enable is set
|
||||
-eula
|
||||
By specifying this flag, you confirm that you have an enterprise license and accept the EULA https://victoriametrics.com/assets/VM_EULA.pdf . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Deprecated, please use -license or -licenseFile flags instead. By specifying this flag, you confirm that you have an enterprise license and accept the ESA https://victoriametrics.com/legal/esa/ . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-failTimeout duration
|
||||
Sets a delay period for load balancing to skip a malfunctioning backend. (defaults 3s)
|
||||
Sets a delay period for load balancing to skip a malfunctioning backend. (default 3s)
|
||||
-flagsAuthKey string
|
||||
Auth key for /flags endpoint. It must be passed via authKey query arg. It overrides httpAuth.* settings
|
||||
-fs.disableMmap
|
||||
@@ -383,6 +390,12 @@ See the docs at https://docs.victoriametrics.com/vmauth.html .
|
||||
Whether to disable caches for interned strings. This may reduce memory usage at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringCacheExpireDuration and -internStringMaxLen
|
||||
-internStringMaxLen int
|
||||
The maximum length for strings to intern. A lower limit may save memory at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringDisableCache and -internStringCacheExpireDuration (default 500)
|
||||
-license string
|
||||
Lisense key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed via file specified by -licenseFile command-line flag
|
||||
-license.forceOffline
|
||||
Whether to enable offline verification for VictoriaMetrics Enterprise license key, which has been passed either via -license or via -licenseFile command-line flag. The issued license key must support offline verification feature. Contact info@victoriametrics.com if you need offline license verification. This flag is avilable only in Enterprise binaries
|
||||
-licenseFile string
|
||||
Path to file with license key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed inline via -license command-line flag
|
||||
-logInvalidAuthTokens
|
||||
Whether to log requests with invalid auth tokens. Such requests are always counted at vmauth_http_request_errors_total{reason="invalid_auth_token"} metric, which is exposed at /metrics page
|
||||
-loggerDisableTimestamps
|
||||
|
||||
@@ -378,6 +378,18 @@ func parseAuthConfig(data []byte) (*AuthConfig, error) {
|
||||
}
|
||||
ui := ac.UnauthorizedUser
|
||||
if ui != nil {
|
||||
if ui.Username != "" {
|
||||
return nil, fmt.Errorf("field username can't be specified for unauthorized_user section")
|
||||
}
|
||||
if ui.Password != "" {
|
||||
return nil, fmt.Errorf("field password can't be specified for unauthorized_user section")
|
||||
}
|
||||
if ui.BearerToken != "" {
|
||||
return nil, fmt.Errorf("field bearer_token can't be specified for unauthorized_user section")
|
||||
}
|
||||
if ui.Name != "" {
|
||||
return nil, fmt.Errorf("field name can't be specified for unauthorized_user section")
|
||||
}
|
||||
ui.requests = metrics.GetOrCreateCounter(`vmauth_unauthorized_user_requests_total`)
|
||||
ui.requestsDuration = metrics.GetOrCreateSummary(`vmauth_unauthorized_user_request_duration_seconds`)
|
||||
ui.concurrencyLimitCh = make(chan struct{}, ui.getMaxConcurrentRequests())
|
||||
|
||||
@@ -76,6 +76,8 @@ users:
|
||||
# For example, request to http://vmauth:8427/non/existing/path are proxied:
|
||||
# - to http://default1:8888/unsupported_url_handler?request_path=/non/existing/path
|
||||
# - or http://default2:8888/unsupported_url_handler?request_path=/non/existing/path
|
||||
#
|
||||
# Regular expressions are allowed in `src_paths` entries.
|
||||
- username: "foobar"
|
||||
url_map:
|
||||
- src_paths:
|
||||
|
||||
@@ -20,6 +20,8 @@ users:
|
||||
# For example, request to http://vmauth:8427/non/existing/path are proxied:
|
||||
# - to http://default1:8888/unsupported_url_handler?request_path=/non/existing/path
|
||||
# - or http://default2:8888/unsupported_url_handler?request_path=/non/existing/path
|
||||
#
|
||||
# Regular expressions are allowed in `src_paths` entries.
|
||||
- username: "foobar"
|
||||
url_map:
|
||||
- src_paths:
|
||||
|
||||
@@ -154,8 +154,16 @@ func processRequest(w http.ResponseWriter, r *http.Request, ui *UserInfo) {
|
||||
up, headers := ui.getURLPrefixAndHeaders(u)
|
||||
isDefault := false
|
||||
if up == nil {
|
||||
missingRouteRequests.Inc()
|
||||
if ui.DefaultURL == nil {
|
||||
// Authorization should be requested for http requests without credentials
|
||||
// to a route that is not in the configuration for unauthorized user.
|
||||
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5236
|
||||
if ui.BearerToken == "" && ui.Username == "" && len(*authUsers.Load()) > 0 {
|
||||
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||
http.Error(w, "missing `Authorization` request header", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
missingRouteRequests.Inc()
|
||||
httpserver.Errorf(w, r, "missing route for %q", u.String())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ See [this article](https://medium.com/@valyala/speeding-up-backups-for-big-time-
|
||||
-envflag.prefix string
|
||||
Prefix for environment variables if -envflag.enable is set
|
||||
-eula
|
||||
By specifying this flag, you confirm that you have an enterprise license and accept the EULA https://victoriametrics.com/assets/VM_EULA.pdf . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Deprecated, please use -license or -licenseFile flags instead. By specifying this flag, you confirm that you have an enterprise license and accept the ESA https://victoriametrics.com/legal/esa/ . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-flagsAuthKey string
|
||||
Auth key for /flags endpoint. It must be passed via authKey query arg. It overrides httpAuth.* settings
|
||||
-fs.disableMmap
|
||||
@@ -225,6 +225,12 @@ See [this article](https://medium.com/@valyala/speeding-up-backups-for-big-time-
|
||||
Whether to disable caches for interned strings. This may reduce memory usage at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringCacheExpireDuration and -internStringMaxLen
|
||||
-internStringMaxLen int
|
||||
The maximum length for strings to intern. A lower limit may save memory at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringDisableCache and -internStringCacheExpireDuration (default 500)
|
||||
-license string
|
||||
Lisense key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed via file specified by -licenseFile command-line flag
|
||||
-license.forceOffline
|
||||
Whether to enable offline verification for VictoriaMetrics Enterprise license key, which has been passed either via -license or via -licenseFile command-line flag. The issued license key must support offline verification feature. Contact info@victoriametrics.com if you need offline license verification. This flag is avilable only in Enterprise binaries
|
||||
-licenseFile string
|
||||
Path to file with license key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed inline via -license command-line flag
|
||||
-loggerDisableTimestamps
|
||||
Whether to disable writing timestamps in logs
|
||||
-loggerErrorsPerSecondLimit int
|
||||
@@ -263,10 +269,6 @@ See [this article](https://medium.com/@valyala/speeding-up-backups-for-big-time-
|
||||
-pushmetrics.url array
|
||||
Optional URL to push metrics exposed at /metrics page. See https://docs.victoriametrics.com/#push-metrics . By default, metrics exposed at /metrics page aren't pushed to any remote storage
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-s2a_enable_appengine_dialer
|
||||
If true, opportunistically use AppEngine-specific dialer to call S2A.
|
||||
-s2a_timeout duration
|
||||
Timeout enforced on the connection to the S2A service for handshake. (default 3s)
|
||||
-s3ForcePathStyle
|
||||
Prefixing endpoint with bucket name when set false, true by default. (default true)
|
||||
-s3StorageClass string
|
||||
@@ -301,7 +303,7 @@ It is recommended using [binary releases](https://github.com/VictoriaMetrics/Vic
|
||||
|
||||
### Development build
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make vmbackup` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds `vmbackup` binary and puts it into the `bin` folder.
|
||||
|
||||
|
||||
@@ -205,7 +205,20 @@ func hasFilepathPrefix(path, prefix string) bool {
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return strings.HasPrefix(pathAbs, prefixAbs)
|
||||
if prefixAbs == pathAbs {
|
||||
return true
|
||||
}
|
||||
rel, err := filepath.Rel(prefixAbs, pathAbs)
|
||||
if err != nil {
|
||||
// if paths can't be related - they don't match
|
||||
return false
|
||||
}
|
||||
if i := strings.Index(rel, "."); i == 0 {
|
||||
// if path can be related only with . as first char - they still don't match
|
||||
return false
|
||||
}
|
||||
// if paths are related - it is a match
|
||||
return true
|
||||
}
|
||||
|
||||
func newOriginFS() (common.OriginFS, error) {
|
||||
|
||||
@@ -26,4 +26,9 @@ func TestHasFilepathPrefix(t *testing.T) {
|
||||
f("fs://"+pwd+"/foo", pwd+"/foo/bar", false)
|
||||
f("fs://"+pwd+"/foo/bar", pwd+"/foo", true)
|
||||
f("fs://"+pwd+"/foo", pwd+"/bar", false)
|
||||
f("fs:///data1", "/data", false)
|
||||
f("fs:///data", "/data1", false)
|
||||
f("fs:///data", "/data/foo", false)
|
||||
f("fs:///data/foo", "/data", true)
|
||||
f("fs:///data/foo/", "/data/", true)
|
||||
}
|
||||
|
||||
@@ -429,7 +429,7 @@ command-line flags:
|
||||
-envflag.prefix string
|
||||
Prefix for environment variables if -envflag.enable is set
|
||||
-eula
|
||||
By specifying this flag, you confirm that you have an enterprise license and accept the EULA https://victoriametrics.com/assets/VM_EULA.pdf . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Deprecated, please use -license or -licenseFile flags instead. By specifying this flag, you confirm that you have an enterprise license and accept the ESA https://victoriametrics.com/legal/esa/ . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-flagsAuthKey string
|
||||
Auth key for /flags endpoint. It must be passed via authKey query arg. It overrides httpAuth.* settings
|
||||
-fs.disableMmap
|
||||
@@ -466,6 +466,12 @@ command-line flags:
|
||||
Keep last N monthly backups. If 0 is specified next retention cycle removes all backups for given time period. (default -1)
|
||||
-keepLastWeekly int
|
||||
Keep last N weekly backups. If 0 is specified next retention cycle removes all backups for given time period. (default -1)
|
||||
-license string
|
||||
Lisense key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed via file specified by -licenseFile command-line flag
|
||||
-license.forceOffline
|
||||
Whether to enable offline verification for VictoriaMetrics Enterprise license key, which has been passed either via -license or via -licenseFile command-line flag. The issued license key must support offline verification feature. Contact info@victoriametrics.com if you need offline license verification. This flag is avilable only in Enterprise binaries
|
||||
-licenseFile string
|
||||
Path to file with license key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed inline via -license command-line flag
|
||||
-loggerDisableTimestamps
|
||||
Whether to disable writing timestamps in logs
|
||||
-loggerErrorsPerSecondLimit int
|
||||
@@ -503,10 +509,6 @@ command-line flags:
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-runOnStart
|
||||
Upload backups immediately after start of the service. Otherwise the backup starts on new hour
|
||||
-s2a_enable_appengine_dialer
|
||||
If true, opportunistically use AppEngine-specific dialer to call S2A.
|
||||
-s2a_timeout duration
|
||||
Timeout enforced on the connection to the S2A service for handshake. (default 3s)
|
||||
-s3ForcePathStyle
|
||||
Prefixing endpoint with bucket name when set false, true by default. (default true)
|
||||
-s3StorageClass string
|
||||
|
||||
@@ -826,7 +826,7 @@ It is possible split migration process into set of smaller batches based on time
|
||||
migrating large volumes of data as this adds indication of progress and ability to restore process from certain point
|
||||
in case of failure.
|
||||
|
||||
To use this you need to specify `--vm-native-step-interval` flag. Supported values are: `month`, `day`, `hour`, `minute`.
|
||||
To use this you need to specify `--vm-native-step-interval` flag. Supported values are: `month`, `week`, `day`, `hour`, `minute`.
|
||||
Note that in order to use this it is required `--vm-native-filter-time-start` to be set to calculate time ranges for
|
||||
export process.
|
||||
|
||||
@@ -836,7 +836,7 @@ Every range is being processed independently, which means that:
|
||||
so it is possible to restart process starting from failed range.
|
||||
|
||||
It is recommended using the `month` step when migrating the data over multiple months,
|
||||
since the migration with `day` and `hour` steps may take longer time to complete because of additional overhead.
|
||||
since the migration with `week`, `day` and `hour` steps may take longer time to complete because of additional overhead.
|
||||
|
||||
Usage example:
|
||||
```console
|
||||
@@ -1023,7 +1023,7 @@ It is recommended using [binary releases](https://github.com/VictoriaMetrics/Vic
|
||||
|
||||
### Development build
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make vmctl` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds `vmctl` binary and puts it into the `bin` folder.
|
||||
|
||||
@@ -1052,7 +1052,7 @@ ARM build may run on Raspberry Pi or on [energy-efficient ARM servers](https://b
|
||||
|
||||
#### Development ARM build
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make vmctl-linux-arm` or `make vmctl-linux-arm64` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds `vmctl-linux-arm` or `vmctl-linux-arm64` binary respectively and puts it into the `bin` folder.
|
||||
|
||||
|
||||
@@ -361,8 +361,9 @@ var (
|
||||
Usage: "The time filter may contain different timestamp formats. See more details here https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#timestamp-formats",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: vmNativeStepInterval,
|
||||
Usage: fmt.Sprintf("Split export data into chunks. Requires setting --%s. Valid values are '%s','%s','%s','%s'.", vmNativeFilterTimeStart, stepper.StepMonth, stepper.StepDay, stepper.StepHour, stepper.StepMinute),
|
||||
Name: vmNativeStepInterval,
|
||||
Usage: fmt.Sprintf("Split export data into chunks. Requires setting --%s. Valid values are '%s','%s','%s','%s','%s'.", vmNativeFilterTimeStart,
|
||||
stepper.StepMonth, stepper.StepWeek, stepper.StepDay, stepper.StepHour, stepper.StepMinute),
|
||||
Value: stepper.StepMonth,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
@@ -556,8 +557,8 @@ var (
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: remoteReadDisablePathAppend,
|
||||
Usage: "Whether to disable automatic appending of the path to the remote storage.",
|
||||
Value: true,
|
||||
Usage: "Whether to disable automatic appending of the /api/v1/read suffix to --remote-read-src-addr",
|
||||
Value: false,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -170,8 +170,5 @@ func (op *otsdbProcessor) do(s queryObj) error {
|
||||
Timestamps: data.Timestamps,
|
||||
Values: data.Values,
|
||||
}
|
||||
if err := op.im.Input(&ts); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return op.im.Input(&ts)
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ func modifyData(msg Metric, normalize bool) (Metric, error) {
|
||||
/*
|
||||
replace bad characters in metric name with _ per the data model
|
||||
*/
|
||||
finalMsg.Metric = promrelabel.SanitizeName(name)
|
||||
finalMsg.Metric = promrelabel.SanitizeMetricName(name)
|
||||
// replace bad characters in tag keys with _ per the data model
|
||||
for key, value := range msg.Tags {
|
||||
// if normalization requested, lowercase the key and value
|
||||
@@ -191,7 +191,7 @@ func modifyData(msg Metric, normalize bool) (Metric, error) {
|
||||
/*
|
||||
replace all explicitly bad characters with _
|
||||
*/
|
||||
key = promrelabel.SanitizeName(key)
|
||||
key = promrelabel.SanitizeLabelName(key)
|
||||
// tags that start with __ are considered custom stats for internal prometheus stuff, we should drop them
|
||||
if !strings.HasPrefix(key, "__") {
|
||||
finalMsg.Tags[key] = value
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
const (
|
||||
// StepMonth represents a one month interval
|
||||
StepMonth string = "month"
|
||||
// StepDay represents a one day interval
|
||||
StepDay string = "day"
|
||||
// StepWeek represents a one week interval
|
||||
StepWeek string = "week"
|
||||
// StepDay represents a one day interval
|
||||
StepDay string = "day"
|
||||
// StepHour represents a one hour interval
|
||||
StepHour string = "hour"
|
||||
// StepMinute represents a one minute interval
|
||||
|
||||
@@ -201,7 +201,12 @@ func (p *vmNativeProcessor) runBackfilling(ctx context.Context, tenantID string,
|
||||
}
|
||||
|
||||
if len(metrics) == 0 {
|
||||
return fmt.Errorf("no metrics found")
|
||||
errMsg := "no metrics found"
|
||||
if tenantID != "" {
|
||||
errMsg = fmt.Sprintf("%s for tenant id: %s", errMsg, tenantID)
|
||||
}
|
||||
log.Println(errMsg)
|
||||
return nil
|
||||
}
|
||||
foundSeriesMsg = fmt.Sprintf("Found %d metrics to import", len(metrics))
|
||||
}
|
||||
|
||||
@@ -291,6 +291,8 @@ The shortlist of configuration flags include the following:
|
||||
Optional path to bearer token file to use for -datasource.url.
|
||||
-datasource.disableKeepAlive
|
||||
Whether to disable long-lived connections to the datasource. If true, disables HTTP keep-alives and will only use the connection to the server for a single HTTP request.
|
||||
-datasource.disableStepParam
|
||||
Whether to disable adding 'step' param to the issued instant queries. This might be useful when using vmalert with datasources that do not support 'step' param for instant queries, like Google Managed Prometheus. It is not recommended to enable this flag if you use vmalert with VictoriaMetrics.
|
||||
-datasource.headers string
|
||||
Optional HTTP extraHeaders to send with each request to the corresponding -datasource.url. For example, -datasource.headers='My-Auth:foobar' would send 'My-Auth: foobar' HTTP header with every request to the corresponding -datasource.url. Multiple headers must be delimited by '^^': -datasource.headers='header1:value1^^header2:value2'
|
||||
-datasource.lookback duration
|
||||
@@ -314,7 +316,7 @@ The shortlist of configuration flags include the following:
|
||||
-datasource.roundDigits int
|
||||
Adds "round_digits" GET param to datasource requests. In VM "round_digits" limits the number of digits after the decimal point in response values.
|
||||
-datasource.showURL
|
||||
Whether to show -datasource.url in the exported metrics. It is hidden by default, since it can contain sensitive info such as auth key
|
||||
Whether to avoid stripping sensitive information such as auth headers or passwords from URLs in log messages or UI and exported metrics. It is hidden by default, since it can contain sensitive info such as auth key
|
||||
-datasource.tlsCAFile string
|
||||
Optional path to TLS CA file to use for verifying connections to -datasource.url. By default, system CA is used
|
||||
-datasource.tlsCertFile string
|
||||
@@ -338,7 +340,7 @@ The shortlist of configuration flags include the following:
|
||||
-envflag.prefix string
|
||||
Prefix for environment variables if -envflag.enable is set
|
||||
-eula
|
||||
By specifying this flag, you confirm that you have an enterprise license and accept the EULA https://victoriametrics.com/assets/VM_EULA.pdf . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Deprecated, please use -license or -licenseFile flags instead. By specifying this flag, you confirm that you have an enterprise license and accept the ESA https://victoriametrics.com/legal/esa/ . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-flagsAuthKey string
|
||||
Auth key for /flags endpoint. It must be passed via authKey query arg. It overrides httpAuth.* settings
|
||||
-fs.disableMmap
|
||||
@@ -369,6 +371,12 @@ The shortlist of configuration flags include the following:
|
||||
Whether to disable caches for interned strings. This may reduce memory usage at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringCacheExpireDuration and -internStringMaxLen
|
||||
-internStringMaxLen int
|
||||
The maximum length for strings to intern. A lower limit may save memory at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringDisableCache and -internStringCacheExpireDuration (default 500)
|
||||
-license string
|
||||
Lisense key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed via file specified by -licenseFile command-line flag
|
||||
-license.forceOffline
|
||||
Whether to enable offline verification for VictoriaMetrics Enterprise license key, which has been passed either via -license or via -licenseFile command-line flag. The issued license key must support offline verification feature. Contact info@victoriametrics.com if you need offline license verification. This flag is avilable only in Enterprise binaries
|
||||
-licenseFile string
|
||||
Path to file with license key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed inline via -license command-line flag
|
||||
-loggerDisableTimestamps
|
||||
Whether to disable writing timestamps in logs
|
||||
-loggerErrorsPerSecondLimit int
|
||||
|
||||
@@ -171,7 +171,7 @@ func (ctx *InsertCtx) dropAggregatedRows(matchIdxs []byte) {
|
||||
src := ctx.mrs
|
||||
if !*streamAggrDropInput {
|
||||
for idx, match := range matchIdxs {
|
||||
if match != 0 {
|
||||
if match == 1 {
|
||||
continue
|
||||
}
|
||||
dst = append(dst, src[idx])
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package opentelemetry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vminsert/common"
|
||||
@@ -23,6 +24,9 @@ func InsertHandler(req *http.Request) error {
|
||||
return err
|
||||
}
|
||||
isGzipped := req.Header.Get("Content-Encoding") == "gzip"
|
||||
if req.Header.Get("Content-Type") == "application/json" {
|
||||
return fmt.Errorf("json encoding isn't supported for opentelemetry format. Use protobuf encoding")
|
||||
}
|
||||
return stream.ParseStream(req.Body, isGzipped, func(tss []prompbmarshal.TimeSeries) error {
|
||||
return insertRows(tss, extraLabels)
|
||||
})
|
||||
|
||||
@@ -134,9 +134,9 @@ func (ctx *Ctx) ApplyRelabeling(labels []prompb.Label) []prompb.Label {
|
||||
for i := range tmpLabels {
|
||||
label := &tmpLabels[i]
|
||||
if label.Name == "__name__" {
|
||||
label.Value = promrelabel.SanitizeName(label.Value)
|
||||
label.Value = promrelabel.SanitizeMetricName(label.Value)
|
||||
} else {
|
||||
label.Name = promrelabel.SanitizeName(label.Name)
|
||||
label.Name = promrelabel.SanitizeLabelName(label.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ i.e. the end result would be similar to [rsync --delete](https://askubuntu.com/q
|
||||
-envflag.prefix string
|
||||
Prefix for environment variables if -envflag.enable is set
|
||||
-eula
|
||||
By specifying this flag, you confirm that you have an enterprise license and accept the EULA https://victoriametrics.com/assets/VM_EULA.pdf . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
|
||||
Deprecated, please use -license or -licenseFile flags instead. By specifying this flag, you confirm that you have an enterprise license and accept the ESA https://victoriametrics.com/legal/esa/ . This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise.html
|
||||
-flagsAuthKey string
|
||||
Auth key for /flags endpoint. It must be passed via authKey query arg. It overrides httpAuth.* settings
|
||||
-fs.disableMmap
|
||||
@@ -129,6 +129,12 @@ i.e. the end result would be similar to [rsync --delete](https://askubuntu.com/q
|
||||
Whether to disable caches for interned strings. This may reduce memory usage at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringCacheExpireDuration and -internStringMaxLen
|
||||
-internStringMaxLen int
|
||||
The maximum length for strings to intern. A lower limit may save memory at the cost of higher CPU usage. See https://en.wikipedia.org/wiki/String_interning . See also -internStringDisableCache and -internStringCacheExpireDuration (default 500)
|
||||
-license string
|
||||
Lisense key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed via file specified by -licenseFile command-line flag
|
||||
-license.forceOffline
|
||||
Whether to enable offline verification for VictoriaMetrics Enterprise license key, which has been passed either via -license or via -licenseFile command-line flag. The issued license key must support offline verification feature. Contact info@victoriametrics.com if you need offline license verification. This flag is avilable only in Enterprise binaries
|
||||
-licenseFile string
|
||||
Path to file with license key for VictoriaMetrics Enterprise. See https://victoriametrics.com/products/enterprise/ . Trial Enterprise license can be obtained from https://victoriametrics.com/products/enterprise/trial/ . This flag is available only in Enterprise binaries. The license key can be also passed inline via -license command-line flag
|
||||
-loggerDisableTimestamps
|
||||
Whether to disable writing timestamps in logs
|
||||
-loggerErrorsPerSecondLimit int
|
||||
@@ -165,10 +171,6 @@ i.e. the end result would be similar to [rsync --delete](https://askubuntu.com/q
|
||||
-pushmetrics.url array
|
||||
Optional URL to push metrics exposed at /metrics page. See https://docs.victoriametrics.com/#push-metrics . By default, metrics exposed at /metrics page aren't pushed to any remote storage
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
-s2a_enable_appengine_dialer
|
||||
If true, opportunistically use AppEngine-specific dialer to call S2A.
|
||||
-s2a_timeout duration
|
||||
Timeout enforced on the connection to the S2A service for handshake. (default 3s)
|
||||
-s3ForcePathStyle
|
||||
Prefixing endpoint with bucket name when set false, true by default. (default true)
|
||||
-s3StorageClass string
|
||||
@@ -201,7 +203,7 @@ It is recommended using [binary releases](https://github.com/VictoriaMetrics/Vic
|
||||
|
||||
### Development build
|
||||
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.19.
|
||||
1. [Install Go](https://golang.org/doc/install). The minimum supported version is Go 1.20.
|
||||
1. Run `make vmrestore` from the root folder of [the repository](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
It builds `vmrestore` binary and puts it into the `bin` folder.
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ func (as *aggrStateAvgZero) Update(values []float64) {
|
||||
as.seriesTotal++
|
||||
}
|
||||
|
||||
func (as *aggrStateAvgZero) Finalize(xFilesFactor float64) []float64 {
|
||||
func (as *aggrStateAvgZero) Finalize(_ float64) []float64 {
|
||||
sums := as.sums
|
||||
values := make([]float64, as.pointsLen)
|
||||
count := float64(as.seriesTotal)
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httputils"
|
||||
)
|
||||
@@ -14,7 +13,7 @@ import (
|
||||
// FunctionsHandler implements /functions handler.
|
||||
//
|
||||
// See https://graphite.readthedocs.io/en/latest/functions.html#function-api
|
||||
func FunctionsHandler(startTime time.Time, w http.ResponseWriter, r *http.Request) error {
|
||||
func FunctionsHandler(w http.ResponseWriter, r *http.Request) error {
|
||||
grouped := httputils.GetBool(r, "grouped")
|
||||
group := r.FormValue("group")
|
||||
result := make(map[string]interface{})
|
||||
@@ -40,7 +39,7 @@ func FunctionsHandler(startTime time.Time, w http.ResponseWriter, r *http.Reques
|
||||
// FunctionDetailsHandler implements /functions/<func_name> handler.
|
||||
//
|
||||
// See https://graphite.readthedocs.io/en/latest/functions.html#function-api
|
||||
func FunctionDetailsHandler(startTime time.Time, funcName string, w http.ResponseWriter, r *http.Request) error {
|
||||
func FunctionDetailsHandler(funcName string, w http.ResponseWriter, r *http.Request) error {
|
||||
result := funcs[funcName]
|
||||
if result == nil {
|
||||
return fmt.Errorf("cannot find function %q", funcName)
|
||||
|
||||
@@ -85,7 +85,7 @@ func MetricsFindHandler(startTime time.Time, w http.ResponseWriter, r *http.Requ
|
||||
if leavesOnly {
|
||||
paths = filterLeaves(paths, delimiter)
|
||||
}
|
||||
paths = deduplicatePaths(paths, delimiter)
|
||||
paths = deduplicatePaths(paths)
|
||||
sortPaths(paths, delimiter)
|
||||
contentType := getContentType(jsonp)
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
@@ -99,7 +99,7 @@ func MetricsFindHandler(startTime time.Time, w http.ResponseWriter, r *http.Requ
|
||||
return nil
|
||||
}
|
||||
|
||||
func deduplicatePaths(paths []string, delimiter string) []string {
|
||||
func deduplicatePaths(paths []string) []string {
|
||||
if len(paths) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ See https://graphite.readthedocs.io/en/stable/render_api.html#json
|
||||
{% code timestamps := s.Timestamps %}
|
||||
{% for i, v := range s.Values %}
|
||||
[
|
||||
{% if math.IsNaN(v) %}null{% else %}{%f= v %}{% endif %},
|
||||
{% if math.IsNaN(v) || math.IsInf(v, 0) %}null{% else %}{%f= v %}{% endif %},
|
||||
{%dl= timestamps[i]/1e3 %}
|
||||
]
|
||||
{% if i+1 < len(timestamps) %},{% endif %}
|
||||
|
||||
@@ -148,7 +148,7 @@ func streamrenderSeriesJSON(qw422016 *qt422016.Writer, s *series) {
|
||||
//line app/vmselect/graphite/render_response.qtpl:48
|
||||
qw422016.N().S(`[`)
|
||||
//line app/vmselect/graphite/render_response.qtpl:50
|
||||
if math.IsNaN(v) {
|
||||
if math.IsNaN(v) || math.IsInf(v, 0) {
|
||||
//line app/vmselect/graphite/render_response.qtpl:50
|
||||
qw422016.N().S(`null`)
|
||||
//line app/vmselect/graphite/render_response.qtpl:50
|
||||
|
||||
@@ -189,7 +189,7 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
func transformTODO(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeriesFunc, error) {
|
||||
func transformTODO(_ *evalConfig, _ *graphiteql.FuncExpr) (nextSeriesFunc, error) {
|
||||
return nil, fmt.Errorf("TODO: implement this function")
|
||||
}
|
||||
|
||||
@@ -1062,7 +1062,7 @@ func transformCumulative(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeriesFun
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return consolidateBy(ec, fe, nextSeries, "sum")
|
||||
return consolidateBy(fe, nextSeries, "sum")
|
||||
}
|
||||
|
||||
// See https://graphite.readthedocs.io/en/stable/functions.html#graphite.render.functions.consolidateBy
|
||||
@@ -1079,10 +1079,10 @@ func transformConsolidateBy(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeries
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return consolidateBy(ec, fe, nextSeries, funcName)
|
||||
return consolidateBy(fe, nextSeries, funcName)
|
||||
}
|
||||
|
||||
func consolidateBy(ec *evalConfig, expr graphiteql.Expr, nextSeries nextSeriesFunc, funcName string) (nextSeriesFunc, error) {
|
||||
func consolidateBy(expr graphiteql.Expr, nextSeries nextSeriesFunc, funcName string) (nextSeriesFunc, error) {
|
||||
consolidateFunc, err := getAggrFunc(funcName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1843,10 +1843,10 @@ func transformHighest(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeriesFunc,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return highestGeneric(ec, fe, nextSeries, n, funcName)
|
||||
return highestGeneric(fe, nextSeries, n, funcName)
|
||||
}
|
||||
|
||||
func highestGeneric(ec *evalConfig, expr graphiteql.Expr, nextSeries nextSeriesFunc, n float64, funcName string) (nextSeriesFunc, error) {
|
||||
func highestGeneric(expr graphiteql.Expr, nextSeries nextSeriesFunc, n float64, funcName string) (nextSeriesFunc, error) {
|
||||
aggrFunc, err := getAggrFunc(funcName)
|
||||
if err != nil {
|
||||
_, _ = drainAllSeries(nextSeries)
|
||||
@@ -1928,7 +1928,7 @@ func transformHighestAverage(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSerie
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return highestGeneric(ec, fe, nextSeries, n, "average")
|
||||
return highestGeneric(fe, nextSeries, n, "average")
|
||||
}
|
||||
|
||||
// See https://graphite.readthedocs.io/en/stable/functions.html#graphite.render.functions.highestCurrent
|
||||
@@ -1945,7 +1945,7 @@ func transformHighestCurrent(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSerie
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return highestGeneric(ec, fe, nextSeries, n, "current")
|
||||
return highestGeneric(fe, nextSeries, n, "current")
|
||||
}
|
||||
|
||||
// See https://graphite.readthedocs.io/en/stable/functions.html#graphite.render.functions.highestMax
|
||||
@@ -1962,7 +1962,7 @@ func transformHighestMax(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeriesFun
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return highestGeneric(ec, fe, nextSeries, n, "max")
|
||||
return highestGeneric(fe, nextSeries, n, "max")
|
||||
}
|
||||
|
||||
// See https://graphite.readthedocs.io/en/stable/functions.html#graphite.render.functions.hitcount
|
||||
@@ -2379,10 +2379,10 @@ func transformLowest(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeriesFunc, e
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lowestGeneric(ec, fe, nextSeries, n, funcName)
|
||||
return lowestGeneric(fe, nextSeries, n, funcName)
|
||||
}
|
||||
|
||||
func lowestGeneric(ec *evalConfig, expr graphiteql.Expr, nextSeries nextSeriesFunc, n float64, funcName string) (nextSeriesFunc, error) {
|
||||
func lowestGeneric(expr graphiteql.Expr, nextSeries nextSeriesFunc, n float64, funcName string) (nextSeriesFunc, error) {
|
||||
aggrFunc, err := getAggrFunc(funcName)
|
||||
if err != nil {
|
||||
_, _ = drainAllSeries(nextSeries)
|
||||
@@ -2459,7 +2459,7 @@ func transformLowestAverage(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeries
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lowestGeneric(ec, fe, nextSeries, n, "average")
|
||||
return lowestGeneric(fe, nextSeries, n, "average")
|
||||
}
|
||||
|
||||
// See https://graphite.readthedocs.io/en/stable/functions.html#graphite.render.functions.lowestCurrent
|
||||
@@ -2476,7 +2476,7 @@ func transformLowestCurrent(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeries
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lowestGeneric(ec, fe, nextSeries, n, "current")
|
||||
return lowestGeneric(fe, nextSeries, n, "current")
|
||||
}
|
||||
|
||||
// See https://graphite.readthedocs.io/en/stable/functions.html#graphite.render.functions.maxSeries
|
||||
@@ -2607,7 +2607,7 @@ func transformMostDeviant(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeriesFu
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return highestGeneric(ec, fe, nextSeries, n, "stddev")
|
||||
return highestGeneric(fe, nextSeries, n, "stddev")
|
||||
}
|
||||
|
||||
// See https://graphite.readthedocs.io/en/stable/functions.html#graphite.render.functions.movingAverage
|
||||
@@ -3862,7 +3862,11 @@ func nextSeriesConcurrentWrapper(nextSeries nextSeriesFunc, f func(s *series) (*
|
||||
}
|
||||
if r.err != nil {
|
||||
// Drain the rest of series before returning the error.
|
||||
for range resultCh {
|
||||
for {
|
||||
_, ok := <-resultCh
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
<-errCh
|
||||
return nil, r.err
|
||||
@@ -4733,7 +4737,7 @@ func transformSortByTotal(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeriesFu
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sortByGeneric(ec, fe, nextSeries, "sum", true)
|
||||
return sortByGeneric(fe, nextSeries, "sum", true)
|
||||
}
|
||||
|
||||
// https://graphite.readthedocs.io/en/stable/functions.html#graphite.render.functions.sortBy
|
||||
@@ -4754,10 +4758,10 @@ func transformSortBy(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeriesFunc, e
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sortByGeneric(ec, fe, nextSeries, funcName, reverse)
|
||||
return sortByGeneric(fe, nextSeries, funcName, reverse)
|
||||
}
|
||||
|
||||
func sortByGeneric(ec *evalConfig, fe *graphiteql.FuncExpr, nextSeries nextSeriesFunc, funcName string, reverse bool) (nextSeriesFunc, error) {
|
||||
func sortByGeneric(fe *graphiteql.FuncExpr, nextSeries nextSeriesFunc, funcName string, reverse bool) (nextSeriesFunc, error) {
|
||||
aggrFunc, err := getAggrFunc(funcName)
|
||||
if err != nil {
|
||||
_, _ = drainAllSeries(nextSeries)
|
||||
@@ -4868,7 +4872,7 @@ func transformSortByMinima(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeriesF
|
||||
}
|
||||
return s, nil
|
||||
})
|
||||
return sortByGeneric(ec, fe, f, "min", false)
|
||||
return sortByGeneric(fe, f, "min", false)
|
||||
}
|
||||
|
||||
// https://graphite.readthedocs.io/en/stable/functions.html#graphite.render.functions.sortByMaxima
|
||||
@@ -4881,7 +4885,7 @@ func transformSortByMaxima(ec *evalConfig, fe *graphiteql.FuncExpr) (nextSeriesF
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sortByGeneric(ec, fe, nextSeries, "max", true)
|
||||
return sortByGeneric(fe, nextSeries, "max", true)
|
||||
}
|
||||
|
||||
// https://graphite.readthedocs.io/en/stable/functions.html#graphite.render.functions.smartSummarize
|
||||
@@ -5286,7 +5290,7 @@ func holtWinterConfidenceBands(ec *evalConfig, fe *graphiteql.FuncExpr, args []*
|
||||
f := nextSeriesConcurrentWrapper(nextSeries, func(s *series) (*series, error) {
|
||||
s.consolidate(&ecCopy, step)
|
||||
timeStamps := s.Timestamps[trimWindowPoints:]
|
||||
analysis := holtWintersAnalysis(&ecCopy, s, seasonalityMs)
|
||||
analysis := holtWintersAnalysis(s, seasonalityMs)
|
||||
forecastValues := analysis.predictions.Values[trimWindowPoints:]
|
||||
deviationValues := analysis.deviations.Values[trimWindowPoints:]
|
||||
valuesLen := len(forecastValues)
|
||||
@@ -5450,7 +5454,7 @@ func transformHoltWintersForecast(ec *evalConfig, fe *graphiteql.FuncExpr) (next
|
||||
trimWindowPoints := ecCopy.pointsLen(step) - ec.pointsLen(step)
|
||||
f := nextSeriesConcurrentWrapper(nextSeries, func(s *series) (*series, error) {
|
||||
s.consolidate(&ecCopy, step)
|
||||
analysis := holtWintersAnalysis(&ecCopy, s, seasonalityMs)
|
||||
analysis := holtWintersAnalysis(s, seasonalityMs)
|
||||
predictions := analysis.predictions
|
||||
|
||||
s.Tags["holtWintersForecast"] = "1"
|
||||
@@ -5468,7 +5472,7 @@ func transformHoltWintersForecast(ec *evalConfig, fe *graphiteql.FuncExpr) (next
|
||||
|
||||
}
|
||||
|
||||
func holtWintersAnalysis(ec *evalConfig, s *series, seasonality int64) holtWintersAnalysisResult {
|
||||
func holtWintersAnalysis(s *series, seasonality int64) holtWintersAnalysisResult {
|
||||
alpha := 0.1
|
||||
gamma := alpha
|
||||
beta := 0.0035
|
||||
|
||||
@@ -236,7 +236,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||
funcName = strings.TrimPrefix(funcName, "/")
|
||||
if funcName == "" {
|
||||
graphiteFunctionsRequests.Inc()
|
||||
if err := graphite.FunctionsHandler(startTime, w, r); err != nil {
|
||||
if err := graphite.FunctionsHandler(w, r); err != nil {
|
||||
graphiteFunctionsErrors.Inc()
|
||||
httpserver.Errorf(w, r, "%s", err)
|
||||
return true
|
||||
@@ -244,7 +244,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||
return true
|
||||
}
|
||||
graphiteFunctionDetailsRequests.Inc()
|
||||
if err := graphite.FunctionDetailsHandler(startTime, funcName, w, r); err != nil {
|
||||
if err := graphite.FunctionDetailsHandler(funcName, w, r); err != nil {
|
||||
graphiteFunctionDetailsErrors.Inc()
|
||||
httpserver.Errorf(w, r, "%s", err)
|
||||
return true
|
||||
|
||||
@@ -26,6 +26,11 @@ var (
|
||||
maxTagValuesPerSearch = flag.Int("search.maxTagValues", 100e3, "The maximum number of tag values returned from /api/v1/label/<label_name>/values")
|
||||
maxSamplesPerSeries = flag.Int("search.maxSamplesPerSeries", 30e6, "The maximum number of raw samples a single query can scan per each time series. This option allows limiting memory usage")
|
||||
maxSamplesPerQuery = flag.Int("search.maxSamplesPerQuery", 1e9, "The maximum number of raw samples a single query can process across all time series. This protects from heavy queries, which select unexpectedly high number of raw samples. See also -search.maxSamplesPerSeries")
|
||||
maxWorkersPerQuery = flag.Int("search.maxWorkersPerQuery", defaultMaxWorkersPerQuery, "The maximum number of CPU cores a single query can use. "+
|
||||
"The default value should work good for most cases. "+
|
||||
"The flag can be set to lower values for improving performance of big number of concurrently executed queries. "+
|
||||
"The flag can be set to bigger values for improving performance of heavy queries, which scan big number of time series (>10K) and/or big number of samples (>100M). "+
|
||||
"There is no sense in setting this flag to values bigger than the number of CPU cores available on the system")
|
||||
)
|
||||
|
||||
// Result is a single timeseries result.
|
||||
@@ -197,13 +202,34 @@ type result struct {
|
||||
|
||||
var resultPool sync.Pool
|
||||
|
||||
// MaxWorkers returns the maximum number of workers netstorage can spin when calling RunParallel()
|
||||
// MaxWorkers returns the maximum number of concurrent goroutines, which can be used by RunParallel()
|
||||
func MaxWorkers() int {
|
||||
return gomaxprocs
|
||||
n := *maxWorkersPerQuery
|
||||
if n <= 0 {
|
||||
return defaultMaxWorkersPerQuery
|
||||
}
|
||||
if n > gomaxprocs {
|
||||
// There is no sense in running more than gomaxprocs CPU-bound concurrent workers,
|
||||
// since this may worsen the query performance.
|
||||
n = gomaxprocs
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
var gomaxprocs = cgroup.AvailableCPUs()
|
||||
|
||||
var defaultMaxWorkersPerQuery = func() int {
|
||||
// maxWorkersLimit is the maximum number of CPU cores, which can be used in parallel
|
||||
// for processing an average query, without significant impact on inter-CPU communications.
|
||||
const maxWorkersLimit = 32
|
||||
|
||||
n := gomaxprocs
|
||||
if n > maxWorkersLimit {
|
||||
n = maxWorkersLimit
|
||||
}
|
||||
return n
|
||||
}()
|
||||
|
||||
// RunParallel runs f in parallel for all the results from rss.
|
||||
//
|
||||
// f shouldn't hold references to rs after returning.
|
||||
|
||||
@@ -649,10 +649,7 @@ func SeriesHandler(qt *querytracer.Tracer, startTime time.Time, w http.ResponseW
|
||||
qt.Donef("start=%d, end=%d", cp.start, cp.end)
|
||||
}
|
||||
WriteSeriesResponse(bw, metricNames, qt, qtDone)
|
||||
if err := bw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return bw.Flush()
|
||||
}
|
||||
|
||||
var seriesDuration = metrics.NewSummary(`vm_request_duration_seconds{path="/api/v1/series"}`)
|
||||
@@ -694,7 +691,10 @@ func QueryHandler(qt *querytracer.Tracer, startTime time.Time, w http.ResponseWr
|
||||
return err
|
||||
}
|
||||
if childQuery, windowExpr, offsetExpr := promql.IsMetricSelectorWithRollup(query); childQuery != "" {
|
||||
window := windowExpr.Duration(step)
|
||||
window, err := windowExpr.NonNegativeDuration(step)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse lookbehind window in square brackets at %s: %w", query, err)
|
||||
}
|
||||
offset := offsetExpr.Duration(step)
|
||||
start -= offset
|
||||
end := start
|
||||
@@ -723,11 +723,17 @@ func QueryHandler(qt *querytracer.Tracer, startTime time.Time, w http.ResponseWr
|
||||
return nil
|
||||
}
|
||||
if childQuery, windowExpr, stepExpr, offsetExpr := promql.IsRollup(query); childQuery != "" {
|
||||
newStep := stepExpr.Duration(step)
|
||||
newStep, err := stepExpr.NonNegativeDuration(step)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse step in square brackets at %s: %w", query, err)
|
||||
}
|
||||
if newStep > 0 {
|
||||
step = newStep
|
||||
}
|
||||
window := windowExpr.Duration(step)
|
||||
window, err := windowExpr.NonNegativeDuration(step)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse lookbehind window in square brackets at %s: %w", query, err)
|
||||
}
|
||||
offset := offsetExpr.Duration(step)
|
||||
start -= offset
|
||||
end := start
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
// ActiveQueriesHandler returns response to /api/v1/status/active_queries
|
||||
//
|
||||
// It writes a JSON with active queries to w.
|
||||
func ActiveQueriesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func ActiveQueriesHandler(w http.ResponseWriter, _ *http.Request) {
|
||||
aqes := activeQueriesV.GetAll()
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
@@ -130,7 +129,7 @@ func aggrPrepareSeries(argOrig []*timeseries, modifier *metricsql.ModifierExpr,
|
||||
for i, ts := range arg {
|
||||
removeGroupTags(&ts.MetricName, modifier)
|
||||
bb.B = marshalMetricNameSorted(bb.B[:0], &ts.MetricName)
|
||||
k := bytesutil.InternBytes(bb.B)
|
||||
k := string(bb.B)
|
||||
if keepOriginal {
|
||||
ts = argOrig[i]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/netstorage"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
|
||||
"github.com/VictoriaMetrics/metricsql"
|
||||
)
|
||||
|
||||
@@ -105,7 +104,7 @@ func (iafc *incrementalAggrFuncContext) updateTimeseries(tsOrig *timeseries, wor
|
||||
removeGroupTags(&ts.MetricName, &iafc.ae.Modifier)
|
||||
bb := bbPool.Get()
|
||||
bb.B = marshalMetricNameSorted(bb.B[:0], &ts.MetricName)
|
||||
k := bytesutil.InternBytes(bb.B)
|
||||
k := string(bb.B)
|
||||
iac := m[k]
|
||||
if iac == nil {
|
||||
if iafc.ae.Limit > 0 && len(m) >= iafc.ae.Limit {
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
|
||||
"github.com/VictoriaMetrics/metricsql"
|
||||
@@ -261,8 +260,7 @@ func groupJoin(singleTimeseriesSide string, be *metricsql.BinaryOpExpr, rvsLeft,
|
||||
bb.B = marshalMetricTagsSorted(bb.B[:0], &tsCopy.MetricName)
|
||||
pair, ok := m[string(bb.B)]
|
||||
if !ok {
|
||||
k := bytesutil.InternBytes(bb.B)
|
||||
m[k] = &tsPair{
|
||||
m[string(bb.B)] = &tsPair{
|
||||
left: &tsCopy,
|
||||
right: tsRight,
|
||||
}
|
||||
@@ -524,7 +522,7 @@ func createTimeseriesMapByTagSet(be *metricsql.BinaryOpExpr, left, right []*time
|
||||
logger.Panicf("BUG: unexpected binary op modifier %q", groupOp)
|
||||
}
|
||||
bb.B = marshalMetricTagsSorted(bb.B[:0], mn)
|
||||
k := bytesutil.InternBytes(bb.B)
|
||||
k := string(bb.B)
|
||||
m[k] = append(m[k], ts)
|
||||
}
|
||||
storage.PutMetricName(mn)
|
||||
|
||||
@@ -548,8 +548,8 @@ func getCommonLabelFilters(tss []*timeseries) []metricsql.LabelFilter {
|
||||
for _, tag := range ts.MetricName.Tags {
|
||||
vc, ok := m[string(tag.Key)]
|
||||
if !ok {
|
||||
k := bytesutil.InternBytes(tag.Key)
|
||||
v := bytesutil.InternBytes(tag.Value)
|
||||
k := string(tag.Key)
|
||||
v := string(tag.Value)
|
||||
m[k] = &valuesCounter{
|
||||
values: map[string]struct{}{
|
||||
v: {},
|
||||
@@ -566,8 +566,7 @@ func getCommonLabelFilters(tss []*timeseries) []metricsql.LabelFilter {
|
||||
}
|
||||
vc.count++
|
||||
if _, ok := vc.values[string(tag.Value)]; !ok {
|
||||
v := bytesutil.InternBytes(tag.Value)
|
||||
vc.values[v] = struct{}{}
|
||||
vc.values[string(tag.Value)] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -896,11 +895,17 @@ func evalRollupFuncWithSubquery(qt *querytracer.Tracer, ec *EvalConfig, funcName
|
||||
// TODO: determine whether to use rollupResultCacheV here.
|
||||
qt = qt.NewChild("subquery")
|
||||
defer qt.Done()
|
||||
step := re.Step.Duration(ec.Step)
|
||||
step, err := re.Step.NonNegativeDuration(ec.Step)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse step in square brackets at %s: %w", expr.AppendString(nil), err)
|
||||
}
|
||||
if step == 0 {
|
||||
step = ec.Step
|
||||
}
|
||||
window := re.Window.Duration(ec.Step)
|
||||
window, err := re.Window.NonNegativeDuration(ec.Step)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse lookbehind window in square brackets at %s: %w", expr.AppendString(nil), err)
|
||||
}
|
||||
|
||||
ecSQ := copyEvalConfig(ec)
|
||||
ecSQ.Start -= window + maxSilenceInterval + step
|
||||
@@ -1042,7 +1047,10 @@ var (
|
||||
func evalRollupFuncWithMetricExpr(qt *querytracer.Tracer, ec *EvalConfig, funcName string, rf rollupFunc,
|
||||
expr metricsql.Expr, me *metricsql.MetricExpr, iafc *incrementalAggrFuncContext, windowExpr *metricsql.DurationExpr) ([]*timeseries, error) {
|
||||
var rollupMemorySize int64
|
||||
window := windowExpr.Duration(ec.Step)
|
||||
window, err := windowExpr.NonNegativeDuration(ec.Step)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse lookbehind window in square brackets at %s: %w", expr.AppendString(nil), err)
|
||||
}
|
||||
if qt.Enabled() {
|
||||
qt = qt.NewChild("rollup %s(): timeRange=%s, step=%d, window=%d", funcName, ec.timeRangeString(), ec.Step, window)
|
||||
defer func() {
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/netstorage"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/querystats"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/decimal"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/querytracer"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
|
||||
@@ -73,7 +72,7 @@ func Exec(qt *querytracer.Tracer, ec *EvalConfig, q string, isFirstPointOnly boo
|
||||
}
|
||||
qt.Printf("leave only the first point in every series")
|
||||
}
|
||||
maySort := maySortResults(e, rv)
|
||||
maySort := maySortResults(e)
|
||||
result, err := timeseriesToResult(rv, maySort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -95,7 +94,7 @@ func Exec(qt *querytracer.Tracer, ec *EvalConfig, q string, isFirstPointOnly boo
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func maySortResults(e metricsql.Expr, tss []*timeseries) bool {
|
||||
func maySortResults(e metricsql.Expr) bool {
|
||||
switch v := e.(type) {
|
||||
case *metricsql.FuncExpr:
|
||||
switch strings.ToLower(v.Name) {
|
||||
@@ -122,7 +121,7 @@ func timeseriesToResult(tss []*timeseries, maySort bool) ([]netstorage.Result, e
|
||||
bb := bbPool.Get()
|
||||
for i, ts := range tss {
|
||||
bb.B = marshalMetricNameSorted(bb.B[:0], &ts.MetricName)
|
||||
k := bytesutil.InternBytes(bb.B)
|
||||
k := string(bb.B)
|
||||
if _, ok := m[k]; ok {
|
||||
return nil, fmt.Errorf(`duplicate output timeseries: %s`, stringMetricName(&ts.MetricName))
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func TestEscapeDotsInRegexpLabelFilters(t *testing.T) {
|
||||
f("2", "2")
|
||||
f(`foo.bar + 123`, `foo.bar + 123`)
|
||||
f(`foo{bar=~"baz.xx.yyy"}`, `foo{bar=~"baz\\.xx\\.yyy"}`)
|
||||
f(`foo(a.b{c="d.e",x=~"a.b.+[.a]",y!~"aaa.bb|cc.dd"}) + x.y(1,sum({x=~"aa.bb"}))`, `foo(a.b{c="d.e",x=~"a\\.b.+[\\.a]",y!~"aaa\\.bb|cc\\.dd"}) + x.y(1, sum({x=~"aa\\.bb"}))`)
|
||||
f(`sum(a.b{c="d.e",x=~"a.b.+[.a]",y!~"aaa.bb|cc.dd"}) + avg_over_time(1,sum({x=~"aa.bb"}))`, `sum(a.b{c="d.e",x=~"a\\.b.+[\\.a]",y!~"aaa\\.bb|cc\\.dd"}) + avg_over_time(1, sum({x=~"aa\\.bb"}))`)
|
||||
}
|
||||
|
||||
func TestExecSuccess(t *testing.T) {
|
||||
@@ -7636,7 +7636,7 @@ func TestExecSuccess(t *testing.T) {
|
||||
})
|
||||
t.Run(`aggr_over_time(multi-func)`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `sort(aggr_over_time(("min_over_time", "count_over_time", "max_over_time"), round(rand(0),0.1)[:10s]))`
|
||||
q := `sort(aggr_over_time(("min_over_time", "median_over_time", "max_over_time"), round(rand(0),0.1)[:10s]))`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0, 0, 0, 0, 0, 0},
|
||||
@@ -7648,21 +7648,21 @@ func TestExecSuccess(t *testing.T) {
|
||||
}}
|
||||
r2 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0.8, 0.9, 1, 0.9, 1, 0.9},
|
||||
Values: []float64{0.4, 0.5, 0.5, 0.75, 0.6, 0.45},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r2.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("rollup"),
|
||||
Value: []byte("max_over_time"),
|
||||
Value: []byte("median_over_time"),
|
||||
}}
|
||||
r3 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{20, 20, 20, 20, 20, 20},
|
||||
Values: []float64{0.8, 0.9, 1, 0.9, 1, 0.9},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r3.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("rollup"),
|
||||
Value: []byte("count_over_time"),
|
||||
Value: []byte("max_over_time"),
|
||||
}}
|
||||
resultExpected := []netstorage.Result{r1, r2, r3}
|
||||
f(q, resultExpected)
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
"github.com/VictoriaMetrics/metricsql"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/decimal"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
"github.com/VictoriaMetrics/metricsql"
|
||||
)
|
||||
|
||||
var minStalenessInterval = flag.Duration("search.minStalenessInterval", 0, "The minimum interval for staleness calculations. "+
|
||||
@@ -58,6 +59,7 @@ var rollupFuncs = map[string]newRollupFunc{
|
||||
"lifetime": newRollupFuncOneArg(rollupLifetime),
|
||||
"mad_over_time": newRollupFuncOneArg(rollupMAD),
|
||||
"max_over_time": newRollupFuncOneArg(rollupMax),
|
||||
"median_over_time": newRollupFuncOneArg(rollupMedian),
|
||||
"min_over_time": newRollupFuncOneArg(rollupMin),
|
||||
"mode_over_time": newRollupFuncOneArg(rollupModeOverTime),
|
||||
"predict_linear": newRollupPredictLinear,
|
||||
@@ -125,6 +127,7 @@ var rollupAggrFuncs = map[string]rollupFunc{
|
||||
"lifetime": rollupLifetime,
|
||||
"mad_over_time": rollupMAD,
|
||||
"max_over_time": rollupMax,
|
||||
"median_over_time": rollupMedian,
|
||||
"min_over_time": rollupMin,
|
||||
"mode_over_time": rollupModeOverTime,
|
||||
"present_over_time": rollupPresent,
|
||||
@@ -224,6 +227,7 @@ var rollupFuncsKeepMetricName = map[string]bool{
|
||||
"holt_winters": true,
|
||||
"last_over_time": true,
|
||||
"max_over_time": true,
|
||||
"median_over_time": true,
|
||||
"min_over_time": true,
|
||||
"mode_over_time": true,
|
||||
"predict_linear": true,
|
||||
@@ -948,11 +952,11 @@ func newRollupHoltWinters(args []interface{}) (rollupFunc, error) {
|
||||
return rfa.prevValue
|
||||
}
|
||||
sf := sfs[rfa.idx]
|
||||
if sf <= 0 || sf >= 1 {
|
||||
if sf < 0 || sf > 1 {
|
||||
return nan
|
||||
}
|
||||
tf := tfs[rfa.idx]
|
||||
if tf <= 0 || tf >= 1 {
|
||||
if tf < 0 || tf > 1 {
|
||||
return nan
|
||||
}
|
||||
|
||||
@@ -1396,6 +1400,10 @@ func rollupMax(rfa *rollupFuncArg) float64 {
|
||||
return maxValue
|
||||
}
|
||||
|
||||
func rollupMedian(rfa *rollupFuncArg) float64 {
|
||||
return quantile(0.5, rfa.values)
|
||||
}
|
||||
|
||||
func rollupTmin(rfa *rollupFuncArg) float64 {
|
||||
// There is no need in handling NaNs here, since they must be cleaned up
|
||||
// before calling rollup funcs.
|
||||
@@ -2222,7 +2230,7 @@ func rollupIntegrate(rfa *rollupFuncArg) float64 {
|
||||
return sum
|
||||
}
|
||||
|
||||
func rollupFake(rfa *rollupFuncArg) float64 {
|
||||
func rollupFake(_ *rollupFuncArg) float64 {
|
||||
logger.Panicf("BUG: rollupFake shouldn't be called")
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -486,8 +486,7 @@ func mergeTimeseries(a, b []*timeseries, bStart int64, ec *EvalConfig) []*timese
|
||||
defer bbPool.Put(bb)
|
||||
for _, ts := range a {
|
||||
bb.B = marshalMetricNameSorted(bb.B[:0], &ts.MetricName)
|
||||
k := bytesutil.InternBytes(bb.B)
|
||||
m[k] = ts
|
||||
m[string(bb.B)] = ts
|
||||
}
|
||||
|
||||
rvs := make([]*timeseries, 0, len(a))
|
||||
@@ -499,7 +498,7 @@ func mergeTimeseries(a, b []*timeseries, bStart int64, ec *EvalConfig) []*timese
|
||||
tmp.MetricName.MoveFrom(&tsB.MetricName)
|
||||
|
||||
bb.B = marshalMetricNameSorted(bb.B[:0], &tmp.MetricName)
|
||||
k := bytesutil.InternBytes(bb.B)
|
||||
k := string(bb.B)
|
||||
tsA := m[k]
|
||||
if tsA == nil {
|
||||
tStart := ec.Start
|
||||
|
||||
@@ -160,7 +160,7 @@ func TestDerivValues(t *testing.T) {
|
||||
testRowsEqual(t, values, timestamps, valuesExpected, timestamps)
|
||||
}
|
||||
|
||||
func testRollupFunc(t *testing.T, funcName string, args []interface{}, meExpected *metricsql.MetricExpr, vExpected float64) {
|
||||
func testRollupFunc(t *testing.T, funcName string, args []interface{}, vExpected float64) {
|
||||
t.Helper()
|
||||
nrf := getRollupFunc(funcName)
|
||||
if nrf == nil {
|
||||
@@ -203,7 +203,7 @@ func TestRollupDurationOverTime(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, maxIntervals}
|
||||
testRollupFunc(t, "duration_over_time", args, &me, dExpected)
|
||||
testRollupFunc(t, "duration_over_time", args, dExpected)
|
||||
}
|
||||
f(-123, 0)
|
||||
f(0, 0)
|
||||
@@ -224,7 +224,7 @@ func TestRollupShareLEOverTime(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, les}
|
||||
testRollupFunc(t, "share_le_over_time", args, &me, vExpected)
|
||||
testRollupFunc(t, "share_le_over_time", args, vExpected)
|
||||
}
|
||||
|
||||
f(-123, 0)
|
||||
@@ -247,7 +247,7 @@ func TestRollupShareGTOverTime(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, gts}
|
||||
testRollupFunc(t, "share_gt_over_time", args, &me, vExpected)
|
||||
testRollupFunc(t, "share_gt_over_time", args, vExpected)
|
||||
}
|
||||
|
||||
f(-123, 1)
|
||||
@@ -270,7 +270,7 @@ func TestRollupShareEQOverTime(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, eqs}
|
||||
testRollupFunc(t, "share_eq_over_time", args, &me, vExpected)
|
||||
testRollupFunc(t, "share_eq_over_time", args, vExpected)
|
||||
}
|
||||
|
||||
f(-123, 0)
|
||||
@@ -289,7 +289,7 @@ func TestRollupCountLEOverTime(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, les}
|
||||
testRollupFunc(t, "count_le_over_time", args, &me, vExpected)
|
||||
testRollupFunc(t, "count_le_over_time", args, vExpected)
|
||||
}
|
||||
|
||||
f(-123, 0)
|
||||
@@ -312,7 +312,7 @@ func TestRollupCountGTOverTime(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, gts}
|
||||
testRollupFunc(t, "count_gt_over_time", args, &me, vExpected)
|
||||
testRollupFunc(t, "count_gt_over_time", args, vExpected)
|
||||
}
|
||||
|
||||
f(-123, 12)
|
||||
@@ -335,7 +335,7 @@ func TestRollupCountEQOverTime(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, eqs}
|
||||
testRollupFunc(t, "count_eq_over_time", args, &me, vExpected)
|
||||
testRollupFunc(t, "count_eq_over_time", args, vExpected)
|
||||
}
|
||||
|
||||
f(-123, 0)
|
||||
@@ -354,7 +354,7 @@ func TestRollupCountNEOverTime(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, nes}
|
||||
testRollupFunc(t, "count_ne_over_time", args, &me, vExpected)
|
||||
testRollupFunc(t, "count_ne_over_time", args, vExpected)
|
||||
}
|
||||
|
||||
f(-123, 12)
|
||||
@@ -373,7 +373,7 @@ func TestRollupQuantileOverTime(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{phis, &metricsql.RollupExpr{Expr: &me}}
|
||||
testRollupFunc(t, "quantile_over_time", args, &me, vExpected)
|
||||
testRollupFunc(t, "quantile_over_time", args, vExpected)
|
||||
}
|
||||
|
||||
f(-123, math.Inf(-1))
|
||||
@@ -395,7 +395,7 @@ func TestRollupPredictLinear(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, secs}
|
||||
testRollupFunc(t, "predict_linear", args, &me, vExpected)
|
||||
testRollupFunc(t, "predict_linear", args, vExpected)
|
||||
}
|
||||
|
||||
f(0e-3, 65.07405077267295)
|
||||
@@ -434,16 +434,16 @@ func TestRollupHoltWinters(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, sfs, tfs}
|
||||
testRollupFunc(t, "holt_winters", args, &me, vExpected)
|
||||
testRollupFunc(t, "holt_winters", args, vExpected)
|
||||
}
|
||||
|
||||
f(-1, 0.5, nan)
|
||||
f(0, 0.5, nan)
|
||||
f(1, 0.5, nan)
|
||||
f(0, 0.5, -856)
|
||||
f(1, 0.5, 34)
|
||||
f(2, 0.5, nan)
|
||||
f(0.5, -1, nan)
|
||||
f(0.5, 0, nan)
|
||||
f(0.5, 1, nan)
|
||||
f(0.5, 0, -54.1474609375)
|
||||
f(0.5, 1, 25.25)
|
||||
f(0.5, 2, nan)
|
||||
f(0.5, 0.5, 34.97794532775879)
|
||||
f(0.1, 0.5, -131.30529492371622)
|
||||
@@ -462,7 +462,7 @@ func TestRollupHoeffdingBoundLower(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{phis, &metricsql.RollupExpr{Expr: &me}}
|
||||
testRollupFunc(t, "hoeffding_bound_lower", args, &me, vExpected)
|
||||
testRollupFunc(t, "hoeffding_bound_lower", args, vExpected)
|
||||
}
|
||||
|
||||
f(0.5, 28.21949401521037)
|
||||
@@ -483,7 +483,7 @@ func TestRollupHoeffdingBoundUpper(t *testing.T) {
|
||||
}}
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{phis, &metricsql.RollupExpr{Expr: &me}}
|
||||
testRollupFunc(t, "hoeffding_bound_upper", args, &me, vExpected)
|
||||
testRollupFunc(t, "hoeffding_bound_upper", args, vExpected)
|
||||
}
|
||||
|
||||
f(0.5, 65.9471726514563)
|
||||
@@ -500,7 +500,7 @@ func TestRollupNewRollupFuncSuccess(t *testing.T) {
|
||||
t.Helper()
|
||||
var me metricsql.MetricExpr
|
||||
args := []interface{}{&metricsql.RollupExpr{Expr: &me}}
|
||||
testRollupFunc(t, funcName, args, &me, vExpected)
|
||||
testRollupFunc(t, funcName, args, vExpected)
|
||||
}
|
||||
|
||||
f("default_rollup", 34)
|
||||
|
||||
@@ -419,7 +419,7 @@ func transformBucketsLimit(tfa *transformFuncArg) ([]*timeseries, error) {
|
||||
mn.CopyFrom(&ts.MetricName)
|
||||
mn.RemoveTag("le")
|
||||
b = marshalMetricNameSorted(b[:0], &mn)
|
||||
k := bytesutil.InternBytes(b)
|
||||
k := string(b)
|
||||
m[k] = append(m[k], x{
|
||||
le: le,
|
||||
ts: ts,
|
||||
@@ -522,7 +522,7 @@ func vmrangeBucketsToLE(tss []*timeseries) []*timeseries {
|
||||
ts.MetricName.RemoveTag("le")
|
||||
ts.MetricName.RemoveTag("vmrange")
|
||||
bb.B = marshalMetricNameSorted(bb.B[:0], &ts.MetricName)
|
||||
k := bytesutil.InternBytes(bb.B)
|
||||
k := string(bb.B)
|
||||
m[k] = append(m[k], x{
|
||||
startStr: startStr,
|
||||
endStr: endStr,
|
||||
@@ -1022,7 +1022,7 @@ func groupLeTimeseries(tss []*timeseries) map[string][]leTimeseries {
|
||||
ts.MetricName.ResetMetricGroup()
|
||||
ts.MetricName.RemoveTag("le")
|
||||
bb.B = marshalMetricTagsSorted(bb.B[:0], &ts.MetricName)
|
||||
k := bytesutil.InternBytes(bb.B)
|
||||
k := string(bb.B)
|
||||
m[k] = append(m[k], leTimeseries{
|
||||
le: le,
|
||||
ts: ts,
|
||||
@@ -1090,18 +1090,18 @@ func transformHour(t time.Time) int {
|
||||
return t.Hour()
|
||||
}
|
||||
|
||||
func runningSum(a, b float64, idx int) float64 {
|
||||
func runningSum(a, b float64, _ int) float64 {
|
||||
return a + b
|
||||
}
|
||||
|
||||
func runningMax(a, b float64, idx int) float64 {
|
||||
func runningMax(a, b float64, _ int) float64 {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func runningMin(a, b float64, idx int) float64 {
|
||||
func runningMin(a, b float64, _ int) float64 {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
@@ -1656,7 +1656,7 @@ func transformUnion(tfa *transformFuncArg) ([]*timeseries, error) {
|
||||
for _, arg := range args {
|
||||
for _, ts := range arg {
|
||||
bb.B = marshalMetricNameSorted(bb.B[:0], &ts.MetricName)
|
||||
k := bytesutil.InternBytes(bb.B)
|
||||
k := string(bb.B)
|
||||
if m[k] {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.c93e8dee.css",
|
||||
"main.js": "./static/js/main.05892dd1.js",
|
||||
"main.css": "./static/css/main.643dbb4b.css",
|
||||
"main.js": "./static/js/main.68a897a8.js",
|
||||
"static/js/522.b5ae4365.chunk.js": "./static/js/522.b5ae4365.chunk.js",
|
||||
"static/media/Lato-Regular.ttf": "./static/media/Lato-Regular.d714fec1633b69a9c2e9.ttf",
|
||||
"static/media/Lato-Bold.ttf": "./static/media/Lato-Bold.32360ba4b57802daa4d6.ttf",
|
||||
"index.html": "./index.html"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.c93e8dee.css",
|
||||
"static/js/main.05892dd1.js"
|
||||
"static/css/main.643dbb4b.css",
|
||||
"static/js/main.68a897a8.js"
|
||||
]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"/><meta name="theme-color" content="#000000"/><meta name="description" content="UI for VictoriaMetrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><script src="./dashboards/index.js" type="module"></script><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="./preview.jpg"><meta name="twitter:title" content="UI for VictoriaMetrics"><meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta name="twitter:site" content="@VictoriaMetrics"><meta property="og:title" content="Metric explorer for VictoriaMetrics"><meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta property="og:image" content="./preview.jpg"><meta property="og:type" content="website"><script defer="defer" src="./static/js/main.05892dd1.js"></script><link href="./static/css/main.c93e8dee.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.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"/><meta name="theme-color" content="#000000"/><meta name="description" content="UI for VictoriaMetrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><script src="./dashboards/index.js" type="module"></script><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="./preview.jpg"><meta name="twitter:title" content="UI for VictoriaMetrics"><meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta name="twitter:site" content="@VictoriaMetrics"><meta property="og:title" content="Metric explorer for VictoriaMetrics"><meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta property="og:image" content="./preview.jpg"><meta property="og:type" content="website"><script defer="defer" src="./static/js/main.68a897a8.js"></script><link href="./static/css/main.643dbb4b.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.643dbb4b.css
Normal file
1
app/vmselect/vmui/static/css/main.643dbb4b.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.68a897a8.js
Normal file
2
app/vmselect/vmui/static/js/main.68a897a8.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.20.7 as build-web-stage
|
||||
FROM golang:1.21.4 as build-web-stage
|
||||
COPY build /build
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
@@ -13,7 +13,6 @@ import ExploreMetrics from "./pages/ExploreMetrics";
|
||||
import PreviewIcons from "./components/Main/Icons/PreviewIcons";
|
||||
import WithTemplate from "./pages/WithTemplate";
|
||||
import Relabel from "./pages/Relabel";
|
||||
import ExploreLogs from "./pages/ExploreLogs/ExploreLogs";
|
||||
import ActiveQueries from "./pages/ActiveQueries";
|
||||
|
||||
const App: FC = () => {
|
||||
@@ -70,10 +69,6 @@ const App: FC = () => {
|
||||
path={router.icons}
|
||||
element={<PreviewIcons/>}
|
||||
/>
|
||||
<Route
|
||||
path={router.logs}
|
||||
element={<ExploreLogs/>}
|
||||
/>
|
||||
</Route>
|
||||
</Routes>
|
||||
)}
|
||||
|
||||
@@ -36,7 +36,7 @@ const DateTimeInput: FC<DateTimeInputProps> = ({
|
||||
const [maskedValue, setMaskedValue] = useState(formatStringDate(value));
|
||||
const [focusToTime, setFocusToTime] = useState(false);
|
||||
const [awaitChangeForEnter, setAwaitChangeForEnter] = useState(false);
|
||||
const error = dayjs(maskedValue).isValid() ? "" : "Expected format: YYYY-MM-DD HH:mm:ss";
|
||||
const error = dayjs(maskedValue).isValid() ? "" : "Invalid date format";
|
||||
|
||||
const handleMaskedChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setMaskedValue(e.currentTarget.value);
|
||||
|
||||
@@ -3,6 +3,7 @@ import classNames from "classnames";
|
||||
import { useMemo } from "preact/compat";
|
||||
import { useAppState } from "../../../state/common/StateContext";
|
||||
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
import TextFieldError from "./TextFieldError";
|
||||
import "./style.scss";
|
||||
|
||||
interface TextFieldProps {
|
||||
@@ -132,12 +133,7 @@ const TextField: FC<TextFieldProps> = ({
|
||||
)
|
||||
}
|
||||
{label && <span className="vm-text-field__label">{label}</span>}
|
||||
<span
|
||||
className="vm-text-field__error"
|
||||
data-show={!!error}
|
||||
>
|
||||
{error}
|
||||
</span>
|
||||
<TextFieldError error={error}/>
|
||||
{helperText && !error && (
|
||||
<span className="vm-text-field__helper-text">
|
||||
{helperText}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import React, { FC, useEffect, useRef, useState } from "react";
|
||||
import useEventListener from "../../../hooks/useEventListener";
|
||||
import classNames from "classnames";
|
||||
import "./style.scss";
|
||||
|
||||
interface TextFieldErrorProps {
|
||||
error: string;
|
||||
}
|
||||
|
||||
const TextFieldError: FC<TextFieldErrorProps> = ({ error }) => {
|
||||
const errorRef = useRef<HTMLSpanElement>(null);
|
||||
const [isErrorTruncated, setIsErrorTruncated] = useState(false);
|
||||
const [showFull, setShowFull] = useState(false);
|
||||
|
||||
const checkIfTextTruncated = () => {
|
||||
const el = errorRef.current;
|
||||
if (el) {
|
||||
const { offsetWidth, scrollWidth, offsetHeight, scrollHeight } = el;
|
||||
// The "+1" is for the scrollbar in Firefox
|
||||
const overflowed = (offsetWidth + 1) < scrollWidth || (offsetHeight + 1) < scrollHeight;
|
||||
setIsErrorTruncated(overflowed);
|
||||
} else {
|
||||
setIsErrorTruncated(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClickError = () => {
|
||||
if (!isErrorTruncated) return;
|
||||
setShowFull(true);
|
||||
setIsErrorTruncated(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setShowFull(false);
|
||||
checkIfTextTruncated();
|
||||
}, [errorRef, error]);
|
||||
|
||||
useEventListener("resize", checkIfTextTruncated);
|
||||
|
||||
return (
|
||||
<span
|
||||
className={classNames({
|
||||
"vm-text-field__error": true,
|
||||
"vm-text-field__error_overflowed": isErrorTruncated,
|
||||
"vm-text-field__error_full": showFull,
|
||||
})}
|
||||
data-show={!!error}
|
||||
ref={errorRef}
|
||||
onClick={handleClickError}
|
||||
>
|
||||
{error}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export default TextFieldError;
|
||||
@@ -40,14 +40,9 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2; /* number of lines to show */
|
||||
line-clamp: 2;
|
||||
-webkit-line-clamp: 1; /* number of lines to show */
|
||||
line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
|
||||
@media (max-width: 500px) {
|
||||
-webkit-line-clamp: 1; /* number of lines to show */
|
||||
line-clamp: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
@@ -56,10 +51,22 @@
|
||||
}
|
||||
|
||||
&__error {
|
||||
top: calc((100% - ($font-size-small/2)) - 2px);
|
||||
position: relative;
|
||||
top: calc($font-size-small/-2);
|
||||
width: fit-content;
|
||||
overflow-wrap: anywhere;
|
||||
color: $color-error;
|
||||
pointer-events: auto;
|
||||
user-select: text;
|
||||
|
||||
&_full {
|
||||
display: block;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
&_overflowed {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&__helper-text {
|
||||
@@ -117,9 +124,9 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-width: 15px;
|
||||
top: auto;
|
||||
top: 0;
|
||||
left: $padding-small;
|
||||
height: 100%;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
color: $color-text-secondary;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ const Tooltip: FC<TooltipProps> = ({
|
||||
return () => {
|
||||
window.removeEventListener("scroll", onScrollWindow);
|
||||
};
|
||||
}, [isOpen]);
|
||||
}, [isOpen, title]);
|
||||
|
||||
const popperStyle = useMemo(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
|
||||
@@ -38,10 +38,6 @@ export const defaultNavigation: NavigationItem[] = [
|
||||
label: routerOptions[router.activeQueries].title,
|
||||
value: router.activeQueries,
|
||||
},
|
||||
{
|
||||
label: routerOptions[router.logs].title,
|
||||
value: router.logs,
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -52,6 +52,7 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
left: $padding-global;
|
||||
bottom: $padding-global;
|
||||
z-index: 999;
|
||||
animation: vm-slide-snackbar 150ms cubic-bezier(0.280, 0.840, 0.420, 1.1);
|
||||
|
||||
&-content {
|
||||
display: grid;
|
||||
@@ -71,15 +72,14 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
animation: vm-slide-snackbar 150ms cubic-bezier(0.280, 0.840, 0.420, 1.1);
|
||||
}
|
||||
|
||||
@keyframes vm-slide-snackbar {
|
||||
0% {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
@keyframes vm-slide-snackbar {
|
||||
0% {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,10 @@
|
||||
|
||||
DOCKER_NAMESPACE ?= victoriametrics
|
||||
|
||||
ROOT_IMAGE ?= alpine:3.18.2
|
||||
ROOT_IMAGE ?= alpine:3.18.4
|
||||
CERTS_IMAGE := alpine:3.18.4
|
||||
|
||||
# Use alpine:3.17.3 instead of 3.18.2 for CERTS_IMAGE
|
||||
# because alpine:3.18.2 is broken for cross-platform builds
|
||||
# TODO: sync it with ROOT_IMAGE when it will be fixed in the new alpine releases
|
||||
CERTS_IMAGE := alpine:3.17.3
|
||||
|
||||
GO_BUILDER_IMAGE := golang:1.20.7-alpine
|
||||
GO_BUILDER_IMAGE := golang:1.21.4-alpine
|
||||
BUILDER_IMAGE := local/builder:2.0.0-$(shell echo $(GO_BUILDER_IMAGE) | tr :/ __)-1
|
||||
BASE_IMAGE := local/base:1.1.4-$(shell echo $(ROOT_IMAGE) | tr :/ __)-$(shell echo $(CERTS_IMAGE) | tr :/ __)
|
||||
DOCKER_BUILD ?= docker build
|
||||
@@ -82,8 +78,8 @@ publish-via-docker: \
|
||||
--build-arg root_image=$(ROOT_IMAGE) \
|
||||
--build-arg APP_NAME=$(APP_NAME) \
|
||||
--tag $(DOCKER_NAMESPACE)/$(APP_NAME):$(PKG_TAG)$(RACE) \
|
||||
--tag $(DOCKER_NAMESPACE)/$(APP_NAME):$(LATEST_TAG)$(RACE) \
|
||||
-o type=image \
|
||||
--provenance=false \
|
||||
-f app/$(APP_NAME)/multiarch/Dockerfile \
|
||||
--push \
|
||||
bin
|
||||
@@ -107,7 +103,9 @@ app-via-docker-linux-amd64:
|
||||
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 $(MAKE) app-via-docker-goos-goarch
|
||||
|
||||
app-via-docker-linux-arm:
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm $(MAKE) app-via-docker-goos-goarch
|
||||
APP_SUFFIX='-linux-arm' \
|
||||
DOCKER_OPTS='--env CGO_ENABLED=0 --env GOOS=linux --env GOARCH=arm --env GOARM=5' \
|
||||
$(MAKE) app-via-docker
|
||||
|
||||
app-via-docker-linux-arm64:
|
||||
APP_SUFFIX='-linux-arm64' \
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '3.5'
|
||||
services:
|
||||
vmagent:
|
||||
container_name: vmagent
|
||||
image: victoriametrics/vmagent:v1.92.1
|
||||
image: victoriametrics/vmagent:v1.93.0
|
||||
depends_on:
|
||||
- "vminsert"
|
||||
ports:
|
||||
@@ -32,7 +32,7 @@ services:
|
||||
|
||||
vmstorage-1:
|
||||
container_name: vmstorage-1
|
||||
image: victoriametrics/vmstorage:v1.92.1-cluster
|
||||
image: victoriametrics/vmstorage:v1.93.0-cluster
|
||||
ports:
|
||||
- 8482
|
||||
- 8400
|
||||
@@ -44,7 +44,7 @@ services:
|
||||
restart: always
|
||||
vmstorage-2:
|
||||
container_name: vmstorage-2
|
||||
image: victoriametrics/vmstorage:v1.92.1-cluster
|
||||
image: victoriametrics/vmstorage:v1.93.0-cluster
|
||||
ports:
|
||||
- 8482
|
||||
- 8400
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
restart: always
|
||||
vminsert:
|
||||
container_name: vminsert
|
||||
image: victoriametrics/vminsert:v1.92.1-cluster
|
||||
image: victoriametrics/vminsert:v1.93.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -68,7 +68,7 @@ services:
|
||||
restart: always
|
||||
vmselect:
|
||||
container_name: vmselect
|
||||
image: victoriametrics/vmselect:v1.92.1-cluster
|
||||
image: victoriametrics/vmselect:v1.93.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -82,7 +82,7 @@ services:
|
||||
|
||||
vmalert:
|
||||
container_name: vmalert
|
||||
image: victoriametrics/vmalert:v1.92.1
|
||||
image: victoriametrics/vmalert:v1.93.0
|
||||
depends_on:
|
||||
- "vmselect"
|
||||
ports:
|
||||
|
||||
@@ -2,7 +2,7 @@ version: "3.5"
|
||||
services:
|
||||
vmagent:
|
||||
container_name: vmagent
|
||||
image: victoriametrics/vmagent:v1.92.1
|
||||
image: victoriametrics/vmagent:v1.93.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
@@ -18,7 +18,7 @@ services:
|
||||
restart: always
|
||||
victoriametrics:
|
||||
container_name: victoriametrics
|
||||
image: victoriametrics/victoria-metrics:v1.92.1
|
||||
image: victoriametrics/victoria-metrics:v1.93.0
|
||||
ports:
|
||||
- 8428:8428
|
||||
- 8089:8089
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
restart: always
|
||||
vmalert:
|
||||
container_name: vmalert
|
||||
image: victoriametrics/vmalert:v1.92.1
|
||||
image: victoriametrics/vmalert:v1.93.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
- "alertmanager"
|
||||
|
||||
@@ -105,7 +105,7 @@ services:
|
||||
- '--config=/config.yml'
|
||||
|
||||
vmsingle:
|
||||
image: victoriametrics/victoria-metrics:v1.92.1
|
||||
image: victoriametrics/victoria-metrics:v1.93.0
|
||||
ports:
|
||||
- '8428:8428'
|
||||
command:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
4. Set variables `DIGITALOCEAN_API_TOKEN` with `VM_VERSION` for `packer` environment and run make from example below:
|
||||
|
||||
```console
|
||||
make release-victoria-metrics-digitalocean-oneclick-droplet DIGITALOCEAN_API_TOKEN="dop_v23_2e46f4759ceeeba0d0248" VM_VERSION="1.92.1"
|
||||
make release-victoria-metrics-digitalocean-oneclick-droplet DIGITALOCEAN_API_TOKEN="dop_v23_2e46f4759ceeeba0d0248" VM_VERSION="1.93.0"
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ On the server:
|
||||
* VictoriaMetrics is running on ports: 8428, 8089, 4242, 2003 and they are bound to the local interface.
|
||||
|
||||
********************************************************************************
|
||||
# This image includes 1.92.1 version of VictoriaMetrics.
|
||||
# See Release notes https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.92.1
|
||||
# This image includes 1.93.0 version of VictoriaMetrics.
|
||||
# See Release notes https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.93.0
|
||||
|
||||
# Welcome to VictoriaMetrics droplet!
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ See also [case studies](https://docs.victoriametrics.com/CaseStudies.html).
|
||||
* [VictoriaMetrics static scraper](https://blog.differentpla.net/blog/2022/10/16/victoria-metrics-static-scraper/)
|
||||
* [VictoriaMetrics and Open Cosmos boldly takes edge computing to the edge of space](https://www.iot-now.com/2022/07/19/122423-victoriametrics-and-open-cosmos-boldly-takes-edge-computing-to-the-edge-of-space/)
|
||||
* [Evaluating Backend Options For Prometheus Metrics](https://www.techetio.com/2022/08/21/evaluating-backend-options-for-prometheus-metrics/)
|
||||
* [Time Series in the Multiverse of Madness (in Korean)](https://www.youtube.com/watch?v=OUyXPgVcdw4), plus [these slides](https://deview.kr/data/deview/session/attach/%5B2B4%5DVictoriaMetrics_%E1%84%89%E1%85%B5%E1%84%80%E1%85%A8%E1%84%8B%E1%85%A7%E1%86%AF_%E1%84%83%E1%85%A6%E1%84%8B%E1%85%B5%E1%84%90%E1%85%A5_%E1%84%83%E1%85%A2%E1%84%92%E1%85%A9%E1%86%AB%E1%84%83%E1%85%A9%E1%86%AB%E1%84%8B%E1%85%B4_%E1%84%86%E1%85%A5%E1%86%AF%E1%84%90%E1%85%B5%E1%84%87%E1%85%A5%E1%84%89%E1%85%B3_Kor+Eng.pdf)
|
||||
|
||||
## Our articles
|
||||
|
||||
|
||||
1900
docs/CHANGELOG.md
1900
docs/CHANGELOG.md
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user