mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-06-26 12:08:43 +03:00
Compare commits
10 Commits
kirillyu/d
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac82971faa | ||
|
|
e30e8be1f4 | ||
|
|
24ac567a9f | ||
|
|
dce8193c16 | ||
|
|
e196479fb2 | ||
|
|
1c774564a2 | ||
|
|
e1c554d4a6 | ||
|
|
3419328f1c | ||
|
|
e841e45877 | ||
|
|
d53d8849e7 |
6
.github/workflows/codeql-analysis-go.yml
vendored
6
.github/workflows/codeql-analysis-go.yml
vendored
@@ -54,14 +54,14 @@ jobs:
|
||||
restore-keys: go-artifacts-${{ runner.os }}-codeql-analyze-${{ steps.go.outputs.go-version }}-
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
||||
uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
|
||||
with:
|
||||
languages: go
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
||||
uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
||||
uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
|
||||
with:
|
||||
category: 'language:go'
|
||||
|
||||
@@ -457,12 +457,10 @@ func TestSetIntervalAsTimeFilter(t *testing.T) {
|
||||
f(`* | count()`, "vlogs", true)
|
||||
f(`error OR _time:5m | count()`, "vlogs", true)
|
||||
f(`(_time: 5m AND error) OR (_time: 5m AND warn) | count()`, "vlogs", true)
|
||||
f(`* | error OR _time:5m | count()`, "vlogs", true)
|
||||
|
||||
f(`_time:5m | count()`, "vlogs", false)
|
||||
f(`_time:2023-04-25T22:45:59Z | count()`, "vlogs", false)
|
||||
f(`error AND _time:5m | count()`, "vlogs", false)
|
||||
f(`* | error AND _time:5m | count()`, "vlogs", false)
|
||||
}
|
||||
|
||||
func TestRecordingRuleExec_Partial(t *testing.T) {
|
||||
|
||||
@@ -4,7 +4,7 @@ The `apptest` package contains the integration tests for the VictoriaMetrics
|
||||
applications (such as vmstorage, vminsert, and vmselect).
|
||||
|
||||
An integration test aims at verifying the behavior of an application as a whole,
|
||||
as apposed to a unit test that verifies the behavior of a building block of an
|
||||
as opposed to a unit test that verifies the behavior of a building block of an
|
||||
application.
|
||||
|
||||
To achieve that an integration test starts an application in a separate process
|
||||
@@ -19,10 +19,10 @@ work together as a system.
|
||||
The package provides a collection of helpers to start applications and make
|
||||
queries to them:
|
||||
|
||||
- `app.go` - contains the generic code for staring an application and should
|
||||
- `app.go` - contains the generic code for starting an application and should
|
||||
not be used by integration tests directly.
|
||||
- `{vmstorage,vminsert,etc}.go` - build on top of `app.go` and provide the
|
||||
code for staring a specific application.
|
||||
code for starting a specific application.
|
||||
- `client.go` - provides helper functions for sending HTTP requests to
|
||||
applications.
|
||||
|
||||
@@ -36,7 +36,7 @@ the application binary files to be built and put into the `bin` directory. The
|
||||
build rule used for running integration tests, `make apptest`,
|
||||
accounts for that, it builds all application binaries before running the tests.
|
||||
But if you want to run the tests without `make`, i.e. by executing
|
||||
`go test ./app/apptest`, you will need to build the binaries first (for example,
|
||||
`go test ./apptest/tests`, you will need to build the binaries first (for example,
|
||||
by executing `make all`).
|
||||
|
||||
Not all binaries can be built from `master` branch, cluster binaries can be built
|
||||
|
||||
@@ -2083,7 +2083,7 @@
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSeу major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSee major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
|
||||
@@ -2388,7 +2388,7 @@
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSeу major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSee major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
|
||||
@@ -2084,7 +2084,7 @@
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSeу major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSee major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
|
||||
@@ -2389,7 +2389,7 @@
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSeу major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSee major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
|
||||
@@ -2165,7 +2165,7 @@
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSeу major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSee major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
|
||||
@@ -1840,7 +1840,7 @@
|
||||
"type": "victoriametrics-metrics-datasource",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSeу major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSee major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
|
||||
@@ -2164,7 +2164,7 @@
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSeу major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSee major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
|
||||
@@ -1839,7 +1839,7 @@
|
||||
"type": "prometheus",
|
||||
"uid": "$ds"
|
||||
},
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSeу major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\n**Lower is better.**\n\nPressure is measured as amount of time within 1sec time window the process was:\n- waiting: at least one thread was blocked on memory.\n- stalled: every thread was blocked on memory (severe pressure).\n\nElevated memory pressure can slowdown the process performance by utilizing more disk IO. Consider increasing amount of available RAM limit or decreasing the load on the process.\n\nSee major page faults rate panel in Troubleshooting section if this metric continued to be high.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
|
||||
@@ -59,7 +59,7 @@ services:
|
||||
- '--external.alert.source=explore?orgId=1&left=["now-1h","now","VictoriaMetrics",{"expr": },{"mode":"Metrics"},{"ui":[true,true,true,"none"]}]'
|
||||
restart: always
|
||||
vmanomaly:
|
||||
image: victoriametrics/vmanomaly:v1.29.6
|
||||
image: victoriametrics/vmanomaly:v1.29.7
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
|
||||
@@ -14,6 +14,17 @@ aliases:
|
||||
---
|
||||
Please find the changelog for VictoriaMetrics Anomaly Detection below.
|
||||
|
||||
## v1.29.7
|
||||
Released: 2026-06-25
|
||||
|
||||
- UI: updated [vmanomaly UI](https://docs.victoriametrics.com/anomaly-detection/ui/) from [v1.7.1](https://docs.victoriametrics.com/anomaly-detection/ui/#v171) to [v1.7.2](https://docs.victoriametrics.com/anomaly-detection/ui/#v172), see respective [release notes](https://docs.victoriametrics.com/anomaly-detection/ui/#v172) for details.
|
||||
|
||||
- IMPROVEMENT: Increased high-cardinality inference scaling by optionally scattering periodic infer jobs to reduce contention on shared resources (e.g. datasource, CPU, RAM) when `settings.n_workers > 1` and `scheduler.infer_every` is smaller than the total time to fetch and process all queries. This is controlled by new `scatter_infer_jobs` boolean argument of [Periodic Scheduler](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/#parameters-1) (default: `false`).
|
||||
|
||||
- IMPROVEMENT: Optimized internal batching for reader post-fetch series processing, exposing reader processing queue depth, and clarifying inference skip logs after data fetch timeouts.
|
||||
|
||||
- IMPROVEMENT: Refined `VmReader` and `VLogsReader` logging after datasource request failures by suppressing the follow-up generic "No data" or "No unseen data" warning for failed fetches. Failed requests now keep the original datasource error while empty successful responses still emit the no-data warning.
|
||||
|
||||
## v1.29.6
|
||||
Released: 2026-06-17
|
||||
|
||||
|
||||
@@ -423,7 +423,7 @@ services:
|
||||
# ...
|
||||
vmanomaly:
|
||||
container_name: vmanomaly
|
||||
image: victoriametrics/vmanomaly:v1.29.6
|
||||
image: victoriametrics/vmanomaly:v1.29.7
|
||||
# ...
|
||||
restart: always
|
||||
volumes:
|
||||
@@ -641,7 +641,7 @@ options:
|
||||
Here’s an example of using the config splitter to divide configurations based on the `extra_filters` argument from the reader section:
|
||||
|
||||
```sh
|
||||
docker pull victoriametrics/vmanomaly:v1.29.6 && docker image tag victoriametrics/vmanomaly:v1.29.6 vmanomaly
|
||||
docker pull victoriametrics/vmanomaly:v1.29.7 && docker image tag victoriametrics/vmanomaly:v1.29.7 vmanomaly
|
||||
```
|
||||
|
||||
```sh
|
||||
|
||||
@@ -45,7 +45,7 @@ There are 2 types of compatibility to consider when migrating in stateful mode:
|
||||
|
||||
| Group start | Group end | Compatibility | Notes |
|
||||
|---------|--------- |------------|-------|
|
||||
| [v1.29.1](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1291) | [v1.29.6](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1296) | Fully Compatible | - |
|
||||
| [v1.29.1](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1291) | [v1.29.7](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1297) | Fully Compatible | - |
|
||||
| [v1.28.7](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1287) | [v1.29.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1290) | Partially compatible* | Dumped models of class [prophet](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet) and [seasonal quantile](https://docs.victoriametrics.com/anomaly-detection/components/models/#online-seasonal-quantile) have problems with loading to [v1.29.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1290) due to dropped `pytz` library. **Upgrading directly from v1.28.7 to [v1.29.1](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1291) with a fix is suggested** |
|
||||
| [v1.26.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1262) | [v1.28.7](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1287) | Fully Compatible | [v1.28.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1280) introduced [rolling](https://docs.victoriametrics.com/anomaly-detection/components/models/#rolling-models) model class drop in favor of [online](https://docs.victoriametrics.com/anomaly-detection/components/models/#online-models) models (`rolling_quantile` and `std` models), however, it does not impact compatibility, as artifacts were not produced by default for rolling models. Also, offline `mad` and `zscore` models are redirecting to their respective online counterparts since [v1.28.4](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1284). |
|
||||
| [v1.25.3](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1253) | [v1.26.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1270) | Partially Compatible* | [v1.25.3](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1253) introduced `forecast_at` argument for base [univariate](https://docs.victoriametrics.com/anomaly-detection/components/models/#univariate-models) and `Prophet` [models](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet), however, itself remains backward-reversible from newer states like [v1.26.2](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1262), [v1.27.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1270). (All models except `isolation_forest_multivariate` class will be dropped) |
|
||||
|
||||
@@ -132,7 +132,7 @@ Below are the steps to get `vmanomaly` up and running inside a Docker container:
|
||||
1. Pull Docker image:
|
||||
|
||||
```sh
|
||||
docker pull victoriametrics/vmanomaly:v1.29.6
|
||||
docker pull victoriametrics/vmanomaly:v1.29.7
|
||||
```
|
||||
|
||||
2. Create the license file with your license key.
|
||||
@@ -152,7 +152,7 @@ docker run -it \
|
||||
-v ./license:/license \
|
||||
-v ./config.yaml:/config.yaml \
|
||||
-p 8490:8490 \
|
||||
victoriametrics/vmanomaly:v1.29.6 \
|
||||
victoriametrics/vmanomaly:v1.29.7 \
|
||||
/config.yaml \
|
||||
--licenseFile=/license \
|
||||
--loggerLevel=INFO \
|
||||
@@ -169,7 +169,7 @@ docker run -it \
|
||||
-e VMANOMALY_DATA_DUMPS_DIR=/tmp/vmanomaly/data \
|
||||
-e VMANOMALY_MODEL_DUMPS_DIR=/tmp/vmanomaly/models \
|
||||
-p 8490:8490 \
|
||||
victoriametrics/vmanomaly:v1.29.6 \
|
||||
victoriametrics/vmanomaly:v1.29.7 \
|
||||
/config.yaml \
|
||||
--licenseFile=/license \
|
||||
--loggerLevel=INFO \
|
||||
@@ -182,7 +182,7 @@ services:
|
||||
# ...
|
||||
vmanomaly:
|
||||
container_name: vmanomaly
|
||||
image: victoriametrics/vmanomaly:v1.29.6
|
||||
image: victoriametrics/vmanomaly:v1.29.7
|
||||
# ...
|
||||
restart: always
|
||||
volumes:
|
||||
@@ -267,6 +267,7 @@ schedulers:
|
||||
# https://docs.victoriametrics.com/anomaly-detection/components/scheduler/#periodic-scheduler
|
||||
class: 'periodic'
|
||||
infer_every: '5m'
|
||||
scatter_infer_jobs: true
|
||||
fit_every: '1d'
|
||||
fit_window: '4w'
|
||||
|
||||
@@ -298,6 +299,7 @@ reader:
|
||||
datasource_url: "https://play.victoriametrics.com/" # [YOUR_DATASOURCE_URL]
|
||||
tenant_id: '0:0'
|
||||
sampling_period: "5m"
|
||||
series_processing_batch_size: 8 # number of time series to process together while preparing data for fit or infer stages
|
||||
queries:
|
||||
# define your queries with MetricsQL - https://docs.victoriametrics.com/victoriametrics/metricsql/
|
||||
cpu_user:
|
||||
@@ -413,11 +415,13 @@ For optimal service behavior, consider the following tweaks when configuring `vm
|
||||
- Configure the **inference frequency** in the [scheduler](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/) section of the configuration file.
|
||||
- Ensure that `infer_every` aligns with your **minimum required alerting frequency**.
|
||||
- For example, if receiving **alerts every 15 minutes** is sufficient (when `anomaly_score > 1`), set `infer_every` to match `reader.sampling_period` or override it per query via `reader.queries.query_xxx.step` for an optimal setup.
|
||||
- Set `scheduler.scatter_infer_jobs` {{% available_from "v1.29.7" anomaly %}} [arg](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/#parameters-1) to `true` to allow for equal distribution of inference jobs across `infer_every` intervals, which can further enhance parallel processing efficiency and reduce resource contention when `reader.queries` contains a large number of queries.
|
||||
|
||||
**Reader**:
|
||||
- Setup the datasource to read data from in the [reader](https://docs.victoriametrics.com/anomaly-detection/components/reader/) section. Include tenant ID if using a [cluster version of VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/) (`multitenant` value {{% available_from "v1.16.2" anomaly %}} can be also used here).
|
||||
- Define queries for input data using [MetricsQL](https://docs.victoriametrics.com/victoriametrics/metricsql/) under `reader.queries` section. Note, it's possible to override reader-level arguments at query level for increased flexibility, e.g. specifying per-query [timezone](https://docs.victoriametrics.com/anomaly-detection/faq/#handling-timezones) or [sampling period](https://docs.victoriametrics.com/anomaly-detection/components/reader/#config-parameters).
|
||||
- For longer `fit_window` intervals in scheduler, consider splitting queries into smaller time ranges to avoid excessive memory usage, timeouts and hitting server-side constraints, so they can be queried separately and reconstructed on `vmanomaly` side. Please refer to this [example](https://docs.victoriametrics.com/anomaly-detection/faq/#handling-large-queries-in-vmanomaly) for more details.
|
||||
- Set `reader.series_processing_batch_size` {{% available_from "v1.29.7" anomaly %}} [arg](https://docs.victoriametrics.com/anomaly-detection/components/reader/#config-parameters) to a reasonable value (4-16, default is 8) to balance between memory usage and processing speed when preparing data for fit or infer stages.
|
||||
|
||||
> If applicable - consider [`VLogsReader`](https://docs.victoriametrics.com/anomaly-detection/components/reader/#victorialogs-reader) {{% available_from "v1.26.0" anomaly %}} to perform anomaly detection on **log-derived metrics**. This is particularly useful for scenarios where log data needs to be analyzed for unusual patterns or behaviors, such as error rates or request latencies.
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ docker run -it --rm \
|
||||
-e VMANOMALY_MCP_SERVER_URL=http://mcp-vmanomaly:8081/mcp \
|
||||
-p 8080:8080 \
|
||||
-p 8490:8490 \
|
||||
victoriametrics/vmanomaly:v1.29.6 \
|
||||
victoriametrics/vmanomaly:v1.29.7 \
|
||||
vmanomaly_config.yaml
|
||||
```
|
||||
|
||||
@@ -640,6 +640,21 @@ If the **results** look good and the **model configuration should be deployed in
|
||||
|
||||
## Changelog
|
||||
|
||||
### v1.7.2
|
||||
Released: 2026-06-25
|
||||
|
||||
vmanomaly version: [v1.29.7](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1297)
|
||||
|
||||
- FEATURE: Added controls for selecting server-configured scheduled models (drop-down inside [model wizard](#model-panel)) and browsing scheduled queries from the running vmanomaly instance ("Queries" button, "scheduled queries" tab).
|
||||
|
||||
- IMPROVEMENT: Surfaced datasource fetch failures from ad-hoc VMUI raw queries as query-level errors instead of returning a successful empty result that triggers a generic "No match" warning. Now the user can see the actual error message from the datasource (e.g. "unauthorized", "not found", etc.) and take appropriate action.
|
||||
|
||||
- BUGFIX: Fixed [UI/query-server](#settings-panel) handling of VictoriaMetrics datasource URLs that already include `/select/multitenant/prometheus`. Such URLs are now recognized as cluster datasource URLs, preserving the multitenant path when proxying VMUI requests and allowing `server.use_reader_connection_settings` to reuse [configured reader credentials for authenticated datasources](#authentication).
|
||||
|
||||
- BUGFIX: Fixed [settings](#settings-panel) inputs for server and datasource URLs so editing, deleting, or pasting text is no longer immediately reverted to the previous value before applying changes.
|
||||
|
||||
- BUGFIX: Fixed [model wizard](#model-panel) settings for [`IsolationForestModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#isolation-forest-multivariate) `contamination`, allowing decimal float values such as `0.1` or `0,1` to be typed or pasted without being collapsed to `0`, while preserving the `"auto"` value.
|
||||
|
||||
### v1.7.1
|
||||
Released: 2026-06-11
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ schedulers:
|
||||
periodic_online: # alias
|
||||
class: 'periodic' # scheduler class
|
||||
infer_every: "30s" # how often to produce anomaly scores for new data
|
||||
scatter_infer_jobs: true # distribute infer jobs evenly across the infer interval to reduce synchronized bursts
|
||||
fit_every: "365d" # how often to re-fit the models, for online models used effectively once, then they are updated with new data and won't require re-fit
|
||||
fit_window: "3d" # how much historical data to use for fit stage
|
||||
start_from: "00:00" # start from specified time, i.e. 00:00 given timezone and do daily fits as `fit_every` is 1 day
|
||||
@@ -56,6 +57,7 @@ schedulers:
|
||||
periodic_offline_1w:
|
||||
class: 'periodic'
|
||||
infer_every: "15m"
|
||||
scatter_infer_jobs: true
|
||||
fit_every: "24h"
|
||||
fit_window: "14d"
|
||||
# if no start_from is specified, jobs will start immediately after service starts
|
||||
@@ -135,6 +137,7 @@ server:
|
||||
port: 8490
|
||||
path_prefix: '/vmanomaly' # optional path prefix for all HTTP routes
|
||||
max_concurrent_tasks: 4 # maximum number of concurrent anomaly detection tasks processed by backend
|
||||
use_reader_connection_settings: True # if True, use reader's datasource_url and credentials for UI requests to datasource
|
||||
uvicorn_config: # optional Uvicorn server configuration
|
||||
log_level: 'warning'
|
||||
```
|
||||
|
||||
@@ -1265,7 +1265,7 @@ monitoring:
|
||||
Let's pull the docker image for `vmanomaly`:
|
||||
|
||||
```sh
|
||||
docker pull victoriametrics/vmanomaly:v1.29.6
|
||||
docker pull victoriametrics/vmanomaly:v1.29.7
|
||||
```
|
||||
|
||||
Now we can run the docker container putting as volumes both config and model file:
|
||||
@@ -1279,7 +1279,7 @@ docker run -it \
|
||||
-v $(PWD)/license:/license \
|
||||
-v $(PWD)/custom_model.py:/vmanomaly/model/custom.py \
|
||||
-v $(PWD)/custom.yaml:/config.yaml \
|
||||
victoriametrics/vmanomaly:v1.29.6 /config.yaml \
|
||||
victoriametrics/vmanomaly:v1.29.7 /config.yaml \
|
||||
--licenseFile=/license
|
||||
--watch
|
||||
```
|
||||
|
||||
@@ -458,6 +458,21 @@ Label names [description](#labelnames)
|
||||
<td>The total number of datapoints received from VictoriaMetrics for the `query_key` query within the specified scheduler `scheduler_alias`, in the `vmanomaly` service running in `preset` mode.</td>
|
||||
<td>
|
||||
|
||||
`url`, `query_key`, `scheduler_alias`, `preset`
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<span style="white-space: nowrap;">`vmanomaly_reader_processing_tasks_queued`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`Gauge`
|
||||
</td>
|
||||
<td>The total number of queued processing tasks {{% available_from "v1.29.7" anomaly %}} (timeseries batches of size `series_processing_batch_size`) for the `query_key` query within the specified scheduler `scheduler_alias`, in the `vmanomaly` service running in `preset` mode. If continuously >0, it may lead to skipped infer runs due to resource contention and timeouts.</td>
|
||||
<td>
|
||||
|
||||
`url`, `query_key`, `scheduler_alias`, `preset`
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -421,7 +421,20 @@ Optional argument{{% available_from "v1.18.1" anomaly %}} allows defining **vali
|
||||
`60s`
|
||||
</td>
|
||||
<td>
|
||||
Optional argument{{% available_from "v1.25.3" anomaly %}} allows specifying a time offset for all queries in `queries`. Defaults to `0s` (0) if not set and can be overridden on a [per-query basis](#per-query-parameters).
|
||||
Optional argument {{% available_from "v1.25.3" anomaly %}}, allows specifying a time offset for all queries in `queries`. Defaults to `0s` (0) if not set and can be overridden on a [per-query basis](#per-query-parameters).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<span style="white-space: nowrap;">`series_processing_batch_size`</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`8`
|
||||
</td>
|
||||
<td>
|
||||
Optional argument {{% available_from "v1.29.7" anomaly %}}, allows specifying the number of time series to process together while preparing data for fit or infer stages. Defaults to `8`. Suggested values are 4-16 for high-cardinality queries.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -450,6 +463,7 @@ reader:
|
||||
sampling_period: '1m'
|
||||
query_from_last_seen_timestamp: True # false by default
|
||||
latency_offset: '1ms'
|
||||
series_processing_batch_size: 8
|
||||
```
|
||||
|
||||
### MetricsQL Playground
|
||||
|
||||
@@ -74,40 +74,7 @@ options={`"scheduler.periodic.PeriodicScheduler"`, `"scheduler.oneoff.OneoffSche
|
||||
|
||||
### Parameters
|
||||
|
||||
For periodic scheduler parameters are defined as differences in times, expressed in difference units, e.g. days, hours, minutes, seconds.
|
||||
|
||||
Examples: `"50s"`, `"4m"`, `"3h"`, `"2d"`, `"1w"`.
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Time granularity</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>s</td>
|
||||
<td>seconds</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m</td>
|
||||
<td>minutes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>h</td>
|
||||
<td>hours</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>d</td>
|
||||
<td>days</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>w</td>
|
||||
<td>weeks</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
For periodic scheduler parameters are defined as differences in times, expressed in difference units, e.g. days, hours, minutes, seconds. Time granularity is defined by the last characters of a string. Examples: `"50s"` (seconds), `"4m"` (minutes), `"3h"` (hours), `"2d"` (days), `"1w"` (weeks).
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
@@ -188,6 +155,21 @@ Specifies when to initiate the first `fit_every` call. Accepts either an ISO 860
|
||||
Defines the local timezone for the `start_from` parameter, if specified. Defaults to `UTC` if no timezone is provided.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<span style="white-space: nowrap;">`scatter_infer_jobs`{{% available_from "v1.29.7" anomaly %}}</span>
|
||||
</td>
|
||||
<td>bool, <span style="white-space: nowrap;">Optional</span></td>
|
||||
<td>
|
||||
|
||||
`true` or `false`
|
||||
</td>
|
||||
<td>
|
||||
|
||||
If `true`, distribute infer jobs and their dependent data-fetch jobs evenly across the infer interval. This reduces synchronized read and inference bursts for high-scale configurations. Defaults to `false`. Useful when `settings.n_workers > 1`, `reader.queries` cardinality is high, and `scheduler.infer_every` is small.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -200,6 +182,7 @@ schedulers:
|
||||
# (or class: "scheduler.periodic.PeriodicScheduler" for versions before v1.13.0, without class alias support)
|
||||
fit_window: "14d"
|
||||
infer_every: "1m"
|
||||
scatter_infer_jobs: true # Distribute infer jobs evenly across the infer interval to reduce synchronized bursts.
|
||||
fit_every: "1h"
|
||||
start_from: "20:00" # If launched before 20:00 (local Kyiv time), the first run starts today at 20:00. Otherwise, it starts tomorrow at 20:00.
|
||||
tz: "Europe/Kyiv" # Defaults to 'UTC' if not specified.
|
||||
|
||||
@@ -395,7 +395,7 @@ services:
|
||||
restart: always
|
||||
vmanomaly:
|
||||
container_name: vmanomaly
|
||||
image: victoriametrics/vmanomaly:v1.29.6
|
||||
image: victoriametrics/vmanomaly:v1.29.7
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
|
||||
@@ -16,39 +16,9 @@ aliases:
|
||||
---
|
||||
## Install Recommendation
|
||||
|
||||
It is recommended to run the latest available release of VictoriaMetrics from [this page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest), as it includes all bug fixes and enhancements.
|
||||
It is recommended to run the latest available release of VictoriaMetrics from [this page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest), since it contains all the bugfixes and enhancements.
|
||||
|
||||
There is no need to tune VictoriaMetrics, as it uses reasonable defaults for its command-line flags. These flags are automatically adjusted for the available CPU and RAM resources. There is no need for operating system tuning because VictoriaMetrics is optimized for default OS settings. The only option is to increase the limit on the [number of open files in the OS](https://medium.com/@muhammadtriwibowo/set-permanently-ulimit-n-open-files-in-ubuntu-4d61064429a), so VictoriaMetrics could accept more incoming connections and could keep open more data files. VictoriaMetrics is tested and developed to run efficiently on these defaults, which fit the majority of workloads. Change a setting only when the docs explicitly instruct you to, including when and why.
|
||||
|
||||
## Memory
|
||||
|
||||
VictoriaMetrics components detect the available memory at startup as the smaller of the host RAM and the cgroup memory limit.
|
||||
To keep them stable:
|
||||
|
||||
1. Do not set `GOMEMLIMIT`. VictoriaMetrics paces garbage collection with `GOGC` and does not use `GOMEMLIMIT` for sizing.
|
||||
`GOMEMLIMIT` bounds only Go runtime memory, not the process's total RSS, off-heap caches, mmap-ed files,
|
||||
or the OS page cache, so it is not a reliable way to size VictoriaMetrics containers. It can curb Go heap growth,
|
||||
but setting it too low makes the garbage collector run more often than `GOGC` dictates,
|
||||
spending in the worst case up to ~50% of CPU time on GC —
|
||||
the ceiling enforced by Go's [GC CPU limiter](https://go.dev/doc/gc-guide).
|
||||
Set the container memory limit, and VictoriaMetrics automatically sizes its caches and memory-aware limits.
|
||||
|
||||
1. Do not hand-tune cache sizes with `-storage.cacheSize*` flags; rely on the defaults.
|
||||
If a component needs larger caches, move it to a host with more memory.
|
||||
See [Cache tuning](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#cache-tuning).
|
||||
|
||||
1. Do not autoscale `vmstorage` with the Vertical Pod Autoscaler (VPA) or the Horizontal Pod Autoscaler (HPA).
|
||||
VPA: cache sizes are derived from the memory limit, read only once at startup.
|
||||
Modes that recreate the pod (`Recreate`, `Auto`) reset the caches and force a cold start,
|
||||
causing slow inserts and query latency spikes. In-place resizing is not picked up at runtime,
|
||||
so `vmstorage` keeps the budget and `vm_available_memory_bytes` initialized at startup, which also skews the dashboards.
|
||||
Set fixed memory requests and limits for `vmstorage` rather than autoscaling.
|
||||
HPA: `vmstorage` is stateful. Adding nodes sends new series to them while existing data stays where it is.
|
||||
Removing nodes makes the data on them unavailable to queries and can cause data loss without replication.
|
||||
Frequent scaling keeps changing the routing and can degrade the cluster.
|
||||
|
||||
1. Leave headroom for the OS page cache and workload spikes —
|
||||
see [capacity planning](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#capacity-planning).
|
||||
There is no need to tune VictoriaMetrics because it uses reasonable defaults for command-line flags. These flags are automatically adjusted for the available CPU and RAM resources. There is no need in Operating System tuning because VictoriaMetrics is optimized for default OS settings. The only option is to increase the limit on the [number of open files in the OS](https://medium.com/@muhammadtriwibowo/set-permanently-ulimit-n-open-files-in-ubuntu-4d61064429a), so VictoriaMetrics could accept more incoming connections and could keep open more data files.
|
||||
|
||||
## Swap
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ If you see unexpected or unreliable query results from VictoriaMetrics, then try
|
||||
|
||||
These are the most common reasons for slow data ingestion in VictoriaMetrics:
|
||||
|
||||
1. [Memory shortage](#memory-shortage) for the given amounts of [active time series](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-an-active-time-series).
|
||||
1. Memory shortage for the given amounts of [active time series](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-an-active-time-series).
|
||||
|
||||
VictoriaMetrics (or `vmstorage` in the cluster version of VictoriaMetrics) maintains an in-memory cache `storage/tsid`
|
||||
for a quick search for internal series IDs for each incoming metric. VictoriaMetrics automatically determines the maximum
|
||||
@@ -352,119 +352,6 @@ These are the solutions that exist for improving the performance of slow queries
|
||||
See also [this article](https://valyala.medium.com/how-to-optimize-promql-and-metricsql-queries-85a1b75bf986),
|
||||
which explains how to identify and optimize slow queries.
|
||||
|
||||
## Memory shortage
|
||||
|
||||
+High memory utilization alone does not indicate a shortage.
|
||||
VictoriaMetrics components could operate normally under high memory utilization,
|
||||
but it is recommended to have
|
||||
[at least 50% of free memory for stability](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#capacity-planning).
|
||||
Before reacting, it is important to identify memory shortage — not enough memory for the workload —
|
||||
apart from high utilization and memory pressure.
|
||||
Memory pressure is the kernel's reclaim activity as shown by [PSI](https://docs.kernel.org/accounting/psi.html).
|
||||
It could be an indicator of a shortage. It is better to avoid memory pressure
|
||||
because it puts a VictoriaMetrics component at risk of not getting enough memory, which can lead to OOMs.
|
||||
|
||||
### Memory resource accounting
|
||||
|
||||
VictoriaMetrics components detect the available memory at startup as the smaller of the host RAM and the cgroup memory limit,
|
||||
and expose it as `vm_available_memory_bytes` metric. Its main observable parts are:
|
||||
|
||||
1. Go (anonymous) memory — `process_resident_memory_anon_bytes`. It includes:
|
||||
|
||||
- A portion of total memory for caches, capped by `-memory.allowedPercent` (default 60%) or `-memory.allowedBytes`.
|
||||
The memory is used for in-process caches, for example, `storage/tsid`, `indexdb` blocks, and the rollup cache.
|
||||
- The Go heap, goroutine stacks, anonymous off-heap allocations, and runtime overhead used for ingestion and queries.
|
||||
|
||||
1. OS page cache for mmap-ed data and index files — the OS uses the memory not taken by the cache budget or the Go heap,
|
||||
and reclaims it as needed. `process_resident_memory_file_bytes` shows the part of these file-backed pages
|
||||
currently resident for the process, so it is a lower bound on the useful page cache.
|
||||
|
||||
Before tuning and troubleshooting memory issues,
|
||||
see [Best practices](https://docs.victoriametrics.com/victoriametrics/bestpractices/#memory)
|
||||
for memory configuration guidance. Be sure that `GOMEMLIMIT` is not set,
|
||||
and that the [VPA](https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler) is not used for `vmstorage` pods.
|
||||
|
||||
### Signals
|
||||
|
||||
These metrics describe how a component uses memory and are visible on the
|
||||
[official Grafana dashboards for VictoriaMetrics](https://grafana.com/orgs/victoriametrics/dashboards).
|
||||
None of them means a shortage on its own — the next section reads them together.
|
||||
|
||||
- `process_resident_memory_anon_bytes` / `vm_available_memory_bytes` — anonymous memory (caches plus Go heap)
|
||||
as a share of the available memory. This memory can't be reclaimed back by OS.
|
||||
|
||||
- `process_resident_memory_file_bytes` — the process's resident file-backed memory for mmap-ed data and index files.
|
||||
It is reclaimable and is a lower bound on the useful page cache.
|
||||
|
||||
- `process_pressure_memory_waiting_seconds_total`, `process_pressure_memory_stalled_seconds_total` —
|
||||
[PSI](https://docs.kernel.org/accounting/psi.html): time tasks were stalled waiting for memory reclaim.
|
||||
Populated only on Linux hosts with PSI support.
|
||||
|
||||
- `vm_cache_size_bytes` and `vm_cache_size_max_bytes` (per `type`, e.g., `storage/tsid`) —
|
||||
current and maximum size of each in-process cache. Their ratio shows how full a cache is.
|
||||
|
||||
- `vm_slow_row_inserts_total` vs `vm_rows_added_to_storage_total` —
|
||||
share of ingested rows that missed the `storage/tsid` cache ([slow inserts](#slow-data-ingestion)).
|
||||
|
||||
- `increase(vm_new_timeseries_created_total[24h])` vs the number of
|
||||
[active time series](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-an-active-time-series) —
|
||||
the [churn rate](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-high-churn-rate):
|
||||
new series registered over a day relative to the active set.
|
||||
|
||||
- `process_major_pagefaults_total` — rate of pages read from disk (page-cache misses, refaults, or swap-in).
|
||||
|
||||
- `go_memstats_heap_inuse_bytes` and the `CPU spent on GC` panel — the Go heap working set and the CPU cost of garbage collection.
|
||||
|
||||
### Shortage patterns
|
||||
|
||||
There are three patterns of memory shortage:
|
||||
|
||||
1. **The cache cannot hold the active series (cache-bound shortage).** The `storage/tsid` cache is full:
|
||||
`vm_cache_size_bytes{type="storage/tsid"}` is close to `vm_cache_size_max_bytes{type="storage/tsid"}`, and slow inserts stay high.
|
||||
Most sustained slow inserts are caused by `storage/tsid` cache misses.
|
||||
The main sources are new series and misses on already-known active series.
|
||||
`indexdb`-rotation repopulation can also contribute to `vm_slow_row_inserts_total`,
|
||||
but it usually appears as a time-bound spike around rotation, not as a sustained high slow-inserts rate.
|
||||
If slow inserts stay above 5% of ingested rows during a stable window without restarts or rerouting
|
||||
and cannot be roughly explained by `rate(vm_new_timeseries_created_total)` plus `rate(vm_timeseries_repopulated_total)`,
|
||||
it points to misses on active series that no longer fit the cache.
|
||||
See the detailed explanation in the [Slow data ingestion](#slow-data-ingestion) section.
|
||||
|
||||
1. **The Go heap exceeds its budget (heap-bound shortage).** `go_memstats_heap_inuse_bytes` climbs well above its stable baseline.
|
||||
Check it together with the non-cache part of anonymous memory:
|
||||
`process_resident_memory_anon_bytes` minus the component's `vm_cache_size_bytes`.
|
||||
There is no fixed normal value, so compare against the component's stable historical data.
|
||||
A `process_resident_memory_anon_bytes / vm_available_memory_bytes` ratio that keeps rising leaves little headroom
|
||||
and may lead to an [OOM kill](#out-of-memory-errors).
|
||||
If heap growth tracks query or ingestion load, it is workload-driven.
|
||||
If it grows regardless of load, suspect a memory leak and collect a heap profile.
|
||||
|
||||
1. **The OS page cache is too small (I/O-bound shortage).** `process_major_pagefaults_total` rises above the component's baseline
|
||||
and `process_resident_memory_file_bytes` shrinks or stays too small for the working set,
|
||||
while disk reads and query latency grow.
|
||||
The file working set (data and index parts) no longer fits within the available memory for the page cache.
|
||||
Add memory according to
|
||||
[capacity planning](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#capacity-planning).
|
||||
|
||||
PSI is an additional confirmation signal: a rising `process_pressure_memory_*` value indicates that the kernel is reclaiming memory for the cgroup.
|
||||
Where PSI is unavailable, rely on the per-pattern signals above.
|
||||
|
||||
### How to fix
|
||||
|
||||
After distinguishing the shortage from normal high memory utilization, and if it is sustained,
|
||||
you can use the approaches below to resolve it:
|
||||
|
||||
- Reduce the number of [active time series](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-an-active-time-series)
|
||||
or the [churn rate](https://docs.victoriametrics.com/victoriametrics/faq/#what-is-high-churn-rate) —
|
||||
see [Slow data ingestion](#slow-data-ingestion).
|
||||
- Increase available memory by scaling vertically or horizontally — see capacity planning for
|
||||
[single-node VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#capacity-planning)
|
||||
and the [cluster version](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#capacity-planning).
|
||||
Scaling memory is preferred over tuning individual caches, as covered in [Out of memory errors](#out-of-memory-errors).
|
||||
- Investigate Go heap growth or a suspected memory leak — collect a memory profile using the profiling guide for
|
||||
[single-node VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#profiling)
|
||||
or [cluster components](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#profiling).
|
||||
|
||||
## Out of memory errors
|
||||
|
||||
The following are the most common sources of out-of-memory (aka OOM) crashes in VictoriaMetrics:
|
||||
|
||||
@@ -26,6 +26,9 @@ See also [LTS releases](https://docs.victoriametrics.com/victoriametrics/lts-rel
|
||||
|
||||
## tip
|
||||
|
||||
* BUGFIX: `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): propagate cache reset operation to `selectNode` when `/internal/resetRollupResultCache` is called. Previously, the propagation only happened when the `delete_series` API was called. See [#11112](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11112).
|
||||
* BUGFIX: [stream aggregation](https://docs.victoriametrics.com/victoriametrics/stream-aggregation/): fix possible unexpected increases in `rate_avg` and `rate_sum` if an out-of-order sample is ingested after the previous flush. See [#11140](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11140).
|
||||
|
||||
## [v1.146.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.146.0)
|
||||
|
||||
Released at 2026-06-22
|
||||
@@ -45,11 +48,11 @@ Released at 2026-06-22
|
||||
* BUGFIX: [stream aggregation](https://docs.victoriametrics.com/victoriametrics/stream-aggregation/): fix issue with producing aggregated samples with identical timestamps between flushes. See [#10808](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/10808).
|
||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/): fix potential corruption of remote-write metadata `Unit` values. See [#11120](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11120). Thanks for @fxrlv for the contribution.
|
||||
* BUGFIX: [vmalert](https://docs.victoriametrics.com/victoriametrics/vmalert/),[vmauth](https://docs.victoriametrics.com/victoriametrics/vmauth/),[vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) and [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/): fix rare unbounded shutdown delay when config reload takes longer than `-configCheckInterval`. See [#11107](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11107). Thanks to @PleasingFungus for contribution.
|
||||
* BUGFIX: [vmbackup](https://docs.victoriametrics.com/vmbackup/), [vmbackupmanager](https://docs.victoriametrics.com/victoriametrics/vmbackupmanager/): do not fail backup list if directory is absent while using `fs://` destination to align with other protocols. See [6c3c548d](https://github.com/VictoriaMetrics/VictoriaMetrics/commit/6c3c548ddb0385b749e731f52276f130e2a4e4a8).
|
||||
* BUGFIX: [vmctl](https://docs.victoriametrics.com/victoriametrics/vmctl/): push metrics to configured `-pushmetrics.url` on shutdown when migration fails. Previously, metrics were not pushed if vmctl exited with an error. See [#11081](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11081). Thanks to @zasdaym for contribution.
|
||||
* BUGFIX: [vmrestore](https://docs.victoriametrics.com/victoriametrics/vmrestore/): disallow restoring parts outside the configured `-storageDataPath` directory. See [710c920d](https://github.com/VictoriaMetrics/VictoriaMetrics/commit/710c920d6083327042a309e449fae4383617d817).
|
||||
* BUGFIX: `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): correctly apply long tenant filters. Previously, such filters could be truncated, causing tenants to be matched incorrectly. See [#11096](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11096). Thanks for @fxrlv for the contribution.
|
||||
* BUGFIX: `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): fix corrupted metrics metadata when a response contains multiple rows. See [#11115](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11115). Thanks for @fxrlv for the contribution.
|
||||
* BUGFIX: [vmbackup](https://docs.victoriametrics.com/vmbackup/), [vmbackupmanager](https://docs.victoriametrics.com/victoriametrics/vmbackupmanager/): do not fail backup list if directory is absent while using `fs://` destination to align with other protocols. See [6c3c548](https://github.com/VictoriaMetrics/VictoriaMetrics/commit/6c3c548ddb0385b749e731f52276f130e2a4e4a8)
|
||||
* BUGFIX: `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): don't cache empty responses for tenant IDs discovery during [multitenant queries](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#multitenant-reads). This problem was visible during integration tests when multitenant queries were executed before the first ingestion happened. See [#10982](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/10982)
|
||||
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): properly escape `metricFamilyName` at metrics metadata response. See [#11129](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11129). Thanks for @fxrlv for the contribution.
|
||||
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): prevent more cases of panic during directory deletion on `NFS`-based mounts. See [#11060](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11060).
|
||||
|
||||
@@ -622,11 +622,13 @@ curl -Is http://localhost:8428/internal/resetRollupResultCache
|
||||
Cluster version of VictoriaMetrics:
|
||||
|
||||
```sh
|
||||
curl -Is http://<vmselect>:8481/internal/resetRollupResultCache
|
||||
curl -Is http://<vmselect>:8481/internal/resetRollupResultCache?propagate=1
|
||||
```
|
||||
|
||||
vmselect will propagate this call to the rest of the vmselects listed in its `-selectNode` cmd-line flag. If this
|
||||
flag isn't set, then cache need to be purged from each vmselect individually.
|
||||
vmselect will propagate this call to the rest of the vmselects listed in its `-selectNode` cmd-line flag when `propagate=1` argument is set.
|
||||
If this flag or the `propagate` argument isn't set, then cache need to be purged from each vmselect individually.
|
||||
|
||||
If `-search.resetCacheAuthKey` is set, it will be attached to the propagation request as query argument.
|
||||
|
||||
### TCP and UDP
|
||||
|
||||
|
||||
2
go.mod
2
go.mod
@@ -7,7 +7,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.22.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.14.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.8.0
|
||||
github.com/VictoriaMetrics/VictoriaLogs v1.121.1-0.20260616132739-c901a1e31cb3
|
||||
github.com/VictoriaMetrics/VictoriaLogs v1.51.1-0.20260624061259-dc94972a8708
|
||||
github.com/VictoriaMetrics/easyproto v1.2.0
|
||||
github.com/VictoriaMetrics/fastcache v1.13.3
|
||||
github.com/VictoriaMetrics/metrics v1.44.0
|
||||
|
||||
4
go.sum
4
go.sum
@@ -52,8 +52,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0/go.mod h1:YqwkQPrWSC7+byyc1VlKbWLBF5JsW5IoL6xUkemYSXk=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/VictoriaMetrics/VictoriaLogs v1.121.1-0.20260616132739-c901a1e31cb3 h1:3eP8RRZitbga5EYiQ3IANrMPxpBwMAX4VA6akDaXwpU=
|
||||
github.com/VictoriaMetrics/VictoriaLogs v1.121.1-0.20260616132739-c901a1e31cb3/go.mod h1:H4sDxcvk6OmC6zOt++IlDyrwfbn4F1eSLwMpR+kpRt8=
|
||||
github.com/VictoriaMetrics/VictoriaLogs v1.51.1-0.20260624061259-dc94972a8708 h1:D9/Jzlm3B8PBnrWxg4ft8KYZdG607dV3lpBfPCoiJD8=
|
||||
github.com/VictoriaMetrics/VictoriaLogs v1.51.1-0.20260624061259-dc94972a8708/go.mod h1:H4sDxcvk6OmC6zOt++IlDyrwfbn4F1eSLwMpR+kpRt8=
|
||||
github.com/VictoriaMetrics/easyproto v1.2.0 h1:FJT9uNXA2isppFuJErbLqD306KoFlehl7Wn2dg/6oIE=
|
||||
github.com/VictoriaMetrics/easyproto v1.2.0/go.mod h1:QlGlzaJnDfFd8Lk6Ci/fuLxfTo3/GThPs2KH23mv710=
|
||||
github.com/VictoriaMetrics/fastcache v1.13.3 h1:rBabE0iIxcqKEMCwUmwHZ9dgEqXerg8FRbRDUvC7OVc=
|
||||
|
||||
@@ -36,10 +36,12 @@ function submitRelabelDebugForm(e) {
|
||||
<div class="container-fluid">
|
||||
<a href="https://docs.victoriametrics.com/victoriametrics/relabeling/" target="_blank">Relabeling docs</a>{% space %}
|
||||
|
||||
{% if targetURL != "" %}
|
||||
<a href="metric-relabel-debug{% if targetID != "" %}?id={%s targetID %}{% endif %}">Metric relabel debug</a>
|
||||
{% else %}
|
||||
<a href="target-relabel-debug{% if targetID != "" %}?id={%s targetID %}{% endif %}">Target relabel debug</a>
|
||||
{% if targetID != "" %}
|
||||
{% if targetURL != "" %}
|
||||
<a href="metric-relabel-debug?id={%s targetID %}">Metric relabel debug</a>
|
||||
{% else %}
|
||||
<a href="target-relabel-debug?id={%s targetID %}">Target relabel debug</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<br>
|
||||
|
||||
@@ -80,425 +80,417 @@ func StreamRelabelDebugStepsHTML(qw422016 *qt422016.Writer, targetURL, targetID
|
||||
//line lib/promrelabel/debug.qtpl:37
|
||||
qw422016.N().S(` `)
|
||||
//line lib/promrelabel/debug.qtpl:39
|
||||
if targetURL != "" {
|
||||
//line lib/promrelabel/debug.qtpl:39
|
||||
qw422016.N().S(`<a href="metric-relabel-debug`)
|
||||
if targetID != "" {
|
||||
//line lib/promrelabel/debug.qtpl:40
|
||||
if targetID != "" {
|
||||
if targetURL != "" {
|
||||
//line lib/promrelabel/debug.qtpl:40
|
||||
qw422016.N().S(`?id=`)
|
||||
//line lib/promrelabel/debug.qtpl:40
|
||||
qw422016.E().S(targetID)
|
||||
//line lib/promrelabel/debug.qtpl:40
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:40
|
||||
qw422016.N().S(`">Metric relabel debug</a>`)
|
||||
qw422016.N().S(`<a href="metric-relabel-debug?id=`)
|
||||
//line lib/promrelabel/debug.qtpl:41
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:41
|
||||
qw422016.N().S(`<a href="target-relabel-debug`)
|
||||
//line lib/promrelabel/debug.qtpl:42
|
||||
if targetID != "" {
|
||||
//line lib/promrelabel/debug.qtpl:42
|
||||
qw422016.N().S(`?id=`)
|
||||
//line lib/promrelabel/debug.qtpl:42
|
||||
qw422016.E().S(targetID)
|
||||
//line lib/promrelabel/debug.qtpl:41
|
||||
qw422016.N().S(`">Metric relabel debug</a>`)
|
||||
//line lib/promrelabel/debug.qtpl:42
|
||||
}
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:42
|
||||
qw422016.N().S(`">Target relabel debug</a>`)
|
||||
qw422016.N().S(`<a href="target-relabel-debug?id=`)
|
||||
//line lib/promrelabel/debug.qtpl:43
|
||||
qw422016.E().S(targetID)
|
||||
//line lib/promrelabel/debug.qtpl:43
|
||||
qw422016.N().S(`">Target relabel debug</a>`)
|
||||
//line lib/promrelabel/debug.qtpl:44
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:45
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:43
|
||||
//line lib/promrelabel/debug.qtpl:45
|
||||
qw422016.N().S(`<br>`)
|
||||
//line lib/promrelabel/debug.qtpl:46
|
||||
//line lib/promrelabel/debug.qtpl:48
|
||||
if err != nil {
|
||||
//line lib/promrelabel/debug.qtpl:47
|
||||
//line lib/promrelabel/debug.qtpl:49
|
||||
htmlcomponents.StreamErrorNotification(qw422016, err)
|
||||
//line lib/promrelabel/debug.qtpl:48
|
||||
//line lib/promrelabel/debug.qtpl:50
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:48
|
||||
//line lib/promrelabel/debug.qtpl:50
|
||||
qw422016.N().S(`<div class="m-3"><form method="POST" onsubmit="submitRelabelDebugForm(event)">`)
|
||||
//line lib/promrelabel/debug.qtpl:52
|
||||
//line lib/promrelabel/debug.qtpl:54
|
||||
streamrelabelDebugFormInputs(qw422016, metric, relabelConfigs)
|
||||
//line lib/promrelabel/debug.qtpl:53
|
||||
//line lib/promrelabel/debug.qtpl:55
|
||||
if targetID != "" {
|
||||
//line lib/promrelabel/debug.qtpl:53
|
||||
//line lib/promrelabel/debug.qtpl:55
|
||||
qw422016.N().S(`<input type="hidden" name="id" value="`)
|
||||
//line lib/promrelabel/debug.qtpl:54
|
||||
//line lib/promrelabel/debug.qtpl:56
|
||||
qw422016.E().S(targetID)
|
||||
//line lib/promrelabel/debug.qtpl:54
|
||||
//line lib/promrelabel/debug.qtpl:56
|
||||
qw422016.N().S(`" />`)
|
||||
//line lib/promrelabel/debug.qtpl:55
|
||||
//line lib/promrelabel/debug.qtpl:57
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:55
|
||||
//line lib/promrelabel/debug.qtpl:57
|
||||
qw422016.N().S(`<input type="submit" value="Submit" class="btn btn-primary m-1" />`)
|
||||
//line lib/promrelabel/debug.qtpl:57
|
||||
//line lib/promrelabel/debug.qtpl:59
|
||||
if targetID != "" {
|
||||
//line lib/promrelabel/debug.qtpl:57
|
||||
//line lib/promrelabel/debug.qtpl:59
|
||||
qw422016.N().S(`<button type="button" onclick="location.href='?id=`)
|
||||
//line lib/promrelabel/debug.qtpl:58
|
||||
//line lib/promrelabel/debug.qtpl:60
|
||||
qw422016.E().S(targetID)
|
||||
//line lib/promrelabel/debug.qtpl:58
|
||||
//line lib/promrelabel/debug.qtpl:60
|
||||
qw422016.N().S(`'" class="btn btn-secondary m-1">Reset</button>`)
|
||||
//line lib/promrelabel/debug.qtpl:59
|
||||
//line lib/promrelabel/debug.qtpl:61
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:59
|
||||
//line lib/promrelabel/debug.qtpl:61
|
||||
qw422016.N().S(`</form></div><div class="row"><main class="col-12">`)
|
||||
//line lib/promrelabel/debug.qtpl:65
|
||||
//line lib/promrelabel/debug.qtpl:67
|
||||
streamrelabelDebugSteps(qw422016, dss, targetURL, targetID)
|
||||
//line lib/promrelabel/debug.qtpl:65
|
||||
//line lib/promrelabel/debug.qtpl:67
|
||||
qw422016.N().S(`</main></div></div></body></html>`)
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
func WriteRelabelDebugStepsHTML(qq422016 qtio422016.Writer, targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) {
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
StreamRelabelDebugStepsHTML(qw422016, targetURL, targetID, dss, metric, relabelConfigs, err)
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
func RelabelDebugStepsHTML(targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) string {
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
WriteRelabelDebugStepsHTML(qb422016, targetURL, targetID, dss, metric, relabelConfigs, err)
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:75
|
||||
func streamrelabelDebugFormInputs(qw422016 *qt422016.Writer, metric, relabelConfigs string) {
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:75
|
||||
qw422016.N().S(`<div>Relabel configs:<br/><textarea name="relabel_configs" style="width: 100%; height: 15em; font-family: monospace" class="m-1">`)
|
||||
//line lib/promrelabel/debug.qtpl:76
|
||||
//line lib/promrelabel/debug.qtpl:78
|
||||
qw422016.E().S(relabelConfigs)
|
||||
//line lib/promrelabel/debug.qtpl:76
|
||||
//line lib/promrelabel/debug.qtpl:78
|
||||
qw422016.N().S(`</textarea></div><div>Labels:<br/><textarea name="metric" style="width: 100%; height: 5em; font-family: monospace" class="m-1">`)
|
||||
//line lib/promrelabel/debug.qtpl:81
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qw422016.E().S(metric)
|
||||
//line lib/promrelabel/debug.qtpl:81
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qw422016.N().S(`</textarea></div>`)
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
func writerelabelDebugFormInputs(qq422016 qtio422016.Writer, metric, relabelConfigs string) {
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
streamrelabelDebugFormInputs(qw422016, metric, relabelConfigs)
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
func relabelDebugFormInputs(metric, relabelConfigs string) string {
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
writerelabelDebugFormInputs(qb422016, metric, relabelConfigs)
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
func writerelabelDebugFormInputs(qq422016 qtio422016.Writer, metric, relabelConfigs string) {
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
streamrelabelDebugFormInputs(qw422016, metric, relabelConfigs)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
func relabelDebugFormInputs(metric, relabelConfigs string) string {
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
writerelabelDebugFormInputs(qb422016, metric, relabelConfigs)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:87
|
||||
func streamrelabelDebugSteps(qw422016 *qt422016.Writer, dss []DebugStep, targetURL, targetID string) {
|
||||
//line lib/promrelabel/debug.qtpl:86
|
||||
//line lib/promrelabel/debug.qtpl:88
|
||||
if len(dss) > 0 {
|
||||
//line lib/promrelabel/debug.qtpl:86
|
||||
//line lib/promrelabel/debug.qtpl:88
|
||||
qw422016.N().S(`<div class="m-3"><b>Original labels:</b> <samp>`)
|
||||
//line lib/promrelabel/debug.qtpl:88
|
||||
//line lib/promrelabel/debug.qtpl:90
|
||||
streammustFormatLabels(qw422016, dss[0].In)
|
||||
//line lib/promrelabel/debug.qtpl:88
|
||||
//line lib/promrelabel/debug.qtpl:90
|
||||
qw422016.N().S(`</samp></div>`)
|
||||
//line lib/promrelabel/debug.qtpl:90
|
||||
//line lib/promrelabel/debug.qtpl:92
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:90
|
||||
//line lib/promrelabel/debug.qtpl:92
|
||||
qw422016.N().S(`<table class="table table-striped table-hover table-bordered table-sm"><thead><tr><th scope="col" style="width: 5%">Step</th><th scope="col" style="width: 25%">Relabeling Rule</th><th scope="col" style="width: 35%">Input Labels</th><th scope="col" stile="width: 35%">Output labels</a></tr></thead><tbody>`)
|
||||
//line lib/promrelabel/debug.qtpl:101
|
||||
for i, ds := range dss {
|
||||
//line lib/promrelabel/debug.qtpl:103
|
||||
for i, ds := range dss {
|
||||
//line lib/promrelabel/debug.qtpl:105
|
||||
inLabels, inErr := promutil.NewLabelsFromString(ds.In)
|
||||
outLabels, outErr := promutil.NewLabelsFromString(ds.Out)
|
||||
changedLabels := getChangedLabelNames(inLabels, outLabels)
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:106
|
||||
//line lib/promrelabel/debug.qtpl:108
|
||||
qw422016.N().S(`<tr><td>`)
|
||||
//line lib/promrelabel/debug.qtpl:108
|
||||
//line lib/promrelabel/debug.qtpl:110
|
||||
qw422016.N().D(i)
|
||||
//line lib/promrelabel/debug.qtpl:108
|
||||
//line lib/promrelabel/debug.qtpl:110
|
||||
qw422016.N().S(`</td><td><b><pre class="m-2">`)
|
||||
//line lib/promrelabel/debug.qtpl:109
|
||||
//line lib/promrelabel/debug.qtpl:111
|
||||
qw422016.E().S(ds.Rule)
|
||||
//line lib/promrelabel/debug.qtpl:109
|
||||
//line lib/promrelabel/debug.qtpl:111
|
||||
qw422016.N().S(`</pre></b></td><td>`)
|
||||
//line lib/promrelabel/debug.qtpl:111
|
||||
//line lib/promrelabel/debug.qtpl:113
|
||||
if inErr == nil {
|
||||
//line lib/promrelabel/debug.qtpl:111
|
||||
//line lib/promrelabel/debug.qtpl:113
|
||||
qw422016.N().S(`<div class="m-2" style="font-size: 0.9em" title="deleted and updated labels highlighted in red">`)
|
||||
//line lib/promrelabel/debug.qtpl:113
|
||||
//line lib/promrelabel/debug.qtpl:115
|
||||
streamlabelsWithHighlight(qw422016, inLabels, changedLabels, "#D15757")
|
||||
//line lib/promrelabel/debug.qtpl:113
|
||||
//line lib/promrelabel/debug.qtpl:115
|
||||
qw422016.N().S(`</div>`)
|
||||
//line lib/promrelabel/debug.qtpl:115
|
||||
//line lib/promrelabel/debug.qtpl:117
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:115
|
||||
//line lib/promrelabel/debug.qtpl:117
|
||||
qw422016.N().S(`<div class="m-2" style="font-size: 0.9em; color: red" title="error parsing input labels"><pre>`)
|
||||
//line lib/promrelabel/debug.qtpl:117
|
||||
qw422016.E().S(inErr.Error())
|
||||
//line lib/promrelabel/debug.qtpl:117
|
||||
qw422016.N().S(`</pre></div>`)
|
||||
//line lib/promrelabel/debug.qtpl:119
|
||||
break
|
||||
//line lib/promrelabel/debug.qtpl:120
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:120
|
||||
qw422016.N().S(`</td><td>`)
|
||||
//line lib/promrelabel/debug.qtpl:123
|
||||
if outErr == nil {
|
||||
//line lib/promrelabel/debug.qtpl:123
|
||||
qw422016.N().S(`<div class="m-2" style="font-size: 0.9em" title="added and updated labels highlighted in blue">`)
|
||||
//line lib/promrelabel/debug.qtpl:125
|
||||
streamlabelsWithHighlight(qw422016, outLabels, changedLabels, "#4495e0")
|
||||
//line lib/promrelabel/debug.qtpl:125
|
||||
qw422016.N().S(`</div>`)
|
||||
//line lib/promrelabel/debug.qtpl:127
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:127
|
||||
qw422016.N().S(`<div class="m-2" style="font-size: 0.9em; color: red" title="error parsing output labels"><pre>`)
|
||||
//line lib/promrelabel/debug.qtpl:129
|
||||
qw422016.E().S(outErr.Error())
|
||||
//line lib/promrelabel/debug.qtpl:129
|
||||
qw422016.E().S(inErr.Error())
|
||||
//line lib/promrelabel/debug.qtpl:119
|
||||
qw422016.N().S(`</pre></div>`)
|
||||
//line lib/promrelabel/debug.qtpl:131
|
||||
//line lib/promrelabel/debug.qtpl:121
|
||||
break
|
||||
//line lib/promrelabel/debug.qtpl:132
|
||||
//line lib/promrelabel/debug.qtpl:122
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:132
|
||||
qw422016.N().S(`</td></tr>`)
|
||||
//line lib/promrelabel/debug.qtpl:135
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:135
|
||||
qw422016.N().S(`</tbody></table>`)
|
||||
//line lib/promrelabel/debug.qtpl:138
|
||||
if len(dss) > 0 {
|
||||
//line lib/promrelabel/debug.qtpl:138
|
||||
qw422016.N().S(`<div class="m-3"><b>Resulting labels:</b> <samp>`)
|
||||
//line lib/promrelabel/debug.qtpl:140
|
||||
streammustFormatLabels(qw422016, dss[len(dss)-1].Out)
|
||||
//line lib/promrelabel/debug.qtpl:140
|
||||
qw422016.N().S(`</samp>`)
|
||||
//line lib/promrelabel/debug.qtpl:141
|
||||
if targetURL != "" {
|
||||
//line lib/promrelabel/debug.qtpl:141
|
||||
qw422016.N().S(`<div><b>Target URL:</b>`)
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.N().S(` `)
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.N().S(`<a href="`)
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.E().S(targetURL)
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.N().S(`" target="_blank">`)
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.E().S(targetURL)
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.N().S(`</a>`)
|
||||
//line lib/promrelabel/debug.qtpl:144
|
||||
if targetID != "" {
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
qw422016.N().S(` `)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
qw422016.N().S(`(<a href="target_response?id=`)
|
||||
//line lib/promrelabel/debug.qtpl:146
|
||||
qw422016.E().S(targetID)
|
||||
//line lib/promrelabel/debug.qtpl:146
|
||||
qw422016.N().S(`" target="_blank" title="click to fetch target response on behalf of the scraper">response</a>)`)
|
||||
//line lib/promrelabel/debug.qtpl:147
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:147
|
||||
//line lib/promrelabel/debug.qtpl:122
|
||||
qw422016.N().S(`</td><td>`)
|
||||
//line lib/promrelabel/debug.qtpl:125
|
||||
if outErr == nil {
|
||||
//line lib/promrelabel/debug.qtpl:125
|
||||
qw422016.N().S(`<div class="m-2" style="font-size: 0.9em" title="added and updated labels highlighted in blue">`)
|
||||
//line lib/promrelabel/debug.qtpl:127
|
||||
streamlabelsWithHighlight(qw422016, outLabels, changedLabels, "#4495e0")
|
||||
//line lib/promrelabel/debug.qtpl:127
|
||||
qw422016.N().S(`</div>`)
|
||||
//line lib/promrelabel/debug.qtpl:149
|
||||
//line lib/promrelabel/debug.qtpl:129
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:129
|
||||
qw422016.N().S(`<div class="m-2" style="font-size: 0.9em; color: red" title="error parsing output labels"><pre>`)
|
||||
//line lib/promrelabel/debug.qtpl:131
|
||||
qw422016.E().S(outErr.Error())
|
||||
//line lib/promrelabel/debug.qtpl:131
|
||||
qw422016.N().S(`</pre></div>`)
|
||||
//line lib/promrelabel/debug.qtpl:133
|
||||
break
|
||||
//line lib/promrelabel/debug.qtpl:134
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:149
|
||||
qw422016.N().S(`</div>`)
|
||||
//line lib/promrelabel/debug.qtpl:151
|
||||
//line lib/promrelabel/debug.qtpl:134
|
||||
qw422016.N().S(`</td></tr>`)
|
||||
//line lib/promrelabel/debug.qtpl:137
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:137
|
||||
qw422016.N().S(`</tbody></table>`)
|
||||
//line lib/promrelabel/debug.qtpl:140
|
||||
if len(dss) > 0 {
|
||||
//line lib/promrelabel/debug.qtpl:140
|
||||
qw422016.N().S(`<div class="m-3"><b>Resulting labels:</b> <samp>`)
|
||||
//line lib/promrelabel/debug.qtpl:142
|
||||
streammustFormatLabels(qw422016, dss[len(dss)-1].Out)
|
||||
//line lib/promrelabel/debug.qtpl:142
|
||||
qw422016.N().S(`</samp>`)
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
if targetURL != "" {
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.N().S(`<div><b>Target URL:</b>`)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
qw422016.N().S(` `)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
qw422016.N().S(`<a href="`)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
qw422016.E().S(targetURL)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
qw422016.N().S(`" target="_blank">`)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
qw422016.E().S(targetURL)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
qw422016.N().S(`</a>`)
|
||||
//line lib/promrelabel/debug.qtpl:146
|
||||
if targetID != "" {
|
||||
//line lib/promrelabel/debug.qtpl:147
|
||||
qw422016.N().S(` `)
|
||||
//line lib/promrelabel/debug.qtpl:147
|
||||
qw422016.N().S(`(<a href="target_response?id=`)
|
||||
//line lib/promrelabel/debug.qtpl:148
|
||||
qw422016.E().S(targetID)
|
||||
//line lib/promrelabel/debug.qtpl:148
|
||||
qw422016.N().S(`" target="_blank" title="click to fetch target response on behalf of the scraper">response</a>)`)
|
||||
//line lib/promrelabel/debug.qtpl:149
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:149
|
||||
qw422016.N().S(`</div>`)
|
||||
//line lib/promrelabel/debug.qtpl:151
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:151
|
||||
qw422016.N().S(`</div>`)
|
||||
//line lib/promrelabel/debug.qtpl:153
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
func writerelabelDebugSteps(qq422016 qtio422016.Writer, dss []DebugStep, targetURL, targetID string) {
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
streamrelabelDebugSteps(qw422016, dss, targetURL, targetID)
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
func relabelDebugSteps(dss []DebugStep, targetURL, targetID string) string {
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
writerelabelDebugSteps(qb422016, dss, targetURL, targetID)
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:156
|
||||
func StreamRelabelDebugStepsJSON(qw422016 *qt422016.Writer, targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) {
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:156
|
||||
qw422016.N().S(`{`)
|
||||
//line lib/promrelabel/debug.qtpl:156
|
||||
if err != nil {
|
||||
//line lib/promrelabel/debug.qtpl:156
|
||||
qw422016.N().S(`"status": "error","error":`)
|
||||
//line lib/promrelabel/debug.qtpl:158
|
||||
qw422016.N().Q(fmt.Sprintf("Error: %s", err))
|
||||
//line lib/promrelabel/debug.qtpl:159
|
||||
} else {
|
||||
if err != nil {
|
||||
//line lib/promrelabel/debug.qtpl:158
|
||||
qw422016.N().S(`"status": "error","error":`)
|
||||
//line lib/promrelabel/debug.qtpl:160
|
||||
qw422016.N().Q(fmt.Sprintf("Error: %s", err))
|
||||
//line lib/promrelabel/debug.qtpl:161
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:162
|
||||
var hasError bool
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:160
|
||||
//line lib/promrelabel/debug.qtpl:162
|
||||
qw422016.N().S(`"status": "success","steps": [`)
|
||||
//line lib/promrelabel/debug.qtpl:163
|
||||
for i, ds := range dss {
|
||||
//line lib/promrelabel/debug.qtpl:165
|
||||
for i, ds := range dss {
|
||||
//line lib/promrelabel/debug.qtpl:167
|
||||
inLabels, inErr := promutil.NewLabelsFromString(ds.In)
|
||||
outLabels, outErr := promutil.NewLabelsFromString(ds.Out)
|
||||
changedLabels := getChangedLabelNames(inLabels, outLabels)
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:168
|
||||
//line lib/promrelabel/debug.qtpl:170
|
||||
qw422016.N().S(`{"inLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:170
|
||||
//line lib/promrelabel/debug.qtpl:172
|
||||
qw422016.N().Q(labelsWithHighlight(inLabels, changedLabels, "#D15757"))
|
||||
//line lib/promrelabel/debug.qtpl:170
|
||||
//line lib/promrelabel/debug.qtpl:172
|
||||
qw422016.N().S(`,"outLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:171
|
||||
//line lib/promrelabel/debug.qtpl:173
|
||||
qw422016.N().Q(labelsWithHighlight(outLabels, changedLabels, "#4495e0"))
|
||||
//line lib/promrelabel/debug.qtpl:171
|
||||
//line lib/promrelabel/debug.qtpl:173
|
||||
qw422016.N().S(`,"rule":`)
|
||||
//line lib/promrelabel/debug.qtpl:172
|
||||
//line lib/promrelabel/debug.qtpl:174
|
||||
qw422016.N().Q(ds.Rule)
|
||||
//line lib/promrelabel/debug.qtpl:172
|
||||
//line lib/promrelabel/debug.qtpl:174
|
||||
qw422016.N().S(`,"errors": {`)
|
||||
//line lib/promrelabel/debug.qtpl:174
|
||||
if inErr != nil {
|
||||
//line lib/promrelabel/debug.qtpl:174
|
||||
qw422016.N().S(`"inLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:175
|
||||
qw422016.N().Q(`<span style="color: #D15757">` + inErr.Error() + `</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:175
|
||||
if outErr != nil {
|
||||
//line lib/promrelabel/debug.qtpl:175
|
||||
qw422016.N().S(`,`)
|
||||
//line lib/promrelabel/debug.qtpl:175
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:176
|
||||
hasError = true
|
||||
|
||||
if inErr != nil {
|
||||
//line lib/promrelabel/debug.qtpl:176
|
||||
qw422016.N().S(`"inLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:177
|
||||
} else {
|
||||
qw422016.N().Q(`<span style="color: #D15757">` + inErr.Error() + `</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:177
|
||||
if outErr != nil {
|
||||
//line lib/promrelabel/debug.qtpl:177
|
||||
qw422016.N().S(`,`)
|
||||
//line lib/promrelabel/debug.qtpl:177
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:178
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:179
|
||||
if outErr != nil {
|
||||
//line lib/promrelabel/debug.qtpl:179
|
||||
qw422016.N().S(`"outLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:180
|
||||
qw422016.N().Q(`<span style="color: #D15757">` + outErr.Error() + `</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:181
|
||||
hasError = true
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:182
|
||||
//line lib/promrelabel/debug.qtpl:179
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:180
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:181
|
||||
if outErr != nil {
|
||||
//line lib/promrelabel/debug.qtpl:181
|
||||
qw422016.N().S(`"outLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:182
|
||||
qw422016.N().Q(`<span style="color: #D15757">` + outErr.Error() + `</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:183
|
||||
hasError = true
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:184
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:184
|
||||
qw422016.N().S(`}}`)
|
||||
//line lib/promrelabel/debug.qtpl:185
|
||||
//line lib/promrelabel/debug.qtpl:187
|
||||
if i != len(dss)-1 {
|
||||
//line lib/promrelabel/debug.qtpl:185
|
||||
//line lib/promrelabel/debug.qtpl:187
|
||||
qw422016.N().S(`,`)
|
||||
//line lib/promrelabel/debug.qtpl:185
|
||||
//line lib/promrelabel/debug.qtpl:187
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:186
|
||||
//line lib/promrelabel/debug.qtpl:188
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:186
|
||||
//line lib/promrelabel/debug.qtpl:188
|
||||
qw422016.N().S(`]`)
|
||||
//line lib/promrelabel/debug.qtpl:188
|
||||
//line lib/promrelabel/debug.qtpl:190
|
||||
if len(dss) > 0 && !hasError {
|
||||
//line lib/promrelabel/debug.qtpl:188
|
||||
//line lib/promrelabel/debug.qtpl:190
|
||||
qw422016.N().S(`,"originalLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:190
|
||||
qw422016.N().Q(mustFormatLabels(dss[0].In))
|
||||
//line lib/promrelabel/debug.qtpl:190
|
||||
qw422016.N().S(`,"resultingLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:191
|
||||
qw422016.N().Q(mustFormatLabels(dss[len(dss)-1].Out))
|
||||
//line lib/promrelabel/debug.qtpl:192
|
||||
qw422016.N().Q(mustFormatLabels(dss[0].In))
|
||||
//line lib/promrelabel/debug.qtpl:192
|
||||
qw422016.N().S(`,"resultingLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:193
|
||||
qw422016.N().Q(mustFormatLabels(dss[len(dss)-1].Out))
|
||||
//line lib/promrelabel/debug.qtpl:194
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:193
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:193
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
qw422016.N().S(`}`)
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
func WriteRelabelDebugStepsJSON(qq422016 qtio422016.Writer, targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) {
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
StreamRelabelDebugStepsJSON(qw422016, targetURL, targetID, dss, metric, relabelConfigs, err)
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
func RelabelDebugStepsJSON(targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) string {
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
WriteRelabelDebugStepsJSON(qb422016, targetURL, targetID, dss, metric, relabelConfigs, err)
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
func streamlabelsWithHighlight(qw422016 *qt422016.Writer, labels *promutil.Labels, highlight map[string]struct{}, color string) {
|
||||
func WriteRelabelDebugStepsJSON(qq422016 qtio422016.Writer, targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) {
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
StreamRelabelDebugStepsJSON(qw422016, targetURL, targetID, dss, metric, relabelConfigs, err)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
func RelabelDebugStepsJSON(targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) string {
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
WriteRelabelDebugStepsJSON(qb422016, targetURL, targetID, dss, metric, relabelConfigs, err)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:199
|
||||
func streamlabelsWithHighlight(qw422016 *qt422016.Writer, labels *promutil.Labels, highlight map[string]struct{}, color string) {
|
||||
//line lib/promrelabel/debug.qtpl:201
|
||||
labelsList := labels.GetLabels()
|
||||
metricName := ""
|
||||
for i, label := range labelsList {
|
||||
@@ -509,153 +501,153 @@ func streamlabelsWithHighlight(qw422016 *qt422016.Writer, labels *promutil.Label
|
||||
}
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:209
|
||||
//line lib/promrelabel/debug.qtpl:211
|
||||
if metricName != "" {
|
||||
//line lib/promrelabel/debug.qtpl:210
|
||||
if _, ok := highlight["__name__"]; ok {
|
||||
//line lib/promrelabel/debug.qtpl:210
|
||||
qw422016.N().S(`<span style="font-weight:bold;color:`)
|
||||
//line lib/promrelabel/debug.qtpl:211
|
||||
qw422016.E().S(color)
|
||||
//line lib/promrelabel/debug.qtpl:211
|
||||
qw422016.N().S(`">`)
|
||||
//line lib/promrelabel/debug.qtpl:211
|
||||
qw422016.E().S(metricName)
|
||||
//line lib/promrelabel/debug.qtpl:211
|
||||
qw422016.N().S(`</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:212
|
||||
} else {
|
||||
if _, ok := highlight["__name__"]; ok {
|
||||
//line lib/promrelabel/debug.qtpl:212
|
||||
qw422016.N().S(`<span style="font-weight:bold;color:`)
|
||||
//line lib/promrelabel/debug.qtpl:213
|
||||
qw422016.E().S(color)
|
||||
//line lib/promrelabel/debug.qtpl:213
|
||||
qw422016.N().S(`">`)
|
||||
//line lib/promrelabel/debug.qtpl:213
|
||||
qw422016.E().S(metricName)
|
||||
//line lib/promrelabel/debug.qtpl:214
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:215
|
||||
if len(labelsList) == 0 {
|
||||
//line lib/promrelabel/debug.qtpl:215
|
||||
return
|
||||
//line lib/promrelabel/debug.qtpl:215
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:216
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:216
|
||||
qw422016.N().S(`{`)
|
||||
//line lib/promrelabel/debug.qtpl:218
|
||||
for i, label := range labelsList {
|
||||
//line lib/promrelabel/debug.qtpl:219
|
||||
if _, ok := highlight[label.Name]; ok {
|
||||
//line lib/promrelabel/debug.qtpl:219
|
||||
qw422016.N().S(`<span style="font-weight:bold;color:`)
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
qw422016.E().S(color)
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
qw422016.N().S(`">`)
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
qw422016.E().S(label.Name)
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
qw422016.N().S(`=`)
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
qw422016.E().Q(label.Value)
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
//line lib/promrelabel/debug.qtpl:213
|
||||
qw422016.N().S(`</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:221
|
||||
//line lib/promrelabel/debug.qtpl:214
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:215
|
||||
qw422016.E().S(metricName)
|
||||
//line lib/promrelabel/debug.qtpl:216
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:217
|
||||
if len(labelsList) == 0 {
|
||||
//line lib/promrelabel/debug.qtpl:217
|
||||
return
|
||||
//line lib/promrelabel/debug.qtpl:217
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:218
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:218
|
||||
qw422016.N().S(`{`)
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
for i, label := range labelsList {
|
||||
//line lib/promrelabel/debug.qtpl:221
|
||||
if _, ok := highlight[label.Name]; ok {
|
||||
//line lib/promrelabel/debug.qtpl:221
|
||||
qw422016.N().S(`<span style="font-weight:bold;color:`)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
qw422016.E().S(color)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
qw422016.N().S(`">`)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
qw422016.E().S(label.Name)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
qw422016.N().S(`=`)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
qw422016.E().Q(label.Value)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
qw422016.N().S(`</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:223
|
||||
}
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
qw422016.E().S(label.Name)
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
qw422016.N().S(`=`)
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
qw422016.E().Q(label.Value)
|
||||
//line lib/promrelabel/debug.qtpl:225
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:226
|
||||
if i < len(labelsList)-1 {
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
//line lib/promrelabel/debug.qtpl:226
|
||||
qw422016.N().S(`,`)
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
//line lib/promrelabel/debug.qtpl:226
|
||||
qw422016.N().S(` `)
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
//line lib/promrelabel/debug.qtpl:226
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:225
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:225
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
qw422016.N().S(`}`)
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
func writelabelsWithHighlight(qq422016 qtio422016.Writer, labels *promutil.Labels, highlight map[string]struct{}, color string) {
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
streamlabelsWithHighlight(qw422016, labels, highlight, color)
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
func labelsWithHighlight(labels *promutil.Labels, highlight map[string]struct{}, color string) string {
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
writelabelsWithHighlight(qb422016, labels, highlight, color)
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
func writelabelsWithHighlight(qq422016 qtio422016.Writer, labels *promutil.Labels, highlight map[string]struct{}, color string) {
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
streamlabelsWithHighlight(qw422016, labels, highlight, color)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
func labelsWithHighlight(labels *promutil.Labels, highlight map[string]struct{}, color string) string {
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
writelabelsWithHighlight(qb422016, labels, highlight, color)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:231
|
||||
func streammustFormatLabels(qw422016 *qt422016.Writer, s string) {
|
||||
//line lib/promrelabel/debug.qtpl:230
|
||||
//line lib/promrelabel/debug.qtpl:232
|
||||
labels, err := promutil.NewLabelsFromString(s)
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:231
|
||||
if err != nil {
|
||||
//line lib/promrelabel/debug.qtpl:231
|
||||
qw422016.N().S(`<span style="color: red" title="error parsing labels:`)
|
||||
//line lib/promrelabel/debug.qtpl:232
|
||||
qw422016.E().S(err.Error())
|
||||
//line lib/promrelabel/debug.qtpl:232
|
||||
qw422016.N().S(`">`)
|
||||
//line lib/promrelabel/debug.qtpl:232
|
||||
qw422016.E().S("error parsing labels: " + err.Error())
|
||||
//line lib/promrelabel/debug.qtpl:232
|
||||
qw422016.N().S(`</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:233
|
||||
} else {
|
||||
if err != nil {
|
||||
//line lib/promrelabel/debug.qtpl:233
|
||||
qw422016.N().S(`<span style="color: red" title="error parsing labels:`)
|
||||
//line lib/promrelabel/debug.qtpl:234
|
||||
streamlabelsWithHighlight(qw422016, labels, nil, "")
|
||||
qw422016.E().S(err.Error())
|
||||
//line lib/promrelabel/debug.qtpl:234
|
||||
qw422016.N().S(`">`)
|
||||
//line lib/promrelabel/debug.qtpl:234
|
||||
qw422016.E().S("error parsing labels: " + err.Error())
|
||||
//line lib/promrelabel/debug.qtpl:234
|
||||
qw422016.N().S(`</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:235
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
streamlabelsWithHighlight(qw422016, labels, nil, "")
|
||||
//line lib/promrelabel/debug.qtpl:237
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
func writemustFormatLabels(qq422016 qtio422016.Writer, s string) {
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
streammustFormatLabels(qw422016, s)
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
func mustFormatLabels(s string) string {
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
writemustFormatLabels(qb422016, s)
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ func (av *rateAggrValue) pushSample(c aggrConfig, sample *pushSample, key string
|
||||
}
|
||||
if ok {
|
||||
state = sv.getState(av.isGreen)
|
||||
if sample.timestamp < state.timestamp {
|
||||
if sample.timestamp < state.timestamp || sample.timestamp < sv.prevTimestamp {
|
||||
// Skip out of order sample
|
||||
return
|
||||
}
|
||||
@@ -143,9 +143,6 @@ func (av *rateAggrValue) flush(c aggrConfig, ctx *flushCtx, key string, isLast b
|
||||
putRateAggrSharedValue(sv)
|
||||
continue
|
||||
}
|
||||
if sv.prevTimestamp == 0 {
|
||||
continue
|
||||
}
|
||||
state = sv.getState(av.isGreen)
|
||||
if state.timestamp > 0 {
|
||||
d := float64(state.timestamp-sv.prevTimestamp) / 1000
|
||||
|
||||
@@ -789,6 +789,24 @@ foo:1m_by_cde_rate_sum{cde="1"} 0.125
|
||||
outputs: [rate_sum, rate_avg]
|
||||
`, "11111")
|
||||
|
||||
// test rate_sum with out of order samples
|
||||
f([]string{`
|
||||
foo 1
|
||||
`, `
|
||||
foo 61
|
||||
`, `
|
||||
foo 31 -70
|
||||
foo 91
|
||||
`, `
|
||||
foo 121
|
||||
`}, time.Minute, `foo:1m_rate_sum 1
|
||||
foo:1m_rate_sum 0.5
|
||||
foo:1m_rate_sum 0.5
|
||||
`, `
|
||||
- interval: 1m
|
||||
outputs: [rate_sum]
|
||||
`, "11111")
|
||||
|
||||
// test rate_sum and rate_avg with different staleness intervals
|
||||
f([]string{`
|
||||
foo{abc="123", cde="1"} 1
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/if_filter.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/if_filter.go
generated
vendored
@@ -30,7 +30,7 @@ func parseIfFilter(lex *lexer) (*ifFilter, error) {
|
||||
return newIfFilter(newFilterNoop()), nil
|
||||
}
|
||||
|
||||
f, err := parseFilter(lex, true)
|
||||
f, err := parseFilter(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse 'if' filter: %w", err)
|
||||
}
|
||||
|
||||
35
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/log_rows.go
generated
vendored
35
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/log_rows.go
generated
vendored
@@ -301,38 +301,43 @@ func (lr *LogRows) NeedFlush() bool {
|
||||
|
||||
// MustAddInsertRow adds r to lr.
|
||||
func (lr *LogRows) MustAddInsertRow(r *InsertRow) {
|
||||
// verify r.StreamTagsCanonical
|
||||
if err := verifyStreamTagsCanonical(r.StreamTagsCanonical, r.Fields); err != nil {
|
||||
st := GetStreamTags()
|
||||
streamTagsCanonical := r.StreamTagsCanonical
|
||||
if err := parseStreamTagsCanonical(st, streamTagsCanonical); err != nil {
|
||||
line := MarshalFieldsToJSON(nil, r.Fields)
|
||||
invalidStreamTagsLogger.Warnf("cannot unmarshal streamTagsCanonical: %s; skipping the log entry; log entry: %s", err, line)
|
||||
PutStreamTags(st)
|
||||
return
|
||||
}
|
||||
|
||||
if st.normalize(r.Fields) {
|
||||
bLen := len(lr.a.b)
|
||||
lr.a.b = st.MarshalCanonical(lr.a.b)
|
||||
streamTagsCanonical = bytesutil.ToUnsafeString(lr.a.b[bLen:])
|
||||
}
|
||||
PutStreamTags(st)
|
||||
|
||||
// Calculate the id for the StreamTags
|
||||
var sid streamID
|
||||
sid.tenantID = r.TenantID
|
||||
streamTagsCanonical := bytesutil.ToUnsafeBytes(r.StreamTagsCanonical)
|
||||
sid.id = hash128(streamTagsCanonical)
|
||||
sid.id = hash128(bytesutil.ToUnsafeBytes(streamTagsCanonical))
|
||||
|
||||
// Store the row
|
||||
lr.mustAddInternal(sid, r.Timestamp, r.Fields, r.StreamTagsCanonical)
|
||||
lr.mustAddInternal(sid, r.Timestamp, r.Fields, streamTagsCanonical)
|
||||
}
|
||||
|
||||
var invalidStreamTagsLogger = logger.WithThrottler("invalid_stream_tags", 5*time.Second)
|
||||
|
||||
func verifyStreamTagsCanonical(streamTagsCanonical string, fields []Field) error {
|
||||
st := GetStreamTags()
|
||||
defer PutStreamTags(st)
|
||||
|
||||
func parseStreamTagsCanonical(dst *StreamTags, streamTagsCanonical string) error {
|
||||
src := bytesutil.ToUnsafeBytes(streamTagsCanonical)
|
||||
tail, err := st.UnmarshalCanonicalInplace(src)
|
||||
tail, err := dst.UnmarshalCanonicalInplace(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot unmarshal streamTagsCanonical: %w", err)
|
||||
}
|
||||
if len(tail) > 0 {
|
||||
return fmt.Errorf("unexpected tail left after unmarshaling streamTagsCanonical; len(tail)=%d; streamTags: %s", len(tail), st)
|
||||
return fmt.Errorf("unexpected tail left after unmarshaling streamTagsCanonical; len(tail)=%d; streamTags: %s", len(tail), dst)
|
||||
}
|
||||
return st.verifyCanonicalFieldValues(fields)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lr *LogRows) mustAdd(tenantID TenantID, timestamp int64, fields []Field) {
|
||||
@@ -394,11 +399,7 @@ func (lr *LogRows) MustAdd(tenantID TenantID, timestamp int64, fields []Field, s
|
||||
invalidStreamTagsLogger.Warnf("cannot parse _stream=%s: %s; skipping the log entry; log entry: %s", f.Value, err, line)
|
||||
return
|
||||
}
|
||||
if err := st.verifyCanonicalFieldValues(fields); err != nil {
|
||||
line := MarshalFieldsToJSON(nil, fields)
|
||||
invalidStreamTagsLogger.Warnf("invalid _stream=%s: %s; skipping the log entry; log entry: %s", f.Value, err, line)
|
||||
return
|
||||
}
|
||||
st.normalize(fields)
|
||||
// Remove _stream field, since it is re-generated from st below.
|
||||
f.Value = ""
|
||||
case "_stream_id":
|
||||
|
||||
32
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/parser.go
generated
vendored
32
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/parser.go
generated
vendored
@@ -1928,7 +1928,7 @@ func parseQuery(lex *lexer) (*Query, error) {
|
||||
lex.pushQueryOptions(&q.opts)
|
||||
defer lex.popQueryOptions()
|
||||
|
||||
f, err := parseFilter(lex, true)
|
||||
f, err := parseFilter(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w; context: [%s]", err, lex.context())
|
||||
}
|
||||
@@ -2113,20 +2113,11 @@ func parseQueryOptions(dstOpts *queryOptions, lex *lexer) error {
|
||||
}
|
||||
}
|
||||
|
||||
func parseFilter(lex *lexer, allowPipeKeywords bool) (filter, error) {
|
||||
func parseFilter(lex *lexer) (filter, error) {
|
||||
if lex.isQueryPartTrailer() {
|
||||
return nil, fmt.Errorf("missing query")
|
||||
}
|
||||
|
||||
if !allowPipeKeywords {
|
||||
// Verify the first token in the filter doesn't match pipe names.
|
||||
firstToken := strings.ToLower(lex.rawToken)
|
||||
if firstToken == "by" || isPipeName(firstToken) || isStatsFuncName(firstToken) {
|
||||
return nil, fmt.Errorf("query filter cannot start with pipe keyword %q; see https://docs.victoriametrics.com/victorialogs/logsql/#query-syntax; "+
|
||||
"please put the first word of the filter into quotes", firstToken)
|
||||
}
|
||||
}
|
||||
|
||||
fo, err := parseFilterOr(lex, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -3875,7 +3866,7 @@ func quoteFieldFilterIfNeeded(s string) string {
|
||||
if wildcard == "" || !needQuoteToken(wildcard) {
|
||||
return s
|
||||
}
|
||||
return strconv.Quote(s)
|
||||
return strconv.Quote(wildcard) + "*"
|
||||
}
|
||||
|
||||
func quoteTokenIfNeeded(s string) string {
|
||||
@@ -3912,7 +3903,7 @@ func isNumberPrefix(s string) bool {
|
||||
}
|
||||
|
||||
func needQuoteToken(s string) bool {
|
||||
if s == "." {
|
||||
if !isWord(s) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3920,14 +3911,10 @@ func needQuoteToken(s string) bool {
|
||||
if _, ok := reservedKeywords[sLower]; ok {
|
||||
return true
|
||||
}
|
||||
if isPipeName(sLower) || isStatsFuncName(sLower) {
|
||||
if isPipeName(sLower) || isStatsFuncName(sLower) || isMathFuncName(sLower) {
|
||||
return true
|
||||
}
|
||||
for _, r := range s {
|
||||
if !isTokenRune(r) && r != '.' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -4008,6 +3995,9 @@ var reservedKeywords = func() map[string]struct{} {
|
||||
|
||||
// 'as' is used in various pipes such as `format ... as ...`
|
||||
"as",
|
||||
|
||||
// 'from' is used in various pipes such as `split ... from ...` and `unpack_json from ...`
|
||||
"from",
|
||||
}
|
||||
m := make(map[string]struct{}, len(kws))
|
||||
for _, kw := range kws {
|
||||
@@ -4057,12 +4047,12 @@ func toFieldsFilters(pf *prefixfilter.Filter) string {
|
||||
|
||||
denyFilters := pf.GetDenyFilters()
|
||||
if len(denyFilters) > 0 {
|
||||
qStr += " | delete " + fieldNamesString(denyFilters)
|
||||
qStr += " | delete " + fieldFiltersString(denyFilters)
|
||||
}
|
||||
|
||||
allowFilters := pf.GetAllowFilters()
|
||||
if len(allowFilters) > 0 && !prefixfilter.MatchAll(allowFilters) {
|
||||
qStr += " | fields " + fieldNamesString(allowFilters)
|
||||
qStr += " | fields " + fieldFiltersString(allowFilters)
|
||||
}
|
||||
|
||||
return qStr
|
||||
|
||||
123
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/parser_utils.go
generated
vendored
Normal file
123
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/parser_utils.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
package logstorage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaLogs/lib/prefixfilter"
|
||||
)
|
||||
|
||||
func parseFieldNamesInParens(lex *lexer) ([]string, error) {
|
||||
fieldNames, err := parseFieldFiltersInParens(lex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, fieldName := range fieldNames {
|
||||
if prefixfilter.IsWildcardFilter(fieldName) {
|
||||
return nil, fmt.Errorf("the field name %q cannot end with '*'", fieldName)
|
||||
}
|
||||
}
|
||||
return fieldNames, nil
|
||||
}
|
||||
|
||||
func parseFieldFiltersInParens(lex *lexer) ([]string, error) {
|
||||
if !lex.isKeyword("(") {
|
||||
return nil, fmt.Errorf("missing `(`")
|
||||
}
|
||||
var fields []string
|
||||
for {
|
||||
lex.nextToken()
|
||||
if lex.isKeyword(")") {
|
||||
lex.nextToken()
|
||||
return fields, nil
|
||||
}
|
||||
if lex.isKeyword(",") {
|
||||
return nil, fmt.Errorf("unexpected `,`")
|
||||
}
|
||||
field, err := parseFieldFilter(lex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fields = append(fields, field)
|
||||
switch {
|
||||
case lex.isKeyword(")"):
|
||||
lex.nextToken()
|
||||
return fields, nil
|
||||
case lex.isKeyword(","):
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected token: %q; expecting ',' or ')'", lex.token)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseCommaSeparatedFieldNames(lex *lexer) ([]string, error) {
|
||||
fieldNames, err := parseCommaSeparatedFieldFilters(lex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, fieldName := range fieldNames {
|
||||
if prefixfilter.IsWildcardFilter(fieldName) {
|
||||
return nil, fmt.Errorf("the field name %q cannot end with '*'", fieldName)
|
||||
}
|
||||
}
|
||||
return fieldNames, nil
|
||||
}
|
||||
|
||||
func parseCommaSeparatedFieldFilters(lex *lexer) ([]string, error) {
|
||||
var fields []string
|
||||
for {
|
||||
field, err := parseFieldFilter(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse field name: %w", err)
|
||||
}
|
||||
fields = append(fields, field)
|
||||
if !lex.isKeyword(",") {
|
||||
return fields, nil
|
||||
}
|
||||
lex.nextToken()
|
||||
}
|
||||
}
|
||||
|
||||
func parseFieldName(lex *lexer) (string, error) {
|
||||
fieldName, err := lex.nextCompoundToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fieldName = getCanonicalColumnName(fieldName)
|
||||
return fieldName, nil
|
||||
}
|
||||
|
||||
func parseFieldFilter(lex *lexer) (string, error) {
|
||||
if lex.isKeyword("*") {
|
||||
lex.nextToken()
|
||||
return "*", nil
|
||||
}
|
||||
|
||||
fieldName, err := lex.nextCompoundToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fieldName = getCanonicalColumnName(fieldName)
|
||||
if !lex.isSkippedSpace && lex.isKeyword("*") {
|
||||
lex.nextToken()
|
||||
fieldName += "*"
|
||||
}
|
||||
|
||||
return fieldName, nil
|
||||
}
|
||||
|
||||
func fieldNamesString(fieldNames []string) string {
|
||||
a := make([]string, len(fieldNames))
|
||||
for i, f := range fieldNames {
|
||||
a[i] = quoteTokenIfNeeded(f)
|
||||
}
|
||||
return strings.Join(a, ", ")
|
||||
}
|
||||
|
||||
func fieldFiltersString(fieldFilters []string) string {
|
||||
a := make([]string, len(fieldFilters))
|
||||
for i, f := range fieldFilters {
|
||||
a[i] = quoteFieldFilterIfNeeded(f)
|
||||
}
|
||||
return strings.Join(a, ", ")
|
||||
}
|
||||
54
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe.go
generated
vendored
54
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe.go
generated
vendored
@@ -146,23 +146,54 @@ func parsePipe(lex *lexer) (pipe, error) {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
lexState := lex.backupState()
|
||||
|
||||
// Try parsing stats pipe without 'stats' keyword
|
||||
ps, err := parsePipeStatsNoStatsKeyword(lex)
|
||||
if err == nil {
|
||||
if isLikelyStatsPipe(lex) {
|
||||
// Try parsing stats pipe without 'stats' keyword
|
||||
ps, err := parsePipeStatsNoStatsKeyword(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse 'stats' pipe: %w", err)
|
||||
}
|
||||
return ps, nil
|
||||
}
|
||||
lex.restoreState(lexState)
|
||||
|
||||
// Try parsing filter pipe without 'filter' keyword
|
||||
pf, err := parsePipeFilterNoFilterKeyword(lex)
|
||||
if err == nil {
|
||||
if isLikelyFilterPipe(lex) {
|
||||
// Try parsing filter pipe without 'filter' keyword
|
||||
pf, err := parsePipeFilterNoFilterKeyword(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse 'filter' pipe: %w", err)
|
||||
}
|
||||
return pf, nil
|
||||
}
|
||||
lex.restoreState(lexState)
|
||||
|
||||
return nil, fmt.Errorf("unexpected pipe %q", lex.token)
|
||||
return nil, fmt.Errorf("unexpected pipe name %q; probably, 'filter' is missing in front of %q; "+
|
||||
"see https://docs.victoriametrics.com/victorialogs/logsql/#filter-pipe", lex.token, lex.token)
|
||||
}
|
||||
|
||||
func isLikelyStatsPipe(lex *lexer) bool {
|
||||
return isStatsFuncName(lex.rawToken) || lex.isKeyword("by", "(")
|
||||
}
|
||||
|
||||
func isLikelyFilterPipe(lex *lexer) bool {
|
||||
if lex.isQuotedToken() {
|
||||
return true
|
||||
}
|
||||
if !isWord(lex.token) {
|
||||
// Any token that isn't a word cannot clash with a pipe name,
|
||||
// since all pipe names are words. So treat it as a filter.
|
||||
return true
|
||||
}
|
||||
if lex.isKeyword("not") {
|
||||
// 'not' is a logical filter operator rather than a pipe name.
|
||||
return true
|
||||
}
|
||||
|
||||
lexState := lex.backupState()
|
||||
defer lex.restoreState(lexState)
|
||||
|
||||
stopTokens := []string{":"}
|
||||
if _, err := lex.nextCompoundTokenExt(stopTokens); err != nil {
|
||||
return false
|
||||
}
|
||||
return lex.isKeyword(":")
|
||||
}
|
||||
|
||||
var pipeParsers map[string]pipeParseFunc
|
||||
@@ -201,6 +232,7 @@ func initPipeParsers() {
|
||||
"generate_sequence": parsePipeGenerateSequence,
|
||||
"hash": parsePipeHash,
|
||||
"join": parsePipeJoin,
|
||||
"json_array_concat": parsePipeJSONArrayConcat,
|
||||
"json_array_len": parsePipeJSONArrayLen,
|
||||
"head": parsePipeLimit,
|
||||
"keep": parsePipeFields,
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_coalesce.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_coalesce.go
generated
vendored
@@ -23,7 +23,7 @@ func (pc *pipeCoalesce) String() string {
|
||||
logger.Panicf("BUG: pipeCoalesce must contain at least one srcField")
|
||||
}
|
||||
|
||||
s := "coalesce(" + fieldNamesString(pc.srcFieldFilters) + ")"
|
||||
s := "coalesce(" + fieldFiltersString(pc.srcFieldFilters) + ")"
|
||||
if pc.defaultValue != "" {
|
||||
s += " default " + quoteTokenIfNeeded(pc.defaultValue)
|
||||
}
|
||||
|
||||
4
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_delete.go
generated
vendored
4
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_delete.go
generated
vendored
@@ -21,7 +21,7 @@ func (pd *pipeDelete) String() string {
|
||||
logger.Panicf("BUG: pipeDelete must contain at least a single field")
|
||||
}
|
||||
|
||||
return "delete " + fieldNamesString(pd.fieldFilters)
|
||||
return "delete " + fieldFiltersString(pd.fieldFilters)
|
||||
}
|
||||
|
||||
func (pd *pipeDelete) splitToRemoteAndLocal(_ int64) (pipe, []pipe) {
|
||||
@@ -87,7 +87,7 @@ func parsePipeDelete(lex *lexer) (pipe, error) {
|
||||
}
|
||||
lex.nextToken()
|
||||
|
||||
fieldFilters, err := parseCommaSeparatedFields(lex)
|
||||
fieldFilters, err := parseCommaSeparatedFieldFilters(lex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
19
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_fields.go
generated
vendored
19
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_fields.go
generated
vendored
@@ -20,7 +20,7 @@ func (pf *pipeFields) String() string {
|
||||
if len(pf.fieldFilters) == 0 {
|
||||
logger.Panicf("BUG: pipeFields must contain at least a single field filter")
|
||||
}
|
||||
return "fields " + fieldNamesString(pf.fieldFilters)
|
||||
return "fields " + fieldFiltersString(pf.fieldFilters)
|
||||
}
|
||||
|
||||
func (pf *pipeFields) splitToRemoteAndLocal(_ int64) (pipe, []pipe) {
|
||||
@@ -100,7 +100,7 @@ func parsePipeFields(lex *lexer) (pipe, error) {
|
||||
}
|
||||
lex.nextToken()
|
||||
|
||||
fieldFilters, err := parseCommaSeparatedFields(lex)
|
||||
fieldFilters, err := parseCommaSeparatedFieldFilters(lex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -109,18 +109,3 @@ func parsePipeFields(lex *lexer) (pipe, error) {
|
||||
}
|
||||
return pf, nil
|
||||
}
|
||||
|
||||
func parseCommaSeparatedFields(lex *lexer) ([]string, error) {
|
||||
var fields []string
|
||||
for {
|
||||
field, err := parseFieldFilter(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse field name: %w", err)
|
||||
}
|
||||
fields = append(fields, field)
|
||||
if !lex.isKeyword(",") {
|
||||
return fields, nil
|
||||
}
|
||||
lex.nextToken()
|
||||
}
|
||||
}
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_filter.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_filter.go
generated
vendored
@@ -124,7 +124,7 @@ func parsePipeFilterExt(lex *lexer, needFilterKeyword bool) (pipe, error) {
|
||||
lex.nextToken()
|
||||
}
|
||||
|
||||
f, err := parseFilter(lex, needFilterKeyword)
|
||||
f, err := parseFilter(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse 'filter': %w", err)
|
||||
}
|
||||
|
||||
1
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_join.go
generated
vendored
1
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_join.go
generated
vendored
@@ -192,7 +192,6 @@ func (pjp *pipeJoinProcessor) writeBlock(workerID uint, br *blockResult) {
|
||||
for i := range cs {
|
||||
name := cs[i].name
|
||||
byValuesIdxs[i] = slices.Index(pj.byFields, name)
|
||||
|
||||
}
|
||||
|
||||
for rowIdx := range br.rowsLen {
|
||||
|
||||
197
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_json_array_concat.go
generated
vendored
Normal file
197
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_json_array_concat.go
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
package logstorage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/atomicutil"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaLogs/lib/prefixfilter"
|
||||
)
|
||||
|
||||
// pipeJSONArrayConcat processes '| json_array_concat ...' pipe.
|
||||
//
|
||||
// See https://docs.victoriametrics.com/victorialogs/logsql/#json_array_concat-pipe
|
||||
type pipeJSONArrayConcat struct {
|
||||
delimiter string
|
||||
fromField string
|
||||
resultField string
|
||||
}
|
||||
|
||||
func (pc *pipeJSONArrayConcat) String() string {
|
||||
s := "json_array_concat"
|
||||
if pc.delimiter != "" {
|
||||
s += " " + quoteTokenIfNeeded(pc.delimiter)
|
||||
}
|
||||
if !isMsgFieldName(pc.fromField) {
|
||||
s += " from " + quoteTokenIfNeeded(pc.fromField)
|
||||
}
|
||||
if pc.resultField != pc.fromField {
|
||||
s += " as " + quoteTokenIfNeeded(pc.resultField)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (pc *pipeJSONArrayConcat) splitToRemoteAndLocal(_ int64) (pipe, []pipe) {
|
||||
return pc, nil
|
||||
}
|
||||
|
||||
func (pc *pipeJSONArrayConcat) canLiveTail() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (pc *pipeJSONArrayConcat) canReturnLastNResults() bool {
|
||||
return pc.resultField != "_time"
|
||||
}
|
||||
|
||||
func (pc *pipeJSONArrayConcat) isFixedOutputFieldsOrder() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (pc *pipeJSONArrayConcat) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
if pf.MatchString(pc.resultField) {
|
||||
pf.AddDenyFilter(pc.resultField)
|
||||
pf.AddAllowFilter(pc.fromField)
|
||||
}
|
||||
}
|
||||
|
||||
func (pc *pipeJSONArrayConcat) hasFilterInWithQuery() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (pc *pipeJSONArrayConcat) initFilterInValues(_ *inValuesCache, _ getFieldValuesFunc) (pipe, error) {
|
||||
return pc, nil
|
||||
}
|
||||
|
||||
func (pc *pipeJSONArrayConcat) visitSubqueries(_ func(q *Query)) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
func (pc *pipeJSONArrayConcat) newPipeProcessor(_ int, _ <-chan struct{}, _ func(), ppNext pipeProcessor) pipeProcessor {
|
||||
pcp := &pipeJSONArrayConcatProcessor{
|
||||
pc: pc,
|
||||
ppNext: ppNext,
|
||||
}
|
||||
pcp.shards.Init = func(shard *pipeJSONArrayConcatProcessorShard) {
|
||||
shard.reset()
|
||||
}
|
||||
return pcp
|
||||
}
|
||||
|
||||
type pipeJSONArrayConcatProcessor struct {
|
||||
pc *pipeJSONArrayConcat
|
||||
ppNext pipeProcessor
|
||||
|
||||
shards atomicutil.Slice[pipeJSONArrayConcatProcessorShard]
|
||||
}
|
||||
|
||||
func (pcp *pipeJSONArrayConcatProcessor) writeBlock(workerID uint, br *blockResult) {
|
||||
if br.rowsLen == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
shard := pcp.shards.Get(workerID)
|
||||
shard.rc.name = pcp.pc.resultField
|
||||
|
||||
c := br.getColumnByName(pcp.pc.fromField)
|
||||
delimiter := pcp.pc.delimiter
|
||||
if c.isConst {
|
||||
// Fast path for const column
|
||||
v := c.valuesEncoded[0]
|
||||
out := shard.concat(v, delimiter)
|
||||
shard.rc.addValue(out)
|
||||
br.addResultColumnConst(shard.rc)
|
||||
} else {
|
||||
// Slow path for other columns
|
||||
values := c.getValues(br)
|
||||
prevOut := ""
|
||||
for rowIdx := range values {
|
||||
if rowIdx == 0 || values[rowIdx] != values[rowIdx-1] {
|
||||
prevOut = shard.concat(values[rowIdx], delimiter)
|
||||
}
|
||||
shard.rc.addValue(prevOut)
|
||||
}
|
||||
br.addResultColumn(shard.rc)
|
||||
}
|
||||
|
||||
pcp.ppNext.writeBlock(workerID, br)
|
||||
|
||||
shard.reset()
|
||||
}
|
||||
|
||||
type pipeJSONArrayConcatProcessorShard struct {
|
||||
a arena
|
||||
rc resultColumn
|
||||
|
||||
tmpValues []string
|
||||
}
|
||||
|
||||
func (shard *pipeJSONArrayConcatProcessorShard) reset() {
|
||||
shard.a.reset()
|
||||
shard.rc.reset()
|
||||
|
||||
shard.tmpValues = shard.tmpValues[:0]
|
||||
}
|
||||
|
||||
func (shard *pipeJSONArrayConcatProcessorShard) concat(arrayStr, delimiter string) string {
|
||||
shard.tmpValues = unpackJSONArray(shard.tmpValues[:0], &shard.a, arrayStr)
|
||||
|
||||
bLen := len(shard.a.b)
|
||||
for i, v := range shard.tmpValues {
|
||||
if i > 0 {
|
||||
shard.a.b = append(shard.a.b, delimiter...)
|
||||
}
|
||||
shard.a.b = append(shard.a.b, v...)
|
||||
}
|
||||
return bytesutil.ToUnsafeString(shard.a.b[bLen:])
|
||||
}
|
||||
|
||||
func (pcp *pipeJSONArrayConcatProcessor) flush() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func parsePipeJSONArrayConcat(lex *lexer) (pipe, error) {
|
||||
if !lex.isKeyword("json_array_concat") {
|
||||
return nil, fmt.Errorf("unexpected token: %q; want %q", lex.token, "json_array_concat")
|
||||
}
|
||||
lex.nextToken()
|
||||
|
||||
delimiter := ""
|
||||
if !lex.isQueryPartTrailer() && !lex.isKeyword("from", "as") {
|
||||
s, err := lex.nextCompoundToken()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse delimiter for 'json_array_concat': %w", err)
|
||||
}
|
||||
delimiter = s
|
||||
}
|
||||
|
||||
fromField := "_msg"
|
||||
if !lex.isQueryPartTrailer() && !lex.isKeyword("as") {
|
||||
if lex.isKeyword("from") {
|
||||
lex.nextToken()
|
||||
}
|
||||
f, err := parseFieldName(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse 'from' field for 'json_array_concat': %w", err)
|
||||
}
|
||||
fromField = f
|
||||
}
|
||||
|
||||
resultField := fromField
|
||||
if !lex.isQueryPartTrailer() {
|
||||
if lex.isKeyword("as") {
|
||||
lex.nextToken()
|
||||
}
|
||||
f, err := parseFieldName(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse result field for 'json_array_concat': %w", err)
|
||||
}
|
||||
resultField = f
|
||||
}
|
||||
|
||||
return &pipeJSONArrayConcat{
|
||||
delimiter: delimiter,
|
||||
fromField: fromField,
|
||||
resultField: resultField,
|
||||
}, nil
|
||||
}
|
||||
60
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_math.go
generated
vendored
60
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_math.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/atomicutil"
|
||||
@@ -567,32 +568,51 @@ func parseMathExprInParens(lex *lexer) (*mathExpr, error) {
|
||||
return me, nil
|
||||
}
|
||||
|
||||
type mathFuncParser func(lex *lexer) (*mathExpr, error)
|
||||
|
||||
var mathFuncParsers map[string]mathFuncParser
|
||||
var mathFuncParsersOnce sync.Once
|
||||
|
||||
func getMathFuncParsers() map[string]mathFuncParser {
|
||||
mathFuncParsersOnce.Do(initMathFuncParsers)
|
||||
return mathFuncParsers
|
||||
}
|
||||
|
||||
func initMathFuncParsers() {
|
||||
mathFuncParsers = map[string]mathFuncParser{
|
||||
"abs": parseMathExprAbs,
|
||||
"ceil": parseMathExprCeil,
|
||||
"exp": parseMathExprExp,
|
||||
"floor": parseMathExprFloor,
|
||||
"ln": parseMathExprLn,
|
||||
"max": parseMathExprMax,
|
||||
"min": parseMathExprMin,
|
||||
"now": parseMathExprNow,
|
||||
"rand": parseMathExprRand,
|
||||
"round": parseMathExprRound,
|
||||
}
|
||||
}
|
||||
|
||||
func isMathFuncName(s string) bool {
|
||||
mps := getMathFuncParsers()
|
||||
sLower := strings.ToLower(s)
|
||||
return mps[sLower] != nil
|
||||
}
|
||||
|
||||
func parseMathExprOperand(lex *lexer) (*mathExpr, error) {
|
||||
if lex.isKeyword("(") {
|
||||
return parseMathExprInParens(lex)
|
||||
}
|
||||
|
||||
// A quoted token (e.g. "abs") isn't a keyword, so isKeyword() returns false for it
|
||||
// and it falls through to parseMathExprFieldName below as a field name.
|
||||
for funcName, parseFunc := range getMathFuncParsers() {
|
||||
if lex.isKeyword(funcName) {
|
||||
return parseFunc(lex)
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case lex.isKeyword("abs"):
|
||||
return parseMathExprAbs(lex)
|
||||
case lex.isKeyword("exp"):
|
||||
return parseMathExprExp(lex)
|
||||
case lex.isKeyword("ln"):
|
||||
return parseMathExprLn(lex)
|
||||
case lex.isKeyword("max"):
|
||||
return parseMathExprMax(lex)
|
||||
case lex.isKeyword("min"):
|
||||
return parseMathExprMin(lex)
|
||||
case lex.isKeyword("now"):
|
||||
return parseMathExprNow(lex)
|
||||
case lex.isKeyword("rand"):
|
||||
return parseMathExprRand(lex)
|
||||
case lex.isKeyword("round"):
|
||||
return parseMathExprRound(lex)
|
||||
case lex.isKeyword("ceil"):
|
||||
return parseMathExprCeil(lex)
|
||||
case lex.isKeyword("floor"):
|
||||
return parseMathExprFloor(lex)
|
||||
case lex.isKeyword("-"):
|
||||
return parseMathExprUnaryMinus(lex)
|
||||
case lex.isKeyword("+"):
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_pack_json.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_pack_json.go
generated
vendored
@@ -20,7 +20,7 @@ type pipePackJSON struct {
|
||||
func (pp *pipePackJSON) String() string {
|
||||
s := "pack_json"
|
||||
if len(pp.fieldFilters) > 0 {
|
||||
s += " fields (" + fieldNamesString(pp.fieldFilters) + ")"
|
||||
s += " fields (" + fieldFiltersString(pp.fieldFilters) + ")"
|
||||
}
|
||||
if !isMsgFieldName(pp.resultField) {
|
||||
s += " as " + quoteTokenIfNeeded(pp.resultField)
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_pack_logfmt.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_pack_logfmt.go
generated
vendored
@@ -20,7 +20,7 @@ type pipePackLogfmt struct {
|
||||
func (pp *pipePackLogfmt) String() string {
|
||||
s := "pack_logfmt"
|
||||
if len(pp.fieldFilters) > 0 {
|
||||
s += " fields (" + fieldNamesString(pp.fieldFilters) + ")"
|
||||
s += " fields (" + fieldFiltersString(pp.fieldFilters) + ")"
|
||||
}
|
||||
if !isMsgFieldName(pp.resultField) {
|
||||
s += " as " + quoteTokenIfNeeded(pp.resultField)
|
||||
|
||||
1
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_replace_regexp.go
generated
vendored
1
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_replace_regexp.go
generated
vendored
@@ -92,7 +92,6 @@ func (pr *pipeReplaceRegexp) newPipeProcessor(_ int, _ <-chan struct{}, _ func()
|
||||
}
|
||||
|
||||
return newPipeUpdateProcessor(updateFunc, ppNext, pr.field, pr.iff)
|
||||
|
||||
}
|
||||
|
||||
func parsePipeReplaceRegexp(lex *lexer) (pipe, error) {
|
||||
|
||||
@@ -25,7 +25,7 @@ func (ps *pipeSetStreamFields) String() string {
|
||||
if ps.iff != nil {
|
||||
s += " " + ps.iff.String()
|
||||
}
|
||||
s += " " + fieldNamesString(ps.streamFieldFilters)
|
||||
s += " " + fieldFiltersString(ps.streamFieldFilters)
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ func parsePipeSetStreamFields(lex *lexer) (pipe, error) {
|
||||
}
|
||||
|
||||
// Parse stream fields
|
||||
streamFieldFilters, err := parseCommaSeparatedFields(lex)
|
||||
streamFieldFilters, err := parseCommaSeparatedFieldFilters(lex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
81
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_stats.go
generated
vendored
81
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_stats.go
generated
vendored
@@ -1395,7 +1395,7 @@ func parsePipeStatsExt(lex *lexer, needStatsKeyword bool) (pipe, error) {
|
||||
for {
|
||||
e, err := parseStatsEntry(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse 'stats' entry: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
ps.entries = append(ps.entries, e)
|
||||
|
||||
@@ -1779,85 +1779,6 @@ func tryParseBucketSize(s string) (float64, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func parseFieldNamesInParens(lex *lexer) ([]string, error) {
|
||||
fieldNames, err := parseFieldFiltersInParens(lex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, fieldName := range fieldNames {
|
||||
if prefixfilter.IsWildcardFilter(fieldName) {
|
||||
return nil, fmt.Errorf("the field name %q cannot end with '*'", fieldName)
|
||||
}
|
||||
}
|
||||
return fieldNames, nil
|
||||
}
|
||||
|
||||
func parseFieldFiltersInParens(lex *lexer) ([]string, error) {
|
||||
if !lex.isKeyword("(") {
|
||||
return nil, fmt.Errorf("missing `(`")
|
||||
}
|
||||
var fields []string
|
||||
for {
|
||||
lex.nextToken()
|
||||
if lex.isKeyword(")") {
|
||||
lex.nextToken()
|
||||
return fields, nil
|
||||
}
|
||||
if lex.isKeyword(",") {
|
||||
return nil, fmt.Errorf("unexpected `,`")
|
||||
}
|
||||
field, err := parseFieldFilter(lex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fields = append(fields, field)
|
||||
switch {
|
||||
case lex.isKeyword(")"):
|
||||
lex.nextToken()
|
||||
return fields, nil
|
||||
case lex.isKeyword(","):
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected token: %q; expecting ',' or ')'", lex.token)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseFieldName(lex *lexer) (string, error) {
|
||||
fieldName, err := lex.nextCompoundToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fieldName = getCanonicalColumnName(fieldName)
|
||||
return fieldName, nil
|
||||
}
|
||||
|
||||
func parseFieldFilter(lex *lexer) (string, error) {
|
||||
if lex.isKeyword("*") {
|
||||
lex.nextToken()
|
||||
return "*", nil
|
||||
}
|
||||
|
||||
fieldName, err := lex.nextCompoundToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fieldName = getCanonicalColumnName(fieldName)
|
||||
if !lex.isSkippedSpace && lex.isKeyword("*") {
|
||||
lex.nextToken()
|
||||
fieldName += "*"
|
||||
}
|
||||
|
||||
return fieldName, nil
|
||||
}
|
||||
|
||||
func fieldNamesString(fields []string) string {
|
||||
a := make([]string, len(fields))
|
||||
for i, f := range fields {
|
||||
a[i] = quoteFieldFilterIfNeeded(f)
|
||||
}
|
||||
return strings.Join(a, ", ")
|
||||
}
|
||||
|
||||
func areConstValues(values []string) bool {
|
||||
if len(values) == 0 {
|
||||
return false
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_top.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_top.go
generated
vendored
@@ -621,7 +621,7 @@ func parsePipeTop(lex *lexer) (pipe, error) {
|
||||
}
|
||||
byFields = bfs
|
||||
} else if !lex.isKeyword("hits", "rank") && !lex.isQueryPartTrailer() {
|
||||
bfs, err := parseCommaSeparatedFields(lex)
|
||||
bfs, err := parseCommaSeparatedFieldNames(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse 'by ...': %w", err)
|
||||
}
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_uniq.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_uniq.go
generated
vendored
@@ -551,7 +551,7 @@ func parsePipeUniq(lex *lexer) (pipe, error) {
|
||||
}
|
||||
byFields = bfs
|
||||
} else if !lex.isKeyword("filter", "with", "hits", "limit") && !lex.isQueryPartTrailer() {
|
||||
bfs, err := parseCommaSeparatedFields(lex)
|
||||
bfs, err := parseCommaSeparatedFieldNames(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse 'by ...': %w", err)
|
||||
}
|
||||
|
||||
1
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_unpack.go
generated
vendored
1
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_unpack.go
generated
vendored
@@ -83,7 +83,6 @@ func (uctx *fieldsUnpackerContext) addField(name, value string) {
|
||||
|
||||
func newPipeUnpackProcessor(unpackFunc func(uctx *fieldsUnpackerContext, s string), ppNext pipeProcessor,
|
||||
fromField string, fieldPrefix string, keepOriginalFields, skipEmptyResults bool, iff *ifFilter) *pipeUnpackProcessor {
|
||||
|
||||
return &pipeUnpackProcessor{
|
||||
unpackFunc: unpackFunc,
|
||||
ppNext: ppNext,
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_unpack_json.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_unpack_json.go
generated
vendored
@@ -41,7 +41,7 @@ func (pu *pipeUnpackJSON) String() string {
|
||||
s += " from " + quoteTokenIfNeeded(pu.fromField)
|
||||
}
|
||||
if !prefixfilter.MatchAll(pu.fieldFilters) {
|
||||
s += " fields (" + fieldNamesString(pu.fieldFilters) + ")"
|
||||
s += " fields (" + fieldFiltersString(pu.fieldFilters) + ")"
|
||||
}
|
||||
if len(pu.preserveKeys) > 0 {
|
||||
s += " preserve_keys (" + fieldNamesString(pu.preserveKeys) + ")"
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_unpack_logfmt.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_unpack_logfmt.go
generated
vendored
@@ -35,7 +35,7 @@ func (pu *pipeUnpackLogfmt) String() string {
|
||||
s += " from " + quoteTokenIfNeeded(pu.fromField)
|
||||
}
|
||||
if !prefixfilter.MatchAll(pu.fieldFilters) {
|
||||
s += " fields (" + fieldNamesString(pu.fieldFilters) + ")"
|
||||
s += " fields (" + fieldFiltersString(pu.fieldFilters) + ")"
|
||||
}
|
||||
if pu.resultPrefix != "" {
|
||||
s += " result_prefix " + quoteTokenIfNeeded(pu.resultPrefix)
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_unroll.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_unroll.go
generated
vendored
@@ -234,7 +234,7 @@ func parsePipeUnroll(lex *lexer) (pipe, error) {
|
||||
}
|
||||
fields = fs
|
||||
} else {
|
||||
fs, err := parseCommaSeparatedFields(lex)
|
||||
fs, err := parseCommaSeparatedFieldNames(lex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse 'by ...': %w", err)
|
||||
}
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/running_stats_count.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/running_stats_count.go
generated
vendored
@@ -11,7 +11,7 @@ type runningStatsCount struct {
|
||||
}
|
||||
|
||||
func (sc *runningStatsCount) String() string {
|
||||
return "count(" + fieldNamesString(sc.fieldFilters) + ")"
|
||||
return "count(" + fieldFiltersString(sc.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (sc *runningStatsCount) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/running_stats_max.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/running_stats_max.go
generated
vendored
@@ -9,7 +9,7 @@ type runningStatsMax struct {
|
||||
}
|
||||
|
||||
func (sm *runningStatsMax) String() string {
|
||||
return "max(" + fieldNamesString(sm.fieldFilters) + ")"
|
||||
return "max(" + fieldFiltersString(sm.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (sm *runningStatsMax) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/running_stats_min.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/running_stats_min.go
generated
vendored
@@ -9,7 +9,7 @@ type runningStatsMin struct {
|
||||
}
|
||||
|
||||
func (sm *runningStatsMin) String() string {
|
||||
return "min(" + fieldNamesString(sm.fieldFilters) + ")"
|
||||
return "min(" + fieldFiltersString(sm.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (sm *runningStatsMin) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/running_stats_sum.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/running_stats_sum.go
generated
vendored
@@ -12,7 +12,7 @@ type runningStatsSum struct {
|
||||
}
|
||||
|
||||
func (ss *runningStatsSum) String() string {
|
||||
return "sum(" + fieldNamesString(ss.fieldFilters) + ")"
|
||||
return "sum(" + fieldFiltersString(ss.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (ss *runningStatsSum) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_avg.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_avg.go
generated
vendored
@@ -15,7 +15,7 @@ type statsAvg struct {
|
||||
}
|
||||
|
||||
func (sa *statsAvg) String() string {
|
||||
return "avg(" + fieldNamesString(sa.fieldFilters) + ")"
|
||||
return "avg(" + fieldFiltersString(sa.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (sa *statsAvg) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_count.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_count.go
generated
vendored
@@ -16,7 +16,7 @@ type statsCount struct {
|
||||
}
|
||||
|
||||
func (sc *statsCount) String() string {
|
||||
return "count(" + fieldNamesString(sc.fieldFilters) + ")"
|
||||
return "count(" + fieldFiltersString(sc.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (sc *statsCount) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_count_empty.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_count_empty.go
generated
vendored
@@ -16,7 +16,7 @@ type statsCountEmpty struct {
|
||||
}
|
||||
|
||||
func (sc *statsCountEmpty) String() string {
|
||||
return "count_empty(" + fieldNamesString(sc.fieldFilters) + ")"
|
||||
return "count_empty(" + fieldFiltersString(sc.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (sc *statsCountEmpty) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_json_values.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_json_values.go
generated
vendored
@@ -28,7 +28,7 @@ type statsJSONValues struct {
|
||||
}
|
||||
|
||||
func (sv *statsJSONValues) String() string {
|
||||
s := "json_values(" + fieldNamesString(sv.fieldFilters) + ")"
|
||||
s := "json_values(" + fieldFiltersString(sv.fieldFilters) + ")"
|
||||
|
||||
if len(sv.sortFields) > 0 {
|
||||
a := make([]string, len(sv.sortFields))
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_max.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_max.go
generated
vendored
@@ -17,7 +17,7 @@ type statsMax struct {
|
||||
}
|
||||
|
||||
func (sm *statsMax) String() string {
|
||||
return "max(" + fieldNamesString(sm.fieldFilters) + ")"
|
||||
return "max(" + fieldFiltersString(sm.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (sm *statsMax) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_median.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_median.go
generated
vendored
@@ -9,7 +9,7 @@ type statsMedian struct {
|
||||
}
|
||||
|
||||
func (sm *statsMedian) String() string {
|
||||
return "median(" + fieldNamesString(sm.sq.fieldFilters) + ")"
|
||||
return "median(" + fieldFiltersString(sm.sq.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (sm *statsMedian) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_min.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_min.go
generated
vendored
@@ -17,7 +17,7 @@ type statsMin struct {
|
||||
}
|
||||
|
||||
func (sm *statsMin) String() string {
|
||||
return "min(" + fieldNamesString(sm.fieldFilters) + ")"
|
||||
return "min(" + fieldFiltersString(sm.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (sm *statsMin) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_quantile.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_quantile.go
generated
vendored
@@ -24,7 +24,7 @@ type statsQuantile struct {
|
||||
func (sq *statsQuantile) String() string {
|
||||
s := "quantile(" + sq.phiStr
|
||||
if !prefixfilter.MatchAll(sq.fieldFilters) {
|
||||
s += ", " + fieldNamesString(sq.fieldFilters)
|
||||
s += ", " + fieldFiltersString(sq.fieldFilters)
|
||||
}
|
||||
s += ")"
|
||||
return s
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_rate_sum.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_rate_sum.go
generated
vendored
@@ -14,7 +14,7 @@ type statsRateSum struct {
|
||||
}
|
||||
|
||||
func (sr *statsRateSum) String() string {
|
||||
return "rate_sum(" + fieldNamesString(sr.ss.fieldFilters) + ")"
|
||||
return "rate_sum(" + fieldFiltersString(sr.ss.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (sr *statsRateSum) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_row_any.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_row_any.go
generated
vendored
@@ -16,7 +16,7 @@ type statsRowAny struct {
|
||||
}
|
||||
|
||||
func (sa *statsRowAny) String() string {
|
||||
return "row_any(" + fieldNamesString(sa.fieldFilters) + ")"
|
||||
return "row_any(" + fieldFiltersString(sa.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (sa *statsRowAny) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_row_max.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_row_max.go
generated
vendored
@@ -21,7 +21,7 @@ type statsRowMax struct {
|
||||
func (sm *statsRowMax) String() string {
|
||||
s := "row_max(" + quoteTokenIfNeeded(sm.srcField)
|
||||
if !prefixfilter.MatchAll(sm.fieldFilters) {
|
||||
s += ", " + fieldNamesString(sm.fieldFilters)
|
||||
s += ", " + fieldFiltersString(sm.fieldFilters)
|
||||
}
|
||||
s += ")"
|
||||
return s
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_row_min.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_row_min.go
generated
vendored
@@ -21,7 +21,7 @@ type statsRowMin struct {
|
||||
func (sm *statsRowMin) String() string {
|
||||
s := "row_min(" + quoteTokenIfNeeded(sm.srcField)
|
||||
if !prefixfilter.MatchAll(sm.fieldFilters) {
|
||||
s += ", " + fieldNamesString(sm.fieldFilters)
|
||||
s += ", " + fieldFiltersString(sm.fieldFilters)
|
||||
}
|
||||
s += ")"
|
||||
return s
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_stddev.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_stddev.go
generated
vendored
@@ -15,7 +15,7 @@ type statsStddev struct {
|
||||
}
|
||||
|
||||
func (ss *statsStddev) String() string {
|
||||
return "stddev(" + fieldNamesString(ss.fieldFilters) + ")"
|
||||
return "stddev(" + fieldFiltersString(ss.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (ss *statsStddev) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_sum.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_sum.go
generated
vendored
@@ -15,7 +15,7 @@ type statsSum struct {
|
||||
}
|
||||
|
||||
func (ss *statsSum) String() string {
|
||||
return "sum(" + fieldNamesString(ss.fieldFilters) + ")"
|
||||
return "sum(" + fieldFiltersString(ss.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (ss *statsSum) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_sum_len.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_sum_len.go
generated
vendored
@@ -14,7 +14,7 @@ type statsSumLen struct {
|
||||
}
|
||||
|
||||
func (ss *statsSumLen) String() string {
|
||||
return "sum_len(" + fieldNamesString(ss.fieldFilters) + ")"
|
||||
return "sum_len(" + fieldFiltersString(ss.fieldFilters) + ")"
|
||||
}
|
||||
|
||||
func (ss *statsSumLen) updateNeededFields(pf *prefixfilter.Filter) {
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_uniq_values.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_uniq_values.go
generated
vendored
@@ -21,7 +21,7 @@ type statsUniqValues struct {
|
||||
}
|
||||
|
||||
func (su *statsUniqValues) String() string {
|
||||
s := "uniq_values(" + fieldNamesString(su.fieldFilters) + ")"
|
||||
s := "uniq_values(" + fieldFiltersString(su.fieldFilters) + ")"
|
||||
if su.limit > 0 {
|
||||
s += fmt.Sprintf(" limit %d", su.limit)
|
||||
}
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_values.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stats_values.go
generated
vendored
@@ -17,7 +17,7 @@ type statsValues struct {
|
||||
}
|
||||
|
||||
func (sv *statsValues) String() string {
|
||||
s := "values(" + fieldNamesString(sv.fieldFilters) + ")"
|
||||
s := "values(" + fieldFiltersString(sv.fieldFilters) + ")"
|
||||
if sv.limit > 0 {
|
||||
s += fmt.Sprintf(" limit %d", sv.limit)
|
||||
}
|
||||
|
||||
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/storage_search.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/storage_search.go
generated
vendored
@@ -1347,7 +1347,6 @@ func (s *Storage) searchParallel(workersCount int, sso *storageSearchOptions, qs
|
||||
putBlockSearch(bs)
|
||||
putBitmap(bm)
|
||||
qs.UpdateAtomic(qsLocal)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1601,7 +1600,6 @@ func (p *part) hasMatchingRows(pso *partitionSearchOptions, stopCh <-chan struct
|
||||
|
||||
putBlockSearch(bs)
|
||||
putBitmap(bm)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
93
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stream_tags.go
generated
vendored
93
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/stream_tags.go
generated
vendored
@@ -44,46 +44,54 @@ func (st *StreamTags) Reset() {
|
||||
st.tags = st.tags[:0]
|
||||
}
|
||||
|
||||
// CopyFrom copies src to dst.
|
||||
func (st *StreamTags) CopyFrom(src *StreamTags) {
|
||||
st.Reset()
|
||||
st.tags = append(st.tags[:0], src.tags...)
|
||||
}
|
||||
|
||||
// String returns string representation of st.
|
||||
func (st *StreamTags) String() string {
|
||||
b := st.marshalString(nil)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (st *StreamTags) verifyCanonicalFieldValues(fields []Field) error {
|
||||
// Verify that the unmarshaled stream tags match the corresponding fields' values.
|
||||
// See https://github.com/VictoriaMetrics/VictoriaLogs/issues/38
|
||||
// normalize synchronizes st with the provided fields and returns true if st was updated.
|
||||
//
|
||||
// This function updates or keeps tags that exist in fields and removes missing ones.
|
||||
func (st *StreamTags) normalize(fields []Field) bool {
|
||||
updated := false
|
||||
|
||||
prevTagName := ""
|
||||
for _, tag := range st.tags {
|
||||
tags := st.tags
|
||||
dstTags := tags[:0]
|
||||
for _, tag := range tags {
|
||||
tagName := tag.Name
|
||||
|
||||
if err := CheckStreamFieldName(tagName); err != nil {
|
||||
return fmt.Errorf("invalid stream tag name: %s; streamTags: %s", tagName, st)
|
||||
var f *Field
|
||||
for j := range fields {
|
||||
if fields[j].Name == tagName {
|
||||
f = &fields[j]
|
||||
// break is skipped intentionally in order to get the last matching field
|
||||
}
|
||||
}
|
||||
if f == nil {
|
||||
updated = true
|
||||
continue
|
||||
}
|
||||
|
||||
if tagName <= prevTagName {
|
||||
return fmt.Errorf("stream tag names must be sorted; got %q after %q; streamTags: %s", tagName, prevTagName, st)
|
||||
}
|
||||
|
||||
tagValue := tag.Value
|
||||
found := false
|
||||
for _, f := range fields {
|
||||
if f.Name != tagName {
|
||||
continue
|
||||
}
|
||||
if f.Value != tagValue {
|
||||
line := MarshalFieldsToJSON(nil, fields)
|
||||
return fmt.Errorf("unexpected value for the stream tag %q; got %q; want %q; streamTags: %s; fields: %s", tagName, f.Value, tagValue, st, line)
|
||||
}
|
||||
found = true
|
||||
}
|
||||
if !found {
|
||||
line := MarshalFieldsToJSON(nil, fields)
|
||||
return fmt.Errorf("cannot find value for the stream tag %q in fields; want %q; streamTags: %s; fields: %s", tagName, tagValue, st, line)
|
||||
if tag.Value != f.Value {
|
||||
tag.Value = f.Value
|
||||
updated = true
|
||||
}
|
||||
dstTags = append(dstTags, tag)
|
||||
}
|
||||
return nil
|
||||
|
||||
if updated {
|
||||
clear(tags[len(dstTags):])
|
||||
st.tags = dstTags
|
||||
}
|
||||
|
||||
return updated
|
||||
}
|
||||
|
||||
func (st *StreamTags) marshalString(dst []byte) []byte {
|
||||
@@ -112,7 +120,13 @@ func (st *StreamTags) unmarshalStringInplace(s string) error {
|
||||
|
||||
var err error
|
||||
st.tags, err = parseStreamFields(st.tags[:0], s)
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sort.Sort(st)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add adds (name:value) tag to st.
|
||||
@@ -136,7 +150,10 @@ func (st *StreamTags) Add(name, value string) {
|
||||
// MarshalCanonical marshal st in a canonical way
|
||||
func (st *StreamTags) MarshalCanonical(dst []byte) []byte {
|
||||
sort.Sort(st)
|
||||
return st.marshalCanonicalInternal(dst)
|
||||
}
|
||||
|
||||
func (st *StreamTags) marshalCanonicalInternal(dst []byte) []byte {
|
||||
tags := st.tags
|
||||
dst = encoding.MarshalVarUint64(dst, uint64(len(tags)))
|
||||
for i := range tags {
|
||||
@@ -160,6 +177,7 @@ func (st *StreamTags) UnmarshalCanonicalInplace(src []byte) ([]byte, error) {
|
||||
return srcOrig, fmt.Errorf("cannot unmarshal tags len")
|
||||
}
|
||||
src = src[nSize:]
|
||||
|
||||
for range n {
|
||||
name, nSize := encoding.UnmarshalBytes(src)
|
||||
if nSize <= 0 {
|
||||
@@ -178,13 +196,28 @@ func (st *StreamTags) UnmarshalCanonicalInplace(src []byte) ([]byte, error) {
|
||||
st.Add(sName, sValue)
|
||||
}
|
||||
|
||||
if !sort.IsSorted(st) {
|
||||
return srcOrig, fmt.Errorf("stream tags must be sorted in alphabetical order; got unsorted: %s", st)
|
||||
if err := st.checkCorrectness(); err != nil {
|
||||
return srcOrig, err
|
||||
}
|
||||
|
||||
return src, nil
|
||||
}
|
||||
|
||||
func (st *StreamTags) checkCorrectness() error {
|
||||
prevTagName := ""
|
||||
for _, tag := range st.tags {
|
||||
tagName := tag.Name
|
||||
if err := CheckStreamFieldName(tagName); err != nil {
|
||||
return fmt.Errorf("invalid stream tag name: %w", err)
|
||||
}
|
||||
if tagName <= prevTagName {
|
||||
return fmt.Errorf("stream tags must be sorted in alphabetical order; got %q which is less or equal than %q; streamTags=%s", tagName, prevTagName, st)
|
||||
}
|
||||
prevTagName = tagName
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStreamTagsString(streamTagsCanonical string) string {
|
||||
st := GetStreamTags()
|
||||
mustUnmarshalStreamTagsInplace(st, streamTagsCanonical)
|
||||
|
||||
1
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/syslog_parser.go
generated
vendored
1
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/syslog_parser.go
generated
vendored
@@ -655,7 +655,6 @@ func (p *SyslogParser) parseCEFExtension(s string) bool {
|
||||
p.AddField(keyName, unescapeCEFValue(s[:n]))
|
||||
s = s[n+1:]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (p *SyslogParser) tryParseTimestampRFC3164(s string) bool {
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -133,7 +133,7 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric
|
||||
# github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0
|
||||
## explicit; go 1.25.0
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping
|
||||
# github.com/VictoriaMetrics/VictoriaLogs v1.121.1-0.20260616132739-c901a1e31cb3
|
||||
# github.com/VictoriaMetrics/VictoriaLogs v1.51.1-0.20260624061259-dc94972a8708
|
||||
## explicit; go 1.26.4
|
||||
github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage
|
||||
github.com/VictoriaMetrics/VictoriaLogs/lib/prefixfilter
|
||||
|
||||
Reference in New Issue
Block a user