mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-06-25 11:38:49 +03:00
Compare commits
1 Commits
master
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04e6fbbeaf |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -65,7 +65,7 @@ jobs:
|
||||
arch: amd64
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
2
.github/workflows/changelog-linter.yml
vendored
2
.github/workflows/changelog-linter.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
contents: read
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
# needed for proper diff
|
||||
fetch-depth: 0
|
||||
|
||||
2
.github/workflows/check-commit-signed.yml
vendored
2
.github/workflows/check-commit-signed.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
fetch-depth: 0 # we need full history for commit verification
|
||||
persist-credentials: false
|
||||
|
||||
2
.github/workflows/check-licenses.yml
vendored
2
.github/workflows/check-licenses.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
2
.github/workflows/codeql-analysis-go.yml
vendored
2
.github/workflows/codeql-analysis-go.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
4
.github/workflows/docs.yaml
vendored
4
.github/workflows/docs.yaml
vendored
@@ -18,13 +18,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
path: __vm
|
||||
persist-credentials: false
|
||||
|
||||
- name: Checkout private code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
repository: VictoriaMetrics/vmdocs
|
||||
token: ${{ secrets.VM_BOT_GH_TOKEN }}
|
||||
|
||||
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
runs-on: 'vm-runner'
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -106,7 +106,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
2
.github/workflows/vmui.yml
vendored
2
.github/workflows/vmui.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
@@ -457,10 +457,12 @@ 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 opposed to a unit test that verifies the behavior of a building block of an
|
||||
as apposed 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 starting an application and should
|
||||
- `app.go` - contains the generic code for staring 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 starting a specific application.
|
||||
code for staring 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 ./apptest/tests`, you will need to build the binaries first (for example,
|
||||
`go test ./app/apptest`, 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\nSee 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\nSeу 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\nSee 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\nSeу 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\nSee 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\nSeу 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\nSee 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\nSeу 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\nSee 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\nSeу 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\nSee 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\nSeу 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\nSee 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\nSeу 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\nSee 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\nSeу 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.7
|
||||
image: victoriametrics/vmanomaly:v1.29.6
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
|
||||
@@ -14,17 +14,6 @@ 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. Notable mentions include `api/v1/server/model` endpoint for accessing production models config and queries from UI, manually or through [AI assistant](https://docs.victoriametrics.com/anomaly-detection/ui/#ai-assistance).
|
||||
|
||||
- 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 (`vmanomaly_reader_processing_tasks_queued` [metric](https://docs.victoriametrics.com/anomaly-detection/components/monitoring/#reader-behaviour-metrics)), and clarifying inference skip logs after data fetch timeouts. See `series_processing_batch_size` argument of [VmReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#vm-reader) and [VLogsReader](https://docs.victoriametrics.com/anomaly-detection/components/reader/#victorialogs-reader) for details.
|
||||
|
||||
- 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.7
|
||||
image: victoriametrics/vmanomaly:v1.29.6
|
||||
# ...
|
||||
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.7 && docker image tag victoriametrics/vmanomaly:v1.29.7 vmanomaly
|
||||
docker pull victoriametrics/vmanomaly:v1.29.6 && docker image tag victoriametrics/vmanomaly:v1.29.6 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.7](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1297) | Fully Compatible | - |
|
||||
| [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.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.7
|
||||
docker pull victoriametrics/vmanomaly:v1.29.6
|
||||
```
|
||||
|
||||
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.7 \
|
||||
victoriametrics/vmanomaly:v1.29.6 \
|
||||
/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.7 \
|
||||
victoriametrics/vmanomaly:v1.29.6 \
|
||||
/config.yaml \
|
||||
--licenseFile=/license \
|
||||
--loggerLevel=INFO \
|
||||
@@ -182,7 +182,7 @@ services:
|
||||
# ...
|
||||
vmanomaly:
|
||||
container_name: vmanomaly
|
||||
image: victoriametrics/vmanomaly:v1.29.7
|
||||
image: victoriametrics/vmanomaly:v1.29.6
|
||||
# ...
|
||||
restart: always
|
||||
volumes:
|
||||
@@ -267,7 +267,6 @@ 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'
|
||||
|
||||
@@ -299,7 +298,6 @@ 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:
|
||||
@@ -415,13 +413,11 @@ 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.7 \
|
||||
victoriametrics/vmanomaly:v1.29.6 \
|
||||
vmanomaly_config.yaml
|
||||
```
|
||||
|
||||
@@ -640,21 +640,6 @@ 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,7 +49,6 @@ 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
|
||||
@@ -57,7 +56,6 @@ 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
|
||||
@@ -137,7 +135,6 @@ 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.7
|
||||
docker pull victoriametrics/vmanomaly:v1.29.6
|
||||
```
|
||||
|
||||
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.7 /config.yaml \
|
||||
victoriametrics/vmanomaly:v1.29.6 /config.yaml \
|
||||
--licenseFile=/license
|
||||
--watch
|
||||
```
|
||||
|
||||
@@ -458,21 +458,6 @@ 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,20 +421,7 @@ 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).
|
||||
</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.
|
||||
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>
|
||||
</tbody>
|
||||
@@ -463,7 +450,6 @@ reader:
|
||||
sampling_period: '1m'
|
||||
query_from_last_seen_timestamp: True # false by default
|
||||
latency_offset: '1ms'
|
||||
series_processing_batch_size: 8
|
||||
```
|
||||
|
||||
### MetricsQL Playground
|
||||
@@ -893,19 +879,6 @@ If a path to a CA bundle file (like `ca.crt`), it will verify the certificate us
|
||||
(Optional) Password for authentication. If set, it will be used to authenticate the request.
|
||||
</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>
|
||||
</table>
|
||||
|
||||
@@ -924,7 +897,6 @@ reader:
|
||||
# tenant_id: '0:0' # for cluster version only
|
||||
sampling_period: '1m'
|
||||
max_points_per_query: 10000
|
||||
series_processing_batch_size: 8
|
||||
data_range: [0, 'inf'] # reader-level
|
||||
offset: '0s' # reader-level
|
||||
timeout: '30s'
|
||||
|
||||
@@ -74,7 +74,40 @@ 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. Time granularity is defined by the last characters of a string. Examples: `"50s"` (seconds), `"4m"` (minutes), `"3h"` (hours), `"2d"` (days), `"1w"` (weeks).
|
||||
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>
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
@@ -155,21 +188,6 @@ 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>
|
||||
|
||||
@@ -182,7 +200,6 @@ 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.7
|
||||
image: victoriametrics/vmanomaly:v1.29.6
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
|
||||
@@ -26,9 +26,6 @@ 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
|
||||
@@ -48,11 +45,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,13 +622,11 @@ curl -Is http://localhost:8428/internal/resetRollupResultCache
|
||||
Cluster version of VictoriaMetrics:
|
||||
|
||||
```sh
|
||||
curl -Is http://<vmselect>:8481/internal/resetRollupResultCache?propagate=1
|
||||
curl -Is http://<vmselect>:8481/internal/resetRollupResultCache
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
### 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.51.1-0.20260624061259-dc94972a8708
|
||||
github.com/VictoriaMetrics/VictoriaLogs v1.121.1-0.20260616132739-c901a1e31cb3
|
||||
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.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/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/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,12 +36,10 @@ function submitRelabelDebugForm(e) {
|
||||
<div class="container-fluid">
|
||||
<a href="https://docs.victoriametrics.com/victoriametrics/relabeling/" target="_blank">Relabeling docs</a>{% space %}
|
||||
|
||||
{% 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 %}
|
||||
{% 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>
|
||||
{% endif %}
|
||||
|
||||
<br>
|
||||
|
||||
@@ -80,417 +80,425 @@ func StreamRelabelDebugStepsHTML(qw422016 *qt422016.Writer, targetURL, targetID
|
||||
//line lib/promrelabel/debug.qtpl:37
|
||||
qw422016.N().S(` `)
|
||||
//line lib/promrelabel/debug.qtpl:39
|
||||
if targetID != "" {
|
||||
if targetURL != "" {
|
||||
//line lib/promrelabel/debug.qtpl:39
|
||||
qw422016.N().S(`<a href="metric-relabel-debug`)
|
||||
//line lib/promrelabel/debug.qtpl:40
|
||||
if targetURL != "" {
|
||||
if targetID != "" {
|
||||
//line lib/promrelabel/debug.qtpl:40
|
||||
qw422016.N().S(`?id=`)
|
||||
//line lib/promrelabel/debug.qtpl:40
|
||||
qw422016.N().S(`<a href="metric-relabel-debug?id=`)
|
||||
//line lib/promrelabel/debug.qtpl:41
|
||||
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(`<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:40
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:45
|
||||
//line lib/promrelabel/debug.qtpl:40
|
||||
qw422016.N().S(`">Metric relabel debug</a>`)
|
||||
//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:42
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:42
|
||||
qw422016.N().S(`">Target relabel debug</a>`)
|
||||
//line lib/promrelabel/debug.qtpl:43
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:45
|
||||
//line lib/promrelabel/debug.qtpl:43
|
||||
qw422016.N().S(`<br>`)
|
||||
//line lib/promrelabel/debug.qtpl:48
|
||||
//line lib/promrelabel/debug.qtpl:46
|
||||
if err != nil {
|
||||
//line lib/promrelabel/debug.qtpl:49
|
||||
//line lib/promrelabel/debug.qtpl:47
|
||||
htmlcomponents.StreamErrorNotification(qw422016, err)
|
||||
//line lib/promrelabel/debug.qtpl:50
|
||||
//line lib/promrelabel/debug.qtpl:48
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:50
|
||||
//line lib/promrelabel/debug.qtpl:48
|
||||
qw422016.N().S(`<div class="m-3"><form method="POST" onsubmit="submitRelabelDebugForm(event)">`)
|
||||
//line lib/promrelabel/debug.qtpl:54
|
||||
//line lib/promrelabel/debug.qtpl:52
|
||||
streamrelabelDebugFormInputs(qw422016, metric, relabelConfigs)
|
||||
//line lib/promrelabel/debug.qtpl:55
|
||||
//line lib/promrelabel/debug.qtpl:53
|
||||
if targetID != "" {
|
||||
//line lib/promrelabel/debug.qtpl:55
|
||||
//line lib/promrelabel/debug.qtpl:53
|
||||
qw422016.N().S(`<input type="hidden" name="id" value="`)
|
||||
//line lib/promrelabel/debug.qtpl:56
|
||||
//line lib/promrelabel/debug.qtpl:54
|
||||
qw422016.E().S(targetID)
|
||||
//line lib/promrelabel/debug.qtpl:56
|
||||
//line lib/promrelabel/debug.qtpl:54
|
||||
qw422016.N().S(`" />`)
|
||||
//line lib/promrelabel/debug.qtpl:57
|
||||
//line lib/promrelabel/debug.qtpl:55
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:57
|
||||
//line lib/promrelabel/debug.qtpl:55
|
||||
qw422016.N().S(`<input type="submit" value="Submit" class="btn btn-primary m-1" />`)
|
||||
//line lib/promrelabel/debug.qtpl:59
|
||||
//line lib/promrelabel/debug.qtpl:57
|
||||
if targetID != "" {
|
||||
//line lib/promrelabel/debug.qtpl:59
|
||||
//line lib/promrelabel/debug.qtpl:57
|
||||
qw422016.N().S(`<button type="button" onclick="location.href='?id=`)
|
||||
//line lib/promrelabel/debug.qtpl:60
|
||||
//line lib/promrelabel/debug.qtpl:58
|
||||
qw422016.E().S(targetID)
|
||||
//line lib/promrelabel/debug.qtpl:60
|
||||
//line lib/promrelabel/debug.qtpl:58
|
||||
qw422016.N().S(`'" class="btn btn-secondary m-1">Reset</button>`)
|
||||
//line lib/promrelabel/debug.qtpl:61
|
||||
//line lib/promrelabel/debug.qtpl:59
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:61
|
||||
//line lib/promrelabel/debug.qtpl:59
|
||||
qw422016.N().S(`</form></div><div class="row"><main class="col-12">`)
|
||||
//line lib/promrelabel/debug.qtpl:67
|
||||
//line lib/promrelabel/debug.qtpl:65
|
||||
streamrelabelDebugSteps(qw422016, dss, targetURL, targetID)
|
||||
//line lib/promrelabel/debug.qtpl:67
|
||||
//line lib/promrelabel/debug.qtpl:65
|
||||
qw422016.N().S(`</main></div></div></body></html>`)
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
func WriteRelabelDebugStepsHTML(qq422016 qtio422016.Writer, targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) {
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
StreamRelabelDebugStepsHTML(qw422016, targetURL, targetID, dss, metric, relabelConfigs, err)
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
func RelabelDebugStepsHTML(targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) string {
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
WriteRelabelDebugStepsHTML(qb422016, targetURL, targetID, dss, metric, relabelConfigs, err)
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
//line lib/promrelabel/debug.qtpl:71
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:75
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
func streamrelabelDebugFormInputs(qw422016 *qt422016.Writer, metric, relabelConfigs string) {
|
||||
//line lib/promrelabel/debug.qtpl:75
|
||||
//line lib/promrelabel/debug.qtpl:73
|
||||
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:78
|
||||
//line lib/promrelabel/debug.qtpl:76
|
||||
qw422016.E().S(relabelConfigs)
|
||||
//line lib/promrelabel/debug.qtpl:78
|
||||
//line lib/promrelabel/debug.qtpl:76
|
||||
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:83
|
||||
//line lib/promrelabel/debug.qtpl:81
|
||||
qw422016.E().S(metric)
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
//line lib/promrelabel/debug.qtpl:81
|
||||
qw422016.N().S(`</textarea></div>`)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
func writerelabelDebugFormInputs(qq422016 qtio422016.Writer, metric, relabelConfigs string) {
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
streamrelabelDebugFormInputs(qw422016, metric, relabelConfigs)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
func relabelDebugFormInputs(metric, relabelConfigs string) string {
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
writerelabelDebugFormInputs(qb422016, metric, relabelConfigs)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
//line lib/promrelabel/debug.qtpl:83
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:87
|
||||
//line lib/promrelabel/debug.qtpl:85
|
||||
func streamrelabelDebugSteps(qw422016 *qt422016.Writer, dss []DebugStep, targetURL, targetID string) {
|
||||
//line lib/promrelabel/debug.qtpl:88
|
||||
//line lib/promrelabel/debug.qtpl:86
|
||||
if len(dss) > 0 {
|
||||
//line lib/promrelabel/debug.qtpl:88
|
||||
//line lib/promrelabel/debug.qtpl:86
|
||||
qw422016.N().S(`<div class="m-3"><b>Original labels:</b> <samp>`)
|
||||
//line lib/promrelabel/debug.qtpl:90
|
||||
//line lib/promrelabel/debug.qtpl:88
|
||||
streammustFormatLabels(qw422016, dss[0].In)
|
||||
//line lib/promrelabel/debug.qtpl:90
|
||||
//line lib/promrelabel/debug.qtpl:88
|
||||
qw422016.N().S(`</samp></div>`)
|
||||
//line lib/promrelabel/debug.qtpl:92
|
||||
//line lib/promrelabel/debug.qtpl:90
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:92
|
||||
//line lib/promrelabel/debug.qtpl:90
|
||||
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:103
|
||||
//line lib/promrelabel/debug.qtpl:101
|
||||
for i, ds := range dss {
|
||||
//line lib/promrelabel/debug.qtpl:105
|
||||
//line lib/promrelabel/debug.qtpl:103
|
||||
inLabels, inErr := promutil.NewLabelsFromString(ds.In)
|
||||
outLabels, outErr := promutil.NewLabelsFromString(ds.Out)
|
||||
changedLabels := getChangedLabelNames(inLabels, outLabels)
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:108
|
||||
//line lib/promrelabel/debug.qtpl:106
|
||||
qw422016.N().S(`<tr><td>`)
|
||||
//line lib/promrelabel/debug.qtpl:110
|
||||
//line lib/promrelabel/debug.qtpl:108
|
||||
qw422016.N().D(i)
|
||||
//line lib/promrelabel/debug.qtpl:110
|
||||
//line lib/promrelabel/debug.qtpl:108
|
||||
qw422016.N().S(`</td><td><b><pre class="m-2">`)
|
||||
//line lib/promrelabel/debug.qtpl:111
|
||||
//line lib/promrelabel/debug.qtpl:109
|
||||
qw422016.E().S(ds.Rule)
|
||||
//line lib/promrelabel/debug.qtpl:111
|
||||
//line lib/promrelabel/debug.qtpl:109
|
||||
qw422016.N().S(`</pre></b></td><td>`)
|
||||
//line lib/promrelabel/debug.qtpl:113
|
||||
//line lib/promrelabel/debug.qtpl:111
|
||||
if inErr == nil {
|
||||
//line lib/promrelabel/debug.qtpl:113
|
||||
//line lib/promrelabel/debug.qtpl:111
|
||||
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:115
|
||||
//line lib/promrelabel/debug.qtpl:113
|
||||
streamlabelsWithHighlight(qw422016, inLabels, changedLabels, "#D15757")
|
||||
//line lib/promrelabel/debug.qtpl:113
|
||||
qw422016.N().S(`</div>`)
|
||||
//line lib/promrelabel/debug.qtpl:115
|
||||
qw422016.N().S(`</div>`)
|
||||
//line lib/promrelabel/debug.qtpl:117
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:117
|
||||
//line lib/promrelabel/debug.qtpl:115
|
||||
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:119
|
||||
//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
|
||||
qw422016.N().S(`</pre></div>`)
|
||||
//line lib/promrelabel/debug.qtpl:121
|
||||
break
|
||||
//line lib/promrelabel/debug.qtpl:122
|
||||
//line lib/promrelabel/debug.qtpl:120
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:122
|
||||
//line lib/promrelabel/debug.qtpl:120
|
||||
qw422016.N().S(`</td><td>`)
|
||||
//line lib/promrelabel/debug.qtpl:125
|
||||
//line lib/promrelabel/debug.qtpl:123
|
||||
if outErr == nil {
|
||||
//line lib/promrelabel/debug.qtpl:125
|
||||
//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:127
|
||||
//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
|
||||
qw422016.N().S(`</div>`)
|
||||
//line lib/promrelabel/debug.qtpl:129
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:129
|
||||
//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:131
|
||||
//line lib/promrelabel/debug.qtpl:129
|
||||
qw422016.E().S(outErr.Error())
|
||||
//line lib/promrelabel/debug.qtpl:131
|
||||
//line lib/promrelabel/debug.qtpl:129
|
||||
qw422016.N().S(`</pre></div>`)
|
||||
//line lib/promrelabel/debug.qtpl:133
|
||||
//line lib/promrelabel/debug.qtpl:131
|
||||
break
|
||||
//line lib/promrelabel/debug.qtpl:134
|
||||
//line lib/promrelabel/debug.qtpl:132
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:134
|
||||
//line lib/promrelabel/debug.qtpl:132
|
||||
qw422016.N().S(`</td></tr>`)
|
||||
//line lib/promrelabel/debug.qtpl:137
|
||||
//line lib/promrelabel/debug.qtpl:135
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:137
|
||||
//line lib/promrelabel/debug.qtpl:135
|
||||
qw422016.N().S(`</tbody></table>`)
|
||||
//line lib/promrelabel/debug.qtpl:140
|
||||
//line lib/promrelabel/debug.qtpl:138
|
||||
if len(dss) > 0 {
|
||||
//line lib/promrelabel/debug.qtpl:140
|
||||
//line lib/promrelabel/debug.qtpl:138
|
||||
qw422016.N().S(`<div class="m-3"><b>Resulting labels:</b> <samp>`)
|
||||
//line lib/promrelabel/debug.qtpl:142
|
||||
//line lib/promrelabel/debug.qtpl:140
|
||||
streammustFormatLabels(qw422016, dss[len(dss)-1].Out)
|
||||
//line lib/promrelabel/debug.qtpl:142
|
||||
//line lib/promrelabel/debug.qtpl:140
|
||||
qw422016.N().S(`</samp>`)
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
//line lib/promrelabel/debug.qtpl:141
|
||||
if targetURL != "" {
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
//line lib/promrelabel/debug.qtpl:141
|
||||
qw422016.N().S(`<div><b>Target URL:</b>`)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.N().S(` `)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.N().S(`<a href="`)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.E().S(targetURL)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.N().S(`" target="_blank">`)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.E().S(targetURL)
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
//line lib/promrelabel/debug.qtpl:143
|
||||
qw422016.N().S(`</a>`)
|
||||
//line lib/promrelabel/debug.qtpl:146
|
||||
//line lib/promrelabel/debug.qtpl:144
|
||||
if targetID != "" {
|
||||
//line lib/promrelabel/debug.qtpl:147
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
qw422016.N().S(` `)
|
||||
//line lib/promrelabel/debug.qtpl:147
|
||||
//line lib/promrelabel/debug.qtpl:145
|
||||
qw422016.N().S(`(<a href="target_response?id=`)
|
||||
//line lib/promrelabel/debug.qtpl:148
|
||||
//line lib/promrelabel/debug.qtpl:146
|
||||
qw422016.E().S(targetID)
|
||||
//line lib/promrelabel/debug.qtpl:148
|
||||
//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:149
|
||||
//line lib/promrelabel/debug.qtpl:147
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:149
|
||||
//line lib/promrelabel/debug.qtpl:147
|
||||
qw422016.N().S(`</div>`)
|
||||
//line lib/promrelabel/debug.qtpl:151
|
||||
//line lib/promrelabel/debug.qtpl:149
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:151
|
||||
//line lib/promrelabel/debug.qtpl:149
|
||||
qw422016.N().S(`</div>`)
|
||||
//line lib/promrelabel/debug.qtpl:153
|
||||
//line lib/promrelabel/debug.qtpl:151
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
func writerelabelDebugSteps(qq422016 qtio422016.Writer, dss []DebugStep, targetURL, targetID string) {
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
streamrelabelDebugSteps(qw422016, dss, targetURL, targetID)
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
func relabelDebugSteps(dss []DebugStep, targetURL, targetID string) string {
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
writerelabelDebugSteps(qb422016, dss, targetURL, targetID)
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
//line lib/promrelabel/debug.qtpl:152
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:156
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
func StreamRelabelDebugStepsJSON(qw422016 *qt422016.Writer, targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) {
|
||||
//line lib/promrelabel/debug.qtpl:156
|
||||
//line lib/promrelabel/debug.qtpl:154
|
||||
qw422016.N().S(`{`)
|
||||
//line lib/promrelabel/debug.qtpl:158
|
||||
//line lib/promrelabel/debug.qtpl:156
|
||||
if err != nil {
|
||||
//line lib/promrelabel/debug.qtpl:158
|
||||
//line lib/promrelabel/debug.qtpl:156
|
||||
qw422016.N().S(`"status": "error","error":`)
|
||||
//line lib/promrelabel/debug.qtpl:160
|
||||
//line lib/promrelabel/debug.qtpl:158
|
||||
qw422016.N().Q(fmt.Sprintf("Error: %s", err))
|
||||
//line lib/promrelabel/debug.qtpl:161
|
||||
//line lib/promrelabel/debug.qtpl:159
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:162
|
||||
//line lib/promrelabel/debug.qtpl:160
|
||||
var hasError bool
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:162
|
||||
//line lib/promrelabel/debug.qtpl:160
|
||||
qw422016.N().S(`"status": "success","steps": [`)
|
||||
//line lib/promrelabel/debug.qtpl:165
|
||||
//line lib/promrelabel/debug.qtpl:163
|
||||
for i, ds := range dss {
|
||||
//line lib/promrelabel/debug.qtpl:167
|
||||
//line lib/promrelabel/debug.qtpl:165
|
||||
inLabels, inErr := promutil.NewLabelsFromString(ds.In)
|
||||
outLabels, outErr := promutil.NewLabelsFromString(ds.Out)
|
||||
changedLabels := getChangedLabelNames(inLabels, outLabels)
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:170
|
||||
//line lib/promrelabel/debug.qtpl:168
|
||||
qw422016.N().S(`{"inLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:172
|
||||
//line lib/promrelabel/debug.qtpl:170
|
||||
qw422016.N().Q(labelsWithHighlight(inLabels, changedLabels, "#D15757"))
|
||||
//line lib/promrelabel/debug.qtpl:172
|
||||
//line lib/promrelabel/debug.qtpl:170
|
||||
qw422016.N().S(`,"outLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:173
|
||||
//line lib/promrelabel/debug.qtpl:171
|
||||
qw422016.N().Q(labelsWithHighlight(outLabels, changedLabels, "#4495e0"))
|
||||
//line lib/promrelabel/debug.qtpl:173
|
||||
//line lib/promrelabel/debug.qtpl:171
|
||||
qw422016.N().S(`,"rule":`)
|
||||
//line lib/promrelabel/debug.qtpl:174
|
||||
//line lib/promrelabel/debug.qtpl:172
|
||||
qw422016.N().Q(ds.Rule)
|
||||
//line lib/promrelabel/debug.qtpl:174
|
||||
//line lib/promrelabel/debug.qtpl:172
|
||||
qw422016.N().S(`,"errors": {`)
|
||||
//line lib/promrelabel/debug.qtpl:176
|
||||
//line lib/promrelabel/debug.qtpl:174
|
||||
if inErr != nil {
|
||||
//line lib/promrelabel/debug.qtpl:176
|
||||
//line lib/promrelabel/debug.qtpl:174
|
||||
qw422016.N().S(`"inLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:177
|
||||
//line lib/promrelabel/debug.qtpl:175
|
||||
qw422016.N().Q(`<span style="color: #D15757">` + inErr.Error() + `</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:177
|
||||
//line lib/promrelabel/debug.qtpl:175
|
||||
if outErr != nil {
|
||||
//line lib/promrelabel/debug.qtpl:177
|
||||
//line lib/promrelabel/debug.qtpl:175
|
||||
qw422016.N().S(`,`)
|
||||
//line lib/promrelabel/debug.qtpl:177
|
||||
//line lib/promrelabel/debug.qtpl:175
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:178
|
||||
//line lib/promrelabel/debug.qtpl:176
|
||||
hasError = true
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:179
|
||||
//line lib/promrelabel/debug.qtpl:177
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:180
|
||||
//line lib/promrelabel/debug.qtpl:178
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:181
|
||||
//line lib/promrelabel/debug.qtpl:179
|
||||
if outErr != nil {
|
||||
//line lib/promrelabel/debug.qtpl:181
|
||||
//line lib/promrelabel/debug.qtpl:179
|
||||
qw422016.N().S(`"outLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:182
|
||||
//line lib/promrelabel/debug.qtpl:180
|
||||
qw422016.N().Q(`<span style="color: #D15757">` + outErr.Error() + `</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:183
|
||||
//line lib/promrelabel/debug.qtpl:181
|
||||
hasError = true
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:184
|
||||
//line lib/promrelabel/debug.qtpl:182
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:184
|
||||
//line lib/promrelabel/debug.qtpl:182
|
||||
qw422016.N().S(`}}`)
|
||||
//line lib/promrelabel/debug.qtpl:187
|
||||
//line lib/promrelabel/debug.qtpl:185
|
||||
if i != len(dss)-1 {
|
||||
//line lib/promrelabel/debug.qtpl:187
|
||||
//line lib/promrelabel/debug.qtpl:185
|
||||
qw422016.N().S(`,`)
|
||||
//line lib/promrelabel/debug.qtpl:187
|
||||
//line lib/promrelabel/debug.qtpl:185
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:188
|
||||
//line lib/promrelabel/debug.qtpl:186
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:188
|
||||
//line lib/promrelabel/debug.qtpl:186
|
||||
qw422016.N().S(`]`)
|
||||
//line lib/promrelabel/debug.qtpl:190
|
||||
//line lib/promrelabel/debug.qtpl:188
|
||||
if len(dss) > 0 && !hasError {
|
||||
//line lib/promrelabel/debug.qtpl:190
|
||||
//line lib/promrelabel/debug.qtpl:188
|
||||
qw422016.N().S(`,"originalLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:192
|
||||
//line lib/promrelabel/debug.qtpl:190
|
||||
qw422016.N().Q(mustFormatLabels(dss[0].In))
|
||||
//line lib/promrelabel/debug.qtpl:192
|
||||
//line lib/promrelabel/debug.qtpl:190
|
||||
qw422016.N().S(`,"resultingLabels":`)
|
||||
//line lib/promrelabel/debug.qtpl:193
|
||||
//line lib/promrelabel/debug.qtpl:191
|
||||
qw422016.N().Q(mustFormatLabels(dss[len(dss)-1].Out))
|
||||
//line lib/promrelabel/debug.qtpl:194
|
||||
//line lib/promrelabel/debug.qtpl:192
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
//line lib/promrelabel/debug.qtpl:193
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
//line lib/promrelabel/debug.qtpl:193
|
||||
qw422016.N().S(`}`)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//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:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
StreamRelabelDebugStepsJSON(qw422016, targetURL, targetID, dss, metric, relabelConfigs, err)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
func RelabelDebugStepsJSON(targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) string {
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
WriteRelabelDebugStepsJSON(qb422016, targetURL, targetID, dss, metric, relabelConfigs, err)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
//line lib/promrelabel/debug.qtpl:195
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:199
|
||||
//line lib/promrelabel/debug.qtpl:197
|
||||
func streamlabelsWithHighlight(qw422016 *qt422016.Writer, labels *promutil.Labels, highlight map[string]struct{}, color string) {
|
||||
//line lib/promrelabel/debug.qtpl:201
|
||||
//line lib/promrelabel/debug.qtpl:199
|
||||
labelsList := labels.GetLabels()
|
||||
metricName := ""
|
||||
for i, label := range labelsList {
|
||||
@@ -501,153 +509,153 @@ func streamlabelsWithHighlight(qw422016 *qt422016.Writer, labels *promutil.Label
|
||||
}
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:211
|
||||
//line lib/promrelabel/debug.qtpl:209
|
||||
if metricName != "" {
|
||||
//line lib/promrelabel/debug.qtpl:212
|
||||
//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
|
||||
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(`">`)
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:213
|
||||
qw422016.E().S(metricName)
|
||||
//line lib/promrelabel/debug.qtpl:213
|
||||
qw422016.N().S(`</span>`)
|
||||
//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
|
||||
//line lib/promrelabel/debug.qtpl:215
|
||||
return
|
||||
//line lib/promrelabel/debug.qtpl:217
|
||||
//line lib/promrelabel/debug.qtpl:215
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:218
|
||||
//line lib/promrelabel/debug.qtpl:216
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:218
|
||||
//line lib/promrelabel/debug.qtpl:216
|
||||
qw422016.N().S(`{`)
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
//line lib/promrelabel/debug.qtpl:218
|
||||
for i, label := range labelsList {
|
||||
//line lib/promrelabel/debug.qtpl:221
|
||||
//line lib/promrelabel/debug.qtpl:219
|
||||
if _, ok := highlight[label.Name]; ok {
|
||||
//line lib/promrelabel/debug.qtpl:221
|
||||
//line lib/promrelabel/debug.qtpl:219
|
||||
qw422016.N().S(`<span style="font-weight:bold;color:`)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
qw422016.E().S(color)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
qw422016.N().S(`">`)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
qw422016.E().S(label.Name)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
qw422016.N().S(`=`)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
qw422016.E().Q(label.Value)
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
//line lib/promrelabel/debug.qtpl:220
|
||||
qw422016.N().S(`</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:223
|
||||
//line lib/promrelabel/debug.qtpl:221
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
qw422016.E().S(label.Name)
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
qw422016.N().S(`=`)
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
//line lib/promrelabel/debug.qtpl:222
|
||||
qw422016.E().Q(label.Value)
|
||||
//line lib/promrelabel/debug.qtpl:225
|
||||
//line lib/promrelabel/debug.qtpl:223
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:226
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
if i < len(labelsList)-1 {
|
||||
//line lib/promrelabel/debug.qtpl:226
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
qw422016.N().S(`,`)
|
||||
//line lib/promrelabel/debug.qtpl:226
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
qw422016.N().S(` `)
|
||||
//line lib/promrelabel/debug.qtpl:226
|
||||
//line lib/promrelabel/debug.qtpl:224
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
//line lib/promrelabel/debug.qtpl:225
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
//line lib/promrelabel/debug.qtpl:225
|
||||
qw422016.N().S(`}`)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//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:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
streamlabelsWithHighlight(qw422016, labels, highlight, color)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
func labelsWithHighlight(labels *promutil.Labels, highlight map[string]struct{}, color string) string {
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
writelabelsWithHighlight(qb422016, labels, highlight, color)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
//line lib/promrelabel/debug.qtpl:227
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:231
|
||||
//line lib/promrelabel/debug.qtpl:229
|
||||
func streammustFormatLabels(qw422016 *qt422016.Writer, s string) {
|
||||
//line lib/promrelabel/debug.qtpl:232
|
||||
//line lib/promrelabel/debug.qtpl:230
|
||||
labels, err := promutil.NewLabelsFromString(s)
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:233
|
||||
//line lib/promrelabel/debug.qtpl:231
|
||||
if err != nil {
|
||||
//line lib/promrelabel/debug.qtpl:233
|
||||
//line lib/promrelabel/debug.qtpl:231
|
||||
qw422016.N().S(`<span style="color: red" title="error parsing labels:`)
|
||||
//line lib/promrelabel/debug.qtpl:234
|
||||
//line lib/promrelabel/debug.qtpl:232
|
||||
qw422016.E().S(err.Error())
|
||||
//line lib/promrelabel/debug.qtpl:234
|
||||
//line lib/promrelabel/debug.qtpl:232
|
||||
qw422016.N().S(`">`)
|
||||
//line lib/promrelabel/debug.qtpl:234
|
||||
//line lib/promrelabel/debug.qtpl:232
|
||||
qw422016.E().S("error parsing labels: " + err.Error())
|
||||
//line lib/promrelabel/debug.qtpl:234
|
||||
//line lib/promrelabel/debug.qtpl:232
|
||||
qw422016.N().S(`</span>`)
|
||||
//line lib/promrelabel/debug.qtpl:235
|
||||
//line lib/promrelabel/debug.qtpl:233
|
||||
} else {
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
//line lib/promrelabel/debug.qtpl:234
|
||||
streamlabelsWithHighlight(qw422016, labels, nil, "")
|
||||
//line lib/promrelabel/debug.qtpl:237
|
||||
//line lib/promrelabel/debug.qtpl:235
|
||||
}
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
func writemustFormatLabels(qq422016 qtio422016.Writer, s string) {
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
streammustFormatLabels(qw422016, s)
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
}
|
||||
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
func mustFormatLabels(s string) string {
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
writemustFormatLabels(qb422016, s)
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
qs422016 := string(qb422016.B)
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
return qs422016
|
||||
//line lib/promrelabel/debug.qtpl:238
|
||||
//line lib/promrelabel/debug.qtpl:236
|
||||
}
|
||||
|
||||
@@ -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 || sample.timestamp < sv.prevTimestamp {
|
||||
if sample.timestamp < state.timestamp {
|
||||
// Skip out of order sample
|
||||
return
|
||||
}
|
||||
@@ -143,6 +143,9 @@ 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,24 +789,6 @@ 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)
|
||||
f, err := parseFilter(lex, true)
|
||||
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,43 +301,38 @@ func (lr *LogRows) NeedFlush() bool {
|
||||
|
||||
// MustAddInsertRow adds r to lr.
|
||||
func (lr *LogRows) MustAddInsertRow(r *InsertRow) {
|
||||
st := GetStreamTags()
|
||||
streamTagsCanonical := r.StreamTagsCanonical
|
||||
if err := parseStreamTagsCanonical(st, streamTagsCanonical); err != nil {
|
||||
// verify r.StreamTagsCanonical
|
||||
if err := verifyStreamTagsCanonical(r.StreamTagsCanonical, r.Fields); 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
|
||||
sid.id = hash128(bytesutil.ToUnsafeBytes(streamTagsCanonical))
|
||||
streamTagsCanonical := bytesutil.ToUnsafeBytes(r.StreamTagsCanonical)
|
||||
sid.id = hash128(streamTagsCanonical)
|
||||
|
||||
// Store the row
|
||||
lr.mustAddInternal(sid, r.Timestamp, r.Fields, streamTagsCanonical)
|
||||
lr.mustAddInternal(sid, r.Timestamp, r.Fields, r.StreamTagsCanonical)
|
||||
}
|
||||
|
||||
var invalidStreamTagsLogger = logger.WithThrottler("invalid_stream_tags", 5*time.Second)
|
||||
|
||||
func parseStreamTagsCanonical(dst *StreamTags, streamTagsCanonical string) error {
|
||||
func verifyStreamTagsCanonical(streamTagsCanonical string, fields []Field) error {
|
||||
st := GetStreamTags()
|
||||
defer PutStreamTags(st)
|
||||
|
||||
src := bytesutil.ToUnsafeBytes(streamTagsCanonical)
|
||||
tail, err := dst.UnmarshalCanonicalInplace(src)
|
||||
tail, err := st.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), dst)
|
||||
return fmt.Errorf("unexpected tail left after unmarshaling streamTagsCanonical; len(tail)=%d; streamTags: %s", len(tail), st)
|
||||
}
|
||||
return nil
|
||||
return st.verifyCanonicalFieldValues(fields)
|
||||
}
|
||||
|
||||
func (lr *LogRows) mustAdd(tenantID TenantID, timestamp int64, fields []Field) {
|
||||
@@ -399,7 +394,11 @@ 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
|
||||
}
|
||||
st.normalize(fields)
|
||||
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
|
||||
}
|
||||
// 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)
|
||||
f, err := parseFilter(lex, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w; context: [%s]", err, lex.context())
|
||||
}
|
||||
@@ -2113,11 +2113,20 @@ func parseQueryOptions(dstOpts *queryOptions, lex *lexer) error {
|
||||
}
|
||||
}
|
||||
|
||||
func parseFilter(lex *lexer) (filter, error) {
|
||||
func parseFilter(lex *lexer, allowPipeKeywords bool) (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
|
||||
@@ -3866,7 +3875,7 @@ func quoteFieldFilterIfNeeded(s string) string {
|
||||
if wildcard == "" || !needQuoteToken(wildcard) {
|
||||
return s
|
||||
}
|
||||
return strconv.Quote(wildcard) + "*"
|
||||
return strconv.Quote(s)
|
||||
}
|
||||
|
||||
func quoteTokenIfNeeded(s string) string {
|
||||
@@ -3903,7 +3912,7 @@ func isNumberPrefix(s string) bool {
|
||||
}
|
||||
|
||||
func needQuoteToken(s string) bool {
|
||||
if !isWord(s) {
|
||||
if s == "." {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3911,10 +3920,14 @@ func needQuoteToken(s string) bool {
|
||||
if _, ok := reservedKeywords[sLower]; ok {
|
||||
return true
|
||||
}
|
||||
if isPipeName(sLower) || isStatsFuncName(sLower) || isMathFuncName(sLower) {
|
||||
if isPipeName(sLower) || isStatsFuncName(sLower) {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, r := range s {
|
||||
if !isTokenRune(r) && r != '.' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -3995,9 +4008,6 @@ 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 {
|
||||
@@ -4047,12 +4057,12 @@ func toFieldsFilters(pf *prefixfilter.Filter) string {
|
||||
|
||||
denyFilters := pf.GetDenyFilters()
|
||||
if len(denyFilters) > 0 {
|
||||
qStr += " | delete " + fieldFiltersString(denyFilters)
|
||||
qStr += " | delete " + fieldNamesString(denyFilters)
|
||||
}
|
||||
|
||||
allowFilters := pf.GetAllowFilters()
|
||||
if len(allowFilters) > 0 && !prefixfilter.MatchAll(allowFilters) {
|
||||
qStr += " | fields " + fieldFiltersString(allowFilters)
|
||||
qStr += " | fields " + fieldNamesString(allowFilters)
|
||||
}
|
||||
|
||||
return qStr
|
||||
|
||||
123
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/parser_utils.go
generated
vendored
123
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/parser_utils.go
generated
vendored
@@ -1,123 +0,0 @@
|
||||
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,54 +146,23 @@ func parsePipe(lex *lexer) (pipe, error) {
|
||||
return p, 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)
|
||||
}
|
||||
lexState := lex.backupState()
|
||||
|
||||
// Try parsing stats pipe without 'stats' keyword
|
||||
ps, err := parsePipeStatsNoStatsKeyword(lex)
|
||||
if err == nil {
|
||||
return ps, nil
|
||||
}
|
||||
lex.restoreState(lexState)
|
||||
|
||||
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)
|
||||
}
|
||||
// Try parsing filter pipe without 'filter' keyword
|
||||
pf, err := parsePipeFilterNoFilterKeyword(lex)
|
||||
if err == nil {
|
||||
return pf, nil
|
||||
}
|
||||
lex.restoreState(lexState)
|
||||
|
||||
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(":")
|
||||
return nil, fmt.Errorf("unexpected pipe %q", lex.token)
|
||||
}
|
||||
|
||||
var pipeParsers map[string]pipeParseFunc
|
||||
@@ -232,7 +201,6 @@ 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(" + fieldFiltersString(pc.srcFieldFilters) + ")"
|
||||
s := "coalesce(" + fieldNamesString(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 " + fieldFiltersString(pd.fieldFilters)
|
||||
return "delete " + fieldNamesString(pd.fieldFilters)
|
||||
}
|
||||
|
||||
func (pd *pipeDelete) splitToRemoteAndLocal(_ int64) (pipe, []pipe) {
|
||||
@@ -87,7 +87,7 @@ func parsePipeDelete(lex *lexer) (pipe, error) {
|
||||
}
|
||||
lex.nextToken()
|
||||
|
||||
fieldFilters, err := parseCommaSeparatedFieldFilters(lex)
|
||||
fieldFilters, err := parseCommaSeparatedFields(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 " + fieldFiltersString(pf.fieldFilters)
|
||||
return "fields " + fieldNamesString(pf.fieldFilters)
|
||||
}
|
||||
|
||||
func (pf *pipeFields) splitToRemoteAndLocal(_ int64) (pipe, []pipe) {
|
||||
@@ -100,7 +100,7 @@ func parsePipeFields(lex *lexer) (pipe, error) {
|
||||
}
|
||||
lex.nextToken()
|
||||
|
||||
fieldFilters, err := parseCommaSeparatedFieldFilters(lex)
|
||||
fieldFilters, err := parseCommaSeparatedFields(lex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -109,3 +109,18 @@ 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)
|
||||
f, err := parseFilter(lex, needFilterKeyword)
|
||||
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,6 +192,7 @@ 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
197
vendor/github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage/pipe_json_array_concat.go
generated
vendored
@@ -1,197 +0,0 @@
|
||||
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,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/atomicutil"
|
||||
@@ -568,51 +567,32 @@ 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 (" + fieldFiltersString(pp.fieldFilters) + ")"
|
||||
s += " fields (" + fieldNamesString(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 (" + fieldFiltersString(pp.fieldFilters) + ")"
|
||||
s += " fields (" + fieldNamesString(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,6 +92,7 @@ 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 += " " + fieldFiltersString(ps.streamFieldFilters)
|
||||
s += " " + fieldNamesString(ps.streamFieldFilters)
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ func parsePipeSetStreamFields(lex *lexer) (pipe, error) {
|
||||
}
|
||||
|
||||
// Parse stream fields
|
||||
streamFieldFilters, err := parseCommaSeparatedFieldFilters(lex)
|
||||
streamFieldFilters, err := parseCommaSeparatedFields(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, err
|
||||
return nil, fmt.Errorf("cannot parse 'stats' entry: %w", err)
|
||||
}
|
||||
ps.entries = append(ps.entries, e)
|
||||
|
||||
@@ -1779,6 +1779,85 @@ 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 := parseCommaSeparatedFieldNames(lex)
|
||||
bfs, err := parseCommaSeparatedFields(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 := parseCommaSeparatedFieldNames(lex)
|
||||
bfs, err := parseCommaSeparatedFields(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,6 +83,7 @@ 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 (" + fieldFiltersString(pu.fieldFilters) + ")"
|
||||
s += " fields (" + fieldNamesString(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 (" + fieldFiltersString(pu.fieldFilters) + ")"
|
||||
s += " fields (" + fieldNamesString(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 := parseCommaSeparatedFieldNames(lex)
|
||||
fs, err := parseCommaSeparatedFields(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(" + fieldFiltersString(sc.fieldFilters) + ")"
|
||||
return "count(" + fieldNamesString(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(" + fieldFiltersString(sm.fieldFilters) + ")"
|
||||
return "max(" + fieldNamesString(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(" + fieldFiltersString(sm.fieldFilters) + ")"
|
||||
return "min(" + fieldNamesString(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(" + fieldFiltersString(ss.fieldFilters) + ")"
|
||||
return "sum(" + fieldNamesString(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(" + fieldFiltersString(sa.fieldFilters) + ")"
|
||||
return "avg(" + fieldNamesString(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(" + fieldFiltersString(sc.fieldFilters) + ")"
|
||||
return "count(" + fieldNamesString(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(" + fieldFiltersString(sc.fieldFilters) + ")"
|
||||
return "count_empty(" + fieldNamesString(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(" + fieldFiltersString(sv.fieldFilters) + ")"
|
||||
s := "json_values(" + fieldNamesString(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(" + fieldFiltersString(sm.fieldFilters) + ")"
|
||||
return "max(" + fieldNamesString(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(" + fieldFiltersString(sm.sq.fieldFilters) + ")"
|
||||
return "median(" + fieldNamesString(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(" + fieldFiltersString(sm.fieldFilters) + ")"
|
||||
return "min(" + fieldNamesString(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 += ", " + fieldFiltersString(sq.fieldFilters)
|
||||
s += ", " + fieldNamesString(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(" + fieldFiltersString(sr.ss.fieldFilters) + ")"
|
||||
return "rate_sum(" + fieldNamesString(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(" + fieldFiltersString(sa.fieldFilters) + ")"
|
||||
return "row_any(" + fieldNamesString(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 += ", " + fieldFiltersString(sm.fieldFilters)
|
||||
s += ", " + fieldNamesString(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 += ", " + fieldFiltersString(sm.fieldFilters)
|
||||
s += ", " + fieldNamesString(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(" + fieldFiltersString(ss.fieldFilters) + ")"
|
||||
return "stddev(" + fieldNamesString(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(" + fieldFiltersString(ss.fieldFilters) + ")"
|
||||
return "sum(" + fieldNamesString(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(" + fieldFiltersString(ss.fieldFilters) + ")"
|
||||
return "sum_len(" + fieldNamesString(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(" + fieldFiltersString(su.fieldFilters) + ")"
|
||||
s := "uniq_values(" + fieldNamesString(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(" + fieldFiltersString(sv.fieldFilters) + ")"
|
||||
s := "values(" + fieldNamesString(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,6 +1347,7 @@ func (s *Storage) searchParallel(workersCount int, sso *storageSearchOptions, qs
|
||||
putBlockSearch(bs)
|
||||
putBitmap(bm)
|
||||
qs.UpdateAtomic(qsLocal)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1600,6 +1601,7 @@ 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,54 +44,46 @@ 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)
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
|
||||
tags := st.tags
|
||||
dstTags := tags[:0]
|
||||
for _, tag := range tags {
|
||||
prevTagName := ""
|
||||
for _, tag := range st.tags {
|
||||
tagName := tag.Name
|
||||
|
||||
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 err := CheckStreamFieldName(tagName); err != nil {
|
||||
return fmt.Errorf("invalid stream tag name: %s; streamTags: %s", tagName, st)
|
||||
}
|
||||
|
||||
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 f == nil {
|
||||
updated = true
|
||||
continue
|
||||
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)
|
||||
}
|
||||
|
||||
if updated {
|
||||
clear(tags[len(dstTags):])
|
||||
st.tags = dstTags
|
||||
}
|
||||
|
||||
return updated
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *StreamTags) marshalString(dst []byte) []byte {
|
||||
@@ -120,13 +112,7 @@ func (st *StreamTags) unmarshalStringInplace(s string) error {
|
||||
|
||||
var err error
|
||||
st.tags, err = parseStreamFields(st.tags[:0], s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sort.Sort(st)
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// Add adds (name:value) tag to st.
|
||||
@@ -150,10 +136,7 @@ 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 {
|
||||
@@ -177,7 +160,6 @@ 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 {
|
||||
@@ -196,28 +178,13 @@ func (st *StreamTags) UnmarshalCanonicalInplace(src []byte) ([]byte, error) {
|
||||
st.Add(sName, sValue)
|
||||
}
|
||||
|
||||
if err := st.checkCorrectness(); err != nil {
|
||||
return srcOrig, err
|
||||
if !sort.IsSorted(st) {
|
||||
return srcOrig, fmt.Errorf("stream tags must be sorted in alphabetical order; got unsorted: %s", st)
|
||||
}
|
||||
|
||||
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,6 +655,7 @@ 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.51.1-0.20260624061259-dc94972a8708
|
||||
# github.com/VictoriaMetrics/VictoriaLogs v1.121.1-0.20260616132739-c901a1e31cb3
|
||||
## explicit; go 1.26.4
|
||||
github.com/VictoriaMetrics/VictoriaLogs/lib/logstorage
|
||||
github.com/VictoriaMetrics/VictoriaLogs/lib/prefixfilter
|
||||
|
||||
Reference in New Issue
Block a user