Compare commits

...

72 Commits

Author SHA1 Message Date
dmitryk-dk
a07f4078de app/vmctl: remove unused channel 2025-03-17 17:40:25 +01:00
dmitryk-dk
de96a937dd app/vmctl: propagate context to avoid data races 2025-03-17 17:27:56 +01:00
hagen1778
bcbe5e80b3 docs/changelog: fix metric name in changelog for vlogs request duration
Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-03-06 11:17:58 +01:00
f41gh7
f7d5b11f00 app/vmgateway properly handle trailing slash when applying rate limiter
Previously, the trailing slash was removed and caused an incorrect redirect path when visiting VMUI.

 This commit leaves it as is. Also it applies minor refactoring to url formatting.

Related issue:
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8439
2025-03-05 18:43:02 +01:00
Andrii Chubatiuk
26fba57cfa lib/protoparser/opentelemetry: properly marshal nested attributes into JSON
Previously, opentelemetry attribute parsed added extra field names according to 
golang JSON parser spec for structs:

```
struct AnyValue{
 StringValue string
}
```
 Was serialized into:
```
{"StringValue": "some-string"}
```
 While opentelemetry-collector serializes it as
```
"some-string"
```

 This commit changes this behaviour it makes parses compatible with opentelemetry-collector format. See test cases for examples.

Related issue:
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8384
2025-03-05 16:35:07 +01:00
hagen1778
e3e5733b77 docs/changelog: fix formatting of update notes
Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-03-05 15:57:21 +01:00
Max Kotliar
e11f5eda1c docs/vmalert: fix available from version (#8433)
### Describe Your Changes

Fix available from version hint. The feature was introduced in
[v1.91.0](https://docs.victoriametrics.com/changelog/changelog_2023/#v1910).

I noticed that the sentence uses both `{{% available_from "v1.91.0" %}}`
and a manual reference like `starting from
[v1.91](https://docs.victoriametrics.com/changelog/#v1910)`. Does {{%
available_from %}} fully supersede the manual changelog reference, and
should the later be removed? Or should\could both be used together?

### Checklist

The following checks are **mandatory**:

- [x] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).
2025-03-05 14:40:52 +01:00
Andrii Chubatiuk
bbdb650f2f docs: remove VictoriaMetrics prefix from anomaly detection menu items titles (#8427)
### Describe Your Changes

Removed VictoriaMetrics prefix from anomaly detection menu items

### Checklist

The following checks are **mandatory**:

- [ ] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).
2025-03-05 14:38:20 +01:00
Jose Gómez-Sellés
400101c674 Add features and guides to VMCloud docs (#8373)
### Describe Your Changes

This PR adds the remaining subsections for the get started part. Some
content is taken from the product page.
Ideally, the get-started page would have some cards instead of raw
links. We should explore that.

### Checklist

The following checks are **mandatory**:

- [x] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).
2025-03-05 01:52:45 -08:00
Zhu Jiekun
08baa8139a app/vmgateway: properly ratelimit for ingestion path
Commit cd39df1 introduced regression, which caused any write path related limits to be ignored.

This commit fixes match typo and adds check to prevent such kind of regression in future.
2025-03-04 18:42:43 +01:00
Aliaksandr Valialkin
97e99e1fc1 docs/VictoriaLogs/README.md: mention about JSONBench benchmark results in the benchmarks section
See https://docs.victoriametrics.com/victorialogs/#benchmarks
2025-03-04 17:40:31 +01:00
Fred Navruzov
6828cca5a6 docs/vmanomaly: release v1.20.0 (#8422)
### Describe Your Changes

> ⚠️ Even if approved, please don't merge it on my behalf, I
still may apply a couple of re-phrasings before merging it on Monday
03.03.2025

- Aligned `vmanomaly` docs with release v1.20.0
- Re-structured root page of anomaly detection docs for clarity
- Added several sections to FAQ, e.g. on how to incorporate domain
knowledge into anomaly detection configs

### Checklist

The following checks are **mandatory**:

- [x] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).
2025-03-04 00:24:34 +02:00
hagen1778
fc5d495900 app/vmui: update error message for no matched rules
Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-03-03 16:56:15 +01:00
Yury Molodov
974c094a52 vmui: fix infinite loader on downsampling page (#8428)
### Describe Your Changes

This PR fixes an issue where the Downsampling filters debug page would
get stuck in an infinite loading state when labels had no matches. Now,
the case is properly handled.

Related issue: #8339

### Checklist

The following checks are **mandatory**:

- [x] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: hagen1778 <roman@victoriametrics.com>
2025-03-03 16:48:11 +01:00
Max Kotliar
649f4d5e00 docs/downsampling: fix terminology. replace "deduplication" with "downsample". (#8421)
### Describe Your Changes

I guess a "downsampling" term is more appropriate than "deduplication"
in the downsampling paragraph.

### Checklist

The following checks are **mandatory**:

- [x] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).
2025-03-03 14:12:36 +01:00
Nikolay
a55ac4495f docs: update release guide (#8423)
* move testing step after assets upload
* add LTS build step before testing step

Signed-off-by: f41gh7 <nik@victoriametrics.com>
2025-03-03 14:10:06 +01:00
Hui Wang
52988ebdc8 vmalert: add time buckets stats pipe check for vlogs expression (#8400)
VictoriaLogs inserts `_time` field as a label in result when query with
[time buckets stats
pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-by-time-buckets),
making the result meaningless and may lead to cardinality issues.
>curl --location --request POST
'https://play-vmlogs.victoriametrics.com/select/logsql/stats_query?query=_time%3A1m%20%7C%20stats%20by%20(_time%3A10s)%20count%20()%20as%20total'

>{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"total","_time":"2025-01-24T12:31:30Z"},"value":[1737721904.4476516,"12"]},{"metric":{"__name__":"total","_time":"2025-01-24T12:31:10Z"},"value":[1737721904.4476516,"10"]},{"metric":{"__name__":"total","_time":"2025-01-24T12:31:00Z"},"value":[1737721904.4476516,"10"]},{"metric":{"__name__":"total","_time":"2025-01-24T12:31:20Z"},"value":[1737721904.4476516,"12"]},{"metric":{"__name__":"total","_time":"2025-01-24T12:30:50Z"},"value":[1737721904.4476516,"10"]},{"metric":{"__name__":"total","_time":"2025-01-24T12:30:40Z"},"value":[1737721904.4476516,"9"]}]}}%

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: hagen1778 <roman@victoriametrics.com>
2025-03-03 14:09:34 +01:00
hagen1778
065a3d068c docs/victorialogs/vmalert: apply consistent formatting and fix typos
* use unified numeric list;
* apply line width limits;
* remove time filter from quantile examples, as we suggest to
not use time filters.

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-03-03 13:57:30 +01:00
Artem Fetishev
43a742ba0c docs: bump last LTS versions
Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2025-03-03 11:44:37 +01:00
Artem Fetishev
e69c744dd4 docs/CHANGELOG.md: update changelog with LTS release notes
Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2025-03-03 11:43:00 +01:00
hagen1778
6db97d6f79 lib/timeutil: add test for ParseDuration
See https://github.com/VictoriaMetrics/VictoriaMetrics/pull/8403#discussion_r1976110052

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-03-03 10:46:01 +01:00
Max Kotliar
7451a3631a docs: fix typo in docs (#8420)
### Describe Your Changes

Just a small typo in the docs

### Checklist

The following checks are **mandatory**:

- [ ] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).
2025-03-03 10:26:41 +01:00
Roman Khavronenko
63f6ac3ff8 lib/promutils: move time-related funcs from promutils to timeutil (#8403)
Since funcs `ParseDuration` and `ParseTimeMsec` are used in vlogs,
vmalert, victoriametrics and other components, importing promutils only
for this reason makes them to export irrelevant
`vm_rows_invalid_total{type="prometheus"}` metric.

This change removes `vm_rows_invalid_total{type="prometheus"}` metric
from /metrics page for these components.

### Describe Your Changes

Please provide a brief description of the changes you made. Be as
specific as possible to help others understand the purpose and impact of
your modifications.

### Checklist

The following checks are **mandatory**:

- [ ] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-03-03 10:25:42 +01:00
Hui Wang
281f1a94e4 vmalert-tool: clean up the temporary storage path when process is ter… (#8407)
…minated by SIGTERM or SIGINT
2025-02-28 15:17:05 +01:00
Zakhar Bessarab
7f6156e46d docs: fix link to quay docker image for single-node (#8414)
### Describe Your Changes

Previous link was incorrectly created by adding repository name to
organization link.
All other links are using proper schema.

This is a follow-up for 6ff61a1c.

### Checklist

The following checks are **mandatory**:

- [x] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
2025-02-28 15:13:52 +01:00
Hui Wang
4015db18bc vmalert-tool: add flag -httpListenPort to specify the port used dur… (#8408)
…ing testing and make the temporary storage path more unique

address https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8393

---------

Co-authored-by: Roman Khavronenko <roman@victoriametrics.com>
2025-02-28 11:25:35 +01:00
Zakhar Bessarab
99de272b72 lib/promrelabel/scrape_url: properly parse IPv6 address from __address__ label
Fix parsing of IPv6 addresses after discovery. Previously, it could lead
to target being discovered and discarded afterwards.

See: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8374

---------

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
2025-02-28 14:19:10 +04:00
Zakhar Bessarab
6ff61a1c09 docs/all: add refs to Quay mirror for docker images (#8406)
### Describe Your Changes

See: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4116

### Checklist

The following checks are **mandatory**:

- [x] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).

---------

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
Co-authored-by: Roman Khavronenko <roman@victoriametrics.com>
2025-02-28 11:14:10 +01:00
Zakhar Bessarab
ed0db37d1d app/vmbackupmanager: fix error propagation for policy apply
Previously error text was silently discarded.

This commit properly formats error message and add actual error cause to it.
2025-02-28 10:40:50 +01:00
Hui Wang
a36c8a9679 app/vmgateway: fix data query in rate limiter
Properly format datasource query request in rate limiter
2025-02-28 10:40:46 +01:00
hagen1778
c80e2d16a5 deployment/docker: fix typo in markdown
Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-28 09:57:12 +01:00
hagen1778
e10b963a4d docs: link to internal docs for alerting and recording rules
Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-28 09:46:57 +01:00
hagen1778
3a04d9aca8 docs: fix markdown in stream aggregation docs
Availability mark was breaking the line.

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-28 09:07:51 +01:00
Aliaksandr Valialkin
bfa9fee424 docs/VictoriaLogs/CHANGELOG.md: typo fix: filter -> filters 2025-02-28 00:09:00 +01:00
Aliaksandr Valialkin
d7431e69fd deployment/docker: update VictoriaLogs Docker image tag from v1.14.0-victorialogs to v1.15.0-victorialogs
See https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.15.0-victorialogs
2025-02-28 00:02:55 +01:00
Aliaksandr Valialkin
0e5e90fe74 docs/VictoriaLogs/CHANGELOG.md: cut v1.15.0-victorialogs release 2025-02-27 22:58:18 +01:00
Aliaksandr Valialkin
5790c5c75d Makefile: update golangc-lint from v1.64.4 to v1.64.5
See https://github.com/golangci/golangci-lint/releases/tag/v1.64.5
2025-02-27 22:54:19 +01:00
Aliaksandr Valialkin
744ac496bd lib/logstorage: add ability to specify field name prefixes inside fields (...) lists passed to pack_json and pack_logfmt pipes 2025-02-27 22:54:18 +01:00
Aliaksandr Valialkin
03a04b4408 docs/changelog/CHANGELOG.md: upgrading from Go1.23.6 to Go1.24.0 doesn't fix any know security issues
The upgrade from Go1.23.6 to Go1.24.0 is a feature, not a security fix.

This is a follow-up for ea6ed4232a
2025-02-27 22:54:18 +01:00
Zhu Jiekun
117b7ce6b7 bugfix: negative rate result when lookbehind window longer than search.maxLookback (#8378)
### Describe Your Changes

#8342 

fix negative rate result when the lookbehind window is longer than
`-search.maxLookback` or `-search.maxStalenessInterval` and data
contains gap.

This issue was introduced since
[v1.110.0](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8072).

### Checklist

The following checks are **mandatory**:

- [x] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).
2025-02-27 22:52:39 +01:00
Roman Khavronenko
38d46d149f lib/prompbmarshal: move MustParsePromMetrics to protoparser/prometheus (#8405)
`MustParsePromMetrics` imports `lib/protoparser/prometheus`, and this
package exposes the following metrics:
```
vm_protoparser_rows_read_total{type="promscrape"}
vm_rows_invalid_total{type="prometheus"}
```

It means every package that uses `lib/prompbmarshal` will start exposing
these metrics. For example, vlogs imports `lib/protoparser/common` which
uses `lib/prompbmarshal.Label`. And only because of this vlogs starts
exposing unrelated prometheus metrics on /metrics page.

Moving `MustParsePromMetrics` to `lib/protoparser/prometheus` seems like
the leas intrusive change.


-----------

Depends on another change
https://github.com/VictoriaMetrics/VictoriaMetrics/pull/8403

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-27 22:50:27 +01:00
Aliaksandr Valialkin
84d5771b41 lib/logstorage: allow passing * at in(*), contains_any(*) and contains_all(*)
Such filters are equivalent to `match all` filter aka `*`. These filters are needed for VictoriaLogs plugin for Grafana.

See https://github.com/VictoriaMetrics/victorialogs-datasource/issues/238#issuecomment-2685447673
2025-02-27 11:37:43 +01:00
Roman Khavronenko
f39ce2aeef dashboards: update victorialogs dashboard (#8398)
* stats panels:
* * add ingested logs/bytes over 24h
* * fix correctness compression ratio and disk space usage panels
* overview panels:
* * add requests errors rate, logs rate, query duration panels
* add troubleshooting section:
* * add non-default falgs, dropped logs panels
* update descriptions of the panels and version requirements

Depends on https://github.com/VictoriaMetrics/VictoriaMetrics/pull/8396

--------------

<img width="1489" alt="image"
src="https://github.com/user-attachments/assets/5257b8e1-a2e7-4143-94c7-bb42b19e4206"
/>

<img width="1499" alt="image"
src="https://github.com/user-attachments/assets/1b521c58-6e12-4d38-b052-93abdac3b4fc"
/>

<img width="1468" alt="image"
src="https://github.com/user-attachments/assets/3010cf0a-8ca7-48d4-9967-328b37fdbc28"
/>

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-27 11:15:52 +01:00
Roman Khavronenko
ba2bf9e73a vlogs: add metrics to track select queries duration (#8396)
This change would help to track slow queries via alerts or dashboards.

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-27 11:11:26 +01:00
hagen1778
47d0bba8f0 docs: update never-firing alerts chapter
* add availability marker
* mention article https://victoriametrics.com/blog/never-firing-alerts/

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-27 09:57:36 +01:00
Zakhar Bessarab
da059d1ea1 deployment/docker/make: publish images to multiple repos (#8391)
### Describe Your Changes

Updated `publish-via-docker` task to push images to multiple registries
as defined by `DOCKER_REGISTRIES`. By default, publish pushes images to
both docker.io and quay.io. It is possible to choose a single repo by
overriding `DOCKER_REGISTRIES`, for example: `DOCKER_REGISTRIES=quay.io
make publish-victoria-logs`

Note that `package-via-docker` task is not using multiple registries as
there is usually little sense in building same image with different tags
for local use.

See: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4116
### Checklist

The following checks are **mandatory**:

- [x] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
2025-02-27 11:49:50 +04:00
f41gh7
ea6ed4232a deployment/docker: update Go builder from 1.23.6 to 1.24.0
Changes: https://github.com/golang/go/issues?q=milestone%3AGo1.24
Release notes: https://tip.golang.org/doc/go1.24

Signed-off-by: f41gh7 <nik@victoriametrics.com>
2025-02-26 19:14:49 +01:00
Andrii Chubatiuk
b27e9437a3 app/vminsert: properly apply relabelingConfig for scrapped metrics
Due to regression introduced at v1.108.0 release with the following commit:
https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7399/files#diff-0f7ec2fdf4bb6e94f786c37f19ec837995eca8c61529c3f3436ae332a4a93a5bR56

VictoriaMetrics single-node started to ignore global relabeling configuration.

 This commit properly checks if relabeling is needed.

Related issue:
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8389
2025-02-26 16:05:26 +01:00
Zhu Jiekun
3d3480140c lib/storage: properly cache extDB metricsID on search error
Previously, if indexDB search failed for some reason during search at previous indexDB (aka extDB), VictoriaMetrics stored empty search result at cache. It could cause incorrect search results at subsequent requests.

 This commit checks search error and stores request results only on success. 

Related issue:
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8345
2025-02-26 15:48:25 +01:00
Aliaksandr Valialkin
ae5e28524e lib/logstorage: do not treat a string with leading zeros as a number at tryParseUint64
The "00123" string shouldn't be treated as 123 number.

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8361
2025-02-25 22:10:36 +01:00
Aliaksandr Valialkin
b484112f22 docs/VictoriaLogs/CHANGELOG.md: fix link to elasticsearch data ingestion docs 2025-02-25 21:31:16 +01:00
Aliaksandr Valialkin
1da04db33a deployment/docker: update VictoriaLogs Docker image tag from v1.13.0-victorialogs to v1.14.0-victorialogs
See https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.14.0-victorialogs
2025-02-25 21:24:42 +01:00
Aliaksandr Valialkin
ef2415e0c5 docs/VictoriaLogs/CHANGELOG.md: cut v1.14.0-victorialogs release 2025-02-25 21:19:58 +01:00
Aliaksandr Valialkin
0de7c8987c app/vlselect/logsql: follow-up for 521af4d7a3
The ts variable must be initialized to the q.GetTimestamp() for every processed row inside the `for range timestamps` loop.

The original bug has been introduced in the commit 42c21ff671

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8312
Updates https://github.com/VictoriaMetrics/VictoriaMetrics/pull/8385
2025-02-25 21:07:54 +01:00
Zhu Jiekun
521af4d7a3 fix: [stats_query_range] fix inconsistent result caused by shared variable (#8385)
### Describe Your Changes

Previously, `timestamp` variable was shared by goroutines and modified
during `writeBlock`, verified in
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8312.

This pull request create new variable within each goroutine to avoid
race condition.

### Checklist

The following checks are **mandatory**:

- [x] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).
- [ ]  Test on sandbox.

Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
2025-02-25 20:56:03 +01:00
Aliaksandr Valialkin
1f75e5bb59 lib/logstorage: optimize common regex filters generated by Grafana
For example, `field:~".+"`, `field:~".*"` or `field:""`

Replace such filters to faster ones. For example, `field:~".*"` is replaced with `*`,
while `field:~".+"` is replaced with `field:*`.
2025-02-25 20:34:28 +01:00
Aliaksandr Valialkin
fef2cb9dc7 lib/regexutil: speed up Regex.MatchString for ".*" 2025-02-25 20:34:28 +01:00
Roman Khavronenko
72bee659f5 docs: point github badge to the main action for master branch (#8388)
Before, badge could have shown the latest build result. Even for open
PRs. Now, it shows the latest build result for `master` branch.

See
https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/monitoring-workflows/adding-a-workflow-status-badge

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-25 18:59:05 +01:00
hagen1778
49fff7989b docs: fix link to release for search.disableImplicitConversion feature
Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-25 18:54:44 +01:00
Aliaksandr Valialkin
82cdcec6c6 lib/logstorage: run make fmt after 30974e7f3f 2025-02-25 18:37:40 +01:00
Aliaksandr Valialkin
128f6d78ff docs/VictoriaLogs/FAQ.md: add a question on how to estimate the needed compute resources for the particular workload 2025-02-25 18:24:51 +01:00
Aliaksandr Valialkin
30974e7f3f lib/logstorage: add le_field and lt_field filters
These filters can be used for selecting logs where one field value is less than another field value.
These filter complement `<=` and `<` filters for constant literals.
2025-02-25 18:24:50 +01:00
Aliaksandr Valialkin
edc750dd55 lib/logstorage: optimize eq_filter when it is applied to fields of the same type 2025-02-25 18:24:15 +01:00
Andrii Chubatiuk
7a1c84b6ec vlinsert: accept ES ping requests to endpoint without trailing slash (#8354)
### Describe Your Changes

related issue
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8353

### Checklist

The following checks are **mandatory**:

- [ ] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: hagen1778 <roman@victoriametrics.com>
2025-02-25 15:48:40 +01:00
Roman Khavronenko
788c740d62 app/vmctl: respect time filter when exploring time series for influxdb (#8371)
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8259


https://docs.influxdata.com/influxdb/v1/query_language/explore-schema/#run-a-show-series-query-limited-by-time

### Checklist

The following checks are **mandatory**:

- [ ] My change adheres [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/contributing/).

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-25 09:26:58 +01:00
Roman Khavronenko
cddccfde57 dashboards: add new panels to VictoriaMetrics dashboards (#8369)
* FEATURE:
[dashboards/single](https://grafana.com/grafana/dashboards/10229) and
[dashboards/cluster](https://grafana.com/grafana/dashboards/11176): add
panel `Deduplication rate` that shows how many samples are
[deduplicated](https://docs.victoriametrics.com/#deduplication) during
merges or read queries by VictoriaMetrics components.
* FEATURE:
[dashboards/single](https://grafana.com/grafana/dashboards/10229) and
[dashboards/cluster](https://grafana.com/grafana/dashboards/11176): add
panel `Number of snapshots` that shows the max number of
[snapshots](https://docs.victoriametrics.com/#how-to-work-with-snapshots)
across vmstorage nodes. This panel should help in disk usage
[troubleshooting](https://docs.victoriametrics.com/#snapshot-troubleshooting).
* FEATURE:
[dashboards/single](https://grafana.com/grafana/dashboards/10229) and
[dashboards/cluster](https://grafana.com/grafana/dashboards/11176):
account for samples dropped according to [relabeling
config](https://docs.victoriametrics.com/#relabeling) in `Samples
dropped for last 1h` panel.
* FEATURE:
[dashboards/single](https://grafana.com/grafana/dashboards/10229) and
[dashboards/cluster](https://grafana.com/grafana/dashboards/11176): show
number of parts in the last partition on `LSM parts max by type` panel.
Before, the resulting graph could be skewed by the max number of parts
across all partitions. Displaying parts for the latest partition is the
correct way to show if storage is currently impacted by merge delays.
* FEATURE:
[dashboards/cluster](https://grafana.com/grafana/dashboards/11176): add
panel `Partial query results` that shows the number of served [partial
responses](https://docs.victoriametrics.com/cluster-victoriametrics/#cluster-availability)
by vmselects.


-------------

Sorry, git diff is a mess. Dashboards switched to Grafana 11 and it
broke consistency of changes.

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-25 09:25:34 +01:00
Roman Khavronenko
8f87427c81 deployment/rules: add alerting rule TooHighQueryLoad (#8365)
TooHighQueryLoad should trigger when vmsingle or vmselect can't start
processing read queries for last 15min.

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-25 09:22:25 +01:00
hagen1778
6a675bb69b docs: put link to index-disabling-feature to a better place
Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-24 17:03:45 +01:00
hagen1778
3828c01540 docs: properly update version tooltips
The version tooltips were incorrectly set to `#tip` instead of `#`,
so ` make docs-update-version` didn't catch them.

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-02-24 17:00:01 +01:00
f41gh7
0314b79727 docs: update vm apps versions to the v1.112.0 release
Signed-off-by: f41gh7 <nik@victoriametrics.com>
2025-02-24 15:55:06 +01:00
f41gh7
1e368add33 docs/changelog: mention LTS releases 2025-02-24 15:34:17 +01:00
f41gh7
1064c15454 CHANGELOG.md: cut v1.112.0 release 2025-02-24 15:34:17 +01:00
134 changed files with 10411 additions and 3241 deletions

View File

@@ -567,7 +567,7 @@ golangci-lint: install-golangci-lint
golangci-lint run
install-golangci-lint:
which golangci-lint || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.64.4
which golangci-lint || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.64.5
remove-golangci-lint:
rm -rf `which golangci-lint`

View File

@@ -3,7 +3,7 @@
![Latest Release](https://img.shields.io/github/v/release/VictoriaMetrics/VictoriaMetrics?sort=semver&label=&filter=!*-victorialogs&logo=github&labelColor=gray&color=gray&link=https%3A%2F%2Fgithub.com%2FVictoriaMetrics%2FVictoriaMetrics%2Freleases%2Flatest)
![Docker Pulls](https://img.shields.io/docker/pulls/victoriametrics/victoria-metrics?label=&logo=docker&logoColor=white&labelColor=2496ED&color=2496ED&link=https%3A%2F%2Fhub.docker.com%2Fr%2Fvictoriametrics%2Fvictoria-metrics)
![Go Report](https://goreportcard.com/badge/github.com/VictoriaMetrics/VictoriaMetrics?link=https%3A%2F%2Fgoreportcard.com%2Freport%2Fgithub.com%2FVictoriaMetrics%2FVictoriaMetrics)
![Build Status](https://github.com/VictoriaMetrics/VictoriaMetrics/workflows/main/badge.svg?link=https%3A%2F%2Fgithub.com%2FVictoriaMetrics%2FVictoriaMetrics%2Factions)
![Build Status](https://github.com/VictoriaMetrics/VictoriaMetrics/actions/workflows/main.yml/badge.svg?branch=master&link=https%3A%2F%2Fgithub.com%2FVictoriaMetrics%2FVictoriaMetrics%2Factions)
![codecov](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/branch/master/graph/badge.svg?link=https%3A%2F%2Fcodecov.io%2Fgh%2FVictoriaMetrics%2FVictoriaMetrics)
![License](https://img.shields.io/github/license/VictoriaMetrics/VictoriaMetrics?labelColor=green&label=&link=https%3A%2F%2Fgithub.com%2FVictoriaMetrics%2FVictoriaMetrics%2Fblob%2Fmaster%2FLICENSE)
![Slack](https://img.shields.io/badge/Join-4A154B?logo=slack&link=https%3A%2F%2Fslack.victoriametrics.com)
@@ -22,7 +22,7 @@ Here are some resources and information about VictoriaMetrics:
- Documentation: [docs.victoriametrics.com](https://docs.victoriametrics.com)
- Case studies: [Grammarly, Roblox, Wix,...](https://docs.victoriametrics.com/casestudies/).
- Available: [Binary releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest), [Docker images](https://hub.docker.com/r/victoriametrics/victoria-metrics/), [Source code](https://github.com/VictoriaMetrics/VictoriaMetrics)
- Available: [Binary releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest), docker images [Docker Hub](https://hub.docker.com/r/victoriametrics/victoria-metrics/) and [Quay](https://quay.io/repository/victoriametrics/victoria-metrics), [Source code](https://github.com/VictoriaMetrics/VictoriaMetrics)
- Deployment types: [Single-node version](https://docs.victoriametrics.com/), [Cluster version](https://docs.victoriametrics.com/cluster-victoriametrics/), and [Enterprise version](https://docs.victoriametrics.com/enterprise/)
- Changelog: [CHANGELOG](https://docs.victoriametrics.com/changelog/), and [How to upgrade](https://docs.victoriametrics.com/#how-to-upgrade-victoriametrics)
- Community: [Slack](https://slack.victoriametrics.com/), [X (Twitter)](https://x.com/VictoriaMetrics), [LinkedIn](https://www.linkedin.com/company/victoriametrics/), [YouTube](https://www.youtube.com/@VictoriaMetrics)

View File

@@ -60,7 +60,7 @@ func RequestHandler(path string, w http.ResponseWriter, r *http.Request) bool {
return true
}
switch path {
case "/":
case "/", "":
switch r.Method {
case http.MethodGet:
// Return fake response for Elasticsearch ping request.

View File

@@ -46,7 +46,9 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
return true
}
switch {
case strings.HasPrefix(path, "/elasticsearch/"):
case strings.HasPrefix(path, "/elasticsearch"):
// some clients may omit trailing slash
// see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8353
path = strings.TrimPrefix(path, "/elasticsearch")
return elasticsearch.RequestHandler(path, w, r)
case strings.HasPrefix(path, "/loki/"):

View File

@@ -101,7 +101,7 @@ func pushProtobufRequest(data []byte, lmp insertutils.LogMessageProcessor, useDe
commonFields = slicesutil.SetLength(commonFields, len(attributes))
for i, attr := range attributes {
commonFields[i].Name = attr.Key
commonFields[i].Value = attr.Value.FormatString()
commonFields[i].Value = attr.Value.FormatString(true)
}
commonFieldsLen := len(commonFields)
for _, sc := range rl.ScopeLogs {
@@ -118,12 +118,12 @@ func pushFieldsFromScopeLogs(sc *pb.ScopeLogs, commonFields []logstorage.Field,
fields = fields[:len(commonFields)]
fields = append(fields, logstorage.Field{
Name: "_msg",
Value: lr.Body.FormatString(),
Value: lr.Body.FormatString(true),
})
for _, attr := range lr.Attributes {
fields = append(fields, logstorage.Field{
Name: attr.Key,
Value: attr.Value.FormatString(),
Value: attr.Value.FormatString(true),
})
}
if len(lr.TraceID) > 0 {

View File

@@ -66,9 +66,9 @@ func TestPushProtoOk(t *testing.T) {
},
},
[]int64{1234, 1235, 1236},
`{"logger":"context","instance_id":"10","node_taints":"[{\"Key\":\"role\",\"Value\":{\"StringValue\":\"dev\",\"BoolValue\":null,\"IntValue\":null,\"DoubleValue\":null,\"ArrayValue\":null,\"KeyValueList\":null,\"BytesValue\":null}},{\"Key\":\"cluster_load_percent\",\"Value\":{\"StringValue\":null,\"BoolValue\":null,\"IntValue\":null,\"DoubleValue\":0.55,\"ArrayValue\":null,\"KeyValueList\":null,\"BytesValue\":null}}]","_msg":"log-line-message","severity":"Trace"}
{"logger":"context","instance_id":"10","node_taints":"[{\"Key\":\"role\",\"Value\":{\"StringValue\":\"dev\",\"BoolValue\":null,\"IntValue\":null,\"DoubleValue\":null,\"ArrayValue\":null,\"KeyValueList\":null,\"BytesValue\":null}},{\"Key\":\"cluster_load_percent\",\"Value\":{\"StringValue\":null,\"BoolValue\":null,\"IntValue\":null,\"DoubleValue\":0.55,\"ArrayValue\":null,\"KeyValueList\":null,\"BytesValue\":null}}]","_msg":"log-line-message-msg-2","severity":"Unspecified"}
{"logger":"context","instance_id":"10","node_taints":"[{\"Key\":\"role\",\"Value\":{\"StringValue\":\"dev\",\"BoolValue\":null,\"IntValue\":null,\"DoubleValue\":null,\"ArrayValue\":null,\"KeyValueList\":null,\"BytesValue\":null}},{\"Key\":\"cluster_load_percent\",\"Value\":{\"StringValue\":null,\"BoolValue\":null,\"IntValue\":null,\"DoubleValue\":0.55,\"ArrayValue\":null,\"KeyValueList\":null,\"BytesValue\":null}}]","_msg":"log-line-message-msg-2","severity":"Unspecified"}`,
`{"logger":"context","instance_id":"10","node_taints":"{\"role\":\"dev\",\"cluster_load_percent\":0.55}","_msg":"log-line-message","severity":"Trace"}
{"logger":"context","instance_id":"10","node_taints":"{\"role\":\"dev\",\"cluster_load_percent\":0.55}","_msg":"log-line-message-msg-2","severity":"Unspecified"}
{"logger":"context","instance_id":"10","node_taints":"{\"role\":\"dev\",\"cluster_load_percent\":0.55}","_msg":"log-line-message-msg-2","severity":"Unspecified"}`,
)
// multi-scope with resource attributes and multi-line
@@ -113,8 +113,8 @@ func TestPushProtoOk(t *testing.T) {
},
},
[]int64{1234, 1235, 2345, 2346, 2347, 2348},
`{"logger":"context","instance_id":"10","node_taints":"[{\"Key\":\"role\",\"Value\":{\"StringValue\":\"dev\",\"BoolValue\":null,\"IntValue\":null,\"DoubleValue\":null,\"ArrayValue\":null,\"KeyValueList\":null,\"BytesValue\":null}},{\"Key\":\"cluster_load_percent\",\"Value\":{\"StringValue\":null,\"BoolValue\":null,\"IntValue\":null,\"DoubleValue\":0.55,\"ArrayValue\":null,\"KeyValueList\":null,\"BytesValue\":null}}]","_msg":"log-line-message","severity":"Trace"}
{"logger":"context","instance_id":"10","node_taints":"[{\"Key\":\"role\",\"Value\":{\"StringValue\":\"dev\",\"BoolValue\":null,\"IntValue\":null,\"DoubleValue\":null,\"ArrayValue\":null,\"KeyValueList\":null,\"BytesValue\":null}},{\"Key\":\"cluster_load_percent\",\"Value\":{\"StringValue\":null,\"BoolValue\":null,\"IntValue\":null,\"DoubleValue\":0.55,\"ArrayValue\":null,\"KeyValueList\":null,\"BytesValue\":null}}]","_msg":"log-line-message-msg-2","severity":"Debug"}
`{"logger":"context","instance_id":"10","node_taints":"{\"role\":\"dev\",\"cluster_load_percent\":0.55}","_msg":"log-line-message","severity":"Trace"}
{"logger":"context","instance_id":"10","node_taints":"{\"role\":\"dev\",\"cluster_load_percent\":0.55}","_msg":"log-line-message-msg-2","severity":"Debug"}
{"_msg":"log-line-resource-scope-1-0-0","severity":"Info2"}
{"_msg":"log-line-resource-scope-1-0-1","severity":"Info2"}
{"_msg":"log-line-resource-scope-1-1-0","severity":"Info4"}

View File

@@ -18,7 +18,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/buildinfo"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/envflag"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil"
)
var (
@@ -306,7 +306,7 @@ type timeFlag struct {
}
func (tf *timeFlag) Set(s string) error {
msec, err := promutils.ParseTimeMsec(s)
msec, err := timeutil.ParseTimeMsec(s)
if err != nil {
return fmt.Errorf("cannot parse time from %q: %w", s, err)
}

View File

@@ -22,7 +22,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httputils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil"
)
// ProcessFacetsRequest handles /select/logsql/facets request.
@@ -116,7 +116,7 @@ func ProcessHitsRequest(ctx context.Context, w http.ResponseWriter, r *http.Requ
if stepStr == "" {
stepStr = "1d"
}
step, err := promutils.ParseDuration(stepStr)
step, err := timeutil.ParseDuration(stepStr)
if err != nil {
httpserver.Errorf(w, r, "cannot parse 'step' arg: %s", err)
return
@@ -131,7 +131,7 @@ func ProcessHitsRequest(ctx context.Context, w http.ResponseWriter, r *http.Requ
if offsetStr == "" {
offsetStr = "0s"
}
offset, err := promutils.ParseDuration(offsetStr)
offset, err := timeutil.ParseDuration(offsetStr)
if err != nil {
httpserver.Errorf(w, r, "cannot parse 'offset' arg: %s", err)
return
@@ -665,7 +665,7 @@ func ProcessStatsQueryRangeRequest(ctx context.Context, w http.ResponseWriter, r
if stepStr == "" {
stepStr = "1d"
}
step, err := promutils.ParseDuration(stepStr)
step, err := timeutil.ParseDuration(stepStr)
if err != nil {
err = fmt.Errorf("cannot parse 'step' arg: %s", err)
httpserver.SendPrometheusError(w, r, err)
@@ -688,19 +688,22 @@ func ProcessStatsQueryRangeRequest(ctx context.Context, w http.ResponseWriter, r
m := make(map[string]*statsSeries)
var mLock sync.Mutex
timestamp := q.GetTimestamp()
writeBlock := func(_ uint, timestamps []int64, columns []logstorage.BlockColumn) {
clonedColumnNames := make([]string, len(columns))
for i, c := range columns {
clonedColumnNames[i] = strings.Clone(c.Name)
}
for i := range timestamps {
// Do not move q.GetTimestamp() outside writeBlock, since ts
// must be initialized to query timestamp for every processed log row.
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8312
ts := q.GetTimestamp()
labels := make([]logstorage.Field, 0, len(byFields))
for j, c := range columns {
if c.Name == "_time" {
nsec, ok := logstorage.TryParseTimestampRFC3339Nano(c.Values[i])
if ok {
timestamp = nsec
ts = nsec
continue
}
}
@@ -721,7 +724,7 @@ func ProcessStatsQueryRangeRequest(ctx context.Context, w http.ResponseWriter, r
dst = logstorage.MarshalFieldsToJSON(dst, labels)
key := string(dst)
p := statsPoint{
Timestamp: timestamp,
Timestamp: ts,
Value: strings.Clone(c.Values[i]),
}
@@ -1119,7 +1122,7 @@ func getTimeNsec(r *http.Request, argName string) (int64, bool, error) {
return 0, false, nil
}
currentTimestamp := time.Now().UnixNano()
nsecs, err := promutils.ParseTimeAt(s, currentTimestamp)
nsecs, err := timeutil.ParseTimeAt(s, currentTimestamp)
if err != nil {
return 0, false, fmt.Errorf("cannot parse %s=%s: %w", argName, s, err)
}

View File

@@ -176,50 +176,62 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
func processSelectRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, path string) bool {
httpserver.EnableCORS(w, r)
startTime := time.Now()
switch path {
case "/select/logsql/facets":
logsqlFacetsRequests.Inc()
logsql.ProcessFacetsRequest(ctx, w, r)
logsqlFacetsDuration.UpdateDuration(startTime)
return true
case "/select/logsql/field_names":
logsqlFieldNamesRequests.Inc()
logsql.ProcessFieldNamesRequest(ctx, w, r)
logsqlFieldNamesDuration.UpdateDuration(startTime)
return true
case "/select/logsql/field_values":
logsqlFieldValuesRequests.Inc()
logsql.ProcessFieldValuesRequest(ctx, w, r)
logsqlFieldValuesDuration.UpdateDuration(startTime)
return true
case "/select/logsql/hits":
logsqlHitsRequests.Inc()
logsql.ProcessHitsRequest(ctx, w, r)
logsqlHitsDuration.UpdateDuration(startTime)
return true
case "/select/logsql/query":
logsqlQueryRequests.Inc()
logsql.ProcessQueryRequest(ctx, w, r)
logsqlQueryDuration.UpdateDuration(startTime)
return true
case "/select/logsql/stats_query":
logsqlStatsQueryRequests.Inc()
logsql.ProcessStatsQueryRequest(ctx, w, r)
logsqlStatsQueryDuration.UpdateDuration(startTime)
return true
case "/select/logsql/stats_query_range":
logsqlStatsQueryRangeRequests.Inc()
logsql.ProcessStatsQueryRangeRequest(ctx, w, r)
logsqlStatsQueryRangeDuration.UpdateDuration(startTime)
return true
case "/select/logsql/stream_field_names":
logsqlStreamFieldNamesRequests.Inc()
logsql.ProcessStreamFieldNamesRequest(ctx, w, r)
logsqlStreamFieldNamesDuration.UpdateDuration(startTime)
return true
case "/select/logsql/stream_field_values":
logsqlStreamFieldValuesRequests.Inc()
logsql.ProcessStreamFieldValuesRequest(ctx, w, r)
logsqlStreamFieldValuesDuration.UpdateDuration(startTime)
return true
case "/select/logsql/stream_ids":
logsqlStreamIDsRequests.Inc()
logsql.ProcessStreamIDsRequest(ctx, w, r)
logsqlStreamIDsDuration.UpdateDuration(startTime)
return true
case "/select/logsql/streams":
logsqlStreamsRequests.Inc()
logsql.ProcessStreamsRequest(ctx, w, r)
logsqlStreamsDuration.UpdateDuration(startTime)
return true
default:
return false
@@ -240,16 +252,39 @@ func getMaxQueryDuration(r *http.Request) time.Duration {
}
var (
logsqlFacetsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/facets"}`)
logsqlFieldNamesRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/field_names"}`)
logsqlFieldValuesRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/field_values"}`)
logsqlHitsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/hits"}`)
logsqlQueryRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/query"}`)
logsqlStatsQueryRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stats_query"}`)
logsqlStatsQueryRangeRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stats_query_range"}`)
logsqlStreamFieldNamesRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stream_field_names"}`)
logsqlFacetsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/facets"}`)
logsqlFacetsDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/facets"}`)
logsqlFieldNamesRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/field_names"}`)
logsqlFieldNamesDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/field_names"}`)
logsqlFieldValuesRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/field_values"}`)
logsqlFieldValuesDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/field_values"}`)
logsqlHitsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/hits"}`)
logsqlHitsDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/hits"}`)
logsqlQueryRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/query"}`)
logsqlQueryDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/query"}`)
logsqlStatsQueryRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stats_query"}`)
logsqlStatsQueryDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/stats_query"}`)
logsqlStatsQueryRangeRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stats_query_range"}`)
logsqlStatsQueryRangeDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/stats_query_range"}`)
logsqlStreamFieldNamesRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stream_field_names"}`)
logsqlStreamFieldNamesDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/stream_field_names"}`)
logsqlStreamFieldValuesRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stream_field_values"}`)
logsqlStreamIDsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stream_ids"}`)
logsqlStreamsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/streams"}`)
logsqlTailRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/tail"}`)
logsqlStreamFieldValuesDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/stream_field_values"}`)
logsqlStreamIDsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/stream_ids"}`)
logsqlStreamIDsDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/stream_ids"}`)
logsqlStreamsRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/streams"}`)
logsqlStreamsDuration = metrics.NewSummary(`vl_http_request_duration_seconds{path="/select/logsql/streams"}`)
// no need to track duration for tail requests, as they usually take long time
logsqlTailRequests = metrics.NewCounter(`vl_http_requests_total{path="/select/logsql/tail"}`)
)

View File

@@ -9,6 +9,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/streamaggr"
"github.com/VictoriaMetrics/metrics"
)
@@ -94,7 +95,7 @@ func TestRemoteWriteContext_TryPush_ImmutableTimeseries(t *testing.T) {
}
offsetMsecs := time.Now().UnixMilli()
inputTss := prompbmarshal.MustParsePromMetrics(input, offsetMsecs)
inputTss := prometheus.MustParsePromMetrics(input, offsetMsecs)
expectedTss := make([]prompbmarshal.TimeSeries, len(inputTss))
// copy inputTss to make sure it is not mutated during TryPush call

View File

@@ -51,6 +51,11 @@ Examples:
Usage: `Optional external URL to template in rule's labels or annotations.`,
Required: false,
},
&cli.StringFlag{
Name: "httpListenPort",
Usage: `Optional local port for incoming HTTP requests. If not specified, a random unoccupied port will be used.`,
Required: false,
},
&cli.StringFlag{
Name: "loggerLevel",
Usage: `Minimum level of errors to log. Possible values: INFO, WARN, ERROR, FATAL, PANIC (default "ERROR").`,
@@ -58,7 +63,7 @@ Examples:
},
},
Action: func(c *cli.Context) error {
if failed := unittest.UnitTest(c.StringSlice("files"), c.Bool("disableAlertgroupLabel"), c.StringSlice("external.label"), c.String("external.url"), c.String("loggerLevel")); failed {
if failed := unittest.UnitTest(c.StringSlice("files"), c.Bool("disableAlertgroupLabel"), c.StringSlice("external.label"), c.String("external.url"), c.String("httpListenPort"), c.String("loggerLevel")); failed {
return fmt.Errorf("unittest failed")
}
return nil

View File

@@ -4,13 +4,18 @@ import (
"context"
"flag"
"fmt"
"net"
"net/http"
"net/http/httptest"
"net/url"
"os"
"os/signal"
"path/filepath"
"reflect"
"sort"
"strconv"
"strings"
"syscall"
"time"
"gopkg.in/yaml.v2"
@@ -28,7 +33,6 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/prometheus"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/promql"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
@@ -38,15 +42,9 @@ import (
var (
storagePath string
httpListenAddr = ":8880"
httpListenAddr string
// insert series from 1970-01-01T00:00:00
testStartTime = time.Unix(0, 0).UTC()
testPromWriteHTTPPath = "http://127.0.0.1" + httpListenAddr + "/api/v1/write"
testDataSourcePath = "http://127.0.0.1" + httpListenAddr + "/prometheus"
testRemoteWritePath = "http://127.0.0.1" + httpListenAddr
testHealthHTTPPath = "http://127.0.0.1" + httpListenAddr + "/health"
testStartTime = time.Unix(0, 0).UTC()
testLogLevel = "ERROR"
disableAlertgroupLabel bool
)
@@ -56,7 +54,7 @@ const (
)
// UnitTest runs unittest for files
func UnitTest(files []string, disableGroupLabel bool, externalLabels []string, externalURL, logLevel string) bool {
func UnitTest(files []string, disableGroupLabel bool, externalLabels []string, externalURL, httpListenPort, logLevel string) bool {
if logLevel != "" {
testLogLevel = logLevel
}
@@ -67,7 +65,42 @@ func UnitTest(files []string, disableGroupLabel bool, externalLabels []string, e
if err := templates.Load([]string{}, *eu); err != nil {
logger.Fatalf("failed to load template: %v", err)
}
storagePath = filepath.Join(os.TempDir(), testStoragePath)
// set up http server
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/prometheus/api/v1/query":
if err := prometheus.QueryHandler(nil, time.Now(), w, r); err != nil {
httpserver.Errorf(w, r, "%s", err)
}
case "/prometheus/api/v1/write", "/api/v1/write":
if err := promremotewrite.InsertHandler(r); err != nil {
httpserver.Errorf(w, r, "%s", err)
}
default:
}
})
if httpListenPort == "" {
server := httptest.NewServer(handler)
httpListenAddr = strings.Split(server.URL, ":")[2]
defer server.Close()
} else {
httpListenAddr = httpListenPort
ln, err := net.Listen("tcp", fmt.Sprintf(":%s", httpListenPort))
if err != nil {
logger.Fatalf("cannot listen on port %s: %v", httpListenPort, err)
}
go func() {
err = http.Serve(ln, handler)
if err != nil {
logger.Fatalf("cannot start http server: %v", err)
}
defer ln.Close()
}()
}
// adding time.Now().UnixNano() to avoid possible file conflict when multiple processes run on a single host
storagePath = filepath.Join(os.TempDir(), testStoragePath, strconv.FormatInt(time.Now().UnixNano(), 10))
processFlags()
vminsert.Init()
vmselect.Init()
@@ -102,16 +135,34 @@ func UnitTest(files []string, disableGroupLabel bool, externalLabels []string, e
}
var failed bool
for fileName, file := range testfiles {
if err := ruleUnitTest(fileName, file, labels); err != nil {
fmt.Println("FAILED")
fmt.Printf("failed to run unit test for file %q: \n%v", fileName, err)
failed = true
} else {
fmt.Println(" SUCCESS")
runTest := func() bool {
for fileName, file := range testfiles {
if err := ruleUnitTest(fileName, file, labels); err != nil {
fmt.Println("FAILED")
fmt.Printf("failed to run unit test for file %q: \n%v", fileName, err)
return true
}
fmt.Println("SUCCESS")
}
return false
}
finishCh := make(chan struct{}, 1)
go func() {
failed = runTest()
finishCh <- struct{}{}
}()
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
select {
case sig := <-sigs:
fmt.Printf("received signal %s\n", sig)
failed = true
break
case <-finishCh:
break
}
return failed
}
@@ -211,8 +262,8 @@ func processFlags() {
{flag: "search.disableCache", value: "true"},
// set storage retention time to 100 years, allow to store series from 1970-01-01T00:00:00.
{flag: "retentionPeriod", value: "100y"},
{flag: "datasource.url", value: testDataSourcePath},
{flag: "remoteWrite.url", value: testRemoteWritePath},
{flag: "datasource.url", value: fmt.Sprintf("http://127.0.0.1:%s/prometheus", httpListenAddr)},
{flag: "remoteWrite.url", value: fmt.Sprintf("http://127.0.0.1:%s", httpListenAddr)},
{flag: "notifier.blackhole", value: "true"},
} {
// panics if flag doesn't exist
@@ -224,27 +275,10 @@ func processFlags() {
func setUp() {
vmstorage.Init(promql.ResetRollupResultCacheIfNeeded)
var ab flagutil.ArrayBool
go httpserver.Serve([]string{httpListenAddr}, &ab, func(w http.ResponseWriter, r *http.Request) bool {
switch r.URL.Path {
case "/prometheus/api/v1/query":
if err := prometheus.QueryHandler(nil, time.Now(), w, r); err != nil {
httpserver.Errorf(w, r, "%s", err)
}
return true
case "/prometheus/api/v1/write", "/api/v1/write":
if err := promremotewrite.InsertHandler(r); err != nil {
httpserver.Errorf(w, r, "%s", err)
}
return true
default:
}
return false
})
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
readyCheckFunc := func() bool {
resp, err := http.Get(testHealthHTTPPath)
resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%s/health", httpListenAddr))
if err != nil {
return false
}
@@ -266,9 +300,6 @@ checkCheck:
}
func tearDown() {
if err := httpserver.Stop([]string{httpListenAddr}); err != nil {
logger.Errorf("cannot stop the webservice: %s", err)
}
vmstorage.Stop()
metrics.UnregisterAllMetrics()
fs.MustRemoveAll(storagePath)
@@ -283,7 +314,7 @@ func (tg *testGroup) test(evalInterval time.Duration, groupOrderMap map[string]i
if tg.Interval == nil {
tg.Interval = promutils.NewDuration(evalInterval)
}
err := writeInputSeries(tg.InputSeries, tg.Interval, testStartTime, testPromWriteHTTPPath)
err := writeInputSeries(tg.InputSeries, tg.Interval, testStartTime, fmt.Sprintf("http://127.0.0.1:%s/api/v1/write", httpListenAddr))
if err != nil {
return []error{err}
}

View File

@@ -8,7 +8,7 @@ func TestUnitTest_Failure(t *testing.T) {
f := func(files []string) {
t.Helper()
failed := UnitTest(files, false, nil, "", "")
failed := UnitTest(files, false, nil, "", "", "")
if !failed {
t.Fatalf("expecting failed test")
}
@@ -20,19 +20,20 @@ func TestUnitTest_Failure(t *testing.T) {
}
func TestUnitTest_Success(t *testing.T) {
f := func(disableGroupLabel bool, files []string, externalLabels []string, externalURL string) {
f := func(disableGroupLabel bool, files []string, externalLabels []string, externalURL, httpPort string) {
t.Helper()
failed := UnitTest(files, disableGroupLabel, externalLabels, externalURL, "")
failed := UnitTest(files, disableGroupLabel, externalLabels, externalURL, httpPort, "")
if failed {
t.Fatalf("unexpected failed test")
}
}
// run multi files
f(false, []string{"./testdata/test1.yaml", "./testdata/test2.yaml"}, []string{"cluster=prod"}, "http://grafana:3000")
// run multi files with random http port
f(false, []string{"./testdata/test1.yaml", "./testdata/test2.yaml"}, []string{"cluster=prod"}, "http://grafana:3000", "")
// disable group label
// template with null external values
f(true, []string{"./testdata/disable-group-label.yaml"}, nil, "")
// specify httpListenAddr
f(true, []string{"./testdata/disable-group-label.yaml"}, nil, "", "8880")
}

View File

@@ -157,6 +157,19 @@ func TestGroupValidate_Failure(t *testing.T) {
f(&Group{}, false, "group name must be set")
f(&Group{
Name: "both record and alert are not set",
Rules: []Rule{
{
Expr: "sum(up == 0 ) by (host)",
For: promutils.NewDuration(10 * time.Millisecond),
},
{
Expr: "sumSeries(time('foo.bar',10))",
},
},
}, false, "invalid rule")
f(&Group{
Name: "negative interval",
Interval: promutils.NewDuration(-1),
@@ -240,59 +253,6 @@ func TestGroupValidate_Failure(t *testing.T) {
},
}, false, "duplicate")
f(&Group{
Name: "test graphite with prometheus expr",
Type: NewGraphiteType(),
Rules: []Rule{
{
Expr: "sum(up == 0 ) by (host)",
For: promutils.NewDuration(10 * time.Millisecond),
},
{
Expr: "sumSeries(time('foo.bar',10))",
},
},
}, false, "invalid rule")
f(&Group{
Name: "test graphite inherit",
Type: NewGraphiteType(),
Rules: []Rule{
{
Expr: "sumSeries(time('foo.bar',10))",
For: promutils.NewDuration(10 * time.Millisecond),
},
{
Expr: "sum(up == 0 ) by (host)",
},
},
}, false, "either `record` or `alert` must be set")
f(&Group{
Name: "test vlogs with prometheus expr",
Type: NewVLogsType(),
Rules: []Rule{
{
Expr: "sum(up == 0 ) by (host)",
For: promutils.NewDuration(10 * time.Millisecond),
},
{
Expr: "sumSeries(time('foo.bar',10))",
},
},
}, false, "invalid rule")
// validate expressions
f(&Group{
Name: "test",
Rules: []Rule{
{
Record: "record",
Expr: "up | 0",
},
},
}, true, "invalid expression")
f(&Group{
Name: "test thanos",
Type: NewRawType("thanos"),
@@ -303,8 +263,20 @@ func TestGroupValidate_Failure(t *testing.T) {
},
}, true, "unknown datasource type")
// validate expressions
f(&Group{
Name: "test graphite",
Name: "test prometheus expr",
Type: NewPrometheusType(),
Rules: []Rule{
{
Record: "record",
Expr: "up | 0",
},
},
}, true, "bad prometheus expr")
f(&Group{
Name: "test graphite expr",
Type: NewGraphiteType(),
Rules: []Rule{
{Alert: "alert", Expr: "up == 1", Labels: map[string]string{
@@ -314,14 +286,63 @@ func TestGroupValidate_Failure(t *testing.T) {
}, true, "bad graphite expr")
f(&Group{
Name: "test vlogs",
Name: "test vlogs expr",
Type: NewVLogsType(),
Rules: []Rule{
{Alert: "alert", Expr: "stats count(*) as requests", Labels: map[string]string{
"description": "some-description",
}},
{Alert: "alert", Expr: "stats count(*) as requests"},
},
}, true, "bad LogsQL expr")
f(&Group{
Name: "test vlogs expr",
Type: NewVLogsType(),
Rules: []Rule{
{Alert: "alert", Expr: "_time: 1m | stats by (path, _time: 1m) count(*) as requests"},
},
}, true, "bad LogsQL expr")
f(&Group{
Name: "test graphite with prometheus expr",
Type: NewGraphiteType(),
Rules: []Rule{
{
Record: "r1",
ID: 1,
Expr: "sumSeries(time('foo.bar',10))",
For: promutils.NewDuration(10 * time.Millisecond),
},
{
Record: "r2",
ID: 2,
Expr: "sum(up == 0 ) by (host)",
},
},
}, true, "bad graphite expr")
f(&Group{
Name: "test vlogs with prometheus exp",
Type: NewVLogsType(),
Rules: []Rule{
{
Record: "r1",
Expr: "sum(up == 0 ) by (host)",
For: promutils.NewDuration(10 * time.Millisecond),
},
},
}, true, "bad LogsQL expr")
f(&Group{
Name: "test prometheus with vlogs exp",
Type: NewPrometheusType(),
Rules: []Rule{
{
Record: "r1",
Expr: "* | stats by (path) count()",
For: promutils.NewDuration(10 * time.Millisecond),
},
},
}, true, "bad prometheus expr")
}
func TestGroupValidate_Success(t *testing.T) {

View File

@@ -71,9 +71,18 @@ func (t *Type) ValidateExpr(expr string) error {
return fmt.Errorf("bad prometheus expr: %q, err: %w", expr, err)
}
case "vlogs":
if _, err := logstorage.ParseStatsQuery(expr, 0); err != nil {
q, err := logstorage.ParseStatsQuery(expr, 0)
if err != nil {
return fmt.Errorf("bad LogsQL expr: %q, err: %w", expr, err)
}
fields, _ := q.GetStatsByFields()
for i := range fields {
// VictoriaLogs inserts `_time` field as a label in result when query with `stats by (_time:step)`,
// making the result meaningless and may lead to cardinality issues.
if fields[i] == "_time" {
return fmt.Errorf("bad LogsQL expr: %q, err: cannot contain time buckets stats pipe `stats by (_time:step)`", expr)
}
}
default:
return fmt.Errorf("unknown datasource type=%q", t.Name)
}

View File

@@ -54,7 +54,7 @@ var (
"If multiple args are set, then they are applied independently for the corresponding -notifier.url")
oauth2Scopes = flagutil.NewArrayString("notifier.oauth2.scopes", "Optional OAuth2 scopes to use for -notifier.url. Scopes must be delimited by ';'. "+
"If multiple args are set, then they are applied independently for the corresponding -notifier.url")
sendTimeout = flagutil.NewArrayDuration("notifier.sendTimeout", time.Second*10, "Timeout for pushing alerts to corresponding -notifier.url.")
sendTimeout = flagutil.NewArrayDuration("notifier.sendTimeout", 10*time.Second, "Timeout when sending alerts to the corresponding -notifier.url")
)
// cw holds a configWatcher for configPath configuration file

View File

@@ -33,7 +33,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/datasource"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/formatutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil"
)
// go template execution fails when it's tree is empty
@@ -259,7 +259,7 @@ func templateFuncs() textTpl.FuncMap {
// parseDuration parses a duration string such as "1h" into the number of seconds it represents
"parseDuration": func(s string) (float64, error) {
d, err := promutils.ParseDuration(s)
d, err := timeutil.ParseDuration(s)
if err != nil {
return 0, err
}
@@ -268,7 +268,7 @@ func templateFuncs() textTpl.FuncMap {
// same with parseDuration but returns a time.Duration
"parseDurationTime": func(s string) (time.Duration, error) {
d, err := promutils.ParseDuration(s)
d, err := timeutil.ParseDuration(s)
if err != nil {
return 0, err
}

View File

@@ -344,7 +344,7 @@ var (
},
&cli.BoolFlag{
Name: influxSkipDatabaseLabel,
Usage: "Wether to skip adding the label 'db' to timeseries.",
Usage: "Whether to skip adding the label 'db' to timeseries.",
Value: false,
},
&cli.BoolFlag{

View File

@@ -1,6 +1,7 @@
package main
import (
"context"
"fmt"
"io"
"log"
@@ -37,7 +38,7 @@ func newInfluxProcessor(ic *influx.Client, im *vm.Importer, cc int, separator st
}
}
func (ip *influxProcessor) run() error {
func (ip *influxProcessor) run(ctx context.Context) error {
series, err := ip.ic.Explore()
if err != nil {
return fmt.Errorf("explore query failed: %s", err)
@@ -67,7 +68,7 @@ func (ip *influxProcessor) run() error {
go func() {
defer wg.Done()
for s := range seriesCh {
if err := ip.do(s); err != nil {
if err := ip.do(ctx, s); err != nil {
errCh <- fmt.Errorf("request failed for %q.%q: %s", s.Measurement, s.Field, err)
return
}
@@ -110,7 +111,7 @@ const dbLabel = "db"
const nameLabel = "__name__"
const valueField = "value"
func (ip *influxProcessor) do(s *influx.Series) error {
func (ip *influxProcessor) do(ctx context.Context, s *influx.Series) error {
cr, err := ip.ic.FetchDataPoints(s)
if err != nil {
return fmt.Errorf("failed to fetch datapoints: %s", err)
@@ -163,7 +164,7 @@ func (ip *influxProcessor) do(s *influx.Series) error {
Timestamps: time,
Values: values,
}
if err := ip.im.Input(&ts); err != nil {
if err := ip.im.Input(ctx, &ts); err != nil {
return err
}
}

View File

@@ -144,9 +144,9 @@ func timeFilter(start, end string) string {
// by checking available (non-empty) tags, fields and measurements
// which unique combination represents all possible
// time series existing in database.
// The explore required to reduce the load on influx
// Explore is required to reduce the load on influx
// by querying field of the exact time series at once,
// instead of fetching all of the values over and over.
// instead of fetching all the values over and over.
//
// May contain non-existing time series.
func (c *Client) Explore() ([]*Series, error) {
@@ -340,10 +340,7 @@ func (c *Client) fieldsByMeasurement() (map[string][]string, error) {
}
func (c *Client) getSeries() ([]*Series, error) {
com := "show series"
if c.filterSeries != "" {
com = fmt.Sprintf("%s %s", com, c.filterSeries)
}
com := c.getSeriesCommand()
q := influx.Query{
Command: com,
Database: c.database,
@@ -389,6 +386,21 @@ func (c *Client) getSeries() ([]*Series, error) {
return result, nil
}
func (c *Client) getSeriesCommand() string {
com := "show series"
if c.filterSeries != "" {
com = fmt.Sprintf("%s %s", com, c.filterSeries)
}
if c.filterTime != "" {
joinStatement := " where "
if strings.Contains(strings.ToLower(com), joinStatement) {
joinStatement = " AND "
}
com = fmt.Sprintf("%s%s%s", com, joinStatement, c.filterTime)
}
return com
}
// getMeasurementTags get the tags for each measurement.
// tags are placed in a map without values (similar to a set) for quick lookups:
// {"measurement1": {"tag1", "tag2"}, "measurement2": {"tag3", "tag4"}}

View File

@@ -103,3 +103,26 @@ func TestTimeFilter(t *testing.T) {
// both start and end filters
f("2020-01-01T20:07:00Z", "2020-01-01T21:07:00Z", "time >= '2020-01-01T20:07:00Z' and time <= '2020-01-01T21:07:00Z'")
}
func TestGetSeriesCommand(t *testing.T) {
f := func(filterSeries, filterTime, expCommand string) {
t.Helper()
c := &Client{
filterTime: filterTime,
filterSeries: filterSeries,
}
gotCommand := c.getSeriesCommand()
if gotCommand != expCommand {
t.Fatalf("unexpected command\ngot\n%s\nwant\n%s", gotCommand, expCommand)
}
}
f("", "", "show series")
f("from cpu", "", "show series from cpu")
f("from cpu where arch='x86'", "", "show series from cpu where arch='x86'")
f("", "time >= '2020-01-01T20:07:00Z'", "show series where time >= '2020-01-01T20:07:00Z'")
f("from cpu", "time >= '2020-01-01T20:07:00Z'", "show series from cpu where time >= '2020-01-01T20:07:00Z'")
f("from cpu where arch='x86'", "time >= '2020-01-01T20:07:00Z'", "show series from cpu where arch='x86' AND time >= '2020-01-01T20:07:00Z'")
f("from cpu where arch='x86' AND hostname='host_2753'", "time >= '2020-01-01T20:07:00Z'", "show series from cpu where arch='x86' AND hostname='host_2753' AND time >= '2020-01-01T20:07:00Z'")
}

View File

@@ -97,7 +97,7 @@ func main() {
}
otsdbProcessor := newOtsdbProcessor(otsdbClient, importer, c.Int(otsdbConcurrency), c.Bool(globalVerbose))
return otsdbProcessor.run()
return otsdbProcessor.run(ctx)
},
},
{
@@ -158,7 +158,7 @@ func main() {
c.Bool(influxSkipDatabaseLabel),
c.Bool(influxPrometheusMode),
c.Bool(globalVerbose))
return processor.run()
return processor.run(ctx)
},
},
{
@@ -261,7 +261,7 @@ func main() {
cc: c.Int(promConcurrency),
isVerbose: c.Bool(globalVerbose),
}
return pp.run()
return pp.run(ctx)
},
},
{

View File

@@ -1,14 +1,16 @@
package main
import (
"context"
"fmt"
"log"
"sync"
"time"
"github.com/cheggaaa/pb/v3"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/opentsdb"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/vm"
"github.com/cheggaaa/pb/v3"
)
type otsdbProcessor struct {
@@ -37,7 +39,7 @@ func newOtsdbProcessor(oc *opentsdb.Client, im *vm.Importer, otsdbcc int, verbos
}
}
func (op *otsdbProcessor) run() error {
func (op *otsdbProcessor) run(ctx context.Context) error {
log.Println("Loading all metrics from OpenTSDB for filters: ", op.oc.Filters)
var metrics []string
for _, filter := range op.oc.Filters {
@@ -93,7 +95,7 @@ func (op *otsdbProcessor) run() error {
go func() {
defer wg.Done()
for s := range seriesCh {
if err := op.do(s); err != nil {
if err := op.do(ctx, s); err != nil {
errCh <- fmt.Errorf("couldn't retrieve series for %s : %s", metric, err)
return
}
@@ -148,7 +150,7 @@ func (op *otsdbProcessor) run() error {
return nil
}
func (op *otsdbProcessor) do(s queryObj) error {
func (op *otsdbProcessor) do(ctx context.Context, s queryObj) error {
start := s.StartTime - s.Tr.Start
end := s.StartTime - s.Tr.End
data, err := op.oc.GetData(s.Series, s.Rt, start, end, op.oc.MsecsTime)
@@ -168,5 +170,5 @@ func (op *otsdbProcessor) do(s queryObj) error {
Timestamps: data.Timestamps,
Values: data.Values,
}
return op.im.Input(&ts)
return op.im.Input(ctx, &ts)
}

View File

@@ -1,6 +1,7 @@
package main
import (
"context"
"fmt"
"log"
"sync"
@@ -30,7 +31,7 @@ type prometheusProcessor struct {
isVerbose bool
}
func (pp *prometheusProcessor) run() error {
func (pp *prometheusProcessor) run(ctx context.Context) error {
blocks, err := pp.cl.Explore()
if err != nil {
return fmt.Errorf("explore failed: %s", err)
@@ -59,7 +60,7 @@ func (pp *prometheusProcessor) run() error {
go func() {
defer wg.Done()
for br := range blockReadersCh {
if err := pp.do(br); err != nil {
if err := pp.do(ctx, br); err != nil {
errCh <- fmt.Errorf("read failed for block %q: %s", br.Meta().ULID, err)
return
}
@@ -100,7 +101,7 @@ func (pp *prometheusProcessor) run() error {
return nil
}
func (pp *prometheusProcessor) do(b tsdb.BlockReader) error {
func (pp *prometheusProcessor) do(ctx context.Context, b tsdb.BlockReader) error {
ss, err := pp.cl.Read(b)
if err != nil {
return fmt.Errorf("failed to read block: %s", err)
@@ -150,7 +151,7 @@ func (pp *prometheusProcessor) do(b tsdb.BlockReader) error {
Timestamps: timestamps,
Values: values,
}
if err := pp.im.Input(&ts); err != nil {
if err := pp.im.Input(ctx, &ts); err != nil {
return err
}
}

View File

@@ -160,7 +160,7 @@ func TestPrometheusProcessorRun(t *testing.T) {
go tt.fields.closer(importer)
}
if err := pp.run(); (err != nil) != tt.wantErr {
if err := pp.run(context.Background()); (err != nil) != tt.wantErr {
t.Fatalf("run() error = %v, wantErr %v", err, tt.wantErr)
}
})

View File

@@ -112,7 +112,7 @@ func (rrp *remoteReadProcessor) run(ctx context.Context) error {
func (rrp *remoteReadProcessor) do(ctx context.Context, filter *remoteread.Filter) error {
return rrp.src.Read(ctx, filter, func(series *vm.TimeSeries) error {
if err := rrp.dst.Input(series); err != nil {
if err := rrp.dst.Input(ctx, series); err != nil {
return fmt.Errorf(
"failed to read data for time range start: %d, end: %d, %s",
filter.StartTimestampMs, filter.EndTimestampMs, err)

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil"
)
const (
@@ -16,7 +16,7 @@ const (
// ParseTime parses time in s string and returns time.Time object
// if parse correctly or error if not
func ParseTime(s string) (time.Time, error) {
msecs, err := promutils.ParseTimeMsec(s)
msecs, err := timeutil.ParseTimeMsec(s)
if err != nil {
return time.Time{}, fmt.Errorf("cannot parse %s: %w", s, err)
}

View File

@@ -69,7 +69,6 @@ type Importer struct {
user string
password string
close chan struct{}
input chan *TimeSeries
errors chan *ImportError
@@ -143,7 +142,6 @@ func NewImporter(ctx context.Context, cfg Config) (*Importer, error) {
user: cfg.User,
password: cfg.Password,
rl: limiter.NewLimiter(cfg.RateLimit),
close: make(chan struct{}),
input: make(chan *TimeSeries, cfg.Concurrency*4),
errors: make(chan *ImportError, cfg.Concurrency),
backoff: cfg.Backoff,
@@ -189,10 +187,10 @@ func (im *Importer) Errors() chan *ImportError { return im.errors }
// Input returns a channel for sending timeseries
// that need to be imported
func (im *Importer) Input(ts *TimeSeries) error {
func (im *Importer) Input(ctx context.Context, ts *TimeSeries) error {
select {
case <-im.close:
return fmt.Errorf("importer is closed")
case <-ctx.Done():
return ctx.Err()
case im.input <- ts:
return nil
case err := <-im.errors:
@@ -207,7 +205,6 @@ func (im *Importer) Input(ts *TimeSeries) error {
// and waits until they are finished
func (im *Importer) Close() {
im.once.Do(func() {
close(im.close)
close(im.input)
im.wg.Wait()
close(im.errors)
@@ -220,24 +217,34 @@ func (im *Importer) startWorker(ctx context.Context, bar barpool.Bar, batchSize,
var waitForBatch time.Time
for {
select {
case <-im.close:
case <-ctx.Done():
for ts := range im.input {
ts = roundTimeseriesValue(ts, significantFigures, roundDigits)
batch = append(batch, ts)
exitErr := &ImportError{
Batch: batch,
}
retryableFunc := func() error { return im.Import(batch) }
_, err := im.backoff.Retry(ctx, retryableFunc)
if err != nil {
exitErr.Err = err
}
im.errors <- exitErr
}
exitErr := &ImportError{
Batch: batch,
}
retryableFunc := func() error { return im.Import(batch) }
_, err := im.backoff.Retry(ctx, retryableFunc)
if err != nil {
exitErr.Err = err
}
im.errors <- exitErr
return
case ts, ok := <-im.input:
if !ok {
continue
// drain all batches before exit
exitErr := &ImportError{
Batch: batch,
}
retryableFunc := func() error { return im.Import(batch) }
_, err := im.backoff.Retry(ctx, retryableFunc)
if err != nil {
exitErr.Err = err
}
im.errors <- exitErr
return
}
// init waitForBatch when first
// value was received

View File

@@ -2,6 +2,7 @@ package prompush
import (
"github.com/VictoriaMetrics/VictoriaMetrics/app/vminsert/common"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vminsert/relabel"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
"github.com/VictoriaMetrics/metrics"
@@ -49,6 +50,7 @@ func push(ctx *common.InsertCtx, tss []prompbmarshal.TimeSeries) {
}
ctx.Reset(rowsLen)
rowsTotal := 0
hasRelabeling := relabel.HasRelabeling()
for i := range tss {
ts := &tss[i]
rowsTotal += len(ts.Samples)
@@ -57,7 +59,7 @@ func push(ctx *common.InsertCtx, tss []prompbmarshal.TimeSeries) {
label := &ts.Labels[j]
ctx.AddLabel(label.Name, label.Value)
}
if !ctx.TryPrepareLabels(false) {
if !ctx.TryPrepareLabels(hasRelabeling) {
continue
}
var metricNameRaw []byte

View File

@@ -373,9 +373,17 @@ func getRollupConfigs(funcName string, rf rollupFunc, expr metricsql.Expr, start
func(values []float64, timestamps []int64), []*rollupConfig, error) {
preFunc := func(_ []float64, _ []int64) {}
funcName = strings.ToLower(funcName)
// window > lookbackDelta could result in negative delta.
// See issue: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8342
stalenessInterval := lookbackDelta
if stalenessInterval != 0 && stalenessInterval < window {
stalenessInterval = window
}
if rollupFuncsRemoveCounterResets[funcName] {
preFunc = func(values []float64, timestamps []int64) {
removeCounterResets(values, timestamps, lookbackDelta)
removeCounterResets(values, timestamps, stalenessInterval)
}
}
samplesScannedPerCall := rollupFuncsSamplesScannedPerCall[funcName]
@@ -487,7 +495,7 @@ func getRollupConfigs(funcName string, rf rollupFunc, expr metricsql.Expr, start
if rollupFuncsRemoveCounterResets[aggrFuncName] {
// There is no need to save the previous preFunc, since it is either empty or the same.
preFunc = func(values []float64, timestamps []int64) {
removeCounterResets(values, timestamps, lookbackDelta)
removeCounterResets(values, timestamps, stalenessInterval)
}
}
rf := rollupAggrFuncs[aggrFuncName]

View File

@@ -1,4 +1,4 @@
FROM golang:1.23.6 AS build-web-stage
FROM golang:1.24.0 AS build-web-stage
COPY build /build
WORKDIR /build

View File

@@ -9,7 +9,7 @@ export const useDebugDownsamplingFilters = () => {
const { serverUrl } = useAppState();
const [searchParams, setSearchParams] = useSearchParams();
const [data, setData] = useState<Map<string, string[]>>(new Map());
const [data, setData] = useState<Map<string, string[] | null>>(new Map());
const [loading, setLoading] = useState(false);
const [metricsError, setMetricsError] = useState<ErrorTypes | string>();
const [flagsError, setFlagsError] = useState<ErrorTypes | string>();

View File

@@ -7,6 +7,7 @@ import { PlayIcon, WikiIcon } from "../../components/Main/Icons";
import { useDebugDownsamplingFilters } from "./hooks/useDebugDownsamplingFilters";
import Spinner from "../../components/Main/Spinner/Spinner";
import { useSearchParams } from "react-router-dom";
import classNames from "classnames";
const example = {
flags: `-downsampling.period={env="dev"}:7d:5m,{env="dev"}:30d:30m
@@ -54,7 +55,14 @@ const DownsamplingFilters: FC = () => {
for (const [key, value] of data) {
rows.push(<tr className="vm-table__row">
<td className="vm-table-cell">{key}</td>
<td className="vm-table-cell">{value.join(" ")}</td>
<td
className={classNames({
"vm-table-cell": true,
"vm-table-cell_empty": !value,
})}
>
{value ? value.join(" ") : "No matching rules found!"}
</td>
</tr>);
}
return (

View File

@@ -94,6 +94,11 @@
white-space: nowrap;
width: 100px;
}
&_empty {
color: $color-text-secondary;
font-style: italic;
}
}
&__sort-icon {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,13 @@
# All these commands must run from repository root.
DOCKER_REGISTRIES ?= docker.io quay.io
DOCKER_NAMESPACE ?= victoriametrics
ROOT_IMAGE ?= alpine:3.21.3
ROOT_IMAGE_SCRATCH ?= scratch
CERTS_IMAGE := alpine:3.21.3
GO_BUILDER_IMAGE := golang:1.23.6-alpine
GO_BUILDER_IMAGE := golang:1.24.0-alpine
BUILDER_IMAGE := local/builder:2.0.0-$(shell echo $(GO_BUILDER_IMAGE) | tr :/ __)-1
BASE_IMAGE := local/base:1.1.4-$(shell echo $(ROOT_IMAGE) | tr :/ __)-$(shell echo $(CERTS_IMAGE) | tr :/ __)
DOCKER ?= docker
@@ -92,8 +93,10 @@ publish-via-docker:
--label "org.opencontainers.image.vendor=VictoriaMetrics" \
--label "org.opencontainers.image.version=$(PKG_TAG)" \
--label "org.opencontainers.image.created=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--tag $(DOCKER_NAMESPACE)/$(APP_NAME):$(PKG_TAG)$(RACE) \
--tag $(DOCKER_NAMESPACE)/$(APP_NAME):$(LATEST_TAG)$(RACE) \
$(foreach registry,$(DOCKER_REGISTRIES),\
--tag $(registry)/$(DOCKER_NAMESPACE)/$(APP_NAME):$(PKG_TAG)$(RACE) \
--tag $(registry)/$(DOCKER_NAMESPACE)/$(APP_NAME):$(LATEST_TAG)$(RACE) \
) \
-o type=image \
--provenance=false \
-f app/$(APP_NAME)/multiarch/Dockerfile \
@@ -110,8 +113,10 @@ publish-via-docker:
--label "org.opencontainers.image.vendor=VictoriaMetrics" \
--label "org.opencontainers.image.version=$(PKG_TAG)" \
--label "org.opencontainers.image.created=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--tag $(DOCKER_NAMESPACE)/$(APP_NAME):$(PKG_TAG)$(RACE)-scratch \
--tag $(DOCKER_NAMESPACE)/$(APP_NAME):$(LATEST_TAG)$(RACE)-scratch \
$(foreach registry,$(DOCKER_REGISTRIES),\
--tag $(registry)/$(DOCKER_NAMESPACE)/$(APP_NAME):$(PKG_TAG)$(RACE)-scratch \
--tag $(registry)/$(DOCKER_NAMESPACE)/$(APP_NAME):$(LATEST_TAG)$(RACE)-scratch \
) \
-o type=image \
--provenance=false \
-f app/$(APP_NAME)/multiarch/Dockerfile \

View File

@@ -209,5 +209,5 @@ Please see more examples on integration of VictoriaLogs with other log shippers
* [journald](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/docker/victorialogs/journald)
* [opentelemetry-collector](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/docker/victorialogs/opentelemetry-collector)
* [telegraf](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/docker/victorialogs/telegraf)
* [fluentd]((https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/docker/victorialogs/fluentd)
* [fluentd](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/docker/victorialogs/fluentd)
* [datadog-serverless](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/docker/victorialogs/datadog-serverless)

View File

@@ -4,7 +4,7 @@ services:
# And forward them to --remoteWrite.url
vmagent:
container_name: vmagent
image: victoriametrics/vmagent:v1.111.0
image: victoriametrics/vmagent:v1.112.0
depends_on:
- "vminsert"
ports:
@@ -39,7 +39,7 @@ services:
# where N is number of vmstorages (2 in this case).
vmstorage-1:
container_name: vmstorage-1
image: victoriametrics/vmstorage:v1.111.0-cluster
image: victoriametrics/vmstorage:v1.112.0-cluster
ports:
- 8482
- 8400
@@ -51,7 +51,7 @@ services:
restart: always
vmstorage-2:
container_name: vmstorage-2
image: victoriametrics/vmstorage:v1.111.0-cluster
image: victoriametrics/vmstorage:v1.112.0-cluster
ports:
- 8482
- 8400
@@ -66,7 +66,7 @@ services:
# pre-process them and distributes across configured vmstorage shards.
vminsert:
container_name: vminsert
image: victoriametrics/vminsert:v1.111.0-cluster
image: victoriametrics/vminsert:v1.112.0-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -81,7 +81,7 @@ services:
# vmselect collects results from configured `--storageNode` shards.
vmselect-1:
container_name: vmselect-1
image: victoriametrics/vmselect:v1.111.0-cluster
image: victoriametrics/vmselect:v1.112.0-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -94,7 +94,7 @@ services:
restart: always
vmselect-2:
container_name: vmselect-2
image: victoriametrics/vmselect:v1.111.0-cluster
image: victoriametrics/vmselect:v1.112.0-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -112,7 +112,7 @@ services:
# It can be used as an authentication proxy.
vmauth:
container_name: vmauth
image: victoriametrics/vmauth:v1.111.0
image: victoriametrics/vmauth:v1.112.0
depends_on:
- "vmselect-1"
- "vmselect-2"
@@ -127,7 +127,7 @@ services:
# vmalert executes alerting and recording rules
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.111.0
image: victoriametrics/vmalert:v1.112.0
depends_on:
- "vmauth"
ports:

View File

@@ -44,7 +44,7 @@ services:
# storing logs and serving read queries.
victorialogs:
container_name: victorialogs
image: victoriametrics/victoria-logs:v1.13.0-victorialogs
image: victoriametrics/victoria-logs:v1.15.0-victorialogs
command:
- "--storageDataPath=/vlogs"
- "--httpListenAddr=:9428"
@@ -59,7 +59,7 @@ services:
# scraping, storing metrics and serve read requests.
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.111.0
image: victoriametrics/victoria-metrics:v1.112.0
ports:
- 8428:8428
volumes:
@@ -78,7 +78,7 @@ services:
# depending on the requested path.
vmauth:
container_name: vmauth
image: victoriametrics/vmauth:v1.111.0
image: victoriametrics/vmauth:v1.112.0
depends_on:
- "victoriametrics"
- "victorialogs"
@@ -95,7 +95,7 @@ services:
# vmalert executes alerting and recording rules according to given rule type.
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.111.0
image: victoriametrics/vmalert:v1.112.0
depends_on:
- "vmauth"
- "alertmanager"

View File

@@ -4,7 +4,7 @@ services:
# And forward them to --remoteWrite.url
vmagent:
container_name: vmagent
image: victoriametrics/vmagent:v1.111.0
image: victoriametrics/vmagent:v1.112.0
depends_on:
- "victoriametrics"
ports:
@@ -20,7 +20,7 @@ services:
# storing metrics and serve read requests.
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.111.0
image: victoriametrics/victoria-metrics:v1.112.0
ports:
- 8428:8428
- 8089:8089
@@ -59,7 +59,7 @@ services:
# vmalert executes alerting and recording rules
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.111.0
image: victoriametrics/vmalert:v1.112.0
depends_on:
- "victoriametrics"
- "alertmanager"

View File

@@ -128,3 +128,21 @@ groups:
summary: "Some rows are rejected on \"{{ $labels.instance }}\" on ingestion attempt"
description: "Ingested rows on instance \"{{ $labels.instance }}\" are rejected due to the
following reason: \"{{ $labels.reason }}\""
- alert: TooHighQueryLoad
expr: increase(vm_concurrent_select_limit_timeout_total[5m]) > 0
for: 15m
labels:
severity: warning
annotations:
summary: "Read queries fail with timeout for {{ $labels.job }} on instance {{ $labels.instance }}"
description: |
Instance {{ $labels.instance }} ({{ $labels.job }}) is failing to serve read queries during last 15m.
Concurrency limit `-search.maxConcurrentRequests` was reached on this instance and extra queries were
put into the queue for `-search.maxQueueDuration` interval. But even after waiting in the queue these queries weren't served.
This happens if instance is overloaded with the current workload, or datasource is too slow to respond.
Possible solutions are the following:
* reduce the query load;
* increase compute resources or number of replicas;
* adjust limits `-search.maxConcurrentRequests` and `-search.maxQueueDuration`.
See more at https://docs.victoriametrics.com/troubleshooting/#slow-queries.

View File

@@ -1,7 +1,7 @@
services:
# meta service will be ignored by compose
.victorialogs:
image: docker.io/victoriametrics/victoria-logs:v1.13.0-victorialogs
image: docker.io/victoriametrics/victoria-logs:v1.15.0-victorialogs
command:
- -storageDataPath=/vlogs
- -loggerFormat=json
@@ -19,7 +19,7 @@ services:
retries: 10
dd-proxy:
image: docker.io/victoriametrics/vmauth:v1.111.0
image: docker.io/victoriametrics/vmauth:v1.112.0
restart: on-failure
volumes:
- ./:/etc/vmauth
@@ -45,7 +45,7 @@ services:
replicas: 0
victoriametrics:
image: victoriametrics/victoria-metrics:v1.111.0
image: victoriametrics/victoria-metrics:v1.112.0
ports:
- '8428:8428'
command:

View File

@@ -1,7 +1,7 @@
services:
vmagent:
container_name: vmagent
image: victoriametrics/vmagent:v1.111.0
image: victoriametrics/vmagent:v1.112.0
depends_on:
- "victoriametrics"
ports:
@@ -18,7 +18,7 @@ services:
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.111.0
image: victoriametrics/victoria-metrics:v1.112.0
ports:
- 8428:8428
volumes:
@@ -50,7 +50,7 @@ services:
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.111.0
image: victoriametrics/vmalert:v1.112.0
depends_on:
- "victoriametrics"
ports:
@@ -72,7 +72,7 @@ services:
restart: always
vmanomaly:
container_name: vmanomaly
image: victoriametrics/vmanomaly:v1.19.2
image: victoriametrics/vmanomaly:v1.20.0
depends_on:
- "victoriametrics"
ports:

View File

@@ -1,4 +1,4 @@
version: '3'
version: "3"
services:
filebeat-elastic:
@@ -18,7 +18,7 @@ services:
- vlogs
generator:
image: golang:1.23.6-alpine
image: golang:1.24.0-alpine
restart: always
working_dir: /go/src/app
volumes:
@@ -33,7 +33,7 @@ services:
- -syslog.addr=filebeat-elastic:12345
- -syslog.addr2=filebeat-vlogs:12345
- -logs.randomSuffix=false
depends_on: [ filebeat-elastic, filebeat-vlogs ]
depends_on: [filebeat-elastic, filebeat-vlogs]
elastic:
image: docker.elastic.co/elasticsearch/elasticsearch:8.8.0
@@ -48,8 +48,8 @@ services:
volumes:
- ./elk/kibana/kibana.yml:/usr/share/kibana/config/kibana.yml
ports:
- '5601:5601'
depends_on: [ elastic ]
- "5601:5601"
depends_on: [elastic]
beat-exporter-elastic:
image: trustpilot/beat-exporter:0.4.0

View File

@@ -1,8 +1,8 @@
version: '3'
version: "3"
services:
generator:
image: golang:1.23.6-alpine
image: golang:1.24.0-alpine
restart: always
working_dir: /go/src/app
volumes:
@@ -18,7 +18,7 @@ services:
- -syslog.addr=rsyslog:514
- -syslog.addr2=rsyslog:514
- -logs.randomSuffix=false
depends_on: [ rsyslog ]
depends_on: [rsyslog]
loki:
image: grafana/loki:2.9.0
@@ -45,8 +45,7 @@ services:
context: rsyslog
volumes:
- ./rsyslog/rsyslog.conf:/etc/rsyslog.conf
depends_on: [ promtail ]
depends_on: [promtail]
volumes:
loki:

View File

@@ -3,7 +3,7 @@ version: "3"
services:
# Run `make package-victoria-logs` to build victoria-logs image
vlogs:
image: docker.io/victoriametrics/victoria-logs:v1.13.0-victorialogs
image: docker.io/victoriametrics/victoria-logs:v1.15.0-victorialogs
volumes:
- vlogs:/vlogs
ports:

View File

@@ -174,9 +174,9 @@ Also see archives containing the word `cluster`.
Docker images for the cluster version are available here:
- `vminsert` - <https://hub.docker.com/r/victoriametrics/vminsert/tags>
- `vmselect` - <https://hub.docker.com/r/victoriametrics/vmselect/tags>
- `vmstorage` - <https://hub.docker.com/r/victoriametrics/vmstorage/tags>
- `vminsert` - [Docker Hub](https://hub.docker.com/r/victoriametrics/vminsert/tags) and [Quay](https://quay.io/repository/victoriametrics/vminsert?tab=tags)
- `vmselect` - [Docker Hub](https://hub.docker.com/r/victoriametrics/vmselect/tags) and [Quay](https://quay.io/repository/victoriametrics/vmselect?tab=tags)
- `vmstorage` - [Docker Hub](https://hub.docker.com/r/victoriametrics/vmstorage/tags) and [Quay](https://quay.io/repository/victoriametrics/vmstorage?tab=tags)
## Building from sources
@@ -761,7 +761,7 @@ Some workloads may need fine-grained resource usage limits. In these cases the f
- `-search.maxDeleteSeries` at `vmselect` limits the number of unique time
series that can be deleted by a single
[/api/v1/admin/tsdb/delete_series](https://docs.victoriametrics.com/url-examples/#apiv1admintsdbdelete_series)
call. The duration is limited via `-search.maxDeleteDuration` flag{{% available_from "#tip" %}}. Deleting too many time series may require big
call. The duration is limited via `-search.maxDeleteDuration` flag{{% available_from "v1.110.0" %}}. Deleting too many time series may require big
amount of CPU and memory at `vmstorage` and this limit guards against unplanned resource usage spikes.
Also see [How to delete time series](#how-to-delete-time-series) section to
learn about different ways of deleting series.

View File

@@ -22,5 +22,5 @@ to [the latest available releases](https://docs.victoriametrics.com/changelog/).
## Currently supported LTS release lines
- v1.110.x - the latest one is [v1.110.1 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.110.1)
- v1.102.x - the latest one is [v1.102.13 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.102.13)
- v1.110.x - the latest one is [v1.110.2 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.110.2)
- v1.102.x - the latest one is [v1.102.15 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.102.15)

View File

@@ -2349,4 +2349,4 @@ VictoriaMetrics performs the following implicit conversions for incoming queries
is passed to [rollup function](#rollup-functions), then a [subquery](#subqueries) with `1i` lookbehind window and `1i` step is automatically formed.
For example, `rate(sum(up))` is automatically converted to `rate((sum(default_rollup(up)))[1i:1i])`.
This behavior can be disabled or logged via `-search.disableImplicitConversion` and `-search.logImplicitConversion` command-line flags
starting from [`v1.101.0` release](https://docs.victoriametrics.com/changelog/).
starting from [`v1.102.0-rc2` release](https://docs.victoriametrics.com/changelog/changelog_2024/#v11020-rc2).

View File

@@ -23,7 +23,7 @@ VictoriaMetrics is distributed in the following forms:
VictoriaMetrics is available as:
* [Docker images](https://hub.docker.com/r/victoriametrics/victoria-metrics/)
* docker images at [Docker Hub](https://hub.docker.com/r/victoriametrics/victoria-metrics/) and [Quay](https://quay.io/repository/victoriametrics/victoria-metrics?tab=tags)
* [Helm Charts](https://github.com/VictoriaMetrics/helm-charts#list-of-charts)
* [Binary releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest)
* [Ansible Roles](https://github.com/VictoriaMetrics/ansible-playbooks)
@@ -55,8 +55,8 @@ under the current directory:
```sh
docker pull victoriametrics/victoria-metrics:v1.111.0
docker run -it --rm -v `pwd`/victoria-metrics-data:/victoria-metrics-data -p 8428:8428 victoriametrics/victoria-metrics:v1.111.0
docker pull victoriametrics/victoria-metrics:v1.112.0
docker run -it --rm -v `pwd`/victoria-metrics-data:/victoria-metrics-data -p 8428:8428 victoriametrics/victoria-metrics:v1.112.0
```

View File

@@ -1,7 +1,7 @@
![Latest Release](https://img.shields.io/github/v/release/VictoriaMetrics/VictoriaMetrics?sort=semver&label=&filter=!*-victorialogs&logo=github&labelColor=gray&color=gray&link=https%3A%2F%2Fgithub.com%2FVictoriaMetrics%2FVictoriaMetrics%2Freleases%2Flatest)
![Docker Pulls](https://img.shields.io/docker/pulls/victoriametrics/victoria-metrics?label=&logo=docker&logoColor=white&labelColor=2496ED&color=2496ED&link=https%3A%2F%2Fhub.docker.com%2Fr%2Fvictoriametrics%2Fvictoria-metrics)
![Go Report](https://goreportcard.com/badge/github.com/VictoriaMetrics/VictoriaMetrics?link=https%3A%2F%2Fgoreportcard.com%2Freport%2Fgithub.com%2FVictoriaMetrics%2FVictoriaMetrics)
![Build Status](https://github.com/VictoriaMetrics/VictoriaMetrics/workflows/main/badge.svg?link=https%3A%2F%2Fgithub.com%2FVictoriaMetrics%2FVictoriaMetrics%2Factions)
![Build Status](https://github.com/VictoriaMetrics/VictoriaMetrics/actions/workflows/main.yml/badge.svg?branch=master&link=https%3A%2F%2Fgithub.com%2FVictoriaMetrics%2FVictoriaMetrics%2Factions)
![codecov](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/branch/master/graph/badge.svg?link=https%3A%2F%2Fcodecov.io%2Fgh%2FVictoriaMetrics%2FVictoriaMetrics)
![License](https://img.shields.io/github/license/VictoriaMetrics/VictoriaMetrics?labelColor=green&label=&link=https%3A%2F%2Fgithub.com%2FVictoriaMetrics%2FVictoriaMetrics%2Fblob%2Fmaster%2FLICENSE)
![Slack](https://img.shields.io/badge/Join-4A154B?logo=slack&link=https%3A%2F%2Fslack.victoriametrics.com)
@@ -12,7 +12,7 @@ VictoriaMetrics is a fast, cost-effective and scalable monitoring solution and t
See [case studies for VictoriaMetrics](https://docs.victoriametrics.com/casestudies/).
VictoriaMetrics is available in [binary releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest),
[Docker images](https://hub.docker.com/r/victoriametrics/victoria-metrics/) and [source code](https://github.com/VictoriaMetrics/VictoriaMetrics).
Docker images at [Docker Hub](https://hub.docker.com/r/victoriametrics/victoria-metrics/) and [Quay](https://quay.io/repository/victoriametrics/victoria-metrics?tab=tags), [source code](https://github.com/VictoriaMetrics/VictoriaMetrics).
Documentation for the cluster version of VictoriaMetrics is available [here](https://docs.victoriametrics.com/cluster-victoriametrics/).
@@ -124,7 +124,7 @@ VictoriaMetrics ecosystem contains the following components additionally to [sin
### Install
To quickly try VictoriaMetrics, just download the [VictoriaMetrics executable](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest)
or [Docker image](https://hub.docker.com/r/victoriametrics/victoria-metrics/) and start it with the desired command-line flags.
or docker image from [Docker Hub](https://hub.docker.com/r/victoriametrics/victoria-metrics/) or [Quay](https://quay.io/repository/victoriametrics/victoria-metrics?tab=tags) and start it with the desired command-line flags.
See also [QuickStart guide](https://docs.victoriametrics.com/quick-start/) for additional information.
VictoriaMetrics can also be installed via these installation methods:
@@ -1076,7 +1076,7 @@ VictoriaMetrics supports the following handlers from [Graphite Tags API](https:/
## How to build from sources
We recommend using either [binary releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest) or
[docker images](https://hub.docker.com/r/victoriametrics/victoria-metrics/) instead of building VictoriaMetrics
docker images ([Docker Hub](https://hub.docker.com/r/victoriametrics/victoria-metrics/) and [Quay](https://quay.io/repository/victoriametrics/victoria-metrics?tab=tags)) instead of building VictoriaMetrics
from sources. Building from sources is reasonable when developing additional features specific
to your needs or when testing bugfixes.
@@ -1770,7 +1770,7 @@ By default, VictoriaMetrics is tuned for an optimal resource usage under typical
- `-search.maxDeleteSeries` limits the number of unique time series that can be
deleted by a single
[/api/v1/admin/tsdb/delete_series](https://docs.victoriametrics.com/url-examples/#apiv1admintsdbdelete_series)
call. The duration is limited via `-search.maxDeleteDuration` flag{{% available_from "#tip" %}}. Deleting too many time series may require big
call. The duration is limited via `-search.maxDeleteDuration` flag{{% available_from "v1.110.0" %}}. Deleting too many time series may require big
amount of CPU and memory and this limit guards against unplanned resource usage spikes. Also see
[How to delete time series](#how-to-delete-time-series) section to learn about
different ways of deleting series.
@@ -1998,7 +1998,7 @@ based on the time range of the query:
Mappings are added to the indexes during the data ingestion:
- In global index each mapping is created only once per retention period.
- In the per-day index each mapping is be created for each unique date that
- In the per-day index each mapping is created for each unique date that
has been seen in the samples for the corresponding time series.
IndexDB respects [retention period](#retention) and once it is over, the indexes
@@ -2102,9 +2102,9 @@ while leaving the last sample per each 1-hour interval for samples older than 18
VictoriaMetrics supports{{% available_from "v1.100.0" %}} configuring independent downsampling per different sets of [time series](https://docs.victoriametrics.com/keyconcepts/#time-series)
via `-downsampling.period=filter:offset:interval` syntax. In this case the given `offset:interval` downsampling is applied only to time series matching the given `filter`.
The `filter` can contain arbitrary [series filter](https://docs.victoriametrics.com/keyconcepts/#filtering).
For example, `-downsampling.period='{__name__=~"(node|process)_.*"}:1d:1m` instructs VictoriaMetrics to deduplicate samples older than one day with one minute interval
For example, `-downsampling.period='{__name__=~"(node|process)_.*"}:1d:1m` instructs VictoriaMetrics to downsample samples older than one day with one minute interval
only for [time series](https://docs.victoriametrics.com/keyconcepts/#time-series) with names starting with `node_` or `process_` prefixes.
The deduplication for other time series can be configured independently via additional `-downsampling.period` command-line flags.
The downsampling for other time series can be configured independently via additional `-downsampling.period` command-line flags.
Downsampling configuration can be tested in enterprise version of vmui on the page `Tools.Downsampling filters debug`.
If the time series doesn't match any `filter`, then it isn't downsampled. If the time series matches multiple filters, then the downsampling
@@ -2608,7 +2608,7 @@ A prominent example is Kubernetes. Services in k8s expose big number of series w
increasing churn rate. The per-day index speeds up data retrieval in this case.
But if your use case assumes low or no churn rate, then you might benefit from disabling the per-day index by setting
the flag `-disablePerDayIndex`{{% available_from "#tip" %}}. This will improve the time series ingestion speed and decrease disk space usage,
the flag `-disablePerDayIndex`{{% available_from "v1.112.0" %}}. This will improve the time series ingestion speed and decrease disk space usage,
since no time or disk space is spent maintaining the per-day index.
Example use cases:

View File

@@ -17,7 +17,7 @@ git remote add enterprise <url>
1. Make sure you have singing key configured
1. Make sure you have github token with at least `read:org, repo, write:packages` permissions exported under `GITHUB_TOKEN` env variable.
You can create token [here](https://github.com/settings/tokens)
1. Make sure you're [authorized](https://hub.docker.com/orgs/victoriametrics/settings/enforce-sign-in/windows) for pushing docker images
1. Make sure you're [authorized](https://hub.docker.com/orgs/victoriametrics/settings/enforce-sign-in/windows) for pushing docker images to `docker.io` and `quay.io`
### For MacOS users
@@ -69,12 +69,6 @@ Bumping the limits may significantly improve build speed.
* linux/ppc64le
* linux/386
This step can be run manually with the command `make publish` from the needed git tag.
1. Verify that created images are stable and don't introduce regressions on [test environment](https://github.com/VictoriaMetrics/VictoriaMetrics-enterprise/blob/master/Release-Guide.md#testing-releases).
1. Test new images on [sandbox](https://github.com/VictoriaMetrics/VictoriaMetrics-enterprise/blob/master/Release-Guide.md#testing-releases).
1. Push the tags `v1.xx.y` and `v1.xx.y-cluster` created at previous steps to public GitHub repository at https://github.com/VictoriaMetrics/VictoriaMetrics.
Push the tags `v1.xx.y`, `v1.xx.y-cluster`, `v1.xx.y-enterprise` and `v1.xx.y-enterprise-cluster` to the corresponding
branches in private repository.
**Important note:** do not push enterprise tags to public GitHub repository - they must be pushed only to private repository.
1. Run `TAG=v1.xx.y make github-create-release github-upload-assets`. This command performs the following tasks:
a) Create draft GitHub release with the name `TAG`. This step can be run manually
with the command `TAG=v1.xx.y make github-create-release`.
@@ -92,6 +86,13 @@ Bumping the limits may significantly improve build speed.
1. Go to <https://github.com/VictoriaMetrics/VictoriaMetrics/releases> and verify that draft release with the name `TAG` has been created
and this release contains all the needed binaries and checksums.
1. Update the release description with the content of [CHANGELOG](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/docs/changelog/CHANGELOG.md) for this release.
1. Follow the instructions in [LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics-enterprise/blob/master/Release-Guide.md#lts-release).
1. Verify that created images are stable and don't introduce regressions on [test environment](https://github.com/VictoriaMetrics/VictoriaMetrics-enterprise/blob/master/Release-Guide.md#testing-releases).
1. Test new images on [sandbox](https://github.com/VictoriaMetrics/VictoriaMetrics-enterprise/blob/master/Release-Guide.md#testing-releases).
1. Push the tags `v1.xx.y` and `v1.xx.y-cluster` created at previous steps to public GitHub repository at https://github.com/VictoriaMetrics/VictoriaMetrics.
Push the tags `v1.xx.y`, `v1.xx.y-cluster`, `v1.xx.y-enterprise` and `v1.xx.y-enterprise-cluster` to the corresponding
branches in private repository.
**Important note:** do not push enterprise tags to public GitHub repository - they must be pushed only to private repository.
1. Publish release by pressing "Publish release" green button in GitHub's UI.
1. Update GitHub tickets related to the new release. Usually, such tickets have label [waiting for release](https://github.com/VictoriaMetrics/VictoriaMetrics/issues?q=is%3Aopen+is%3Aissue+label%3A%22waiting+for+release%22). Close such tickets by mentioning which release they were included into, and remove the label. See example [here](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6637#issuecomment-2390729511).
1. Bump VictoriaMetrics version at `deployment/docker/docker-compose.yml` and at `deployment/docker/docker-compose-cluster.yml`.

View File

@@ -16,6 +16,30 @@ according to [these docs](https://docs.victoriametrics.com/victorialogs/quicksta
## tip
## [v1.15.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.15.0-victorialogs)
Released at 2025-02-27
* FEATURE: [`pack_json` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#pack_json-pipe): allow packing fields, which start with the given prefixes. For example, `pack_json fields (foo.*, bar.*)` creates a JSON containing all the fields, which start with either `foo.` or `bar.`.
* FEATURE: [`pack_logfmt` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#pack_logfmt-pipe): allow packing fields, which start with the given prefixes. For example, `pack_logfmt fields (foo.*, bar.*)` creates [logfmt](https://brandur.org/logfmt) message containing all the fields, which start with either `foo.` or `bar.`.
* FEATURE: expose `vl_http_request_duration_seconds` [summaries](https://docs.victoriametrics.com/keyconcepts/#summary) for [select APIs](https://docs.victoriametrics.com/victorialogs/querying/#http-api) at the [/metrics](https://docs.victoriametrics.com/victorialogs/#monitoring) page.
* FEATURE: allow passing `*` as a subquery inside [`in(*)`, `contains_any(*)` and `contains_all(*)` filters](https://docs.victoriametrics.com/victorialogs/logsql/#subquery-filter). Such filters are treated as `match all` aka `*`. This is going to be used by [Grafana plugin for VictoriaLogs](https://docs.victoriametrics.com/victorialogs/victorialogs-datasource/). See [this issue](https://github.com/VictoriaMetrics/victorialogs-datasource/issues/238#issuecomment-2685447673).
* FEATURE: [victorialogs dashboard](https://grafana.com/grafana/dashboards/22084-victorialogs/): add panels to display amount of ingested logs in bytes, latency of [select APIs](https://docs.victoriametrics.com/victorialogs/querying/#http-api) calls, troubleshooting panels.
* FEATURE: provide alternative registry for all VictoriaLogs components at [Quay.io](https://quay.io/organization/victoriametrics): [VictoriaLogs](https://quay.io/repository/victoriametrics/victoria-logs?tab=tags) and [vlogscli](https://quay.io/repository/victoriametrics/vlogscli?tab=tags).
* BUGFIX: do not treat a string containing leading zeros as a number during data ingestion and querying. For example, `00123` string shouldn't be treated as `123` number. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8361).
* BUGFIX: [data ingestion](https://docs.victoriametrics.com/victorialogs/data-ingestion/): Properly convert nested OpenTelemetry attributes into JSON. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8384).
## [v1.14.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.14.0-victorialogs)
Released at 2025-02-25
* FEATURE: add [`lt_field` filter](https://docs.victoriametrics.com/victorialogs/logsql/#lt_field-filter), which can be used for obtaining logs where the given [field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) value doesn't exceed the other field value.
* FEATURE: add [`le_field` filter](https://docs.victoriametrics.com/victorialogs/logsql/#le_field-filter), which can be used for obtaining logs where the given [field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) value is smaller or equal to the other field value.
* BUGFIX: [elasticsearch data ingestion](https://docs.victoriametrics.com/victorialogs/data-ingestion/#elasticsearch-bulk-api): support health-check endpoint requested by Jaeger v2. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8353).
* BUGFIX: [`stats_query_range` HTTP endpoint](https://docs.victoriametrics.com/victorialogs/querying/#querying-log-range-stats): fix inconsistent result of `stats_query_range` API. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8312).
## [v1.13.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.13.0-victorialogs)
Released at 2025-02-22

View File

@@ -91,8 +91,7 @@ VictoriaLogs is designed solely for logs. VictoriaLogs uses [similar design idea
VictoriaLogs provides easy to use query language with full-text search specifically optimized
for log analysis - [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/).
LogsQL is usually easier to use than SQL for typical log analysis tasks, while some
non-trivial analytics may require SQL power.
LogsQL is usually easier to use than SQL for typical log analysis tasks - see [these docs](https://docs.victoriametrics.com/victorialogs/sql-to-logsql/).
- VictoriaLogs accepts logs from popular log shippers out of the box - see [these docs](https://docs.victoriametrics.com/victorialogs/data-ingestion/).
@@ -141,28 +140,23 @@ for limiting the amounts of exported logs.
## I want to ingest logs without message field, is that possible?
Starting from version `v0.30.0`, VictoriaLogs started blocking the ingestion of logs **without a message field**, as it is a requirement of the [VictoriaLogs data model](https://docs.victoriametrics.com/victorialogs/keyconcepts/#message-field).
VictoriaLogs [accepts](https://docs.victoriametrics.com/victorialogs/data-ingestion/) logs without [`_msg` field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#message-field).
In this case the `_msg` field is set to the default value, which can be configured via `-defaultMsgValue` command-line flag.
However, some logs do not have a message field and only contain other fields, such as logs in [this comment](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7056#issuecomment-2434189718) and [this slack thread](https://victoriametrics.slack.com/archives/C05UNTPAEDN/p1730982146818249). Therefore, starting from version `v0.39.0`, logs without a message field are **allowed to be ingested**,
and their message field will be recorded as:
```json
{"_msg": "missing _msg field; see https://docs.victoriametrics.com/victorialogs/keyconcepts/#message-field"}
```
The default message field value can be changed using the `-defaultMsgValue` flag, for example, `-defaultMsgValue=foo`.
Please note that the message field is **crucial** for VictoriaLogs, so it is important to fill it with meaningful content.
Please note that the `_msg` field is **crucial** for VictoriaLogs, so it is highly recommended to fill it with meaningful content.
## What if my logs have multiple message fields candidates?
When ingesting with VictoriaLogs, the message fields is specified through `_msg_field` param, which can accept **multiple fields**, and the **first non-empty field** will be used as the message field.
Here is an example URL when pushing logs to VictoriaLogs with Promtail:
```yaml
clients:
- url: http://localhost:9428/insert/loki/api/v1/push?_stream_fields=instance,job,host,app&_msg=message,body
```
If you [ingest](https://docs.victoriametrics.com/victorialogs/data-ingestion/) logs into VictoriaLogs
without [`_msg` field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#message-field), then this field
is filled according to the `_msg_field` HTTP query arg and/or `VL-Msg-Field` HTTP header.
See [these docs](https://docs.victoriametrics.com/victorialogs/data-ingestion/#http-parameters) for details.
If the `_msg_field` HTTP query arg and/or `VL-Msg-Field` HTTP header contains a list of comma-separated field names,
then the first non-empty field from this list is used as `_msg` field.
For example, if the following [log entry](https://docs.victoriametrics.com/victorialogs/keyconcepts/)
is ingested into VictoriaLogs with `_msg_field=message,body`:
For the following log, its `_msg` will be `foo bar in message`:
```json
{
"message": "foo bar in message",
@@ -170,14 +164,18 @@ For the following log, its `_msg` will be `foo bar in message`:
}
```
And for the following log, its `_msg` will be `foo bar in body`:
Then `_msg` field is set to `foo bar in message`.
If the following log entry is ingested into VictoriaLogs with `_msg_field=message,body`:
```json
{
"message": "",
"body": "foo bar in body"
}
```
Then `_msg` field is set to `foo bar in body`.
## What length a log record is expected to have?
VictoriaLogs works optimally with log records of up to `10KB`. It works OK with
@@ -307,7 +305,7 @@ _time:1d | count_uniq(_stream)
## Does LogsQL support subqueries?
LogsQL supports subqieries via [`in(<subquery>)` filter](https://docs.victoriametrics.com/victorialogs/logsql/#multi-exact-filter).
Yes. See [these docs](https://docs.victoriametrics.com/victorialogs/logsql/#subquery-filter).
For example, the following query returns the total number of unique values for the `user_id` [field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model)
across top 3 [log streams](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) with the biggest number of logs during the last hour:
@@ -325,4 +323,27 @@ The query works in the following way:
- Then it selects all the logs across the selected log streams over the last hour with the help of [`_stream_id:...` filter](https://docs.victoriametrics.com/victorialogs/logsql/#_stream_id-filter).
See also [`subquery filters`](https://docs.victoriametrics.com/victorialogs/logsql/#subquery-filter).
## How to estimate the needed compute resources for the given workload?
The needed storage space depends on the following factors:
- Data compressibility. VictoraLogs compresses the ingested logs before storing them to disk. The compression ratio depends on the "randomness" of the ingested logs.
Less "random" logs with many repeated field values and small differences between log messages compress the best (up to 100x and more).
More "random" logs with many unique field values may have very low compression rate.
- [Data retention](https://docs.victoriametrics.com/victorialogs/#retention). For example, a year-long retention needs 52x more storage space than a week-long retention.
The needed RAM, CPU, storage IO and network bandwidth depends on the type and the rate of queries over the ingested logs.
- "Lightweight" queries over the recently ingested logs with very narrow [log stream filters](https://docs.victoriametrics.com/victorialogs/logsql/#stream-filter)
require very low compute resources, even if they are executed at 1000 rps.
- "Heavy" queries over the long time range, which do not contain [log stream filters](https://docs.victoriametrics.com/victorialogs/logsql/#stream-filter)
or have some heavy [pipe processing](https://docs.victoriametrics.com/victorialogs/logsql/#pipes) such as [analytics' calculations](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe)
or [sorting over billions of rows](https://docs.victoriametrics.com/victorialogs/logsql/#sort-pipe) may require hundreds of CPU cores and terabytes of RAM
for fast execution. It is OK to execute such queries on machines with a few CPU cores and a few GiB of RAM - these queries will take more time to execute.
The best approach to estimate the needed compute resources for the given workload is to start a VictoriaLogs, to ingest a share (1%-10%) of your production logs into it,
and to execute typical queries on it, while [measuring](https://docs.victoriametrics.com/victorialogs/#monitoring) the consumed compute resources.
Then you can extrapolate the needed compute resources for the full production workload in your case.

View File

@@ -277,6 +277,8 @@ The list of LogsQL filters:
- [Length range filter](#length-range-filter) - matches logs with [field values](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) of the given length range
- [Value type filter](#value_type-filter) - matches logs with [fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) stored under the given value type
- [Fields' equality filter](#eq_field-filter) - matches logs, which contain identical values in the given [fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model)
- [`Less than` filter](#lt_field-filter) - matches logs where the given field value is smaller than the other field value
- [`Less than or equal` filter](#le_field-filter) - matches logs where the given field value doesn't exceed the other field value
- [Logical filter](#logical-filter) - allows combining other filters
@@ -749,6 +751,8 @@ See also:
- [String range filter](#string-range-filter)
- [Range filter](#range-filter)
- [`le_field` filter](#le_field-filter)
- [`lt_field` filter](#lt_field-filter)
### Empty value filter
@@ -1365,6 +1369,48 @@ Quick tip: use `NOT user_id:eq_field(customer_id)` for finding logs where `user_
See also:
- [`exact` filter](#exact-filter)
- [`le_field` filter](#le_field-filter)
- [`lt_field` filter](#lt_field-filter)
### le_field filter
Sometimes it is needed to find logs where one [field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) value doesn't exceed the other field value.
This can be done with `field1:le_field(field2)` filter.
For example, the following query matches logs where `duration` [field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) doesn't exceed the `max_duration` field:
```logsql
duration:le_field(max_duration)
```
Quick tip: use `NOT duration:le_field(max_duration)` for finding logs where `duration` exceeds the `max_duration`.
See also:
- [range comparison filter](#range-comparison-filter)
- [`lt_field` filter](#lt_field-filter)
- [`eq_field` filter](#eq_field-filter)
### lt_field filter
Sometimes it is needed to find logs where one [field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) value is smaller than the other field value.
This can be done with `field1:lt_field(field2)` filter.
For example, the following query matches logs where `duration` [field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) is smaller than the `max_duration` field:
```logsql
duration:lt_field(max_duration)
```
Quick tip: use `NOT duration:lt_field(max_duration)` for finding logs where `duration` is bigger or equal to the `max_duration`.
See also:
- [range comparison filter](#range-comparison-filter)
- [`le_field` filter](#le_field-filter)
- [`eq_field` filter](#eq_field-filter)
### Logical filter
@@ -2391,6 +2437,13 @@ only and stores the result in `baz` field:
_time:5m | pack_json fields (foo, bar) as baz
```
It is possible to pass field prefixes into `fields (...)` in order to pack only the fields, which start with the given prefixes.
For example, the following query builds JSON with all the fields, which start with either `foo.` or `bar.`:
```logsql
_time:5m | pack_json fields (foo.*, bar.*) as baz
```
The `pack_json` doesn't modify or delete other labels. If you do not need them, then add [`| fields ...`](#fields-pipe) after the `pack_json` pipe. For example, the following query
leaves only the `foo` label with the original log fields packed into JSON:
@@ -2430,6 +2483,13 @@ For example, the following query builds [logfmt](https://brandur.org/logfmt) mes
_time:5m | pack_logfmt fields (foo, bar) as baz
```
It is possible to pass field prefixes into `fields (...)` in order to pack only the fields, which start with the given prefixes.
For example, the following query builds `logfmt` message with all the fields, which start with either `foo.` or `bar.`:
```logsql
_time:5m | pack_logfmt fields (foo.*, bar.*) as baz
```
The `pack_logfmt` doesn't modify or delete other labels. If you do not need them, then add [`| fields ...`](#fields-pipe) after the `pack_logfmt` pipe. For example, the following query
leaves only the `foo` label with the original log fields packed into [logfmt](https://brandur.org/logfmt):

View File

@@ -33,8 +33,8 @@ Just download archive for the needed Operating system and architecture, unpack i
For example, the following commands download VictoriaLogs archive for Linux/amd64, unpack and run it:
```sh
curl -L -O https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.13.0-victorialogs/victoria-logs-linux-amd64-v1.13.0-victorialogs.tar.gz
tar xzf victoria-logs-linux-amd64-v1.13.0-victorialogs.tar.gz
curl -L -O https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.15.0-victorialogs/victoria-logs-linux-amd64-v1.15.0-victorialogs.tar.gz
tar xzf victoria-logs-linux-amd64-v1.15.0-victorialogs.tar.gz
./victoria-logs-prod
```
@@ -58,7 +58,7 @@ Here is the command to run VictoriaLogs in a Docker container:
```sh
docker run --rm -it -p 9428:9428 -v ./victoria-logs-data:/victoria-logs-data \
docker.io/victoriametrics/victoria-logs:v1.13.0-victorialogs
docker.io/victoriametrics/victoria-logs:v1.15.0-victorialogs
```
See also:

View File

@@ -289,7 +289,10 @@ or similar authorization proxies.
## Benchmarks
See [the comparison of VictoriaLogs with Elasticsearch, MongoDB, TimescaleDB, PostgreSQL, MySQL and SQLite](https://benchmark.clickhouse.com/#eyJzeXN0ZW0iOnsiQWxsb3lEQiI6ZmFsc2UsIkFsbG95REIgKHR1bmVkKSI6ZmFsc2UsIkF0aGVuYSAocGFydGl0aW9uZWQpIjpmYWxzZSwiQXRoZW5hIChzaW5nbGUpIjpmYWxzZSwiQXVyb3JhIGZvciBNeVNRTCI6ZmFsc2UsIkF1cm9yYSBmb3IgUG9zdGdyZVNRTCI6ZmFsc2UsIkJ5Q29uaXR5IjpmYWxzZSwiQnl0ZUhvdXNlIjpmYWxzZSwiY2hEQiAoRGF0YUZyYW1lKSI6ZmFsc2UsImNoREIgKFBhcnF1ZXQsIHBhcnRpdGlvbmVkKSI6ZmFsc2UsImNoREIiOmZhbHNlLCJDaXR1cyI6ZmFsc2UsIkNsaWNrSG91c2UgQ2xvdWQgKGF3cykiOmZhbHNlLCJDbGlja0hvdXNlIENsb3VkIChhenVyZSkiOmZhbHNlLCJDbGlja0hvdXNlIENsb3VkIChnY3ApIjpmYWxzZSwiQ2xpY2tIb3VzZSAoZGF0YSBsYWtlLCBwYXJ0aXRpb25lZCkiOmZhbHNlLCJDbGlja0hvdXNlIChkYXRhIGxha2UsIHNpbmdsZSkiOmZhbHNlLCJDbGlja0hvdXNlIChQYXJxdWV0LCBwYXJ0aXRpb25lZCkiOmZhbHNlLCJDbGlja0hvdXNlIChQYXJxdWV0LCBzaW5nbGUpIjpmYWxzZSwiQ2xpY2tIb3VzZSAod2ViKSI6ZmFsc2UsIkNsaWNrSG91c2UiOmZhbHNlLCJDbGlja0hvdXNlICh0dW5lZCkiOmZhbHNlLCJDbGlja0hvdXNlICh0dW5lZCwgbWVtb3J5KSI6ZmFsc2UsIkNsb3VkYmVycnkiOmZhbHNlLCJDcmF0ZURCIjpmYWxzZSwiQ3J1bmNoeSBCcmlkZ2UgZm9yIEFuYWx5dGljcyAoUGFycXVldCkiOmZhbHNlLCJEYXRhYmVuZCI6ZmFsc2UsIkRhdGFGdXNpb24gKFBhcnF1ZXQsIHBhcnRpdGlvbmVkKSI6ZmFsc2UsIkRhdGFGdXNpb24gKFBhcnF1ZXQsIHNpbmdsZSkiOmZhbHNlLCJBcGFjaGUgRG9yaXMiOmZhbHNlLCJEcmlsbCI6ZmFsc2UsIkRydWlkIjpmYWxzZSwiRHVja0RCIChEYXRhRnJhbWUpIjpmYWxzZSwiRHVja0RCIChtZW1vcnkpIjpmYWxzZSwiRHVja0RCIChQYXJxdWV0LCBwYXJ0aXRpb25lZCkiOmZhbHNlLCJEdWNrREIiOmZhbHNlLCJFbGFzdGljc2VhcmNoIjp0cnVlLCJFbGFzdGljc2VhcmNoICh0dW5lZCkiOmZhbHNlLCJHbGFyZURCIjpmYWxzZSwiR3JlZW5wbHVtIjpmYWxzZSwiSGVhdnlBSSI6ZmFsc2UsIkh5ZHJhIjpmYWxzZSwiSW5mb2JyaWdodCI6ZmFsc2UsIktpbmV0aWNhIjpmYWxzZSwiTWFyaWFEQiBDb2x1bW5TdG9yZSI6ZmFsc2UsIk1hcmlhREIiOmZhbHNlLCJNb25ldERCIjpmYWxzZSwiTW9uZ29EQiI6dHJ1ZSwiTW90aGVyRHVjayI6ZmFsc2UsIk15U1FMIChNeUlTQU0pIjpmYWxzZSwiTXlTUUwiOnRydWUsIk9jdG9TUUwiOmZhbHNlLCJPeGxhIjpmYWxzZSwiUGFuZGFzIChEYXRhRnJhbWUpIjpmYWxzZSwiUGFyYWRlREIgKFBhcnF1ZXQsIHBhcnRpdGlvbmVkKSI6ZmFsc2UsIlBhcmFkZURCIChQYXJxdWV0LCBzaW5nbGUpIjpmYWxzZSwicGdfZHVja2RiIChNb3RoZXJEdWNrIGVuYWJsZWQpIjpmYWxzZSwicGdfZHVja2RiIjpmYWxzZSwiUGlub3QiOmZhbHNlLCJQb2xhcnMgKERhdGFGcmFtZSkiOmZhbHNlLCJQb2xhcnMgKFBhcnF1ZXQpIjpmYWxzZSwiUG9zdGdyZVNRTCAodHVuZWQpIjpmYWxzZSwiUG9zdGdyZVNRTCI6dHJ1ZSwiUXVlc3REQiI6ZmFsc2UsIlJlZHNoaWZ0IjpmYWxzZSwiU2VsZWN0REIiOmZhbHNlLCJTaW5nbGVTdG9yZSI6ZmFsc2UsIlNub3dmbGFrZSI6ZmFsc2UsIlNwYXJrIjpmYWxzZSwiU1FMaXRlIjp0cnVlLCJTdGFyUm9ja3MiOmZhbHNlLCJUYWJsZXNwYWNlIjpmYWxzZSwiVGVtYm8gT0xBUCAoY29sdW1uYXIpIjpmYWxzZSwiVGltZXNjYWxlIENsb3VkIjpmYWxzZSwiVGltZXNjYWxlREIgKG5vIGNvbHVtbnN0b3JlKSI6ZmFsc2UsIlRpbWVzY2FsZURCIjp0cnVlLCJUaW55YmlyZCAoRnJlZSBUcmlhbCkiOmZhbHNlLCJVbWJyYSI6ZmFsc2UsIlZpY3RvcmlhTG9ncyI6dHJ1ZX0sInR5cGUiOnsiQyI6dHJ1ZSwiY29sdW1uLW9yaWVudGVkIjp0cnVlLCJQb3N0Z3JlU1FMIGNvbXBhdGlibGUiOnRydWUsIm1hbmFnZWQiOnRydWUsImdjcCI6dHJ1ZSwic3RhdGVsZXNzIjp0cnVlLCJKYXZhIjp0cnVlLCJDKysiOnRydWUsIk15U1FMIGNvbXBhdGlibGUiOnRydWUsInJvdy1vcmllbnRlZCI6dHJ1ZSwiQ2xpY2tIb3VzZSBkZXJpdmF0aXZlIjp0cnVlLCJlbWJlZGRlZCI6dHJ1ZSwic2VydmVybGVzcyI6dHJ1ZSwiZGF0YWZyYW1lIjp0cnVlLCJhd3MiOnRydWUsImF6dXJlIjp0cnVlLCJhbmFseXRpY2FsIjp0cnVlLCJSdXN0Ijp0cnVlLCJzZWFyY2giOnRydWUsImRvY3VtZW50Ijp0cnVlLCJHbyI6dHJ1ZSwic29tZXdoYXQgUG9zdGdyZVNRTCBjb21wYXRpYmxlIjp0cnVlLCJEYXRhRnJhbWUiOnRydWUsInBhcnF1ZXQiOnRydWUsInRpbWUtc2VyaWVzIjp0cnVlfSwibWFjaGluZSI6eyIxNiB2Q1BVIDEyOEdCIjpmYWxzZSwiOCB2Q1BVIDY0R0IiOmZhbHNlLCJzZXJ2ZXJsZXNzIjpmYWxzZSwiMTZhY3UiOmZhbHNlLCJjNmEuNHhsYXJnZSwgNTAwZ2IgZ3AyIjp0cnVlLCJMIjpmYWxzZSwiTSI6ZmFsc2UsIlMiOmZhbHNlLCJYUyI6ZmFsc2UsImM2YS5tZXRhbCwgNTAwZ2IgZ3AyIjpmYWxzZSwiMTkyR0IiOmZhbHNlLCIyNEdCIjpmYWxzZSwiMzYwR0IiOmZhbHNlLCI0OEdCIjpmYWxzZSwiNzIwR0IiOmZhbHNlLCI5NkdCIjpmYWxzZSwiZGV2IjpmYWxzZSwiNzA4R0IiOmZhbHNlLCJjNW4uNHhsYXJnZSwgNTAwZ2IgZ3AyIjpmYWxzZSwiQW5hbHl0aWNzLTI1NkdCICg2NCB2Q29yZXMsIDI1NiBHQikiOmZhbHNlLCJjNS40eGxhcmdlLCA1MDBnYiBncDIiOmZhbHNlLCJjNmEuNHhsYXJnZSwgMTUwMGdiIGdwMiI6dHJ1ZSwiY2xvdWQiOmZhbHNlLCJkYzIuOHhsYXJnZSI6ZmFsc2UsInJhMy4xNnhsYXJnZSI6ZmFsc2UsInJhMy40eGxhcmdlIjpmYWxzZSwicmEzLnhscGx1cyI6ZmFsc2UsIlMyIjpmYWxzZSwiUzI0IjpmYWxzZSwiMlhMIjpmYWxzZSwiM1hMIjpmYWxzZSwiNFhMIjpmYWxzZSwiWEwiOmZhbHNlLCJMMSAtIDE2Q1BVIDMyR0IiOmZhbHNlLCJjNmEuNHhsYXJnZSwgNTAwZ2IgZ3AzIjpmYWxzZSwiMTYgdkNQVSA2NEdCIjpmYWxzZSwiNCB2Q1BVIDE2R0IiOmZhbHNlLCI4IHZDUFUgMzJHQiI6ZmFsc2V9LCJjbHVzdGVyX3NpemUiOnsiMSI6dHJ1ZSwiMiI6ZmFsc2UsIjQiOmZhbHNlLCI4IjpmYWxzZSwiMTYiOmZhbHNlLCIzMiI6ZmFsc2UsIjY0IjpmYWxzZSwiMTI4IjpmYWxzZSwic2VydmVybGVzcyI6ZmFsc2UsInVuZGVmaW5lZCI6ZmFsc2V9LCJtZXRyaWMiOiJob3QiLCJxdWVyaWVzIjpbdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZV19).
See the following benchmark results:
- [JSONBench: the comparison of VictoriaLogs with Elasticsearch, MongoDB, DuckDB and PostgreSQL](https://jsonbench.com/#eyJzeXN0ZW0iOnsiQ2xpY2tIb3VzZSAobHo0KSI6ZmFsc2UsIkNsaWNrSG91c2UgKHpzdGQpIjpmYWxzZSwiRHVja0RCIjp0cnVlLCJFbGFzdGljc2VhcmNoIChubyBzb3VyY2UsIGJlc3QgY29tcHJlc3Npb24pIjpmYWxzZSwiRWxhc3RpY3NlYXJjaCAobm8gc291cmNlLCBkZWZhdWx0KSI6ZmFsc2UsIkVsYXN0aWNzZWFyY2ggKGJlc3QgY29tcHJlc3Npb24pIjpmYWxzZSwiRWxhc3RpY3NlYXJjaCAoZGVmYXVsdCkiOnRydWUsIkVsYXN0aWNzZWFyY2giOmZhbHNlLCJNb25nb0RCIChzbmFwcHksIGNvdmVyZWQgaW5kZXgpIjpmYWxzZSwiTW9uZ29EQiAoenN0ZCwgY292ZXJlZCBpbmRleCkiOmZhbHNlLCJNb25nb0RCIChzbmFwcHkpIjpmYWxzZSwiTW9uZ29EQiAoenN0ZCkiOnRydWUsIlBvc3RncmVTUUwgKGx6NCkiOnRydWUsIlBvc3RncmVTUUwgKHBnbHopIjpmYWxzZSwiVmljdG9yaWFMb2dzIjp0cnVlfSwic2NhbGUiOjEwMDAwMDAwMDAsIm1ldHJpYyI6ImhvdCIsInF1ZXJpZXMiOlt0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWVdfQ==). The benchmark can be reproduced by running `main.sh` file inside `victorialogs` directory of the [JSONBench repository](https://github.com/ClickHouse/JSONBench).
- [ClickBench: the comparison of VictoriaLogs with Elasticsearch, MongoDB, TimescaleDB, PostgreSQL, MySQL and SQLite](https://benchmark.clickhouse.com/#eyJzeXN0ZW0iOnsiQWxsb3lEQiI6ZmFsc2UsIkFsbG95REIgKHR1bmVkKSI6ZmFsc2UsIkF0aGVuYSAocGFydGl0aW9uZWQpIjpmYWxzZSwiQXRoZW5hIChzaW5nbGUpIjpmYWxzZSwiQXVyb3JhIGZvciBNeVNRTCI6ZmFsc2UsIkF1cm9yYSBmb3IgUG9zdGdyZVNRTCI6ZmFsc2UsIkJ5Q29uaXR5IjpmYWxzZSwiQnl0ZUhvdXNlIjpmYWxzZSwiY2hEQiAoRGF0YUZyYW1lKSI6ZmFsc2UsImNoREIgKFBhcnF1ZXQsIHBhcnRpdGlvbmVkKSI6ZmFsc2UsImNoREIiOmZhbHNlLCJDaXR1cyI6ZmFsc2UsIkNsaWNrSG91c2UgQ2xvdWQgKGF3cykiOmZhbHNlLCJDbGlja0hvdXNlIENsb3VkIChhenVyZSkiOmZhbHNlLCJDbGlja0hvdXNlIENsb3VkIChnY3ApIjpmYWxzZSwiQ2xpY2tIb3VzZSAoZGF0YSBsYWtlLCBwYXJ0aXRpb25lZCkiOmZhbHNlLCJDbGlja0hvdXNlIChkYXRhIGxha2UsIHNpbmdsZSkiOmZhbHNlLCJDbGlja0hvdXNlIChQYXJxdWV0LCBwYXJ0aXRpb25lZCkiOmZhbHNlLCJDbGlja0hvdXNlIChQYXJxdWV0LCBzaW5nbGUpIjpmYWxzZSwiQ2xpY2tIb3VzZSAod2ViKSI6ZmFsc2UsIkNsaWNrSG91c2UiOmZhbHNlLCJDbGlja0hvdXNlICh0dW5lZCkiOmZhbHNlLCJDbGlja0hvdXNlICh0dW5lZCwgbWVtb3J5KSI6ZmFsc2UsIkNsb3VkYmVycnkiOmZhbHNlLCJDcmF0ZURCIjpmYWxzZSwiQ3J1bmNoeSBCcmlkZ2UgZm9yIEFuYWx5dGljcyAoUGFycXVldCkiOmZhbHNlLCJEYXRhYmVuZCI6ZmFsc2UsIkRhdGFGdXNpb24gKFBhcnF1ZXQsIHBhcnRpdGlvbmVkKSI6ZmFsc2UsIkRhdGFGdXNpb24gKFBhcnF1ZXQsIHNpbmdsZSkiOmZhbHNlLCJBcGFjaGUgRG9yaXMiOmZhbHNlLCJEcmlsbCI6ZmFsc2UsIkRydWlkIjpmYWxzZSwiRHVja0RCIChEYXRhRnJhbWUpIjpmYWxzZSwiRHVja0RCIChtZW1vcnkpIjpmYWxzZSwiRHVja0RCIChQYXJxdWV0LCBwYXJ0aXRpb25lZCkiOmZhbHNlLCJEdWNrREIiOmZhbHNlLCJFbGFzdGljc2VhcmNoIjp0cnVlLCJFbGFzdGljc2VhcmNoICh0dW5lZCkiOmZhbHNlLCJHbGFyZURCIjpmYWxzZSwiR3JlZW5wbHVtIjpmYWxzZSwiSGVhdnlBSSI6ZmFsc2UsIkh5ZHJhIjpmYWxzZSwiSW5mb2JyaWdodCI6ZmFsc2UsIktpbmV0aWNhIjpmYWxzZSwiTWFyaWFEQiBDb2x1bW5TdG9yZSI6ZmFsc2UsIk1hcmlhREIiOmZhbHNlLCJNb25ldERCIjpmYWxzZSwiTW9uZ29EQiI6dHJ1ZSwiTW90aGVyRHVjayI6ZmFsc2UsIk15U1FMIChNeUlTQU0pIjpmYWxzZSwiTXlTUUwiOnRydWUsIk9jdG9TUUwiOmZhbHNlLCJPeGxhIjpmYWxzZSwiUGFuZGFzIChEYXRhRnJhbWUpIjpmYWxzZSwiUGFyYWRlREIgKFBhcnF1ZXQsIHBhcnRpdGlvbmVkKSI6ZmFsc2UsIlBhcmFkZURCIChQYXJxdWV0LCBzaW5nbGUpIjpmYWxzZSwicGdfZHVja2RiIChNb3RoZXJEdWNrIGVuYWJsZWQpIjpmYWxzZSwicGdfZHVja2RiIjpmYWxzZSwiUGlub3QiOmZhbHNlLCJQb2xhcnMgKERhdGFGcmFtZSkiOmZhbHNlLCJQb2xhcnMgKFBhcnF1ZXQpIjpmYWxzZSwiUG9zdGdyZVNRTCAodHVuZWQpIjpmYWxzZSwiUG9zdGdyZVNRTCI6dHJ1ZSwiUXVlc3REQiI6ZmFsc2UsIlJlZHNoaWZ0IjpmYWxzZSwiU2VsZWN0REIiOmZhbHNlLCJTaW5nbGVTdG9yZSI6ZmFsc2UsIlNub3dmbGFrZSI6ZmFsc2UsIlNwYXJrIjpmYWxzZSwiU1FMaXRlIjp0cnVlLCJTdGFyUm9ja3MiOmZhbHNlLCJUYWJsZXNwYWNlIjpmYWxzZSwiVGVtYm8gT0xBUCAoY29sdW1uYXIpIjpmYWxzZSwiVGltZXNjYWxlIENsb3VkIjpmYWxzZSwiVGltZXNjYWxlREIgKG5vIGNvbHVtbnN0b3JlKSI6ZmFsc2UsIlRpbWVzY2FsZURCIjp0cnVlLCJUaW55YmlyZCAoRnJlZSBUcmlhbCkiOmZhbHNlLCJVbWJyYSI6ZmFsc2UsIlZpY3RvcmlhTG9ncyI6dHJ1ZX0sInR5cGUiOnsiQyI6dHJ1ZSwiY29sdW1uLW9yaWVudGVkIjp0cnVlLCJQb3N0Z3JlU1FMIGNvbXBhdGlibGUiOnRydWUsIm1hbmFnZWQiOnRydWUsImdjcCI6dHJ1ZSwic3RhdGVsZXNzIjp0cnVlLCJKYXZhIjp0cnVlLCJDKysiOnRydWUsIk15U1FMIGNvbXBhdGlibGUiOnRydWUsInJvdy1vcmllbnRlZCI6dHJ1ZSwiQ2xpY2tIb3VzZSBkZXJpdmF0aXZlIjp0cnVlLCJlbWJlZGRlZCI6dHJ1ZSwic2VydmVybGVzcyI6dHJ1ZSwiZGF0YWZyYW1lIjp0cnVlLCJhd3MiOnRydWUsImF6dXJlIjp0cnVlLCJhbmFseXRpY2FsIjp0cnVlLCJSdXN0Ijp0cnVlLCJzZWFyY2giOnRydWUsImRvY3VtZW50Ijp0cnVlLCJHbyI6dHJ1ZSwic29tZXdoYXQgUG9zdGdyZVNRTCBjb21wYXRpYmxlIjp0cnVlLCJEYXRhRnJhbWUiOnRydWUsInBhcnF1ZXQiOnRydWUsInRpbWUtc2VyaWVzIjp0cnVlfSwibWFjaGluZSI6eyIxNiB2Q1BVIDEyOEdCIjpmYWxzZSwiOCB2Q1BVIDY0R0IiOmZhbHNlLCJzZXJ2ZXJsZXNzIjpmYWxzZSwiMTZhY3UiOmZhbHNlLCJjNmEuNHhsYXJnZSwgNTAwZ2IgZ3AyIjp0cnVlLCJMIjpmYWxzZSwiTSI6ZmFsc2UsIlMiOmZhbHNlLCJYUyI6ZmFsc2UsImM2YS5tZXRhbCwgNTAwZ2IgZ3AyIjpmYWxzZSwiMTkyR0IiOmZhbHNlLCIyNEdCIjpmYWxzZSwiMzYwR0IiOmZhbHNlLCI0OEdCIjpmYWxzZSwiNzIwR0IiOmZhbHNlLCI5NkdCIjpmYWxzZSwiZGV2IjpmYWxzZSwiNzA4R0IiOmZhbHNlLCJjNW4uNHhsYXJnZSwgNTAwZ2IgZ3AyIjpmYWxzZSwiQW5hbHl0aWNzLTI1NkdCICg2NCB2Q29yZXMsIDI1NiBHQikiOmZhbHNlLCJjNS40eGxhcmdlLCA1MDBnYiBncDIiOmZhbHNlLCJjNmEuNHhsYXJnZSwgMTUwMGdiIGdwMiI6dHJ1ZSwiY2xvdWQiOmZhbHNlLCJkYzIuOHhsYXJnZSI6ZmFsc2UsInJhMy4xNnhsYXJnZSI6ZmFsc2UsInJhMy40eGxhcmdlIjpmYWxzZSwicmEzLnhscGx1cyI6ZmFsc2UsIlMyIjpmYWxzZSwiUzI0IjpmYWxzZSwiMlhMIjpmYWxzZSwiM1hMIjpmYWxzZSwiNFhMIjpmYWxzZSwiWEwiOmZhbHNlLCJMMSAtIDE2Q1BVIDMyR0IiOmZhbHNlLCJjNmEuNHhsYXJnZSwgNTAwZ2IgZ3AzIjpmYWxzZSwiMTYgdkNQVSA2NEdCIjpmYWxzZSwiNCB2Q1BVIDE2R0IiOmZhbHNlLCI4IHZDUFUgMzJHQiI6ZmFsc2V9LCJjbHVzdGVyX3NpemUiOnsiMSI6dHJ1ZSwiMiI6ZmFsc2UsIjQiOmZhbHNlLCI4IjpmYWxzZSwiMTYiOmZhbHNlLCIzMiI6ZmFsc2UsIjY0IjpmYWxzZSwiMTI4IjpmYWxzZSwic2VydmVybGVzcyI6ZmFsc2UsInVuZGVmaW5lZCI6ZmFsc2V9LCJtZXRyaWMiOiJob3QiLCJxdWVyaWVzIjpbdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZV19). The benchmark can be reproduced by running `benchmark.sh` file inside `victorialogs` directory of the [ClickBench repository](https://github.com/ClickHouse/ClickBench/).
Here is a [benchmark suite](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/logs-benchmark) for comparing data ingestion performance
and resource usage between VictoriaLogs and Elasticsearch or Loki.

View File

@@ -18,13 +18,13 @@ It has the following features:
- It supports live tailing - see [these docs](#live-tailing).
This tool can be obtained from the linked release pages at the [changelog](https://docs.victoriametrics.com/victorialogs/changelog/)
or from [docker images](https://hub.docker.com/r/victoriametrics/vlogscli/tags).
or from docker images at [Docker Hub](https://hub.docker.com/r/victoriametrics/vlogscli/tags) and [Quay](https://quay.io/repository/victoriametrics/vlogscli?tab=tags).
### Running `vlogscli` from release binary
```sh
curl -L -O https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.13.0-victorialogs/vlogscli-linux-amd64-v1.13.0-victorialogs.tar.gz
tar xzf vlogscli-linux-amd64-v1.13.0-victorialogs.tar.gz
curl -L -O https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.15.0-victorialogs/vlogscli-linux-amd64-v1.15.0-victorialogs.tar.gz
tar xzf vlogscli-linux-amd64-v1.15.0-victorialogs.tar.gz
./vlogscli-prod
```

View File

@@ -21,14 +21,16 @@ _Note: This page provides only integration instructions for vmalert and Victoria
Run vmalert with the following settings:
```sh
./bin/vmalert -rule=alert.rules \ # Path to the files or http url with alerting and/or recording rules in YAML format.
-datasource.url=http://localhost:9428 \ # VictoriaLogs address.
-notifier.url=http://localhost:9093 \ # AlertManager URL (required if alerting rules are used)
-remoteWrite.url=http://localhost:8428 \ # Remote write compatible storage to persist rules and alerts state info (required for recording rules)
-remoteRead.url=http://localhost:8428 \ # Prometheus HTTP API compatible datasource to restore alerts state from
./bin/vmalert -rule=alert.rules \ # Path to the files or http url with alerting and/or recording rules in YAML format.
-datasource.url=http://victorialogs:9428 \ # VictoriaLogs address.
-notifier.url=http://alertmanager:9093 \ # AlertManager URL (required if alerting rules are used)
-remoteWrite.url=http://victoriametrics:8428 \ # Remote write compatible storage to persist recording rules and alerts state info
-remoteRead.url=http://victoriametrics:8428 \ # Prometheus HTTP API compatible datasource to restore alerts state from
```
> Note: By default, vmalert assumes configured rules have `prometheus` type and will validate them accordingly. For rules in [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/) specify `type: vlogs` on [Group level](#groups). Or set `-rule.defaultRuleType=vlogs` cmd-line flag to automatically apply `type: vlogs` to all groups.
> Note: By default, vmalert assumes all configured rules have `prometheus` type and will validate them accordingly.
> For rules in [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/) specify `type: vlogs` on [Group level](#groups).
> Or set `-rule.defaultRuleType=vlogs` cmd-line flag to apply `type: vlogs` to all configured groups.
Each `-rule` file may contain arbitrary number of [groups](https://docs.victoriametrics.com/vmalert/#groups).
See examples in [Groups](#groups) section. See the full list of configuration flags and their descriptions in [configuration](#configuration) section.
@@ -37,9 +39,11 @@ With configuration example above, vmalert will perform the following interaction
![vmalert](vmalert_victorialogs.webp)
1. Rules listed in `-rule` file are executed against VictoriaLogs service configured via `-datasource.url`;
2. Triggered alerting notifications are sent to [Alertmanager](https://github.com/prometheus/alertmanager) service configured via `-notifier.url`;
3. Results of recording rules expressions and alerts state are persisted to Prometheus-compatible remote-write endpoint (i.e. VictoriaMetrics) configured via `-remoteWrite.url`;
4. On vmalert restarts, alerts state [can be restored](https://docs.victoriametrics.com/vmalert/#alerts-state-on-restarts) by querying Prometheus-compatible HTTP API endpoint (i.e. VictoriaMetrics) configured via `-remoteRead.url`.
1. Triggered alerting notifications are sent to [Alertmanager](https://github.com/prometheus/alertmanager) service configured via `-notifier.url`;
1. Results of recording rules expressions and alerts state are persisted to Prometheus-compatible remote-write endpoint
(i.e. VictoriaMetrics) configured via `-remoteWrite.url`;
1. On vmalert restarts, alerts state [can be restored](https://docs.victoriametrics.com/vmalert/#alerts-state-on-restarts)
by querying Prometheus-compatible HTTP API endpoint (i.e. VictoriaMetrics) configured via `-remoteRead.url`.
## Configuration
@@ -82,7 +86,7 @@ The following are key flags related to integration with VictoriaLogs:
Since there is no intentional search delay in VictoriaLogs, `-rule.evalDelay` can be reduced to a few seconds to accommodate network and ingestion time.
```
For more configuration options, such as `notifiers`, visit https://docs.victoriametrics.com/vmalert/#configuration.
See full list of configuration options [here](https://docs.victoriametrics.com/vmalert/#configuration).
### Groups
@@ -148,7 +152,7 @@ groups:
description: "Connection from address {{$labels.ip}} has {{$value}}% failed requests in last 5 minutes"
```
User can also specify a customized time filter if needed. For example, rule below will be evaluated every 5 minutes,
User can specify a customized time filter if needed. For example, rule below will be evaluated every 5 minutes,
but will calculate result over the logs from the last 10 minutes.
```yaml
groups:
@@ -162,7 +166,7 @@ groups:
description: "Connection from address {{$labels.ip}} has {{$value}}% failed requests in last 10 minutes"
```
Please note, vmalert doesn't support [backfilling](#rules-backfilling) for rules with a customized time filter now. (Might be added in future)
_Please note, vmalert doesn't support [backfilling](#rules-backfilling) for rules with a customized time filter now. (Might be added in future)._
## Rules backfilling
@@ -180,8 +184,8 @@ See more details about backfilling [here](https://docs.victoriametrics.com/vmale
## Performance tip
LogsQL allows users to obtain multiple stats from a single expression.
For instance, the following query calculates 50th, 90th and 99th percentiles for the `request_duration_seconds` field over logs for the last 5 minutes:
LogsQL allows users to obtain multiple stats from a single expression. For instance, the following query calculates
50th, 90th and 99th percentiles for the `request_duration_seconds` field over logs for the last 5 minutes:
```logsql
_time:5m | stats
@@ -198,8 +202,9 @@ groups:
interval: 5m
rules:
- record: requestDurationQuantile
expr: '_time:5m | stats by (service) quantile(0.5, request_duration_seconds) p50, quantile(0.9, request_duration_seconds) p90, quantile(0.99, request_duration_seconds) p99'
expr: '* | stats by (service) quantile(0.5, request_duration_seconds) p50, quantile(0.9, request_duration_seconds) p90, quantile(0.99, request_duration_seconds) p99'
```
This creates three metrics for each service:
```
requestDurationQuantile{stats_result="p50", service="service-1"}
@@ -217,6 +222,7 @@ For additional tips on writing LogsQL, refer to this [doc](https://docs.victoria
## Frequently Asked Questions
### How to use [multitenancy](https://docs.victoriametrics.com/victorialogs/#multitenancy) in rules?
vmalert doesn't support multi-tenancy for VictoriaLogs in the same way as it [supports it for VictoriaMetrics in ENT version](https://docs.victoriametrics.com/vmalert/#multitenancy).
However, it is possible to specify the queried tenant from VictoriaLogs datasource via `headers` param in [Group config](https://docs.victoriametrics.com/vmalert/#groups).
For example, the following config will execute all the rules within the group against tenant with `AccountID=1` and `ProjectID=2`:
@@ -288,10 +294,12 @@ To persist different rule results to different tenants in VictoriaMetrics, there
```
### How to use one vmalert for VictoriaLogs and VictoriaMetrics rules in the same time?
We recommend running separate instances of vmalert for VictoriaMetrics and VictoriaLogs.
However, vmalert allows having many groups with different rule types (`vlogs`, `prometheus`, `graphite`).
But only one `-datasource.url` cmd-line flag can be specified, so it can't be configured with more than 1 datasource.
However, VictoriaMetrics and VictoriaLogs datasources have different query path prefixes, and it is possible to use [vmauth](https://docs.victoriametrics.com/vmauth/) to route requests of different types between datasources.
VictoriaMetrics and VictoriaLogs datasources have different query path prefixes, so it is possible to use
[vmauth](https://docs.victoriametrics.com/vmauth/) to route requests of different types between datasources.
See example of vmauth config for such routing below:
```yaml
unauthorized_user:
@@ -303,4 +311,5 @@ See example of vmauth config for such routing below:
- "/select/logsql/.*"
url_prefix: "http://victorialogs:9428"
```
Now, vmalert needs to be configured with `--datasource.url=http://vmauth:8427/` to send queries to vmauth, and vmauth will route them to the specified destinations as in configuration example above.
Now, vmalert can be configured with `--datasource.url=http://vmauth:8427/` to send queries to vmauth,
and vmauth will route them to the specified destinations as in configuration example above.

View File

@@ -11,6 +11,15 @@ aliases:
---
Please find the changelog for VictoriaMetrics Anomaly Detection below.
## v1.20.0
Released: 2025-03-03
- FEATURE: The `scale` argument is now a [common argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#scale), previously supported only by [`ProphetModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet) and [`OnlineQuantileModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#online-seasonal-quantile). Additionally, `scale` is now **two-sided**, represented as `[scale_lb, scale_ub]`. The previous format (`scale: x`) remains supported and will be automatically converted to `scale: [x, x]`.
- FEATURE: Introduced a post-processing step to clip `yhat`, `yhat_lower`, and `yhat_upper` to the configured `data_range` [values](https://docs.victoriametrics.com/anomaly-detection/components/reader/?highlight=data_range#config-parameters) in `VmReader`, if defined. This feature is disabled by default for backward compatibility. It can be enabled for models that generate predictions and estimates, such as [`ProphetModel`](https://docs.victoriametrics.com/anomaly-detection/components/models/#prophet), by setting the [common argument](https://docs.victoriametrics.com/anomaly-detection/components/models/#clip-predictions) `clip_predictions` to `True`.
- IMPROVEMENT: Introduced the `anomaly_score_outside_data_range` [parameter](https://docs.victoriametrics.com/anomaly-detection/components/models/#score-outside-data-range) to allow overriding the default anomaly score (`1.01`) assigned when input values (`y`) fall outside the defined `data_range` (data domain violation). It improves flexibility for alerting rules and enables clearer visual distinction between different anomaly scenarios. Override can be configured at the **service level** (`settings`) or per **model instance** (`models.model_xxx`), with model-level values taking priority. If not explicitly set, the default anomaly score remains `1.01` for backward compatibility.
## v1.19.2
Released: 2025-01-27

View File

@@ -93,16 +93,74 @@ To visualize and interact with both [self-monitoring metrics](https://docs.victo
## Choosing the right model for vmanomaly
Selecting the best model for `vmanomaly` depends on the data's nature and the [types of anomalies](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-2/#categories-of-anomalies) to detect. For instance, [Z-score](https://docs.victoriametrics.com/anomaly-detection/components/models#z-score) is suitable for data without trends or seasonality, while more complex patterns might require models like [Prophet](https://docs.victoriametrics.com/anomaly-detection/components/models#prophet).
Selecting the best model for `vmanomaly` depends on the data's nature and the [types of anomalies](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-2/#categories-of-anomalies) to detect. For instance, [Z-score](https://docs.victoriametrics.com/anomaly-detection/components/models#online-z-score) is suitable for data without trends or seasonality, while more complex patterns might require models like [Prophet](https://docs.victoriametrics.com/anomaly-detection/components/models#prophet).
Also, it's possible to auto-tune the most important params of selected model class {{% available_from "v1.12.0" anomaly %}}, find [the details here](https://docs.victoriametrics.com/anomaly-detection/components/models#autotuned).
Also, there is an option to auto-tune the most important (hyper)parameters of selected model class {{% available_from "v1.12.0" anomaly %}}, find [the details here](https://docs.victoriametrics.com/anomaly-detection/components/models#autotuned).
Please refer to [respective blogpost on anomaly types and alerting heuristics](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-2/) for more details.
Still not 100% sure what to use? We are [here to help](https://docs.victoriametrics.com/anomaly-detection/#get-in-touch).
## Incorporating domain knowledge
Anomaly detection models can significantly improve when incorporating business-specific assumptions about the data and what constitutes an anomaly. `vmanomaly` supports various [business-side configuration parameters](https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args) across all built-in models to **reduce [false positives](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-1/#false-positive)** and **align model behavior with business needs**, for example:
- **Setting `detection_direction`** use [`detection_direction`](https://docs.victoriametrics.com/anomaly-detection/components/models/#detection-direction) to specify whether anomalies occur **above or below expectations**:
- Set to `above_expected` for metrics like error rates, where spikes indicate anomalies.
- Set to `below_expected` for metrics like customer satisfaction scores or SLAs, where drops indicate anomalies.
- **Defining a `data_range`** configure [`data_range`](https://docs.victoriametrics.com/anomaly-detection/components/reader/?highlight=data_range#config-parameters) for the models input query to **automatically assign anomaly scores > 1** for values (`y`) that fall outside the defined range.
- **Filtering minor fluctuations with `min_dev_from_expected`** use [`min_dev_from_expected`](https://docs.victoriametrics.com/anomaly-detection/components/models/#minimal-deviation-from-expected) to **ignore insignificant deviations** and prevent small fluctuations from triggering [false positives](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-1/#false-positive).
- **Applying `scale` for asymmetric confidence adjustments** use [`scale`](https://docs.victoriametrics.com/anomaly-detection/components/models/#scale) to adjust confidence intervals **differently for spikes and drops**, ensuring more appropriate anomaly detection.
**Example:**
Consider a metric tracking the percentage of HTTP 4xx status codes for a specific endpoint. Hypothetical business expectations for anomaly detection may be defined as follows:
- **Expected data range**: The percentage naturally falls between `0%` and `100%` (`[0, 1]`).
- **Threshold-based anomaly detection**: If the error rate exceeds `5%`, it should be **automatically flagged as an anomaly** ([anomaly score](#what-is-anomaly-score) > 1), encouraging an incident investigation.
- **Regime shift detection**: A **continuous increase** in error rates (e.g., from `1.5%` to `3%`) should also be considered **anomalous**, as regime change may indicate underlying system problem, e.g. with a new release.
- **Avoiding false positives**: **Small, infrequent deviations** (e.g., from `1%` to `1.3%`) should **not** trigger alerts to **prevent unnecessary SRE escalations**. Let it be on the level of 0.5%.
Then, the following config may be used to benefit from incorporating domain knowledge into model behavior:
```yaml
# other sections, like writer, monitoring ...
schedulers:
periodic_http:
class: periodic
fit_every: 12w
fit_window: 1w
infer_every: 1m
# other schedulers ...
reader:
# other reader args, like datasource_url, tenant_id ...
queries:
percentage_4xx:
expr: respective_metricsQL_expr
data_range: [0, 0.05] # to automatically trigger anomaly score > 1 for error rates > 5%
step: 1m
models:
# other models ...
zscore: # let it be online Z-score, for simplicity
class: zscore_online # online model update itself each infer call, resulting in resource-efficient setups
z_threshold: 3.0
schedulers: ['periodic_http']
queries: ['percentage_4xx']
detection_direction: 'above_expected' # as interested only in spikes, drops are OK
min_dev_from_expected: 0.005 # <0.5% deviations vs expected values should be neglected, generating anomaly score == 0
# to align predictions to be within [0, 5%] interval, defined in reader.queries.percentage_4xx.data_range
clip_predictions: True
# specify output series produced by vmanomaly to be written to VictoriaMetrics in `writer`
provide_series: ['anomaly_score', 'y', 'yhat', 'yhat_lower', 'yhat_upper']
```
## Alert generation in vmanomaly
While `vmanomaly` detects anomalies and produces scores, it *does not directly generate alerts*. The anomaly scores are written back to VictoriaMetrics, where an external alerting tool, like [`vmalert`](https://docs.victoriametrics.com/vmalert), can be used to create alerts based on these scores for integrating it with your alerting management system.
While `vmanomaly` detects anomalies and produces scores, it *does not directly generate alerts*. The anomaly scores are written back to VictoriaMetrics, where respective alerting tool, like [`vmalert`](https://docs.victoriametrics.com/vmalert), can be used to create alerts based on these scores for integrating it with your alerting management system. See an example diagram of how `vmanomaly` integrates into observability pipeline for anomaly detection on `node_exporter` metrics:
<img src="https://docs.victoriametrics.com/anomaly-detection/guides/guide-vmanomaly-vmalert/guide-vmanomaly-vmalert_overview.webp" alt="node_exporter_example_diagram" style="width:60%"/>
## Preventing alert fatigue
Produced anomaly scores are designed in such a way that values from 0.0 to 1.0 indicate non-anomalous data, while a value greater than 1.0 is generally classified as an anomaly. However, there are no perfect models for anomaly detection, that's why reasonable defaults expressions like `anomaly_score > 1` may not work 100% of the time. However, anomaly scores, produced by `vmanomaly` are written back as metrics to VictoriaMetrics, where tools like [`vmalert`](https://docs.victoriametrics.com/vmalert) can use [MetricsQL](https://docs.victoriametrics.com/metricsql/) expressions to fine-tune alerting thresholds and conditions, balancing between avoiding [false negatives](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-1/#false-negative) and reducing [false positives](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-1/#false-positive).
@@ -166,7 +224,7 @@ services:
# ...
vmanomaly:
container_name: vmanomaly
image: victoriametrics/vmanomaly:v1.19.2
image: victoriametrics/vmanomaly:v1.20.0
# ...
ports:
- "8490:8490"
@@ -339,7 +397,7 @@ For **horizontal** scalability, `vmanomaly` can be deployed as multiple independ
- Splitting by **queries** [defined in the reader section](https://docs.victoriametrics.com/anomaly-detection/components/reader#vm-reader) and assigning each subset to a separate service instance should be used when having *a single query returning a large number of timeseries*. This can be further split by applying global MetricsQL filters using the `extra_filters` [parameter in the reader](https://docs.victoriametrics.com/anomaly-detection/components/reader?highlight=extra_filters#vm-reader). See example below.
- Spliting by **models** should be used when running multiple models on the same query. This is commonly done to reduce false positives by alerting only if multiple models detect an anomaly. See the `queries` argument in the [model configuration](https://docs.victoriametrics.com/anomaly-detection/components/models#queries). Additionally, this approach is useful when you just have a large set of resource-intensive independent models.
- Spliting by **models** should be used when running multiple models on the same query. This is commonly done to reduce [false positives](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-1/#false-positive) by alerting only if multiple models detect an anomaly. See the `queries` argument in the [model configuration](https://docs.victoriametrics.com/anomaly-detection/components/models#queries). Additionally, this approach is useful when you just have a large set of resource-intensive independent models.
- Splitting by **schedulers** should be used when the same models needs to be trained or inferred under different schedules. Refer to the `schedulers` argument in the [model section](https://docs.victoriametrics.com/anomaly-detection/components/models#schedulers) and the `scheduler` [component documentation](https://docs.victoriametrics.com/anomaly-detection/components/scheduler).
@@ -373,7 +431,7 @@ options:
Heres 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.19.2 && docker image tag victoriametrics/vmanomaly:v1.19.2 vmanomaly
docker pull victoriametrics/vmanomaly:v1.20.0 && docker image tag victoriametrics/vmanomaly:v1.20.0 vmanomaly
```
```sh

View File

@@ -1,15 +1,17 @@
---
weight: 1
title: VictoriaMetrics Anomaly Detection Quick Start
title: Quick Start
menu:
docs:
parent: "anomaly-detection"
identifier: "vmanomaly-quick-start"
weight: 1
title: Quick Start
aliases:
- /anomaly-detection/QuickStart.html
---
For a broader overview please visit the [navigation page](https://docs.victoriametrics.com/anomaly-detection/).
## How to install and run vmanomaly
> To run `vmanomaly`, you need to have VictoriaMetrics Enterprise license. You can get a trial license key [**here**](https://victoriametrics.com/products/enterprise/trial/).
@@ -19,15 +21,13 @@ The following options are available:
- [To run Docker image](#docker)
- [To run in Kubernetes with Helm charts](#kubernetes-with-helm-charts)
> **Note**: Starting from [v1.13.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1130) there is a mode to keep anomaly detection models on host filesystem after `fit` stage (instead of keeping them in-memory by default); This may lead to **noticeable reduction of RAM used** on bigger setups. See instructions [here](https://docs.victoriametrics.com/anomaly-detection/faq/#on-disk-mode).
> **Note**: Starting from [v1.16.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1160), a similar optimization is available for data read from VictoriaMetrics TSDB. See instructions [here](https://docs.victoriametrics.com/anomaly-detection/faq/#on-disk-mode).
> **Note**: There is a mode {{% available_from "v1.13.0" anomaly %}} to keep anomaly detection models on host filesystem after `fit` stage (instead of keeping them in-memory by default); This may lead to **noticeable reduction of RAM used** on bigger setups. Similar optimization {{% available_from "v1.16.0" anomaly %}} can be set for data read from VictoriaMetrics TSDB. See instructions [here](https://docs.victoriametrics.com/anomaly-detection/faq/#on-disk-mode).
### Command-line arguments
The `vmanomaly` service supports several command-line arguments to configure its behavior, including options for licensing, logging levels, and more. These arguments can be passed when starting the service via Docker or any other setup. Below is the list of available options:
> **Note**: Starting from [v1.18.5](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1185) `vmanomaly` support running on config *directories*, see the `config` positional arg description in help message below.
> **Note**: `vmanomaly` support {{% available_from "v1.18.5" anomaly %}} running on config *directories*, see the `config` positional arg description in help message below.
```shellhelp
usage: vmanomaly.py [-h] [--license STRING | --licenseFile PATH] [--license.forceOffline] [--loggerLevel {INFO,DEBUG,ERROR,WARNING,FATAL}] [--watch] config [config ...]
@@ -51,6 +51,7 @@ options:
```
You can specify these options when running `vmanomaly` to fine-tune logging levels or handle licensing configurations, as per your requirements.
### Licensing
The license key can be passed via the following command-line flags: `--license`, `--licenseFile`, `--license.forceOffline`
@@ -94,20 +95,29 @@ groups:
```
### Docker
> To run `vmanomaly`, you need to have VictoriaMetrics Enterprise license. You can get a trial license key [**here**](https://victoriametrics.com/products/enterprise/trial/).
> To run `vmanomaly`, you need to have VictoriaMetrics Enterprise license. You can get a trial license key [**here**](https://victoriametrics.com/products/enterprise/trial/). <br><br>
> Due to the upcoming [DockerHub pull limits](https://docs.docker.com/docker-hub/usage/pulls), an additional image registry, **Quay.io**, has been introduced for VictoriaMetrics images, including [`vmanomaly`](https://quay.io/repository/victoriametrics/vmanomaly). If you encounter pull rate limits, switch from:
> ```
> docker pull victoriametrics/vmanomaly:vX.Y.Z
> ```
> to:
> ```
> docker pull quay.io/victoriametrics/vmanomaly:vX.Y.Z
> ```
Below are the steps to get `vmanomaly` up and running inside a Docker container:
1. Pull Docker image:
```sh
docker pull victoriametrics/vmanomaly:v1.19.2
docker pull victoriametrics/vmanomaly:v1.20.0
```
2. (Optional step) tag the `vmanomaly` Docker image:
```sh
docker image tag victoriametrics/vmanomaly:v1.19.2 vmanomaly
docker image tag victoriametrics/vmanomaly:v1.20.0 vmanomaly
```
3. Start the `vmanomaly` Docker container with a *license file*, use the command below.
@@ -141,7 +151,7 @@ docker run -it --user 1000:1000 \
services:
# ...
vmanomaly:
image: victoriametrics/vmanomaly:v1.19.2
image: victoriametrics/vmanomaly:v1.20.0
volumes:
$YOUR_LICENSE_FILE_PATH:/license
$YOUR_CONFIG_FILE_PATH:/config.yml
@@ -165,6 +175,10 @@ See also:
> To run `vmanomaly`, you need to have VictoriaMetrics Enterprise license. You can get a trial license key [**here**](https://victoriametrics.com/products/enterprise/trial/).
> With the forthcoming [DockerHub pull limits](https://docs.docker.com/docker-hub/usage/pulls) additional image registry was introduced (quay.io) for VictoriaMetric images, [vmanomaly images in particular](https://quay.io/repository/victoriametrics/vmanomaly).
If hitting pull limits, try switching your `docker pull quay.io/victoriametrics/vmanomaly:vX.Y.Z` to `docker pull quay.io/victoriametrics/vmanomaly:vX.Y.Z`
```
You can run `vmanomaly` in Kubernetes environment
with [these Helm charts](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-anomaly/README.md).
@@ -219,20 +233,22 @@ writer:
### Recommended steps
**Schedulers**:
- Define how often to run and make inferences in the [scheduler](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/) section of a config file.
- 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.
**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/cluster-victoriametrics/) for reading the data.
- Define queries for input data using [MetricsQL](https://docs.victoriametrics.com/metricsql/) under `reader.queries` section.
- 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/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/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, data frequency, data range, etc.
**Writer**:
- Specify where and how to store anomaly detection metrics in the [writer](https://docs.victoriametrics.com/anomaly-detection/components/writer/) section.
- Include tenant ID if using a [cluster version of VictoriaMetrics](https://docs.victoriametrics.com/cluster-victoriametrics/) for writing the results.
- Adding `for` label to `metric_format` argument is recommended for smoother visual experience in the [anomaly score dashboard](https://docs.victoriametrics.com/anomaly-detection/presets/#default).
- Adding `for` label to `metric_format` argument is recommended for smoother visual experience in the [anomaly score dashboard](https://docs.victoriametrics.com/anomaly-detection/presets/#default). Please refer to `metric_format` argument description [here](https://docs.victoriametrics.com/anomaly-detection/components/writer/?highlight=metric_format#config-parameters).
**Models**:
- Configure built-in models parameters according to your needs in the [models](https://docs.victoriametrics.com/anomaly-detection/components/models/) section.
- (Optionally) Develop or integrate your [custom models](https://docs.victoriametrics.com/anomaly-detection/components/models/#custom-model-guide) with `vmanomaly`.
- Configure built-in models parameters according to your needs in the [models](https://docs.victoriametrics.com/anomaly-detection/components/models/) section. Where possible, incorporate [domain knowledge](https://docs.victoriametrics.com/anomaly-detection/faq/#incorporating-domain-knowledge) for optimal results.
- (Optional) Develop or integrate your [custom models](https://docs.victoriametrics.com/anomaly-detection/components/models/#custom-model-guide) with `vmanomaly`.
- Adding `y` to `provide_series` arg values is recommended for smoother visual experience in the [anomaly score dashboard](https://docs.victoriametrics.com/anomaly-detection/presets/#default). Also, other `vmanomaly` [output](https://docs.victoriametrics.com/anomaly-detection/components/models#vmanomaly-output) can be used in `provide_series`. <br>**Note:** Only [univariate models](https://docs.victoriametrics.com/anomaly-detection/components/models/#univariate-models) support the generation of such output.
## Check also

View File

@@ -1,41 +1,68 @@
In the dynamic and complex world of system monitoring, [VictoriaMetrics Anomaly Detection](https://victoriametrics.com/products/enterprise/anomaly-detection/) (or shortly, `vmanomaly`), being a part of our [Enterprise offering](https://victoriametrics.com/products/enterprise/), stands as a pivotal tool for achieving advanced observability. It empowers SREs and DevOps teams by automating the identification of abnormal behavior in time-series data. It goes beyond traditional threshold-based alerting, utilizing machine learning techniques to not only detect anomalies but also minimize false positives, thus reducing alert fatigue. By providing simplified alerting mechanisms atop of [unified anomaly scores](https://docs.victoriametrics.com/anomaly-detection/components/models/#vmanomaly-output), it enables teams to spot and address potential issues faster, ensuring system reliability and operational efficiency.
In today's fast-paced and complex landscape of system monitoring, [VictoriaMetrics Anomaly Detection](https://victoriametrics.com/products/enterprise/anomaly-detection/) (`vmanomaly`), part of our [Enterprise offering](https://victoriametrics.com/products/enterprise/), serves as a **powerful observability tool** for SREs and DevOps teams. It **automates the detection of anomalies in time-series data**, reducing manual efforts required to identify abnormal system behavior.
Unlike traditional threshold-based alerting, which relies on **raw metric values** and requires constant tuning and maintenance of thresholds and alerting rules, `vmanomaly` introduces a **unified, interpretable [anomaly score](https://docs.victoriametrics.com/anomaly-detection/faq/#what-is-anomaly-score)** - a **de-trended, de-seasonalized metric** generated through machine learning. This approach eliminates the need for frequent manual adjustments by enabling **stable, long-term static thresholds (as simple as `anomaly_score > 1`)** that remain effective over time through continuous model retraining.
By shifting to anomaly-based detection, teams can **identify and respond to potential issues faster**, enhancing system reliability and operational efficiency while significantly **reducing the engineering effort spent on maintaining alerting rules**.
## What does it do?
- Designed to periodically scan new data points across selected metrics, it forecasts unified [anomaly scores](https://docs.victoriametrics.com/anomaly-detection/faq/#what-is-anomaly-score).
- Scores are recorded back to VictoriaMetrics TSDB for utilization in subsequent applications, such as alerting services.
- Simplified alerting rules can be established and observability insights received, enhancing your operational efficiency.
`vmanomaly` is designed to **periodically analyze new data points** across selected metrics, generating a **unified metric** called [anomaly score](https://docs.victoriametrics.com/anomaly-detection/faq/#what-is-anomaly-score).
Key functions:
- **Automated anomaly detection** continuously scans time-series data to identify deviations from expected behavior.
- **Seamless integration** anomaly scores are stored in VictoriaMetrics TSDB for use in **alerting, visualization, and downstream analytics**.
The diagram below illustrates how `vmanomaly` fits into an observability setup, such as detecting anomalies in metrics collected by `node_exporter`:
<img src="https://docs.victoriametrics.com/anomaly-detection/guides/guide-vmanomaly-vmalert/guide-vmanomaly-vmalert_overview.webp" alt="node_exporter_example_diagram" style="width:60%"/>
## How does it work?
At its core, VictoriaMetrics Anomaly Detection autonomously re-trains either pre-defined machine learning models or custom models tailored to your business needs on your data.
- ML models are employed to calculate anomaly scores for newly collected data points, as per a predefined schedule.
- Alerts can be triggered based on simplified thresholds (i.e. anomaly_score > 1) that simplify and automate your observability setup.
- Ongoing evaluations, presented either as specific point estimates or as ranges of confidence intervals, are designed to integrate seamlessly with downstream applications.
VictoriaMetrics Anomaly Detection **continuously re-fit and apply machine learning models** - either [built-in](https://docs.victoriametrics.com/anomaly-detection/components/models/#built-in-models) or [custom](https://docs.victoriametrics.com/anomaly-detection/components/models/#custom-model-guide), specific to your business needs — on your [input](https://docs.victoriametrics.com/anomaly-detection/components/reader) data. This ensures that the default cut-off threshold (`anomaly score == 1`), which differentiates **normal** (`≤ 1`) from **anomalous** (`> 1`) data points, remains **relevant over time**.
## Practical Guides and Installation
- **Automated anomaly scoring** - ML models calculate [anomaly scores](https://docs.victoriametrics.com/anomaly-detection/faq/#what-is-anomaly-score) for new data points based on a predefined [schedule](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/).
- **Simplified alerting** - alerts can be triggered using **straightforward thresholds** (e.g., `anomaly_score > 1`), reducing complexity in observability setups.
- **Additional model outputs** - beyond anomaly scores, models provide [supplementary outputs](https://docs.victoriametrics.com/anomaly-detection/components/models/#vmanomaly-output), including:
- **Point estimates** (`yhat`)
- **Confidence intervals** (`[yhat_lower, yhat_upper]`)
These outputs integrate seamlessly into downstream applications, making it easier to **visually inspect anomalies**, e.g. in respective [Grafana dashboards](https://docs.victoriametrics.com/anomaly-detection/presets/#grafana-dashboard).
Get started with VictoriaMetrics Anomaly Detection efficiently by following our guides and installation options:
<img src="https://docs.victoriametrics.com/anomaly-detection/components/vmanomaly-components.webp" alt="node_exporter_example_diagram" style="width:80%"/>
## Key benefits
`vmanomaly` is designed to **reduce MTTR (Mean Time to Resolution)** in observability workflows by **automating anomaly detection** and **eliminating the need for manual threshold tuning**. It is particularly beneficial for:
- **Reducing alerting rule maintenance** shifts from manually maintaining static thresholds on raw metric values to a **stable anomaly score threshold** that remains **reliable and interpretable over time**.
- **Handling complex metrics** effectively detects anomalies in **trending, seasonal, or dynamically scaling data**, where **fixed thresholds and simpler models usually fail**.
- **Detecting anomalies in interconnected metrics** supports **[multivariate anomaly detection](http://docs.victoriametrics.com/anomaly-detection/components/models#multivariate-models)**, identifying patterns across **related metrics** instead of treating them in isolation as [univariate metrics](http://docs.victoriametrics.com/anomaly-detection/components/models#univariate-models).
## Practical guides and installation
Get started with VictoriaMetrics Anomaly Detection by following our guides and installation options:
- **Quickstart**: Learn how to quickly set up `vmanomaly` by following the [Quickstart Guide](https://docs.victoriametrics.com/anomaly-detection/quickstart/).
- **Integration**: Integrate anomaly detection into your existing observability stack. Find detailed steps [here](https://docs.victoriametrics.com/anomaly-detection/guides/guide-vmanomaly-vmalert/).
- **Anomaly Detection Presets**: Enable anomaly detection on predefined sets of metrics that require frequent static threshold changes for alerting. Learn more [here](https://docs.victoriametrics.com/anomaly-detection/presets/).
- **Anomaly Detection Presets**: Enable anomaly detection on predefined sets of metrics. Learn more [here](https://docs.victoriametrics.com/anomaly-detection/presets/).
- **Installation Options**: Choose the installation method that best fits your infrastructure:
- **Docker Installation**: Ideal for containerized environments. Follow the [Docker Installation Guide](https://docs.victoriametrics.com/anomaly-detection/quickstart/#docker).
- **Helm Chart Installation**: Recommended for Kubernetes deployments. See our [Helm charts](https://github.com/VictoriaMetrics/helm-charts/tree/master/charts/victoria-metrics-anomaly).
- **Self-Monitoring**: Ensure `vmanomaly` is functioning optimally with built-in self-monitoring capabilities. Use the provided Grafana dashboards and alerting rules to track service health and operational metrics. Find the complete docs [here](https://docs.victoriametrics.com/anomaly-detection/self-monitoring/).
- **Self-Monitoring**: Ensure `vmanomaly` is functioning optimally, using provided Grafana dashboards and alerting rules to track service health and operational metrics. Find the guide [here](https://docs.victoriametrics.com/anomaly-detection/self-monitoring/).
> **Note**: starting from [v1.5.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v150) `vmanomaly` requires a [license key](https://docs.victoriametrics.com/anomaly-detection/quickstart/#licensing) to run. You can obtain a trial license key [**here**](https://victoriametrics.com/products/enterprise/trial/).
## Key Components
Explore the integral components that configure VictoriaMetrics Anomaly Detection:
* [Explore components and their interation](https://docs.victoriametrics.com/anomaly-detection/components/)
- [Models](https://docs.victoriametrics.com/anomaly-detection/components/models/)
- [Reader](https://docs.victoriametrics.com/anomaly-detection/components/reader/)
- [Scheduler](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/)
- [Writer](https://docs.victoriametrics.com/anomaly-detection/components/writer/)
- [Monitoring](https://docs.victoriametrics.com/anomaly-detection/components/monitoring/)
Explore the [integral components](https://docs.victoriametrics.com/anomaly-detection/components/) that define VictoriaMetrics Anomaly Detection:
- [Models](https://docs.victoriametrics.com/anomaly-detection/components/models/)
- [Reader](https://docs.victoriametrics.com/anomaly-detection/components/reader/)
- [Scheduler](https://docs.victoriametrics.com/anomaly-detection/components/scheduler/)
- [Writer](https://docs.victoriametrics.com/anomaly-detection/components/writer/)
- [Monitoring](https://docs.victoriametrics.com/anomaly-detection/components/monitoring/)
## Deep Dive into Anomaly Detection
Enhance your knowledge with our handbook on Anomaly Detection & Root Cause Analysis and stay updated:

View File

@@ -1,5 +1,5 @@
---
title: VictoriaMetrics Anomaly Detection
title: Anomaly Detection
weight: 50
menu:
docs:

View File

@@ -226,7 +226,7 @@ models:
queries: ['normal_behavior'] # use the default where it's not needed
```
### Group By
### Group by
> **Note**: The `groupby` argument works only in combination with [multivariate models](#multivariate-models).
@@ -264,6 +264,135 @@ models:
groupby: [host]
```
### Scale
Previously available only to [ProphetModel](#prophet) and [OnlineQuantileModel](#online-seasonal-quantile), the `scale` {{% available_from "v1.20.0" anomaly %}} parameter is now applicable to all models that support generating predictions (`yhat`, `yhat_lower`, `yhat_upper`). Also, it is **two-sided** now, represented as a list of two positive float values, allowing separate scaling for the intervals `[yhat, yhat_upper]` and `[yhat_lower, yhat]`. The new margins are calculated as:
- **Upper margin:** `|yhat_upper - yhat| * scale_upper`
- **Lower margin:** `|yhat - yhat_lower| * scale_lower`
For backward compatibility, the previous format (`scale: x`) remains supported and will be automatically converted to `scale: [x, x]`.
For example, setting `scale: [1.2, 0.75]` for particular model will:
- **Increase** the width of the lower confidence interval by **20%**.
- **Decrease** the width of the upper confidence boundary by **25%**.
The most common **use case** is when there is a preference to **widen one side** to blacklist smaller false positives (which otherwise would have [anomaly scores](https://docs.victoriametrics.com/anomaly-detection/faq/#how-is-anomaly-score-calculated) **only slightly higher than 1.0**, still making such data points **anomalous**), while **tightening the other side** to avoid missing true positives due to an overly loose margin (leading to [anomaly scores](https://docs.victoriametrics.com/anomaly-detection/faq/#how-is-anomaly-score-calculated) being slightly less than 1.0, making such data points **non-anomalous**).
```yaml
# other components like reader, writer, schedulers, monitoring ...
models:
zscore_no_scale:
class: 'zscore' # or 'model.zscore.ZscoreModel' until v1.13.0
z_threshold: 3
# if not set, equals to [1.0, 1.0], meaning no scaling is applied
# scale: [1.0, 1.0]
zscore_scaled:
class: 'zscore' # or 'model.zscore.ZscoreModel' until v1.13.0
z_threshold: 3
# vs `zscore_no_scale`, increase lower confidence interval width by 1.2x, decrease upper confidence width by 25%
scale: [1.2, 0.75]
```
### Clip predictions
A post-processing step to **clip model predictions** (`yhat`, `yhat_lower`, and `yhat_upper` series) to the configured [`data_range` values](https://docs.victoriametrics.com/anomaly-detection/components/reader/?highlight=data_range#config-parameters) in `VmReader` is available.
This behavior is controlled by the boolean argument `clip_predictions` {{% available_from "v1.20.0" anomaly %}}:
- **Disabled by default** for backward compatibility.
- **Works** for models that generate predictions and estimates (e.g., [`ProphetModel`](#prophet)) by setting `clip_predictions` to `True` for respective model in `models` section.
The primary use case is to **align domain knowledge** about data behavior (defined via `data_range`) with what is shown in visualizations, such as in the [Grafana dashboard](https://docs.victoriametrics.com/anomaly-detection/presets/#grafana-dashboard). This ensures that predictions (`yhat`, `yhat_lower`, `yhat_upper`) are plotted consistently alongside real metric values (`y`) and remain within reasonable expected bounds.
> Note: This parameter does not impact the generation of anomaly scores > 1 for datapoints where `y` falls outside the defined `data_range`.
```yaml
# other components like writer, schedulers, monitoring ...
reader:
# ...
queries:
q1_clipped:
expr: 'q1_metricsql'
data_range: [0, "inf"]
q2_no_clip:
expr: 'q2_metricsql'
# if no data range defined, it will be implicitly converted to ["-inf", "inf"]
models:
zscore_mixed:
class: 'zscore' # or 'model.zscore.ZscoreModel' until v1.13.0
z_threshold: 3
clip_predictions: True
queries: [
# `yhat`, `yhat_lower`, `yhat_upper` will be within [0, inf]
# for all `zscore_mixed` instances that are fit on series returned by `q1_clipped` query
# anomaly scores > 1 will still be produced for `y` outside of data_range
'q1_clipped',
# there will be no (explicit) clip of `yhat`, `yhat_lower`, `yhat_upper`
# for all `zscore_mixed` instances that are fit on series returned by `q2_no_clip` query
# even when `clip_predictions` arg is set, because data_range was not set for `q2_no_clip`
'q2_no_clip',
]
zscore_no_clip:
class: 'zscore' # or 'model.zscore.ZscoreModel' until v1.13.0
z_threshold: 3
# if not set, by default resolved to `clip_predictions: False`
queries: [
# `yhat`, `yhat_lower`, `yhat_upper` won't be clipped to [0, inf]
# even though `data_range` for `q1_clipped` is set
# however, anomaly scores > 1 will still be produced for y outside of data_range
'q1_clipped',
# there will be no (explicit) clip of yhat, yhat_lower, yhat_upper
# for all `zscore_mixed` instances that are fit on series returned by `q2_no_clip` query
# as `clip_predictions` arg is not set, regardless of data_range for `q2_no_clip`
'q2_no_clip',
]
```
### Score outside data range
The `anomaly_score_outside_data_range` {{% available_from "v1.20.0" anomaly %}} parameter allows overriding the default **anomaly score (`1.01`)** assigned when actual values (`y`) fall **outside the defined `data_range` if defined in [reader](https://docs.victoriametrics.com/anomaly-detection/components/reader/)**. This provides greater flexibility for **alerting rule configurations** and enables **clearer visual differentiation** between different types of anomalies:
- By default, `y` values **outside `data_range`** trigger an anomaly score of `1.01`, which serves as a basic alerting rule.
- However, some users may require **higher anomaly scores** (e.g., `> 1.2`) to **trigger alerts reliably** in their monitoring setups.
**How it works**
- If **not set**, the **default value (`1.01`)** is used for backward compatibility.
- If defined at the **service level** (`settings`), it applies to all models **unless overridden at the model level**.
- If set **per model**, it takes **priority over the global setting**.
**Example (override)**
```yaml
settings:
# other parameters ...
# all the models in `models` section will inherit this value unless overridden at the model level
anomaly_score_outside_data_range: 1.2
models:
model_score_override:
class: 'zscore_online'
# explicitly set, takes priority over `settings`'s value
anomaly_score_outside_data_range: 1.5
model_score_from_settings_level:
class: 'zscore_online'
# inherits from `settings`, will be `1.2`, same as setting
# anomaly_score_outside_data_range: 1.2
```
**Example (default vs custom)**
```yaml
models:
model_default_score:
class: 'zscore_online'
# default anomaly score (1.01) is applied when y is outside data_range, same as setting
# anomaly_score_outside_data_range: 1.01
model_higher_out_of_data_range_score:
class: 'zscore_online'
# explicitly set, takes priority over `settings`'s value
anomaly_score_outside_data_range: 3.0
```
## Model types
@@ -276,7 +405,7 @@ Each of these models can be of type
- [Rolling](#rolling-models)
- [Non-rolling](#non-rolling-models)
Moreover, starting from [v1.15.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1150), there exist **[online (incremental) models](#online-models)** subclass. Please refer to the [correspondent section](#online-models) for more details.
Moreover, {{% available_from "v1.15.0" anomaly %}}, there exist **[online (incremental) models](#online-models)** subclass. Please refer to the [correspondent section](#online-models) for more details.
### Univariate Models
@@ -299,7 +428,7 @@ For a multivariate type, **one shared model** is fit/used for inference on **all
For example, if you have some **multivariate** model to use 3 [MetricQL queries](https://docs.victoriametrics.com/metricsql/), each returning 5 time series, there will be one shared model created in total. Once fit, this model will expect **exactly 15 time series with exact same labelsets as an input**. This model will produce **one shared [output](#vmanomaly-output)**.
> **Note:** Starting from [v1.16.0](https://docs.victoriametrics.com/anomaly-detection/changelog#v1160), N models — one for each unique combination of label values specified in the `groupby` [common argument](#group-by) — can be trained. This allows for context separation (e.g., one model per host, region, or other relevant grouping label), leading to improved accuracy and faster training. See an example [here](#group-by).
> **Note:** {{% available_from "v1.16.0" anomaly %}}, N models — one for each unique combination of label values specified in the `groupby` [common argument](#group-by) — can be trained. This allows for context separation (e.g., one model per host, region, or other relevant grouping label), leading to improved accuracy and faster training. See an example [here](#group-by).
If during an inference, you got a **different amount of series** or some series having a **new labelset** (not present in any of fitted models), the inference will be skipped until you get a model, trained particularly for such labelset during forthcoming re-fit step.
@@ -386,16 +515,16 @@ Every other model that isn't [online](#online-models). Offline models are comple
## Built-in Models
### Overview
VictoriaMetrics Anomaly Detection models support 2 groups of parameters:
Built-in models support 2 groups of arguments:
- **`vmanomaly`-specific** arguments - please refer to *Parameters specific for vmanomaly* and *Default model parameters* subsections for each of the models below.
- Arguments to **inner model** (say, [Facebook's Prophet](https://facebook.github.io/prophet/docs/quick_start#python-api)), passed in a `args` argument as key-value pairs, that will be directly given to the model during initialization to allow granular control. Optional.
- Arguments to **inner model** (say, [Facebook's Prophet](https://facebook.github.io/prophet/docs/quick_start#python-api)), passed inside `args` argument as key-value pairs, that will be directly given to the model during initialization to allow granular control. Optional.
> **Note**: For users who may not be familiar with Python data types such as `list[dict]`, a [dictionary](https://www.w3schools.com/python/python_dictionaries.asp) in Python is a data structure that stores data values in key-value pairs. This structure allows for efficient data retrieval and management.
**Models**:
* [AutoTuned](#autotuned) - designed to take the cognitive load off the user, allowing any of built-in models below to be re-tuned for best params on data seen during each `fit` phase of the algorithm. Tradeoff is between increased computational time and optimized results / simpler maintenance.
* [AutoTuned](#autotuned) - designed to take the cognitive load off the user, allowing any of built-in models below to be re-tuned for best hyperparameters on data seen during each `fit` phase of the algorithm. Tradeoff is between increased computational time and optimized results / simpler maintenance.
* [Prophet](#prophet) - the most versatile one for production usage, especially for complex data ([trends](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-1/#trend), [change points](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-2/#novelties), [multi-seasonality](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-1/#seasonality))
* [Z-score](#z-score) - useful for initial testing and for simpler data ([de-trended](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-1/#trend) data without strict [seasonality](https://victoriametrics.com/blog/victoriametrics-anomaly-detection-handbook-chapter-1/#seasonality) and with anomalies of similar magnitude as your "normal" data)
* [Online Z-score](#online-z-score) - [online](#online-models) alternative to [Z-score](#z-score) model with exact same behavior and use cases.
@@ -418,7 +547,7 @@ Tuning hyperparameters of a model can be tricky and often requires in-depth know
* `tuned_class_name` (string) - Built-in model class to tune, i.e. `model.zscore.ZscoreModel` (or `zscore`with class alias support{{% available_from "v1.13.0" anomaly %}}).
* `optimization_params` (dict) - Optimization parameters for unsupervised model tuning. Control % of found anomalies, as well as a tradeoff between time spent and the accuracy. The more `timeout` and `n_trials` are, the better model configuration can be found for `tuned_class_name`, but the longer it takes and vice versa. Set `n_jobs` to `-1` to use all the CPUs available, it makes sense if only you have a big dataset to train on during `fit` calls, otherwise overhead isn't worth it.
- `anomaly_percentage` (float) - Expected percentage of anomalies that can be seen in training data, from (0, 0.5) interval.
- `optimized_business_params` (list[string]) - Starting from [v1.15.0](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1150) this argument allows particular business-specific parameters such as [`detection_direction`](https://docs.victoriametrics.com/anomaly-detection/components/models/#detection-direction) or [`min_dev_from_expected`](https://docs.victoriametrics.com/anomaly-detection/components/models/#minimal-deviation-from-expected) to remain **unchanged during optimizations, retaining their default values**. I.e. setting `optimized_business_params` to `['detection_direction']` will allow to optimize only `detection_direction` business-specific arg, while `min_dev_from_expected` will retain its default value (0.0). By default and if not set, will be equal to `[]` (empty list), meaning no business params will be optimized. **A recommended option is to leave it empty** for more stable results and increased convergence (less iterations needed for a good result).
- `optimized_business_params` (list[string]) - {{% available_from "v1.15.0" anomaly %}} this argument allows particular business-specific parameters such as [`detection_direction`](https://docs.victoriametrics.com/anomaly-detection/components/models/#detection-direction) or [`min_dev_from_expected`](https://docs.victoriametrics.com/anomaly-detection/components/models/#minimal-deviation-from-expected) to remain **unchanged during optimizations, retaining their default values**. I.e. setting `optimized_business_params` to `['detection_direction']` will allow to optimize only `detection_direction` business-specific arg, while `min_dev_from_expected` will retain its default value (0.0). By default and if not set, will be equal to `[]` (empty list), meaning no business params will be optimized. **A recommended option is to leave it empty** for more stable results and increased convergence (less iterations needed for a good result).
- `seed` (int) - Random seed for reproducibility and deterministic nature of underlying optimizations.
- `n_splits` (int) - How many folds to create for hyperparameter tuning out of your data. The higher, the longer it takes but the better the results can be. Defaults to 3.
- `n_trials` (int) - How many trials to sample from hyperparameter search space. The higher, the longer it takes but the better the results can be. Defaults to 128.
@@ -453,19 +582,17 @@ models:
### [Prophet](https://facebook.github.io/prophet/)
`vmanomaly` uses the Facebook Prophet implementation for time series forecasting, with detailed usage provided in the [Prophet library documentation](https://facebook.github.io/prophet/docs/quick_start#python-api). All original Prophet parameters are supported and can be directly passed to the model via `args` argument.
> **Note**: `ProphetModel` is a [univariate](#univariate-models), [non-rolling](#non-rolling-models), [offline](#offline-models) model.
> **Note**: Starting with [v1.18.2](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1182), the format for `tz_seasonalities` has been updated to enhance flexibility. Previously, it accepted a list of strings (e.g., `['hod', 'minute']`). Now, it follows the same structure as custom seasonalities defined in the `seasonalities` argument (e.g., `{"name": "hod", "fourier_order": 5, "mode": "additive"}`). This change is backward-compatible, so older configurations will be automatically converted to the new format using default values.
> **Note**: {{% available_from "v1.18.2" anomaly %}} the format for `tz_seasonalities` has been updated to enhance flexibility. Previously, it accepted a list of strings (e.g., `['hod', 'minute']`). Now, it follows the same structure as custom seasonalities defined in the `seasonalities` argument (e.g., `{"name": "hod", "fourier_order": 5, "mode": "additive"}`). This change is backward-compatible, so older configurations will be automatically converted to the new format using default values.
*Parameters specific for vmanomaly*:
- `class` (string) - model class name `"model.prophet.ProphetModel"` (or `prophet` with class alias support{{% available_from "v1.13.0" anomaly %}})
- `seasonalities` (list[dict], optional): Additional seasonal components to include in Prophet. See Prophets [`add_seasonality()`](https://facebook.github.io/prophet/docs/seasonality,_holiday_effects,_and_regressors#modeling-holidays-and-special-events:~:text=modeling%20the%20cycle-,Specifying,-Custom%20Seasonalities) documentation for details.
- `scale`{{% available_from "v1.18.0" anomaly %}} (float): Is used to adjust the margin between `yhat` and [`yhat_lower`, `yhat_upper`]. New margin = `|yhat_* - yhat_lower| * scale`. Defaults to 1 (no scaling is applied).
- `scale`{{% available_from "v1.18.0" anomaly %}} (float): Is used to adjust the margins between `yhat` and [`yhat_lower`, `yhat_upper`]. New margin = `|yhat_* - yhat_lower| * scale`. Defaults to 1 (no scaling is applied). See `scale`[common arg](https://docs.victoriametrics.com/anomaly-detection/components/models/#scale) section for detailed instructions and 2-sided option.
- `tz_aware`{{% available_from "v1.18.0" anomaly %}} (bool): Enables handling of timezone-aware timestamps. Default is `False`. Should be used with `tz_seasonalities` and `tz_use_cyclical_encoding` parameters.
- `tz_seasonalities`{{% available_from "v1.18.0" anomaly %}} (list[dict]): Specifies timezone-aware seasonal components. Requires `tz_aware=True`. Supported options include `minute`, `hod` (hour of day), `dow` (day of week), and `month` (month of year). Starting with [v1.18.2](https://docs.victoriametrics.com/anomaly-detection/changelog/#v1182), users can configure additional parameters for each seasonality, such as `fourier_order`, `prior_scale`, and `mode`. For more details, please refer to the **Timezone-unaware** configuration example below.
- `tz_seasonalities`{{% available_from "v1.18.0" anomaly %}} (list[dict]): Specifies timezone-aware seasonal components. Requires `tz_aware=True`. Supported options include `minute`, `hod` (hour of day), `dow` (day of week), and `month` (month of year). {{% available_from "v1.18.2" anomaly %}} users can configure additional parameters for each seasonality, such as `fourier_order`, `prior_scale`, and `mode`. For more details, please refer to the **Timezone-unaware** configuration example below.
- `tz_use_cyclical_encoding`{{% available_from "v1.18.0" anomaly %}} (bool): If set to `True`, applies [cyclical encoding technique](https://www.kaggle.com/code/avanwyk/encoding-cyclical-features-for-deep-learning) to timezone-aware seasonalities. Should be used with `tz_aware=True` and `tz_seasonalities`.
> **Note**: Apart from standard [`vmanomaly` output](#vmanomaly-output), Prophet model can provide additional metrics.
@@ -489,6 +616,17 @@ models:
your_desired_alias_for_a_model:
class: 'prophet' # or 'model.prophet.ProphetModel' until v1.13.0
provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper', 'trend']
# Common arguments for built-in model, if not set, default to
# See https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args
#
# provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper', 'trend']
# schedulers: [all scheduler aliases defined in `scheduler` section]
# queries: [all query aliases defined in `reader.queries` section]
# detection_direction: 'both' # meaning both drops and spikes will be captured
# min_dev_from_expected: 0.0 # meaning, no minimal threshold is applied to prevent smaller anomalies
# scale: [1.0, 1.0] # if needed, prediction intervals' width can be increased (>1) or narrowed (<1)
# clip_predictions: False # if data_range for respective `queries` is set in reader, `yhat.*` columns will be clipped
# anomaly_score_outside_data_range: 1.01 # auto anomaly score (1.01) if `y` (real value) is outside of data_range, if set
seasonalities:
- name: 'hourly'
period: 0.04166666666
@@ -508,6 +646,17 @@ models:
your_desired_alias_for_a_model:
class: 'prophet' # or 'model.prophet.ProphetModel' until v1.13.0
provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper', 'trend']
# Common arguments for built-in model, if not set, default to
# See https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args
#
# provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper', 'trend']
# schedulers: [all scheduler aliases defined in `scheduler` section]
# queries: [all query aliases defined in `reader.queries` section]
# detection_direction: 'both' # meaning both drops and spikes will be captured
# min_dev_from_expected: 0.0 # meaning, no minimal threshold is applied to prevent smaller anomalies
# scale: [1.0, 1.0] # if needed, prediction intervals' width can be increased (>1) or narrowed (<1)
# clip_predictions: False # if data_range for respective `queries` is set in reader, `yhat.*` columns will be clipped
# anomaly_score_outside_data_range: 1.01 # auto anomaly score (1.01) if `y` (real value) is outside of data_range, if set
tz_aware: True
tz_use_cyclical_encoding: True
tz_seasonalities: # intra-day + intra-week seasonality, no intra-year / sub-hour seasonality
@@ -544,6 +693,17 @@ models:
your_desired_alias_for_a_model:
class: "zscore" # or 'model.zscore.ZscoreModel' until v1.13.0
z_threshold: 3.5
# Common arguments for built-in model, if not set, default to
# See https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args
#
# provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper']
# schedulers: [all scheduler aliases defined in `scheduler` section]
# queries: [all query aliases defined in `reader.queries` section]
# detection_direction: 'both' # meaning both drops and spikes will be captured
# min_dev_from_expected: 0.0 # meaning, no minimal threshold is applied to prevent smaller anomalies
# scale: [1.0, 1.0] # if needed, prediction intervals' width can be increased (>1) or narrowed (<1)
# clip_predictions: False # if data_range for respective `queries` is set in reader, `yhat.*` columns will be clipped
# anomaly_score_outside_data_range: 1.01 # auto anomaly score (1.01) if `y` (real value) is outside of data_range, if set
```
Resulting metrics of the model are described [here](#vmanomaly-output).
@@ -569,6 +729,17 @@ models:
z_threshold: 3.5
min_n_samples_seen: 128 # i.e. calculate it as full seasonality / data freq
provide_series: ['anomaly_score', 'yhat'] # common arg example
# Common arguments for built-in model, if not set, default to
# See https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args
#
# provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper']
# schedulers: [all scheduler aliases defined in `scheduler` section]
# queries: [all query aliases defined in `reader.queries` section]
# detection_direction: 'both' # meaning both drops and spikes will be captured
# min_dev_from_expected: 0.0 # meaning, no minimal threshold is applied to prevent smaller anomalies
# scale: [1.0, 1.0] # if needed, prediction intervals' width can be increased (>1) or narrowed (<1)
# clip_predictions: False # if data_range for respective `queries` is set in reader, `yhat.*` columns will be clipped
# anomaly_score_outside_data_range: 1.01 # auto anomaly score (1.01) if `y` (real value) is outside of data_range, if set
```
Resulting metrics of the model are described [here](#vmanomaly-output).
@@ -614,6 +785,17 @@ models:
args:
seasonal: 'add'
initialization_method: 'estimated'
# Common arguments for built-in model, if not set, default to
# See https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args
#
# provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper']
# schedulers: [all scheduler aliases defined in `scheduler` section]
# queries: [all query aliases defined in `reader.queries` section]
# detection_direction: 'both' # meaning both drops and spikes will be captured
# min_dev_from_expected: 0.0 # meaning, no minimal threshold is applied to prevent smaller anomalies
# scale: [1.0, 1.0] # if needed, prediction intervals' width can be increased (>1) or narrowed (<1)
# clip_predictions: False # if data_range for respective `queries` is set in reader, `yhat.*` columns will be clipped
# anomaly_score_outside_data_range: 1.01 # auto anomaly score (1.01) if `y` (real value) is outside of data_range, if set
```
@@ -639,6 +821,17 @@ models:
your_desired_alias_for_a_model:
class: "mad" # or 'model.mad.MADModel' until v1.13.0
threshold: 2.5
# Common arguments for built-in model, if not set, default to
# See https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args
#
# provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper']
# schedulers: [all scheduler aliases defined in `scheduler` section]
# queries: [all query aliases defined in `reader.queries` section]
# detection_direction: 'both' # meaning both drops and spikes will be captured
# min_dev_from_expected: 0.0 # meaning, no minimal threshold is applied to prevent smaller anomalies
# scale: [1.0, 1.0] # if needed, prediction intervals' width can be increased (>1) or narrowed (<1)
# clip_predictions: False # if data_range for respective `queries` is set in reader, `yhat.*` columns will be clipped
# anomaly_score_outside_data_range: 1.01 # auto anomaly score (1.01) if `y` (real value) is outside of data_range, if set
```
Resulting metrics of the model are described [here](#vmanomaly-output).
@@ -668,6 +861,17 @@ models:
min_n_samples_seen: 128 # i.e. calculate it as full seasonality / data freq
compression: 100 # higher values mean higher accuracy but higher memory usage
provide_series: ['anomaly_score', 'yhat'] # common arg example
# Common arguments for built-in model, if not set, default to
# See https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args
#
# provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper']
# schedulers: [all scheduler aliases defined in `scheduler` section]
# queries: [all query aliases defined in `reader.queries` section]
# detection_direction: 'both' # meaning both drops and spikes will be captured
# min_dev_from_expected: 0.0 # meaning, no minimal threshold is applied to prevent smaller anomalies
# scale: [1.0, 1.0] # if needed, prediction intervals' width can be increased (>1) or narrowed (<1)
# clip_predictions: False # if data_range for respective `queries` is set in reader, `yhat.*` columns will be clipped
# anomaly_score_outside_data_range: 1.01 # auto anomaly score (1.01) if `y` (real value) is outside of data_range, if set
```
Resulting metrics of the model are described [here](#vmanomaly-output).
@@ -693,6 +897,17 @@ models:
class: "rolling_quantile" # or 'model.rolling_quantile.RollingQuantileModel' until v1.13.0
quantile: 0.9
window_steps: 96
# Common arguments for built-in model, if not set, default to
# See https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args
#
# provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper']
# schedulers: [all scheduler aliases defined in `scheduler` section]
# queries: [all query aliases defined in `reader.queries` section]
# detection_direction: 'both' # meaning both drops and spikes will be captured
# min_dev_from_expected: 0.0 # meaning, no minimal threshold is applied to prevent smaller anomalies
# scale: [1.0, 1.0] # if needed, prediction intervals' width can be increased (>1) or narrowed (<1)
# clip_predictions: False # if data_range for respective `queries` is set in reader, `yhat.*` columns will be clipped
# anomaly_score_outside_data_range: 1.01 # auto anomaly score (1.01) if `y` (real value) is outside of data_range, if set
```
Resulting metrics of the model are described [here](#vmanomaly-output).
@@ -716,7 +931,7 @@ It uses the `quantiles` triplet to calculate `yhat_lower`, `yhat`, and `yhat_upp
* `min_subseason` (str, optional) - the minimum interval to estimate quantiles for. By default not set. Note that the minimum interval should be a multiple of the seasonal interval, i.e. if seasonal_interval='2h', then min_subseason='15m' is valid, but '37m' is not.
* `use_transform` (bool, optional) - whether to internally apply a `log1p(abs(x)) * sign(x)` transformation to the data to stabilize internal quantile estimation. Does not affect the scale of produced output (i.e. `yhat`) By default False.
* `global_smoothing` (float, optional) - the smoothing parameter for the global quantiles. i.e. the output is a weighted average of the global and seasonal quantiles (if `seasonal_interval` and `min_subseason` args are set). Should be from `[0, 1]` interval, where 0 means no smoothing and 1 means using only global quantile values.
* `scale` (float, optional) - the scaling factor for the `yhat_lower` and `yhat_upper` quantiles. By default 1.0 (no scaling). if > 1, increases the boundaries [`yhat_lower`, `yhat_upper`] that define "non-anomalous" points. Should be > 0.
* `scale` (float, optional) - Is used to adjust the margins between `yhat` and [`yhat_lower`, `yhat_upper`]. New margin = `|yhat_* - yhat_lower| * scale`. Defaults to 1 (no scaling is applied). See `scale`[common arg](https://docs.victoriametrics.com/anomaly-detection/components/models/#scale) section for detailed instructions and 2-sided option.
* `season_starts_from` (str, optional) - the start date for the seasonal adjustment, as a reference point to start counting the intervals. By default '1970-01-01'.
* `min_n_samples_seen` (int, optional) - the minimum number of samples to be seen (`n_samples_seen_` property) before computing the anomaly score. Otherwise, the **anomaly score will be 0**, as there is not enough data to trust the model's predictions. Defaults to 16.
* `compression` (int, optional) - the compression parameter for the underlying [t-digests](https://www.sciencedirect.com/science/article/pii/S2665963820300403). Higher values mean higher accuracy but higher memory usage. By default 100.
@@ -737,6 +952,17 @@ models:
season_starts_from: '2024-01-01' # interval calculation starting point, especially for uncommon seasonalities like '36h' or '12d'
compression: 100 # higher values mean higher accuracy but higher memory usage
provide_series: ['anomaly_score', 'yhat'] # common arg example
# Common arguments for built-in model, if not set, default to
# See https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args
#
# provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper']
# schedulers: [all scheduler aliases defined in `scheduler` section]
# queries: [all query aliases defined in `reader.queries` section]
# detection_direction: 'both' # meaning both drops and spikes will be captured
# min_dev_from_expected: 0.0 # meaning, no minimal threshold is applied to prevent smaller anomalies
# scale: [1.0, 1.0] # if needed, prediction intervals' width can be increased (>1) or narrowed (<1)
# clip_predictions: False # if data_range for respective `queries` is set in reader, `yhat.*` columns will be clipped
# anomaly_score_outside_data_range: 1.01 # auto anomaly score (1.01) if `y` (real value) is outside of data_range, if set
```
Resulting metrics of the model are described [here](#vmanomaly-output).
@@ -763,6 +989,17 @@ models:
your_desired_alias_for_a_model:
class: "std" # or 'model.std.StdModel' starting from v1.13.0
period: 2
# Common arguments for built-in model, if not set, default to
# See https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args
#
# provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper']
# schedulers: [all scheduler aliases defined in `scheduler` section]
# queries: [all query aliases defined in `reader.queries` section]
# detection_direction: 'both' # meaning both drops and spikes will be captured
# min_dev_from_expected: 0.0 # meaning, no minimal threshold is applied to prevent smaller anomalies
# scale: [1.0, 1.0] # if needed, prediction intervals' width can be increased (>1) or narrowed (<1)
# clip_predictions: False # if data_range for respective `queries` is set in reader, `yhat.*` columns will be clipped
# anomaly_score_outside_data_range: 1.01 # auto anomaly score (1.01) if `y` (real value) is outside of data_range, if set
```
@@ -818,6 +1055,13 @@ models:
n_estimators: 100
# i.e. to assure reproducibility of produced results each time model is fit on the same input
random_state: 42
# Common arguments for built-in model, if not set, default to
# See https://docs.victoriametrics.com/anomaly-detection/components/models/#common-args
#
# provide_series: ['anomaly_score', 'yhat', 'yhat_lower', 'yhat_upper']
# schedulers: [all scheduler aliases defined in `scheduler` section]
# queries: [all query aliases defined in `reader.queries` section]
# anomaly_score_outside_data_range: 1.01 # auto anomaly score (1.01) if `y` (real value) is outside of data_range, if set
```
@@ -994,7 +1238,7 @@ monitoring:
Let's pull the docker image for `vmanomaly`:
```sh
docker pull victoriametrics/vmanomaly:v1.19.2
docker pull victoriametrics/vmanomaly:v1.20.0
```
Now we can run the docker container putting as volumes both config and model file:
@@ -1008,7 +1252,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.19.2 /config.yaml \
victoriametrics/vmanomaly:v1.20.0 /config.yaml \
--licenseFile=/license
```

View File

@@ -2,9 +2,9 @@
- To use *vmanomaly*, part of the enterprise package, a license key is required. Obtain your key [here](https://victoriametrics.com/products/enterprise/trial/) for this tutorial or for enterprise use.
- In the tutorial, we'll be using the following VictoriaMetrics components:
- [VictoriaMetrics Single-Node](https://docs.victoriametrics.com/single-server-victoriametrics) (v1.111.0)
- [vmalert](https://docs.victoriametrics.com/vmalert/) (v1.111.0)
- [vmagent](https://docs.victoriametrics.com/vmagent/) (v1.111.0)
- [VictoriaMetrics Single-Node](https://docs.victoriametrics.com/single-server-victoriametrics) (v1.112.0)
- [vmalert](https://docs.victoriametrics.com/vmalert/) (v1.112.0)
- [vmagent](https://docs.victoriametrics.com/vmagent/) (v1.112.0)
- [Grafana](https://grafana.com/) (v.10.2.1)
- [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/)
- [Node exporter](https://github.com/prometheus/node_exporter#node-exporter) (v1.7.0) and [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) (v0.27.0)
@@ -315,7 +315,7 @@ Let's wrap it all up together into the `docker-compose.yml` file.
services:
vmagent:
container_name: vmagent
image: victoriametrics/vmagent:v1.111.0
image: victoriametrics/vmagent:v1.112.0
depends_on:
- "victoriametrics"
ports:
@@ -332,7 +332,7 @@ services:
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.111.0
image: victoriametrics/victoria-metrics:v1.112.0
ports:
- 8428:8428
volumes:
@@ -365,7 +365,7 @@ services:
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.111.0
image: victoriametrics/vmalert:v1.112.0
depends_on:
- "victoriametrics"
ports:
@@ -387,7 +387,7 @@ services:
restart: always
vmanomaly:
container_name: vmanomaly
image: victoriametrics/vmanomaly:v1.19.2
image: victoriametrics/vmanomaly:v1.20.0
depends_on:
- "victoriametrics"
ports:

View File

@@ -18,10 +18,58 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
## tip
**Update note 1: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/) and [vmagent](https://docs.victoriametrics.com/vmagent/) include a fix which enforces IPv6 addresses escaping for containers discovered with [Kubernetes service-discovery](https://docs.victoriametrics.com/sd_configs/#kubernetes_sd_configs) and `role: pod` which do not have exposed ports defined. This means that `address` for these containers will always be wrapped in square brackets, this might affect some relabeling rules which were relying on previous behaviour.**
**Update note 2: [vmalert](https://docs.victoriametrics.com/vmalert/) disallow using [time buckets stats pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-by-time-buckets) in alerting or recording rules with VictoriaLogs as datasource. Time buckets used with [stats query API](https://docs.victoriametrics.com/victorialogs/querying/#querying-log-stats) may produce unexpected results for user and result into cardinality issues.**
* FEATURE: upgrade Go builder from Go1.23.6 to Go1.24. See [Go1.24 release notes](https://tip.golang.org/doc/go1.24).
* FEATURE: [alerts](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/deployment/docker/rules/alerts-vmalert.yml): add alerting rule `TooHighQueryLoad` to notify user when VictoriaMetrics or vmselect weren't able to serve requests in timely manner during last 15min.
* FEATURE: [dashboards/single](https://grafana.com/grafana/dashboards/10229) and [dashboards/cluster](https://grafana.com/grafana/dashboards/11176): add panel `Deduplication rate` that shows how many samples are [deduplicated](https://docs.victoriametrics.com/#deduplication) during merges or read queries by VictoriaMetrics components.
* FEATURE: [dashboards/single](https://grafana.com/grafana/dashboards/10229) and [dashboards/cluster](https://grafana.com/grafana/dashboards/11176): add panel `Number of snapshots` that shows the max number of [snapshots](https://docs.victoriametrics.com/#how-to-work-with-snapshots) across vmstorage nodes. This panel should help in disk usage [troubleshooting](https://docs.victoriametrics.com/#snapshot-troubleshooting).
* FEATURE: [dashboards/single](https://grafana.com/grafana/dashboards/10229) and [dashboards/cluster](https://grafana.com/grafana/dashboards/11176): account for samples dropped according to [relabeling config](https://docs.victoriametrics.com/#relabeling) in `Samples dropped for last 1h` panel.
* FEATURE: [dashboards/single](https://grafana.com/grafana/dashboards/10229) and [dashboards/cluster](https://grafana.com/grafana/dashboards/11176): show number of parts in the last partition on `LSM parts max by type` panel. Before, the resulting graph could be skewed by the max number of parts across all partitions. Displaying parts for the latest partition is the correct way to show if storage is currently impacted by merge delays.
* FEATURE: [dashboards/cluster](https://grafana.com/grafana/dashboards/11176): add panel `Partial query results` that shows the number of served [partial responses](https://docs.victoriametrics.com/cluster-victoriametrics/#cluster-availability) by vmselects.
* FEATURE: provide alternative registry for all VictoriaMetrics components at [Quay.io](https://quay.io/organization/victoriametrics).
* FEATURE: [vmalert-tool](https://docs.victoriametrics.com/vmalert-tool/): add command-line flag `-httpListenPort` to specify the port used during testing. If not provided, a random unoccupied port will be assigned. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8393).
* FEATURE: [vmalert-tool](https://docs.victoriametrics.com/vmalert-tool/): make the temporary storage path for unittest unique, allowing user to run multiple vmalert-tool processes on a single host simultaneously. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8393).
* FEATURE: [vmalert](https://docs.victoriametrics.com/vmalert/): disallow using [time buckets stats pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-by-time-buckets) in VictoriaLogs rule expressions. Such construction produces meaningless results for [stats query API](https://docs.victoriametrics.com/victorialogs/querying/#querying-log-stats) and may lead to cardinality issues.
* FEATURE: [data ingestion](https://docs.victoriametrics.com/victorialogs/data-ingestion/): make `KeyValueList`, `ArrayValue` [OpenTelemetry protocol for metrics](https://docs.victoriametrics.com/#sending-data-via-opentelemetry) attributes label values compatible with open-telemetry-collector format. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8384).
* BUGFIX: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and [vmstorage](https://docs.victoriametrics.com/victoriametrics/): fix the incorrect caching of extMetricsIDs when a query timeout error occurs. This can lead to incorrect query results. Thanks to @changshun-shi for [the bug report issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8345).
* BUGFIX: [vmctl](https://docs.victoriametrics.com/vmctl/): respect time filter when exploring time series for [influxdb mode](https://docs.victoriametrics.com/vmctl/#migrating-data-from-influxdb-1x). See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8259) for details.
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/): properly apply global relabeling configuration, defined with `-relabelConfig` flag, for metrics scrapped with `-promscrape.config`. Bug was introduces in [v1.108.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.108.0). See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8389).
* BUGFIX: [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanager/): properly propagate an error message when applying retention policy fails. Previously, an actual error messages was discarded.
* BUGFIX: [vmgateway](https://docs.victoriametrics.com/vmgateway): fix data query in [rate limiter](https://docs.victoriametrics.com/vmgateway/#rate-limiter). The bug was introduced in [this commit](https://github.com/VictoriaMetrics/VictoriaMetrics/commit/68bad22fd26d1436ad0236b1f3ced8604c5d851c) starting from [v1.106.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.106.0).
* BUGFIX: [vmgateway](https://docs.victoriametrics.com/vmgateway): properly apply the [rate limiter](https://docs.victoriametrics.com/vmgateway/#rate-limiter) for the `rows_inserted` limit type. Previously, the rate limit for this type was ignored.
* BUGFIX: [vmgateway](https://docs.victoriametrics.com/vmgateway): properly handle HTTP requests with path ending with a trailing `/` when using the [rate limiter](https://docs.victoriametrics.com/vmgateway/#rate-limiter). Previously, the trailing slash was removed and caused an incorrect redirect path when visiting VMUI. Thanks to @jindov for [the bug report issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8439).
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/) and [vmagent](https://docs.victoriametrics.com/vmagent/): properly escape IPv6 address in [Kubernetes service-discovery](https://docs.victoriametrics.com/sd_configs/#kubernetes_sd_configs) with `role: pod` for containers without exposed ports. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8374).
* BUGFIX: [vmalert-tool](https://docs.victoriametrics.com/vmalert-tool/): clean up the temporary storage path when process is terminated by SIGTERM or SIGINT. Previously, unclean shut down might affect the next run.
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix an infinite loader on the [Downsampling filters debug page](https://docs.victoriametrics.com/#vmui) when provided configuration matches no series. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8339).
## [v1.102.15](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.102.15)
Released at 2025-02-28
**v1.102.x is a line of [LTS releases](https://docs.victoriametrics.com/lts-releases/). It contains important up-to-date bugfixes for [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise.html).
All these fixes are also included in [the latest community release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest).
The v1.102.x line will be supported for at least 12 months since [v1.102.0](https://docs.victoriametrics.com/changelog/#v11020) release**
**Update note 1: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/) and [vmagent](https://docs.victoriametrics.com/vmagent/) include a fix which enforces IPv6 addresses escaping for containers discovered with [Kubernetes service-discovery](https://docs.victoriametrics.com/sd_configs/#kubernetes_sd_configs) and `role: pod` which do not have exposed ports defined. This means that `address` for these containers will always be wrapped in square brackets, this might affect some relabeling rules which were relying on previous behaviour.**
* SECURITY: upgrade golang.org/x/net from v0.31.0 to v0.33.0 to address [GHSA-w32m-9786-jp63](https://github.com/advisories/GHSA-w32m-9786-jp63).
* BUGFIX: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and [vmstorage](https://docs.victoriametrics.com/victoriametrics/): fix the incorrect caching of extMetricsIDs when a query timeout error occurs. This can lead to incorrect query results. Thanks to @changshun-shi for [the bug report issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8345).
* BUGFIX: [vmctl](https://docs.victoriametrics.com/vmctl/): respect time filter when exploring time series for [influxdb mode](https://docs.victoriametrics.com/vmctl/#migrating-data-from-influxdb-1x). See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8259) for details.
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/) and [vmagent](https://docs.victoriametrics.com/vmagent/): properly escape IPv6 address in [Kubernetes service-discovery](https://docs.victoriametrics.com/sd_configs/#kubernetes_sd_configs) with `role: pod` for containers without exposed ports. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8374).
## [v1.112.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.112.0)
Released at 2025-02-21
* SECURITY: upgrade Go builder from Go1.23.5 to Go1.23.6. See the list of issues addressed in [Go1.23.6](https://github.com/golang/go/issues?q=milestone%3AGo1.23.6+label%3ACherryPickApproved).
* SECURITY: upgrade base docker image (Alpine) from 3.21.2 to 3.21.3. See [Alpine 3.21.3 release notes](https://alpinelinux.org/posts/Alpine-3.18.12-3.19.7-3.20.6-3.21.3-released.html).
* FEATURE: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and [vmstorage](https://docs.victoriametrics.com/victoriametrics/): allow disabling per-day indexes for workloads with [low or zero churn rates](https://docs.victoriametrics.com/#index-tuning-for-low-churn-rate) via `-disablePerDayIndex` cmd-line flag. This option works the best for IoT cases and significantly loads resource and disk usage. See [this PR](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/6976).
* FEATURE: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and [vmstorage](https://docs.victoriametrics.com/victoriametrics/): allow [disabling per-day indexes](https://docs.victoriametrics.com/#index-tuning-for-low-churn-rate) for workloads with low or zero churn rates via `-disablePerDayIndex` cmd-line flag. This option works the best for IoT cases and significantly loads resource and disk usage. See [this PR](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/6976).
* FEATURE: [vmalert](https://docs.victoriametrics.com/vmalert/): add command-line flag `-notifier.sendTimeout(default 10s)` to allow configuring request timeout when sending alerts to the corresponding `-notifier.url`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8287) for details. Thanks to @gjkim42 for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/8297).
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent/) and [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/): add support of [aggregation windows](https://docs.victoriametrics.com/stream-aggregation/#aggregation-windows) to improve accuracy of stream aggregation. This feature is especially important for aggregation of [histrograms](https://docs.victoriametrics.com/keyconcepts/#histogram), but enabling this feature requires additional memory. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4580).
* FEATURE: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/), `vminsert` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/) and [vmagent](https://docs.victoriametrics.com/vmagent/): add `-influx.forceStreamMode` cmd-line flag to force stream processing for data ingested via [InfluxDB protocol](https://docs.victoriametrics.com/#how-to-send-data-from-influxdb-compatible-agents-such-as-telegraf). See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8269).
@@ -39,8 +87,39 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert/): fix polluted alert messages when multiple Alertmanager instances are configured with `alert_relabel_configs`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8040), and thanks to @evkuzin for [the pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/8258).
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert/): fix the auto-generated metrics for alerts and groups. Previously, metrics might be missing after reload. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8229) for the details.
* BUGFIX: `vminsert` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/) and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): properly return parsing errors during data ingestion in [multi-level cluster setup](https://docs.victoriametrics.com/cluster-victoriametrics/#multi-level-cluster-setup). Before, some of the errors could have been silently ignored.
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/), `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): fix negative rate result when the lookbehind window is longer than `-search.maxLookback` or `-search.maxStalenessInterval` and data contains gap. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8342).
* BUGFIX: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and [vmselect](https://docs.victoriametrics.com/cluster-victoriametrics/): properly enforce presence of default `-retentionPeriod` configuration for [retention filters](https://docs.victoriametrics.com/#retention-filters) debug interface. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8343).
## [v1.110.2](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.110.2)
Released at 2025-02-21
**v1.110.x is a line of [LTS releases](https://docs.victoriametrics.com/lts-releases/). It contains important up-to-date bugfixes for [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise.html).
All these fixes are also included in [the latest community release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest).
The v1.110.x line will be supported for at least 12 months since [v1.110.0](https://docs.victoriametrics.com/changelog/#v11100) release**
* SECURITY: upgrade Go builder from Go1.23.5 to Go1.23.6. See the list of issues addressed in [Go1.23.6](https://github.com/golang/go/issues?q=milestone%3AGo1.23.6+label%3ACherryPickApproved).
* SECURITY: upgrade base docker image (Alpine) from 3.21.2 to 3.21.3. See [Alpine 3.21.3 release notes](https://alpinelinux.org/posts/Alpine-3.18.12-3.19.7-3.20.6-3.21.3-released.html).
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert/): fix polluted alert messages when multiple Alertmanager instances are configured with `alert_relabel_configs`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8040), and thanks to @evkuzin for [the pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/8258).
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert/): fix the auto-generated metrics for alerts and groups. Previously, metrics might be missing after reload. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8229) for the details.
* BUGFIX: `vminsert` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/) and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): properly return parsing errors during data ingestion in [multi-level cluster setup](https://docs.victoriametrics.com/cluster-victoriametrics/#multi-level-cluster-setup). Before, some of the errors could have been silently ignored.
* BUGFIX: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and [vmselect](https://docs.victoriametrics.com/cluster-victoriametrics/): properly enforce presence of default `-retentionPeriod` configuration for [retention filters](https://docs.victoriametrics.com/#retention-filters) debug interface. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8343).
## [v1.102.14](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.102.14)
Released at 2025-02-21
**v1.102.x is a line of [LTS releases](https://docs.victoriametrics.com/lts-releases/). It contains important up-to-date bugfixes for [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise.html).
All these fixes are also included in [the latest community release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest).
The v1.102.x line will be supported for at least 12 months since [v1.102.0](https://docs.victoriametrics.com/changelog/#v11020) release**
* SECURITY: upgrade Go builder from Go1.23.5 to Go1.23.6. See the list of issues addressed in [Go1.23.6](https://github.com/golang/go/issues?q=milestone%3AGo1.23.6+label%3ACherryPickApproved).
* SECURITY: upgrade base docker image (Alpine) from 3.21.2 to 3.21.3. See [Alpine 3.21.3 release notes](https://alpinelinux.org/posts/Alpine-3.18.12-3.19.7-3.20.6-3.21.3-released.html).
* BUGFIX: `vminsert` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/) and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): properly return parsing error for data ingestion.
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert/): fix the auto-generated metrics for alerts and groups. Previously, metrics might be missing after reload. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8229) for the details.
## [v1.111.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.111.0)
Released at 2025-02-10

View File

@@ -16,7 +16,7 @@ VictoriaMetrics community components are open source and are free to use - see [
and [the license](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/LICENSE).
VictoriaMetrics Enterprise components are available in binary form at [releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest)
and at [docker hub](https://hub.docker.com/u/victoriametrics). Enterprise binaries and packages have `enterprise` suffix in their names.
and at [Docker Hub](https://hub.docker.com/u/victoriametrics) and [Quay](https://quay.io/organization/victoriametrics). Enterprise binaries and packages have `enterprise` suffix in their names.
## Valid cases for VictoriaMetrics Enterprise
@@ -82,7 +82,7 @@ VictoriaMetrics Enterprise components are available in the following forms:
It is allowed to run VictoriaMetrics Enterprise components in [cases listed here](#valid-cases-for-victoriametrics-enterprise).
Binary releases of VictoriaMetrics Enterprise are available [at the releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest).
Enterprise binaries and packages have `enterprise` suffix in their names. For example, `victoria-metrics-linux-amd64-v1.111.0-enterprise.tar.gz`.
Enterprise binaries and packages have `enterprise` suffix in their names. For example, `victoria-metrics-linux-amd64-v1.112.0-enterprise.tar.gz`.
In order to run binary release of VictoriaMetrics Enterprise component, please download the `*-enterprise.tar.gz` archive for your OS and architecture
from the [releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest) and unpack it. Then run the unpacked binary.
@@ -100,8 +100,8 @@ For example, the following command runs VictoriaMetrics Enterprise binary with t
obtained at [this page](https://victoriametrics.com/products/enterprise/trial/):
```sh
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.111.0/victoria-metrics-linux-amd64-v1.111.0-enterprise.tar.gz
tar -xzf victoria-metrics-linux-amd64-v1.111.0-enterprise.tar.gz
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.112.0/victoria-metrics-linux-amd64-v1.112.0-enterprise.tar.gz
tar -xzf victoria-metrics-linux-amd64-v1.112.0-enterprise.tar.gz
./victoria-metrics-prod -license=BASE64_ENCODED_LICENSE_KEY
```
@@ -115,8 +115,8 @@ Alternatively, VictoriaMetrics Enterprise license can be stored in the file and
It is allowed to run VictoriaMetrics Enterprise components in [cases listed here](#valid-cases-for-victoriametrics-enterprise).
Docker images for VictoriaMetrics Enterprise are available [at VictoriaMetrics DockerHub](https://hub.docker.com/u/victoriametrics).
Enterprise docker images have `enterprise` suffix in their names. For example, `victoriametrics/victoria-metrics:v1.111.0-enterprise`.
Docker images for VictoriaMetrics Enterprise are available at VictoriaMetrics [Docker Hub](https://hub.docker.com/u/victoriametrics) and [Quay](https://quay.io/organization/victoriametrics).
Enterprise docker images have `enterprise` suffix in their names. For example, `victoriametrics/victoria-metrics:v1.112.0-enterprise`.
In order to run Docker image of VictoriaMetrics Enterprise component, it is required to provide the license key via command-line
flag as described [here](#binary-releases).
@@ -126,13 +126,13 @@ Enterprise license key can be obtained at [this page](https://victoriametrics.co
For example, the following command runs VictoriaMetrics Enterprise Docker image with the specified license key:
```sh
docker run --name=victoria-metrics victoriametrics/victoria-metrics:v1.111.0-enterprise -license=BASE64_ENCODED_LICENSE_KEY
docker run --name=victoria-metrics victoriametrics/victoria-metrics:v1.112.0-enterprise -license=BASE64_ENCODED_LICENSE_KEY
```
Alternatively, the license code can be stored in the file and then referred via `-licenseFile` command-line flag:
```sh
docker run --name=victoria-metrics -v /vm-license:/vm-license victoriametrics/victoria-metrics:v1.111.0-enterprise -licenseFile=/path/to/vm-license
docker run --name=victoria-metrics -v /vm-license:/vm-license victoriametrics/victoria-metrics:v1.112.0-enterprise -licenseFile=/path/to/vm-license
```
Example docker-compose configuration:
@@ -141,7 +141,7 @@ version: "3.5"
services:
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.111.0
image: victoriametrics/victoria-metrics:v1.112.0
ports:
- 8428:8428
volumes:
@@ -173,7 +173,7 @@ is used to provide key in plain-text:
```yaml
server:
image:
tag: v1.111.0-enterprise
tag: v1.112.0-enterprise
license:
key: {BASE64_ENCODED_LICENSE_KEY}
@@ -184,7 +184,7 @@ In order to provide key via existing secret, the following values file is used:
```yaml
server:
image:
tag: v1.111.0-enterprise
tag: v1.112.0-enterprise
license:
secret:
@@ -233,7 +233,7 @@ spec:
license:
key: {BASE64_ENCODED_LICENSE_KEY}
image:
tag: v1.111.0-enterprise
tag: v1.112.0-enterprise
```
In order to provide key via existing secret, the following custom resource is used:
@@ -250,7 +250,7 @@ spec:
name: vm-license
key: license
image:
tag: v1.111.0-enterprise
tag: v1.112.0-enterprise
```
Example secret with license key:

View File

@@ -236,27 +236,27 @@ services:
- grafana_data:/var/lib/grafana/
vmsingle:
image: victoriametrics/victoria-metrics:v1.111.0
image: victoriametrics/victoria-metrics:v1.112.0
command:
- -httpListenAddr=0.0.0.0:8429
vmstorage:
image: victoriametrics/vmstorage:v1.111.0-cluster
image: victoriametrics/vmstorage:v1.112.0-cluster
vminsert:
image: victoriametrics/vminsert:v1.111.0-cluster
image: victoriametrics/vminsert:v1.112.0-cluster
command:
- -storageNode=vmstorage:8400
- -httpListenAddr=0.0.0.0:8480
vmselect:
image: victoriametrics/vmselect:v1.111.0-cluster
image: victoriametrics/vmselect:v1.112.0-cluster
command:
- -storageNode=vmstorage:8401
- -httpListenAddr=0.0.0.0:8481
vmagent:
image: victoriametrics/vmagent:v1.111.0
image: victoriametrics/vmagent:v1.112.0
volumes:
- ./scrape.yaml:/etc/vmagent/config.yaml
command:
@@ -265,7 +265,7 @@ services:
- -remoteWrite.url=http://vmsingle:8429/api/v1/write
vmgateway-cluster:
image: victoriametrics/vmgateway:v1.111.0-enterprise
image: victoriametrics/vmgateway:v1.112.0-enterprise
ports:
- 8431:8431
volumes:
@@ -281,7 +281,7 @@ services:
- -auth.oidcDiscoveryEndpoints=http://keycloak:8080/realms/master/.well-known/openid-configuration
vmgateway-single:
image: victoriametrics/vmgateway:v1.111.0-enterprise
image: victoriametrics/vmgateway:v1.112.0-enterprise
ports:
- 8432:8431
volumes:
@@ -393,7 +393,7 @@ Once iDP configuration is done, vmagent configuration needs to be updated to use
```yaml
vmagent:
image: victoriametrics/vmagent:v1.111.0
image: victoriametrics/vmagent:v1.112.0
volumes:
- ./scrape.yaml:/etc/vmagent/config.yaml
- ./vmagent-client-secret:/etc/vmagent/oauth2-client-secret

View File

@@ -30,8 +30,8 @@ scrape_configs:
After you created the `scrape.yaml` file, download and unpack [single-node VictoriaMetrics](https://docs.victoriametrics.com/) to the same directory:
```
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.111.0/victoria-metrics-linux-amd64-v1.111.0.tar.gz
tar xzf victoria-metrics-linux-amd64-v1.111.0.tar.gz
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.112.0/victoria-metrics-linux-amd64-v1.112.0.tar.gz
tar xzf victoria-metrics-linux-amd64-v1.112.0.tar.gz
```
Then start VictoriaMetrics and instruct it to scrape targets defined in `scrape.yaml` and save scraped metrics
@@ -146,8 +146,8 @@ Then start [single-node VictoriaMetrics](https://docs.victoriametrics.com/) acco
```yaml
# Download and unpack single-node VictoriaMetrics
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.111.0/victoria-metrics-linux-amd64-v1.111.0.tar.gz
tar xzf victoria-metrics-linux-amd64-v1.111.0.tar.gz
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.112.0/victoria-metrics-linux-amd64-v1.112.0.tar.gz
tar xzf victoria-metrics-linux-amd64-v1.112.0.tar.gz
# Run single-node VictoriaMetrics with the given scrape.yaml
./victoria-metrics-prod -promscrape.config=scrape.yaml

View File

@@ -1164,9 +1164,8 @@ It depends on network lag, load, clock synchronization, etc. In most scenarios i
deduplication results, which are consistent within margin of error. But for metrics represented as a collection of series,
like [histograms](https://docs.victoriametrics.com/keyconcepts/#histogram), such inaccuracy leads to invalid aggregation results.
For this case, streaming aggregation and deduplication support mode with aggregation windows {{% available_from "#tip" %}}
for current and previous state. With this mode, flush doesn't happen immediately but is shifted by a calculated samples
lag that improves correctness for delayed data.
For this case, streaming aggregation and deduplication support mode with aggregation windows for current and previous state.
With this mode, flush doesn't happen immediately but is shifted by a calculated samples lag that improves correctness for delayed data. {{% available_from "v1.112.0" %}}
Enabling of this mode has increased resource usage: memory usage is expected to double as aggregation will store two states
instead of one. However, this significantly improves accuracy of calculations. Aggregation windows can be enabled via

View File

@@ -1,10 +1,9 @@
VictoriaMetrics Cloud is a managed, easy to use monitoring solution that integrates seamlessly with
other tools and frameworks in the Observability ecosystem such as OpenTelemetry, Grafana, Prometheus, Graphite,
InfluxDB, OpenTSDB and DataDog - see [these docs](https://docs.victoriametrics.com/#how-to-import-time-series-data)
for further details.
for further details about importing time series data into VictoriaMetrics.
<br>
<!--TODO: Just a test: Needs to be changed by something better!-->
![](/victoriametrics-cloud/get-started/get_started_preview.webp)
<br>
@@ -13,35 +12,16 @@ for further details.
* [Quick Start](/victoriametrics-cloud/quickstart/) documentation.
* [Try it now](https://console.victoriametrics.cloud/signUp?utm_source=website&utm_campaign=docs_overview) with a free trial.
## Use cases
The most common use cases for VictoriaMetrics Cloud are:
* Long-term remote storage for Prometheus metrics.
VictoriaMetrics Cloud is designed for teams and organizations that handle any volume of metrics. The most common use cases for VictoriaMetrics Cloud are:
* Long-term remote storage for Prometheus, OpenTelemetry and any other standardized metrics.
* Reliable and efficient drop-in replacement for Prometheus and Graphite.
* Easy and cost-saving enterprise managed alternative solution for Prometheus, Thanos, Mimir or Cortex.
* Efficient replacement for InfluxDB and OpenTSDB by consuming lower amounts of RAM, CPU and disk.
* Cost-efficient alternative for Observability services like DataDog.
* Cost-efficient alternative for other Observability services like DataDog or Grafana Cloud.
## Benefits
We run VictoriaMetrics Cloud deployments in our environment on AWS and provide easy-to-use endpoints
for data ingestion and querying. The VictoriaMetrics team takes care of optimal configuration and software
maintenance. This means that VictoriaMetrics Cloud allows users to run the Enterprise version of VictoriaMetrics, hosted on AWS,
without the hustle to perform typical DevOps tasks such as:
* Managing configuration.
* Monitoring.
* Logs collection.
* Access protection.
* Software updates.
* Regular backups.
* Control costs.
## Features
VictoriaMetrics Cloud comes with the following features:
* It can be used as a Managed Prometheus - just configure Prometheus or vmagent to write data to VictoriaMetrics Cloud and then use the provided endpoint as a Prometheus datasource in Grafana.
* Built-in [Alerting & Recording](https://docs.victoriametrics.com/victoriametrics-cloud/alertmanager-setup-for-deployment/#configure-alerting-rules) rules execution.
* Hosted [Alertmanager](https://docs.victoriametrics.com/victoriametrics-cloud/alertmanager-setup-for-deployment/) for sending notifications.
* Every VictoriaMetrics Cloud deployment runs in an isolated environment, so deployments cannot interfere with each other.
* VictoriaMetrics Cloud deployment can be scaled up or scaled down in a few clicks.
* Automated backups.
* No surprises. Select a tier and pay only for the actual used resources - compute, storage, traffic.
Discover VictoriaMetrics Cloud Features and Benefits [here](/victoriametrics-cloud/get-started/features).
## Learn more
* [VictoriaMetrics Cloud announcement](https://victoriametrics.com/blog/introduction-to-managed-monitoring/).

View File

@@ -1,7 +1,6 @@
---
title: VictoriaMetrics Cloud Overview
title: VictoriaMetrics Cloud
weight: 40
disableToc: true
menu:
docs:
weight: 40

View File

@@ -16,7 +16,7 @@ This guide explains the different ways in which you can use vmalert in conjuncti
## Preconditions
* [vmalert](https://docs.victoriametrics.com/vmalert/) is installed. You can obtain it by building it from [source](https://docs.victoriametrics.com/vmalert/#quickstart), downloading it from the [GitHub releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest), or using the [docker image](https://hub.docker.com/r/victoriametrics/vmalert) for the container ecosystem (such as docker, k8s, etc.).
* [vmalert](https://docs.victoriametrics.com/vmalert/) is installed. You can obtain it by building it from [source](https://docs.victoriametrics.com/vmalert/#quickstart), downloading it from the [GitHub releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest), or using the docker image [Docker Hub](https://hub.docker.com/r/victoriametrics/vmalert) or [Quay](https://quay.io/repository/victoriametrics/vmalert?tab=tags) for the container ecosystem (such as docker, k8s, etc.).
* [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) is installed.
* You have a [single or cluster](https://docs.victoriametrics.com/victoriametrics-cloud/quickstart/#creating-deployment) deployment in [VictoriaMetrics Cloud](https://docs.victoriametrics.com/victoriametrics-cloud/overview/).
* If you are using helm, add the [VictoriaMetrics helm chart](https://docs.victoriametrics.com/helm/victoriametrics-alert#how-to-install) repository to your helm repositories. This step is optional.

View File

@@ -10,18 +10,15 @@ menu:
---
In this section you will find everything you need to start using [VictoriaMetrics Cloud](https://console.victoriametrics.cloud/signUp?utm_source=website&utm_campaign=docs_vm_get_started).
* [Overview of VictoriaMetrics Cloud](overview/)
* [Quick Start](quickstart/)
* [Overview of VictoriaMetrics Cloud](https://docs.victoriametrics.com/victoriametrics-cloud/get-started/overview/)
* [Key Features & Benefits](https://docs.victoriametrics.com/victoriametrics-cloud/get-started/features/)
* [Quick Start](https://docs.victoriametrics.com/victoriametrics-cloud/get-started/quickstart/)
* [Guides and Best Practices](https://docs.victoriametrics.com/victoriametrics-cloud/get-started/guides/)
## Guides
* [Understand Your Setup Size](/guides/understand-your-setup-size/)
* [Alerting & recording rules with Alertmanager configuration for VictoriaMetrics Cloud deployment](/victoriametrics-cloud/alertmanager-setup-for-deployment/)
* [Kubernetes Monitoring with VictoriaMetrics Cloud](/victoriametrics-cloud/how-to-monitor-k8s/)
* [Setup Notifications](/victoriametrics-cloud/setup-notifications/)
* [User Management](/victoriametrics-cloud/user-managment/)
<details>
<summary>Learn more about VictoriaMetrics Cloud</summary>
Learn more about VictoriaMetrics Cloud:
* [VictoriaMetrics Cloud announcement](https://victoriametrics.com/blog/introduction-to-managed-monitoring/)
* [Pricing comparison for Managed Prometheus](https://victoriametrics.com/blog/managed-prometheus-pricing/)
* [Monitoring Proxmox VE via VictoriaMetrics Cloud and vmagent](https://victoriametrics.com/blog/proxmox-monitoring-with-dbaas/)
</details>

View File

@@ -0,0 +1,142 @@
---
weight: 2
title: Key Features & Benefits
menu:
docs:
parent: get-started
weight: 2
aliases:
- /victoriametrics-cloud/quickstart/features.html
- /managed-victoriametrics/quickstart/features.html
---
VictoriaMetrics Cloud helps optimizing your data and maximizing its value in the most reliable way. It can be used as an **Enterprise-level Managed Prometheus**: just configure Prometheus, [vmagent](https://docs.victoriametrics.com/vmagent/), an OpenTelemetry Collector or any agent to write data to VictoriaMetrics Cloud, and point Grafana to VictoriaMetrics Cloud by configuring it as a Prometheus datasource.
## Features
VictoriaMetrics Cloud offers a robust suite of features designed to optimize your cloud experience. Seamless integrations, scalability and cost-saving measures, and comprehensive operational tools ensure that VictoriaMetrics Cloud can support your business needs.
<details>
<summary>Integrations and Compatibility</summary>
* **Observability protocols**: OpenTelemetry, InfluxDB, DataDog, NewRelic, OpenTSDB & Graphite.
* **Data visualization**: Use built-in [VictoriaMetrics UI](https://play.victoriametrics.com/) or integrate seamlessly with your current stack to query and visualize your data in [Grafana](https://grafana.com/) or [Perses](https://perses.dev).
* [**AWS PrivateLink**](https://aws.amazon.com/privatelink/): enabling even more secure communication with VictoriaMetrics Cloud deployments directly from your VPC.
![Integrations](https://docs.victoriametrics.com/victoriametrics-cloud/get-started/features_integrations.webp)
<figcaption style="text-align: center; font-style: italic;">VictoriaMetrics Cloud Integrations</figcaption>
</details>
<details>
<summary>Scale as you go and save costs</summary>
* **Easy Scaling**: VictoriaMetrics Cloud deployments can be scaled up or down with just a few clicks in line with growth and needs.
* **Downsampling**: Lower your disk footprint (and save on storage costs!) by keeping fewer data points for historical data and speed up queries for it, while preserving high precision for your operational data.
* **Retention filters**: Configure a custom retention period on a team (tenant) level or time series level by using label filters so that unneeded time series are wiped out freeing up storage space for new metrics data enabling additional cost savings
* **Recording rules**: Improve query performance with recording rules, facilitating quicker data access & dashboard responsiveness.
</details>
<details>
<summary>Operations</summary>
* **Enterprise, managed VictoriaMetrics Solution**: Comes with all the proven features in VictoriaMetrics open source & Enterprise.
* **Single-node** & **Cluster** configurations with automatic software version and security updates.
* Built-in [Alerting & Recording](https://docs.victoriametrics.com/victoriametrics-cloud/alertmanager-setup-for-deployment/#configure-alerting-rules) rules execution. Define your rules & get immediate alerts as issues arise, enabling swift action & minimizing disruption to your users.
* Hosted [Alertmanager](https://docs.victoriametrics.com/victoriametrics-cloud/alertmanager-setup-for-deployment/) for sending notifications.
* **Isolated Deployments**: VictoriaMetrics Cloud provisions dedicated resources for your deployments, so you wont encounter “noisy neighbors” problems as deployments do not compete for resources.
* **Multitenancy**: Easily serve multiple teams (tenants) with one Cluster deployment by having a dedicated namespace for each team.
* **Automated Backups**: Regular backup procedures are in place. Your data is automatically saved to a backup storage, so you can easily restore it when the need arises.
* **High-availability** & replication.
* **Reliability** & extraordinary performance with 99.95% SLA.
</details>
## Get instant value from your data
VictoriaMetrics Cloud allows you to explore and optimize both your data and deployments.
<details>
<summary>Query your own metrics</summary>
* Visualize your own data in graphs, table or json formats
* Combine several queries at the same time
* Prettify your queries to improve readability
* Autocomplete to help you writing queries
* Trace your queries to understand behavior
![Query](https://docs.victoriametrics.com/victoriametrics-cloud/get-started/features_query.webp)
<figcaption style="text-align: center; font-style: italic;">Query your data with VictoriaMetrics Cloud</figcaption>
</details>
<details>
<summary>Explore valuable insights</summary>
* List your Prometheus metrics by Job and Instance
* Inspect your time series data cardinality to optimize usage and costs
* Discover top used or heaviest queries
![Cardinality](https://docs.victoriametrics.com/victoriametrics-cloud/get-started/features_cardinality.webp)
<figcaption style="text-align: center; font-style: italic;">Understand your data with VictoriaMetrics Cloud</figcaption>
</details>
<details>
<summary>Analyze, debug and learn</summary>
* Trace and query analyzer to debug queries
* WITH templating for MetricsQL: functions, variables and filters
* Debug metrics relabling with easy-to-follow examples
![Traces](https://docs.victoriametrics.com/victoriametrics-cloud/get-started/features_traces.webp)
<figcaption style="text-align: center; font-style: italic;">Debug your queries</figcaption>
</details>
## Benefits
In brief, we run VictoriaMetrics Cloud deployments in our AWS environment and provide direct endpoints
for data ingestion and querying. The VictoriaMetrics team takes care of optimal configuration and software
maintenance. You can think of it as having access to a **fully supported, enterprise** version of VictoriaMetrics
that runs outside your environment, helping you to save resources and costs, without the hustle of performing
typical DevOps tasks such as configuration management, monitoring, log collection, access protection, perform
software and infrastructure upgrades, store backups regularly or control costs. **We take care of that**.
> VictoriaMetrics Cloud is able to handle larger workloads than competing solutions at a far lower cost.
<details>
<summary>Easy Migration</summary>
* Migrate from costly & less scalable monitoring solutions such as Managed Prometheus service from AWS, GCP or Azure, InfluxDB Cloud, or your on-premises setup.
* Get higher data resolution with much higher cardinality.
* Run more complex queries.
</details>
<details>
<summary>Enterprise level support</summary>
Includes all VictoriaMetrics Enterprise Features Plus:
* Business days & hours support
* 8 hours response time for system impaired issues
</details>
<details>
<summary>Cost-efficient Scaling</summary>
* Only pay for the resources that you actually use (compute, disk and network).
* Downsampling and retention filters features enable additional cost-savings.
</details>
<details>
<summary>Ease of Budgeting</summary>
**No invoice surprises**: pick a tier at a fixed price. Our pricing model protects you from surprise overages coming from unexpected changes in workload such as spikes in data ingestion rate, cardinality explosions or accidental heavy queries.
</details>
<details>
<summary>Ease of use</summary>
The VictoriaMetrics team takes care of optimal configuration and handles all software maintenance, so you can focus on the monitoring.
</details>

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -0,0 +1,19 @@
---
weight: 4
title: Guides and Best Practices
menu:
docs:
parent: get-started
weight: 4
aliases:
- /victoriametrics-cloud/quickstart/best-practices.html
- /managed-victoriametrics/quickstart/best-practices.html
---
Here you can find some guides and best practices:
* [Understand Your Setup Size](https://docs.victoriametrics.com/guides/understand-your-setup-size/)
* [Alerting & recording rules with Alertmanager configuration for VictoriaMetrics Cloud deployment](https://docs.victoriametrics.com/victoriametrics-cloud/alertmanager-setup-for-deployment/)
* [Kubernetes Monitoring with VictoriaMetrics Cloud](https://docs.victoriametrics.com/victoriametrics-cloud/how-to-monitor-k8s/)
* [Setup Notifications](https://docs.victoriametrics.com/victoriametrics-cloud/setup-notifications/)
* [User Management](https://docs.victoriametrics.com/victoriametrics-cloud/user-managment/)

View File

@@ -55,7 +55,7 @@ additionally to [discovering Prometheus-compatible targets and scraping metrics
## Quick Start
Please download `vmutils-*` archive from [releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest) (
`vmagent` is also available in [docker images](https://hub.docker.com/r/victoriametrics/vmagent/tags)),
`vmagent` is also available in docker images [Docker Hub](https://hub.docker.com/r/victoriametrics/vmagent/tags) and [Quay](https://quay.io/repository/victoriametrics/vmagent?tab=tags)),
unpack it and pass the following flags to the `vmagent` binary in order to start scraping Prometheus-compatible targets
and sending the data to the Prometheus-compatible remote storage:
@@ -1368,7 +1368,7 @@ and gzipped [JSON line](https://docs.victoriametrics.com/#json-line-format) mess
These command-line flags are available only in [enterprise](https://docs.victoriametrics.com/enterprise/) version of `vmagent`,
which can be downloaded for evaluation from [releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest) page
(see `vmutils-...-enterprise.tar.gz` archives) and from [docker images](https://hub.docker.com/r/victoriametrics/vmagent/tags) with tags containing `enterprise` suffix.
(see `vmutils-...-enterprise.tar.gz` archives) and from docker images [Docker Hub](https://hub.docker.com/r/victoriametrics/vmagent/tags) and [Quay](https://quay.io/repository/victoriametrics/vmagent?tab=tags) with tags containing `enterprise` suffix.
```sh
-gcp.pubsub.subscribe.credentialsFile string
@@ -1402,7 +1402,7 @@ These messages can be read later from Google PubSub by another `vmagent` instanc
These command-line flags are available only in [enterprise](https://docs.victoriametrics.com/enterprise/) version of `vmagent`,
which can be downloaded for evaluation from [releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest) page
(see `vmutils-...-enterprise.tar.gz` archives) and from [docker images](https://hub.docker.com/r/victoriametrics/vmagent/tags) with tags containing `enterprise` suffix.
(see `vmutils-...-enterprise.tar.gz` archives) and from docker images [Docker Hub](https://hub.docker.com/r/victoriametrics/vmagent/tags) and [Quay](https://quay.io/repository/victoriametrics/vmagent?tab=tags) with tags containing `enterprise` suffix.
```sh
-gcp.pubsub.publish.byteThreshold int
@@ -1431,7 +1431,7 @@ which can be downloaded for evaluation from [releases](https://github.com/Victor
* [Writing metrics to Kafka](#writing-metrics-to-kafka)
The enterprise version of vmagent is available for evaluation at [releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest) page
in `vmutils-...-enterprise.tar.gz` archives and in [docker images](https://hub.docker.com/r/victoriametrics/vmagent/tags) with tags containing `enterprise` suffix.
in `vmutils-...-enterprise.tar.gz` archives and in docker images [Docker Hub](https://hub.docker.com/r/victoriametrics/vmagent/tags) and [Quay](https://quay.io/repository/victoriametrics/vmagent?tab=tags) with tags containing `enterprise` suffix.
See how to request a free trial license [here](https://victoriametrics.com/products/enterprise/trial/).
### Reading metrics from Kafka
@@ -1507,7 +1507,7 @@ See also [how to write metrics to multiple distinct tenants](https://docs.victor
These command-line flags are available only in [enterprise](https://docs.victoriametrics.com/enterprise/) version of `vmagent`,
which can be downloaded for evaluation from [releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest) page
(see `vmutils-...-enterprise.tar.gz` archives) and from [docker images](https://hub.docker.com/r/victoriametrics/vmagent/tags) with tags containing `enterprise` suffix.
(see `vmutils-...-enterprise.tar.gz` archives) and from docker images [Docker Hub](https://hub.docker.com/r/victoriametrics/vmagent/tags) and [Quay](https://quay.io/repository/victoriametrics/vmagent?tab=tags) with tags containing `enterprise` suffix.
```sh
-kafka.consumer.topic array

View File

@@ -312,6 +312,8 @@ Run `vmalert-tool unittest --help` to get all configuration options:
Optional label in the form 'name=value' to add to all generated recording rules and alerts. Supports an array of values separated by comma or specified via multiple flags.
-external.url
Optional external URL to template in rule's labels or annotations.
-httpListenPort
Optional local port for incoming HTTP requests. If not specified, a random unoccupied port will be used.
-loggerLevel
Minimum level of errors to log. Possible values: INFO, WARN, ERROR, FATAL, PANIC (default "ERROR").
```

View File

@@ -8,8 +8,8 @@ title: vmalert
aliases:
- /vmalert.html
---
`vmalert` executes a list of the given [alerting](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/)
or [recording](https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/)
`vmalert` executes a list of the given [alerting](https://docs.victoriametrics.com/vmalert/#alerting-rules)
or [recording](https://docs.victoriametrics.com/vmalert/#recording-rules)
rules against configured `-datasource.url`. For sending alerting notifications
`vmalert` relies on [Alertmanager](https://github.com/prometheus/alertmanager) configured via `-notifier.url` flag.
Recording rules results are persisted via [remote write](https://prometheus.io/docs/prometheus/latest/storage/#remote-storage-integrations)
@@ -521,7 +521,7 @@ is obtained from `-defaultTenant.prometheus` or `-defaultTenant.graphite` depend
The enterprise version of vmalert is available in `vmutils-*-enterprise.tar.gz` files
at [release page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest) and in `*-enterprise`
tags at [Docker Hub](https://hub.docker.com/r/victoriametrics/vmalert/tags).
tags at [Docker Hub](https://hub.docker.com/r/victoriametrics/vmalert/tags) and [Quay](https://quay.io/repository/victoriametrics/vmalert?tab=tags).
### Reading rules from object storage
@@ -952,7 +952,7 @@ Sensitive info is stripped from the `curl` examples - see [security](#security)
### Never-firing alerts
vmalert can detect if alert's expression doesn't match any time series in runtime
vmalert can detect{{% available_from "v1.91.0" %}} if alert's expression doesn't match any time series in runtime
starting from [v1.91](https://docs.victoriametrics.com/changelog/#v1910). This problem usually happens
when alerting expression selects time series which aren't present in the datasource (i.e. wrong `job` label)
or there is a typo in the series selector (i.e. `env=prod`). Such alerting rules will be marked with special icon in
@@ -964,8 +964,8 @@ used to detect rules matching no series:
max(vmalert_alerting_rules_last_evaluation_series_fetched) by(group, alertname) == 0
```
See more details [here](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4039).
This feature is available only if vmalert is using VictoriaMetrics v1.90 or higher as a datasource.
See more details [here](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4039) and
read [Never-firing alerts](https://victoriametrics.com/blog/never-firing-alerts/) blogpost.
### Series with the same labelset
@@ -1269,7 +1269,7 @@ The shortlist of configuration flags is the following:
Supports an array of values separated by comma or specified via multiple flags.
Value can contain comma inside single-quoted or double-quoted string, {}, [] and () braces.
-notifier.sendTimeout
Timeout for sending alerts to the configured -notifier.url. (default 10s)
Timeout when sending alerts to the corresponding -notifier.url. (default 10s)
-notifier.showURL
Whether to avoid stripping sensitive information such as passwords from URL in log messages or UI for -notifier.url. It is hidden by default, since it can contain sensitive info such as auth key
-notifier.suppressDuplicateTargetErrors

View File

@@ -28,7 +28,7 @@ The port can be modified via `-httpListenAddr` command-line flag.
See [how to reload config without restart](#config-reload).
Docker images for `vmauth` are available [here](https://hub.docker.com/r/victoriametrics/vmauth/tags).
Docker images for `vmauth` are available at [Docker Hub](https://hub.docker.com/r/victoriametrics/vmauth/tags) and [Quay](https://quay.io/repository/victoriametrics/vmauth?tab=tags).
See how `vmauth` used in [docker-compose env](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/deployment/docker/README.md#victoriametrics-cluster).
Pass `-help` to `vmauth` in order to see all the supported command-line flags with their descriptions.

View File

@@ -1191,7 +1191,7 @@ Flags available only for the `opentsdb` command:
--influx-measurement-field-separator value
The {separator} symbol used to concatenate {measurement} and {field} names into series name {measurement}{separator}{field}. (default: "_")
--influx-skip-database-label
Wether to skip adding the label 'db' to timeseries. (default: false)
Whether to skip adding the label 'db' to timeseries. (default: false)
--influx-prometheus-mode
Whether to restore the original timeseries name previously written from Prometheus to InfluxDB v1 via remote_write. (default: false)
--influx-cert-file value

2
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/VictoriaMetrics/VictoriaMetrics
go 1.23.6
go 1.24.0
// This is needed in order to avoid vmbackup and vmrestore binary size increase by 20MB
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8008

View File

@@ -5,7 +5,7 @@ import (
"net/http"
"strconv"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil"
)
// GetDuration returns duration in milliseconds from the given argKey query arg.
@@ -21,7 +21,7 @@ func GetDuration(r *http.Request, argKey string, defaultValue int64) (int64, err
secs, err := strconv.ParseFloat(argValue, 64)
if err != nil {
// Try parsing string format
d, err := promutils.ParseDuration(argValue)
d, err := timeutil.ParseDuration(argValue)
if err != nil {
return 0, fmt.Errorf("cannot parse %q=%q: %w", argKey, argValue, err)
}

View File

@@ -6,7 +6,7 @@ import (
"net/http"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil"
)
// GetTime returns time in milliseconds from the given argKey query arg.
@@ -28,7 +28,7 @@ func GetTime(r *http.Request, argKey string, defaultMs int64) (int64, error) {
return maxTimeMsecs, nil
}
// Parse argValue
msecs, err := promutils.ParseTimeMsec(argValue)
msecs, err := timeutil.ParseTimeMsec(argValue)
if err != nil {
return 0, fmt.Errorf("cannot parse %s=%s: %w", argKey, argValue, err)
}

View File

@@ -3,6 +3,8 @@ package logstorage
import (
"fmt"
"sync"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
)
// filterEqField matches if the given fields have equivalent values.
@@ -23,6 +25,10 @@ func (fe *filterEqField) updateNeededFields(neededFields fieldsSet) {
}
func (fe *filterEqField) applyToBlockResult(br *blockResult, bm *bitmap) {
if fe.fieldName == fe.otherFieldName {
return
}
c := br.getColumnByName(fe.fieldName)
cOther := br.getColumnByName(fe.otherFieldName)
@@ -34,7 +40,44 @@ func (fe *filterEqField) applyToBlockResult(br *blockResult, bm *bitmap) {
}
return
}
if c.isTime && cOther.isTime {
// c and cOther point to the same _time column, since only a single _time column may exist
return
}
if c.valueType != cOther.valueType {
// Slow path - c and cOther have different valueType, so convert them to string values and compare them
applyFilterEqString(br, bm, c, cOther)
return
}
switch c.valueType {
case valueTypeString:
applyFilterEqString(br, bm, c, cOther)
case valueTypeDict:
applyFilterEqDict(br, bm, c, cOther)
case valueTypeUint8:
applyFilterEqBinValues(br, bm, c, cOther)
case valueTypeUint16:
applyFilterEqBinValues(br, bm, c, cOther)
case valueTypeUint32:
applyFilterEqBinValues(br, bm, c, cOther)
case valueTypeUint64:
applyFilterEqBinValues(br, bm, c, cOther)
case valueTypeInt64:
applyFilterEqBinValues(br, bm, c, cOther)
case valueTypeFloat64:
applyFilterEqBinValues(br, bm, c, cOther)
case valueTypeIPv4:
applyFilterEqBinValues(br, bm, c, cOther)
case valueTypeTimestampISO8601:
applyFilterEqBinValues(br, bm, c, cOther)
default:
logger.Panicf("FATAL: unknown valueType=%d", c.valueType)
}
}
func applyFilterEqString(br *blockResult, bm *bitmap, c, cOther *blockResultColumn) {
values := c.getValues(br)
valuesOther := cOther.getValues(br)
bm.forEachSetBit(func(idx int) bool {
@@ -42,7 +85,87 @@ func (fe *filterEqField) applyToBlockResult(br *blockResult, bm *bitmap) {
})
}
func applyFilterEqDict(br *blockResult, bm *bitmap, c, cOther *blockResultColumn) {
valuesEncoded := c.getValuesEncoded(br)
valuesEncodedOther := cOther.getValuesEncoded(br)
bm.forEachSetBit(func(idx int) bool {
dictIdx := valuesEncoded[idx][0]
dictIdxOther := valuesEncodedOther[idx][0]
v := c.dictValues[dictIdx]
vOther := cOther.dictValues[dictIdxOther]
return v == vOther
})
}
func applyFilterEqBinValues(br *blockResult, bm *bitmap, c, cOther *blockResultColumn) {
valuesEncoded := c.getValuesEncoded(br)
valuesEncodedOther := cOther.getValuesEncoded(br)
bm.forEachSetBit(func(idx int) bool {
return valuesEncoded[idx] == valuesEncodedOther[idx]
})
}
func (fe *filterEqField) applyToBlockSearch(bs *blockSearch, bm *bitmap) {
if fe.fieldName == fe.otherFieldName {
return
}
v := bs.getConstColumnValue(fe.fieldName)
vOther := bs.getConstColumnValue(fe.otherFieldName)
if v != "" || vOther != "" {
if v != "" && vOther != "" {
if v != vOther {
bm.resetBits()
}
return
}
fe.applyFilterString(bs, bm)
return
}
ch := bs.getColumnHeader(fe.fieldName)
chOther := bs.getColumnHeader(fe.otherFieldName)
if ch == nil || chOther == nil {
if ch == nil && chOther == nil {
return
}
fe.applyFilterString(bs, bm)
return
}
if ch.valueType != chOther.valueType {
// Slow path - c and cOther have different valueType, so convert them to string values and compare them
fe.applyFilterString(bs, bm)
return
}
switch ch.valueType {
case valueTypeString:
fe.applyFilterString(bs, bm)
case valueTypeDict:
fe.applyFilterDict(bs, bm, ch, chOther)
case valueTypeUint8:
fe.applyFilterBinValue(bs, bm, ch, chOther)
case valueTypeUint16:
fe.applyFilterBinValue(bs, bm, ch, chOther)
case valueTypeUint32:
fe.applyFilterBinValue(bs, bm, ch, chOther)
case valueTypeUint64:
fe.applyFilterBinValue(bs, bm, ch, chOther)
case valueTypeInt64:
fe.applyFilterBinValue(bs, bm, ch, chOther)
case valueTypeFloat64:
fe.applyFilterBinValue(bs, bm, ch, chOther)
case valueTypeIPv4:
fe.applyFilterBinValue(bs, bm, ch, chOther)
case valueTypeTimestampISO8601:
fe.applyFilterBinValue(bs, bm, ch, chOther)
default:
logger.Panicf("FATAL: %s: unknown valueType=%d", bs.partPath(), ch.valueType)
}
}
func (fe *filterEqField) applyFilterString(bs *blockSearch, bm *bitmap) {
br := getBlockResult()
br.mustInit(bs, bm)
br.initRequestedColumns([]string{fe.fieldName, fe.otherFieldName})
@@ -63,6 +186,26 @@ func (fe *filterEqField) applyToBlockSearch(bs *blockSearch, bm *bitmap) {
putBlockResult(br)
}
func (fe *filterEqField) applyFilterDict(bs *blockSearch, bm *bitmap, ch, chOther *columnHeader) {
valuesEncoded := bs.getValuesForColumn(ch)
valuesEncodedOther := bs.getValuesForColumn(chOther)
bm.forEachSetBit(func(idx int) bool {
dictIdx := valuesEncoded[idx][0]
dictIdxOther := valuesEncodedOther[idx][0]
v := ch.valuesDict.values[dictIdx]
vOther := chOther.valuesDict.values[dictIdxOther]
return v == vOther
})
}
func (fe *filterEqField) applyFilterBinValue(bs *blockSearch, bm *bitmap, ch, chOther *columnHeader) {
valuesEncoded := bs.getValuesForColumn(ch)
valuesEncodedOther := bs.getValuesForColumn(chOther)
bm.forEachSetBit(func(idx int) bool {
return valuesEncoded[idx] == valuesEncodedOther[idx]
})
}
func getBlockResult() *blockResult {
v := brPool.Get()
if v == nil {

View File

@@ -17,6 +17,18 @@ func TestFilterEqField(t *testing.T) {
"abc def",
},
},
{
name: "bar",
values: []string{
"abc def",
},
},
{
name: "baz",
values: []string{
"qwerty",
},
},
}
// match
@@ -26,6 +38,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0})
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "other-non-existing-column",
@@ -33,6 +51,12 @@ func TestFilterEqField(t *testing.T) {
testFilterMatchForColumns(t, columns, fe, "foo", []int{0})
// mismatch
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "foo", nil)
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "non-existing-column",
@@ -56,6 +80,22 @@ func TestFilterEqField(t *testing.T) {
"abc def",
},
},
{
name: "bar",
values: []string{
"abc def",
"abc def",
"abc def",
},
},
{
name: "baz",
values: []string{
"qwerty",
"qwerty",
"qwerty",
},
},
}
// match
@@ -65,6 +105,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2})
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "non-existing-column",
@@ -72,6 +118,12 @@ func TestFilterEqField(t *testing.T) {
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2})
// mismatch
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "foo", nil)
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "non-existing-column",
@@ -99,6 +151,30 @@ func TestFilterEqField(t *testing.T) {
"foobar",
},
},
{
name: "bar",
values: []string{
"xabc",
"xfoobar",
"",
"",
"xfddf foobarbaz",
"afoobarbaz",
"xfoobar",
},
},
{
name: "baz",
values: []string{
"xabc",
"xfoobar",
"x",
"x",
"xfddf foobarbaz",
"xafoobarbaz",
"xfoobar",
},
},
}
// match
@@ -108,6 +184,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6})
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{2, 5})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "other-non-existing-column",
@@ -125,6 +207,13 @@ func TestFilterEqField(t *testing.T) {
otherFieldName: "foo",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{2})
// mismatch
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "foo", nil)
})
t.Run("strings", func(t *testing.T) {
@@ -144,6 +233,36 @@ func TestFilterEqField(t *testing.T) {
"a !!,23.(!1)",
},
},
{
name: "bar",
values: []string{
"a foo",
"xa foobar",
"aa abc a",
"",
"xa fddf foobarbaz",
"",
"xa foobar baz",
"a kjlkjf dfff",
"a ТЕСТЙЦУК НГКШ ",
"xa !!,23.(!1)",
},
},
{
name: "baz",
values: []string{
"xa foo",
"xa foobar",
"xaa abc a",
"xca afdf a,foobar baz",
"xa fddf foobarbaz",
"x",
"xa foobar baz",
"xa kjlkjf dfff",
"xa ТЕСТЙЦУК НГКШ ",
"xa !!,23.(!1)",
},
},
}
// match
@@ -153,6 +272,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 2, 5, 7, 8})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "non-existing-column",
@@ -170,6 +295,13 @@ func TestFilterEqField(t *testing.T) {
otherFieldName: "foo",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{5})
// mismatch
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "foo", nil)
})
t.Run("uint8", func(t *testing.T) {
@@ -190,6 +322,38 @@ func TestFilterEqField(t *testing.T) {
"5",
},
},
{
name: "bar",
values: []string{
"23",
"12",
"42",
"0",
"10",
"12",
"10",
"2",
"30",
"4",
"50",
},
},
{
name: "baz",
values: []string{
"230",
"120",
"20",
"10",
"20",
"120",
"10",
"20",
"30",
"40",
"50",
},
},
}
// match
@@ -199,6 +363,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 3, 5, 7, 9})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "other-non-existing-column",
@@ -206,6 +376,12 @@ func TestFilterEqField(t *testing.T) {
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
// mismatch
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "foo", nil)
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "non-exsiting-column",
@@ -237,6 +413,38 @@ func TestFilterEqField(t *testing.T) {
"5",
},
},
{
name: "bar",
values: []string{
"23",
"12",
"2",
"0",
"10",
"12",
"560",
"2",
"43",
"4",
"50",
},
},
{
name: "baz",
values: []string{
"1123",
"112",
"132",
"10",
"10",
"112",
"1256",
"12",
"13",
"14",
"15",
},
},
}
// match
@@ -246,6 +454,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 3, 5, 7, 9})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "non-existing-column",
@@ -253,6 +467,12 @@ func TestFilterEqField(t *testing.T) {
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
// mismatch
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "foo", nil)
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "non-existing-column",
@@ -284,6 +504,38 @@ func TestFilterEqField(t *testing.T) {
"5",
},
},
{
name: "bar",
values: []string{
"1123",
"12",
"132",
"0",
"10",
"12",
"165536",
"2",
"13",
"4",
"15",
},
},
{
name: "baz",
values: []string{
"2123",
"212",
"232",
"20",
"20",
"212",
"265536",
"22",
"23",
"24",
"25",
},
},
}
// match
@@ -293,6 +545,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 3, 5, 7, 9})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "non-existing-column",
@@ -300,6 +558,12 @@ func TestFilterEqField(t *testing.T) {
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
// mismatch
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "foo", nil)
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "non-existing-column",
@@ -331,6 +595,38 @@ func TestFilterEqField(t *testing.T) {
"5",
},
},
{
name: "bar",
values: []string{
"1123",
"12",
"132",
"0",
"10",
"12",
"112345678901",
"2",
"13",
"4",
"15",
},
},
{
name: "baz",
values: []string{
"2123",
"212",
"232",
"20",
"20",
"212",
"212345678901",
"22",
"23",
"24",
"25",
},
},
}
// match
@@ -340,6 +636,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 3, 5, 7, 9})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "non-existing-column",
@@ -347,6 +649,12 @@ func TestFilterEqField(t *testing.T) {
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
// mismatch
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "foo", nil)
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "non-existing-column",
@@ -378,6 +686,38 @@ func TestFilterEqField(t *testing.T) {
"5",
},
},
{
name: "bar",
values: []string{
"3123",
"12",
"332",
"0",
"30",
"-12",
"312345678901",
"2",
"33",
"4",
"35",
},
},
{
name: "baz",
values: []string{
"2123",
"212",
"232",
"20",
"20",
"-212",
"212345678901",
"22",
"23",
"24",
"25",
},
},
}
// match
@@ -387,6 +727,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 3, 5, 7, 9})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "non-existing-column",
@@ -394,6 +740,12 @@ func TestFilterEqField(t *testing.T) {
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
// mismatch
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "foo", nil)
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "non-existing-column",
@@ -423,6 +775,34 @@ func TestFilterEqField(t *testing.T) {
"4",
},
},
{
name: "bar",
values: []string{
"11234",
"0",
"23454",
"-65536",
"21234.5678901",
"1",
"22",
"3",
"24",
},
},
{
name: "baz",
values: []string{
"21234",
"20",
"23454",
"-265536",
"21234.5678901",
"21",
"22",
"23",
"24",
},
},
}
// match
@@ -432,6 +812,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8})
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 3, 5, 7})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "other-non-existing-column",
@@ -439,6 +825,12 @@ func TestFilterEqField(t *testing.T) {
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8})
// mismatch
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "foo", nil)
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "non-existing-column",
@@ -471,6 +863,40 @@ func TestFilterEqField(t *testing.T) {
"7.7.7.7",
},
},
{
name: "bar",
values: []string{
"21.2.3.4",
"0.0.0.0",
"227.0.0.1",
"254.255.255.255",
"227.0.0.1",
"127.0.0.1",
"227.0.4.2",
"127.0.0.1",
"212.0.127.6",
"55.55.55.55",
"26.66.66.66",
"7.7.7.7",
},
},
{
name: "baz",
values: []string{
"31.2.3.4",
"30.0.0.0",
"37.0.0.1",
"34.255.255.255",
"37.0.0.1",
"37.0.0.1",
"37.0.4.2",
"37.0.0.1",
"32.0.127.6",
"35.55.55.55",
"36.66.66.66",
"37.7.7.7",
},
},
}
// match
@@ -480,6 +906,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 3, 5, 7, 9, 11})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "non-existing-column",
@@ -487,6 +919,12 @@ func TestFilterEqField(t *testing.T) {
testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
// mismatch
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "foo", nil)
fe = &filterEqField{
fieldName: "foo",
otherFieldName: "non-existing-column",
@@ -516,6 +954,34 @@ func TestFilterEqField(t *testing.T) {
"2006-01-02T15:04:05.009Z",
},
},
{
name: "bar",
values: []string{
"2007-01-02T15:04:05.001Z",
"2006-01-02T15:04:05.002Z",
"2007-01-02T15:04:05.003Z",
"2006-01-02T15:04:05.004Z",
"2007-01-02T15:04:05.005Z",
"2006-01-02T15:04:05.006Z",
"2007-01-02T15:04:05.007Z",
"2006-01-02T15:04:05.008Z",
"2007-01-02T15:04:05.009Z",
},
},
{
name: "baz",
values: []string{
"2009-01-02T15:04:05.001Z",
"2009-01-02T15:04:05.002Z",
"2009-01-02T15:04:05.003Z",
"2009-01-02T15:04:05.004Z",
"2009-01-02T15:04:05.005Z",
"2009-01-02T15:04:05.006Z",
"2009-01-02T15:04:05.007Z",
"2009-01-02T15:04:05.008Z",
"2009-01-02T15:04:05.009Z",
},
},
}
// match
@@ -525,6 +991,12 @@ func TestFilterEqField(t *testing.T) {
}
testFilterMatchForColumns(t, columns, fe, "_msg", []int{0, 1, 2, 3, 4, 5, 6, 7, 8})
fe = &filterEqField{
fieldName: "_msg",
otherFieldName: "bar",
}
testFilterMatchForColumns(t, columns, fe, "_msg", []int{1, 3, 5, 7})
fe = &filterEqField{
fieldName: "non-existing-column",
otherFieldName: "non-exsiting-column",
@@ -532,6 +1004,12 @@ func TestFilterEqField(t *testing.T) {
testFilterMatchForColumns(t, columns, fe, "_msg", []int{0, 1, 2, 3, 4, 5, 6, 7, 8})
// mimatch
fe = &filterEqField{
fieldName: "_msg",
otherFieldName: "baz",
}
testFilterMatchForColumns(t, columns, fe, "_msg", nil)
fe = &filterEqField{
fieldName: "_msg",
otherFieldName: "non-existing-column",

View File

@@ -0,0 +1,296 @@
package logstorage
import (
"fmt"
"math"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
)
// filterLeField matches if the fieldName field is smaller or equal to the otherFieldName field
//
// Example LogsQL: `fieldName:le_field(otherField)`
type filterLeField struct {
fieldName string
otherFieldName string
excludeEqualValues bool
}
func (fe *filterLeField) String() string {
funcName := "le_field"
if fe.excludeEqualValues {
funcName = "lt_field"
}
return fmt.Sprintf("%s%s(%s)", quoteFieldNameIfNeeded(fe.fieldName), funcName, quoteTokenIfNeeded(fe.otherFieldName))
}
func (fe *filterLeField) updateNeededFields(neededFields fieldsSet) {
neededFields.add(fe.fieldName)
neededFields.add(fe.otherFieldName)
}
func (fe *filterLeField) applyToBlockResult(br *blockResult, bm *bitmap) {
if fe.fieldName == fe.otherFieldName {
if fe.excludeEqualValues {
bm.resetBits()
}
return
}
c := br.getColumnByName(fe.fieldName)
cOther := br.getColumnByName(fe.otherFieldName)
if c.isConst && cOther.isConst {
v := c.valuesEncoded[0]
vOther := cOther.valuesEncoded[0]
if !leValuesString(v, vOther, fe.excludeEqualValues) {
bm.resetBits()
}
return
}
if c.isTime && cOther.isTime {
// c and cOther point to the same _time column, since only a single _time column may exist
if fe.excludeEqualValues {
bm.resetBits()
}
return
}
if c.valueType != cOther.valueType {
// Slow path - c and cOther have different valueType, so convert them to string values and compare them
applyFilterLeString(br, bm, c, cOther, fe.excludeEqualValues)
return
}
switch c.valueType {
case valueTypeString:
applyFilterLeString(br, bm, c, cOther, fe.excludeEqualValues)
case valueTypeDict:
applyFilterLeDict(br, bm, c, cOther, fe.excludeEqualValues)
case valueTypeUint8:
applyFilterLeUint(br, bm, c, cOther, fe.excludeEqualValues)
case valueTypeUint16:
applyFilterLeUint(br, bm, c, cOther, fe.excludeEqualValues)
case valueTypeUint32:
applyFilterLeUint(br, bm, c, cOther, fe.excludeEqualValues)
case valueTypeUint64:
applyFilterLeUint(br, bm, c, cOther, fe.excludeEqualValues)
case valueTypeInt64:
applyFilterLeInt64(br, bm, c, cOther, fe.excludeEqualValues)
case valueTypeFloat64:
applyFilterLeFloat64(br, bm, c, cOther, fe.excludeEqualValues)
case valueTypeIPv4:
applyFilterLeUint(br, bm, c, cOther, fe.excludeEqualValues)
case valueTypeTimestampISO8601:
applyFilterLeUint(br, bm, c, cOther, fe.excludeEqualValues)
default:
logger.Panicf("FATAL: unknown valueType=%d", c.valueType)
}
}
func applyFilterLeString(br *blockResult, bm *bitmap, c, cOther *blockResultColumn, excludeEqualValues bool) {
values := c.getValues(br)
valuesOther := cOther.getValues(br)
bm.forEachSetBit(func(idx int) bool {
return leValuesString(values[idx], valuesOther[idx], excludeEqualValues)
})
}
func applyFilterLeDict(br *blockResult, bm *bitmap, c, cOther *blockResultColumn, excludeEqualValues bool) {
valuesEncoded := c.getValuesEncoded(br)
valuesEncodedOther := cOther.getValuesEncoded(br)
bm.forEachSetBit(func(idx int) bool {
dictIdx := valuesEncoded[idx][0]
dictIdxOther := valuesEncodedOther[idx][0]
v := c.dictValues[dictIdx]
vOther := cOther.dictValues[dictIdxOther]
return leValuesString(v, vOther, excludeEqualValues)
})
}
func applyFilterLeUint(br *blockResult, bm *bitmap, c, cOther *blockResultColumn, excludeEqualValues bool) {
valuesEncoded := c.getValuesEncoded(br)
valuesEncodedOther := cOther.getValuesEncoded(br)
bm.forEachSetBit(func(idx int) bool {
return leValuesString(valuesEncoded[idx], valuesEncodedOther[idx], excludeEqualValues)
})
}
func applyFilterLeInt64(br *blockResult, bm *bitmap, c, cOther *blockResultColumn, excludeEqualValues bool) {
valuesEncoded := c.getValuesEncoded(br)
valuesEncodedOther := cOther.getValuesEncoded(br)
bm.forEachSetBit(func(idx int) bool {
n := unmarshalInt64(valuesEncoded[idx])
nOther := unmarshalInt64(valuesEncodedOther[idx])
return leValuesInt64(n, nOther, excludeEqualValues)
})
}
func applyFilterLeFloat64(br *blockResult, bm *bitmap, c, cOther *blockResultColumn, excludeEqualValues bool) {
valuesEncoded := c.getValuesEncoded(br)
valuesEncodedOther := cOther.getValuesEncoded(br)
bm.forEachSetBit(func(idx int) bool {
f := unmarshalFloat64(valuesEncoded[idx])
fOther := unmarshalFloat64(valuesEncodedOther[idx])
return leValuesFloat64(f, fOther, excludeEqualValues)
})
}
func (fe *filterLeField) applyToBlockSearch(bs *blockSearch, bm *bitmap) {
if fe.fieldName == fe.otherFieldName {
if fe.excludeEqualValues {
bm.resetBits()
}
return
}
v := bs.getConstColumnValue(fe.fieldName)
vOther := bs.getConstColumnValue(fe.otherFieldName)
if v != "" || vOther != "" {
if v != "" && vOther != "" {
if !leValuesString(v, vOther, fe.excludeEqualValues) {
bm.resetBits()
}
return
}
fe.applyFilterString(bs, bm)
return
}
ch := bs.getColumnHeader(fe.fieldName)
chOther := bs.getColumnHeader(fe.otherFieldName)
if ch == nil || chOther == nil {
if ch == nil && chOther == nil {
if fe.excludeEqualValues {
bm.resetBits()
}
return
}
fe.applyFilterString(bs, bm)
return
}
if ch.valueType != chOther.valueType {
// Slow path - c and cOther have different valueType, so convert them to string values and compare them
fe.applyFilterString(bs, bm)
return
}
switch ch.valueType {
case valueTypeString:
fe.applyFilterString(bs, bm)
case valueTypeDict:
fe.applyFilterDict(bs, bm, ch, chOther)
case valueTypeUint8:
fe.applyFilterUint(bs, bm, ch, chOther)
case valueTypeUint16:
fe.applyFilterUint(bs, bm, ch, chOther)
case valueTypeUint32:
fe.applyFilterUint(bs, bm, ch, chOther)
case valueTypeUint64:
fe.applyFilterUint(bs, bm, ch, chOther)
case valueTypeInt64:
fe.applyFilterInt64(bs, bm, ch, chOther)
case valueTypeFloat64:
fe.applyFilterFloat64(bs, bm, ch, chOther)
case valueTypeIPv4:
fe.applyFilterUint(bs, bm, ch, chOther)
case valueTypeTimestampISO8601:
fe.applyFilterUint(bs, bm, ch, chOther)
default:
logger.Panicf("FATAL: %s: unknown valueType=%d", bs.partPath(), ch.valueType)
}
}
func (fe *filterLeField) applyFilterString(bs *blockSearch, bm *bitmap) {
br := getBlockResult()
br.mustInit(bs, bm)
br.initRequestedColumns([]string{fe.fieldName, fe.otherFieldName})
c := br.getColumnByName(fe.fieldName)
cOther := br.getColumnByName(fe.otherFieldName)
values := c.getValues(br)
valuesOther := cOther.getValues(br)
srcIdx := 0
bm.forEachSetBit(func(_ int) bool {
ok := leValuesString(values[srcIdx], valuesOther[srcIdx], fe.excludeEqualValues)
srcIdx++
return ok
})
putBlockResult(br)
}
func (fe *filterLeField) applyFilterDict(bs *blockSearch, bm *bitmap, ch, chOther *columnHeader) {
valuesEncoded := bs.getValuesForColumn(ch)
valuesEncodedOther := bs.getValuesForColumn(chOther)
bm.forEachSetBit(func(idx int) bool {
dictIdx := valuesEncoded[idx][0]
dictIdxOther := valuesEncodedOther[idx][0]
v := ch.valuesDict.values[dictIdx]
vOther := chOther.valuesDict.values[dictIdxOther]
return leValuesString(v, vOther, fe.excludeEqualValues)
})
}
func (fe *filterLeField) applyFilterUint(bs *blockSearch, bm *bitmap, ch, chOther *columnHeader) {
valuesEncoded := bs.getValuesForColumn(ch)
valuesEncodedOther := bs.getValuesForColumn(chOther)
bm.forEachSetBit(func(idx int) bool {
return leValuesString(valuesEncoded[idx], valuesEncodedOther[idx], fe.excludeEqualValues)
})
}
func (fe *filterLeField) applyFilterInt64(bs *blockSearch, bm *bitmap, ch, chOther *columnHeader) {
valuesEncoded := bs.getValuesForColumn(ch)
valuesEncodedOther := bs.getValuesForColumn(chOther)
bm.forEachSetBit(func(idx int) bool {
n := unmarshalInt64(valuesEncoded[idx])
nOther := unmarshalInt64(valuesEncodedOther[idx])
return leValuesInt64(n, nOther, fe.excludeEqualValues)
})
}
func (fe *filterLeField) applyFilterFloat64(bs *blockSearch, bm *bitmap, ch, chOther *columnHeader) {
valuesEncoded := bs.getValuesForColumn(ch)
valuesEncodedOther := bs.getValuesForColumn(chOther)
bm.forEachSetBit(func(idx int) bool {
f := unmarshalFloat64(valuesEncoded[idx])
fOther := unmarshalFloat64(valuesEncodedOther[idx])
return leValuesFloat64(f, fOther, fe.excludeEqualValues)
})
}
func leValuesString(a, b string, excludeEqualValues bool) bool {
fA := parseMathNumber(a)
if !math.IsNaN(fA) {
fB := parseMathNumber(b)
if !math.IsNaN(fB) {
if excludeEqualValues {
return fA < fB
}
return fA <= fB
}
}
if excludeEqualValues {
return a < b
}
return a <= b
}
func leValuesInt64(a, b int64, excludeEqualValues bool) bool {
if excludeEqualValues {
return a < b
}
return a <= b
}
func leValuesFloat64(a, b float64, excludeEqualValues bool) bool {
if excludeEqualValues {
return a < b
}
return a <= b
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,8 +11,8 @@ import (
"unicode/utf8"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/regexutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil"
)
type lexer struct {
@@ -1461,8 +1461,12 @@ func parseGenericFilter(lex *lexer, fieldName string) (filter, error) {
return parseFilterIn(lex, fieldName)
case lex.isKeyword("ipv4_range"):
return parseFilterIPv4Range(lex, fieldName)
case lex.isKeyword("le_field"):
return parseFilterLeField(lex, fieldName)
case lex.isKeyword("len_range"):
return parseFilterLenRange(lex, fieldName)
case lex.isKeyword("lt_field"):
return parseFilterLtField(lex, fieldName)
case lex.isKeyword("range"):
return parseFilterRange(lex, fieldName)
case lex.isKeyword("re"):
@@ -1862,6 +1866,9 @@ func parseInValues(lex *lexer, fieldName string, f filter, iv *inValues) (filter
if err != nil {
return nil, err
}
if q == nil {
return &filterNoop{}, nil
}
iv.q = q
iv.qFieldName = qFieldName
@@ -1888,6 +1895,28 @@ func parseFilterEqField(lex *lexer, fieldName string) (filter, error) {
})
}
func parseFilterLeField(lex *lexer, fieldName string) (filter, error) {
return parseFuncArg(lex, fieldName, func(arg string) (filter, error) {
fe := &filterLeField{
fieldName: fieldName,
otherFieldName: arg,
}
return fe, nil
})
}
func parseFilterLtField(lex *lexer, fieldName string) (filter, error) {
return parseFuncArg(lex, fieldName, func(arg string) (filter, error) {
fe := &filterLeField{
fieldName: fieldName,
otherFieldName: arg,
excludeEqualValues: true,
}
return fe, nil
})
}
func parseFilterExact(lex *lexer, fieldName string) (filter, error) {
return parseFuncArgMaybePrefix(lex, "exact", fieldName, func(phrase string, isFilterPrefix bool) (filter, error) {
if isFilterPrefix {
@@ -1906,23 +1935,23 @@ func parseFilterExact(lex *lexer, fieldName string) (filter, error) {
}
func parseFilterRegexp(lex *lexer, fieldName string) (filter, error) {
funcName := lex.token
return parseFuncArg(lex, fieldName, func(arg string) (filter, error) {
re, err := regexutil.NewRegex(arg)
if err != nil {
return nil, fmt.Errorf("invalid regexp %q for %s(): %w", arg, funcName, err)
}
fr := &filterRegexp{
fieldName: fieldName,
re: re,
}
return fr, nil
return newFilterRegexp(fieldName, arg)
})
}
func parseFilterTilda(lex *lexer, fieldName string) (filter, error) {
lex.nextToken()
arg := getCompoundFuncArg(lex)
func newFilterRegexp(fieldName, arg string) (filter, error) {
// Optimizations for typical regexps generated by Grafana
if arg == "" || arg == ".*" {
return &filterNoop{}, nil
}
if arg == ".+" {
fp := &filterPrefix{
fieldName: fieldName,
}
return fp, nil
}
re, err := regexutil.NewRegex(arg)
if err != nil {
return nil, fmt.Errorf("invalid regexp %q: %w", arg, err)
@@ -1934,6 +1963,12 @@ func parseFilterTilda(lex *lexer, fieldName string) (filter, error) {
return fr, nil
}
func parseFilterTilda(lex *lexer, fieldName string) (filter, error) {
lex.nextToken()
arg := getCompoundFuncArg(lex)
return newFilterRegexp(fieldName, arg)
}
func parseFilterNotTilda(lex *lexer, fieldName string) (filter, error) {
f, err := parseFilterTilda(lex, fieldName)
if err != nil {
@@ -2391,25 +2426,9 @@ func getDayRangeArg(lex *lexer) (int64, string, error) {
if err != nil {
return 0, "", err
}
n := strings.IndexByte(argStr, ':')
if n < 0 {
return 0, "", fmt.Errorf("invalid format for day_range arg; want 'hh:mm'; got %q", argStr)
}
hoursStr := argStr[:n]
minutesStr := argStr[n+1:]
hours, ok := tryParseUint64(hoursStr)
offset, ok := tryParseHHMM(argStr)
if !ok {
return 0, "", fmt.Errorf("cannot parse hh from %q; expected format: 'hh:mm'", hoursStr)
}
minutes, ok := tryParseUint64(minutesStr)
if !ok {
return 0, "", fmt.Errorf("cannot parse mm from %q; expected format: 'hh:mm'", minutesStr)
}
offset := int64(hours*nsecsPerHour + minutes*nsecsPerMinute)
if offset < 0 {
offset = 0
return 0, "", fmt.Errorf("cannot parse %q as 'hh:mm'", argStr)
}
if offset >= nsecsPerDay {
offset = nsecsPerDay - 1
@@ -2803,6 +2822,9 @@ func parseFilterStreamIDIn(lex *lexer) (filter, error) {
if err != nil {
return nil, err
}
if q == nil {
return &filterNoop{}, nil
}
fs = &filterStreamID{
q: q,
@@ -2816,7 +2838,9 @@ func parseInQuery(lex *lexer) (*Query, string, error) {
if err != nil {
return nil, "", fmt.Errorf("cannot parse in(...) query: %w", err)
}
if q.isStarQuery() {
return nil, "", nil
}
qFieldName, err := getFieldNameFromPipes(q.pipes)
if err != nil {
return nil, "", fmt.Errorf("cannot determine field name for values in 'in(%s)': %w", q, err)
@@ -2824,6 +2848,20 @@ func parseInQuery(lex *lexer) (*Query, string, error) {
return q, qFieldName, nil
}
func (q *Query) isStarQuery() bool {
if len(q.pipes) > 0 {
return false
}
switch t := q.f.(type) {
case *filterNoop:
return true
case *filterPrefix:
return len(t.prefix) == 0
default:
return false
}
}
func getFieldNameFromPipes(pipes []pipe) (string, error) {
if len(pipes) == 0 {
return "", fmt.Errorf("missing 'fields' or 'uniq' pipes at the end of query")
@@ -2874,7 +2912,7 @@ func parseTime(lex *lexer) (int64, string, error) {
if err != nil {
return 0, "", err
}
nsecs, err := promutils.ParseTimeAt(s, lex.currentTimestamp)
nsecs, err := timeutil.ParseTimeAt(s, lex.currentTimestamp)
if err != nil {
return 0, "", err
}
@@ -2998,7 +3036,9 @@ var reservedKeywords = func() map[string]struct{} {
"i",
"in",
"ipv4_range",
"le_field",
"len_range",
"lt_field",
"range",
"re",
"seq",

View File

@@ -169,7 +169,7 @@ func TestParseDayRange(t *testing.T) {
}
f("[00:00, 24:00]", 0, nsecsPerDay-1, 0)
f("[10:20, 125:00]", 10*nsecsPerHour+20*nsecsPerMinute, nsecsPerDay-1, 0)
f("[10:20, 24:00]", 10*nsecsPerHour+20*nsecsPerMinute, nsecsPerDay-1, 0)
f("(00:00, 24:00)", 1, nsecsPerDay-2, 0)
f("[08:00, 18:00)", 8*nsecsPerHour, 18*nsecsPerHour-1, 0)
f("[08:00, 18:00) offset 2h", 8*nsecsPerHour, 18*nsecsPerHour-1, 2*nsecsPerHour)
@@ -522,6 +522,19 @@ func TestParseFilterIn(t *testing.T) {
f(`a:in(* | fields bar)`, `a`, nil)
}
func TestParseFilterInStar(t *testing.T) {
s := "in(*)"
q, err := ParseQuery(s)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
_, ok := q.f.(*filterNoop)
if !ok {
t.Fatalf("unexpected filter type; got %T; want *filterNoop; filter: %s", q.f, q.f)
}
}
func TestParseFilterContainsAll(t *testing.T) {
f := func(s, fieldNameExpected string, valuesExpected []string) {
t.Helper()
@@ -684,7 +697,7 @@ func TestParseFilterRegexp(t *testing.T) {
}
}
f(`""`, ``)
f(`"."`, `.`)
f(`foo`, `foo`)
f(`"foo.+|bar.*"`, `foo.+|bar.*`)
f(`"foo(bar|baz),x[y]"`, `foo(bar|baz),x[y]`)
@@ -969,6 +982,9 @@ func TestParseQuery_Success(t *testing.T) {
`_stream_id:in(0000007b000001c8302bc96e02e54e5524b3a68ec271e55e,0000007b000001c850d9950ea6196b1a4812081265faa1c7)`)
f(`_stream_id:in(_time:5m | fields _stream_id)`, `_stream_id:in(_time:5m | fields _stream_id)`)
// _stream_id filter with star
f(`_stream_id:in(*)`, `*`)
// _stream filters
f(`_stream:{}`, `{}`)
f(`_stream:{foo="bar", baz=~"x" OR or!="b", "x=},"="d}{"}`, `{foo="bar",baz=~"x" or "or"!="b","x=},"="d}{"}`)
@@ -1066,6 +1082,12 @@ func TestParseQuery_Success(t *testing.T) {
f("eq_field", `"eq_field"`)
f("eq_field:a", `"eq_field":a`)
f("a:eq_field", `a:"eq_field"`)
f("le_field", `"le_field"`)
f("le_field:a", `"le_field":a`)
f("a:le_field", `a:"le_field"`)
f("lt_field", `"lt_field"`)
f("lt_field:a", `"lt_field":a`)
f("a:lt_field", `a:"lt_field"`)
f("exact", `"exact"`)
f("exact:a", `"exact":a`)
f("exact-foo", `"exact-foo"`)
@@ -1126,6 +1148,22 @@ func TestParseQuery_Success(t *testing.T) {
f(`a:!eq_field(b)`, `!a:eq_field(b)`)
f(`a:-eq_field(b)`, `!a:eq_field(b)`)
// le_field filter
f("le_field(foo)", "le_field(foo)")
f(`"a":le_field('b')`, "a:le_field(b)")
f("-le_field(a)", `!le_field(a)`)
f(`-a:le_field(b)`, `!a:le_field(b)`)
f(`a:!le_field(b)`, `!a:le_field(b)`)
f(`a:-le_field(b)`, `!a:le_field(b)`)
// lt_field filter
f("lt_field(foo)", "lt_field(foo)")
f(`"a":lt_field('b')`, "a:lt_field(b)")
f("-lt_field(a)", `!lt_field(a)`)
f(`-a:lt_field(b)`, `!a:lt_field(b)`)
f(`a:!lt_field(b)`, `!a:lt_field(b)`)
f(`a:-lt_field(b)`, `!a:lt_field(b)`)
// exact filter
f("exact(foo)", `=foo`)
f("exact(foo*)", `=foo*`)
@@ -1154,6 +1192,10 @@ func TestParseQuery_Success(t *testing.T) {
f(`in("foo bar", baz)`, `in("foo bar",baz)`)
f(`foo:in(foo-bar/baz)`, `foo:in("foo-bar/baz")`)
// in filter with star
f(`in(*)`, `*`)
f(`foo:in(*)`, `*`)
// in filter with query
f(`in(err|fields x)`, `in(err | fields x)`)
f(`ip:in(foo and user:in(admin, moderator)|fields ip)`, `ip:in(foo user:in(admin,moderator) | fields ip)`)
@@ -1168,6 +1210,10 @@ func TestParseQuery_Success(t *testing.T) {
f(`contains_any("foo bar", baz)`, `contains_any("foo bar",baz)`)
f(`foo:contains_any(foo-bar/baz)`, `foo:contains_any("foo-bar/baz")`)
// contains_any filter with star
f(`contains_any(*)`, `*`)
f(`foo:contains_any(*)`, `*`)
// contains_any filter with query
f(`contains_any(err|fields x)`, `contains_any(err | fields x)`)
f(`ip:contains_any(foo and user:contains_any(admin, moderator)|fields ip)`, `ip:contains_any(foo user:contains_any(admin,moderator) | fields ip)`)
@@ -1182,6 +1228,10 @@ func TestParseQuery_Success(t *testing.T) {
f(`contains_all("foo bar", baz)`, `contains_all("foo bar",baz)`)
f(`foo:contains_all(foo-bar/baz)`, `foo:contains_all("foo-bar/baz")`)
// contains_all filter with star
f(`contains_all(*)`, `*`)
f(`foo:contains_all(*)`, `*`)
// contains_all filter with query
f(`contains_all(err|fields x)`, `contains_all(err | fields x)`)
f(`ip:contains_all(foo and user:contains_all(admin, moderator)|fields ip)`, `ip:contains_all(foo user:contains_all(admin,moderator) | fields ip)`)
@@ -1237,7 +1287,13 @@ func TestParseQuery_Success(t *testing.T) {
f(`foo:re(foo-bar/baz.)`, `foo:~"foo-bar/baz."`)
f(`~foo.bar.baz !~bar`, `~foo.bar.baz !~bar`)
f(`foo:~~foo~ba/ba>z`, `foo:~"~foo~ba/ba>z"`)
f(`foo:~'.*'`, `foo:~".*"`)
f(`foo:~'.*'`, `*`)
f(`foo:~'.+'`, `foo:*`)
f(`~".*"`, `*`)
f(`~".+"`, `*`)
f(`foo bar:~".*"`, `foo`)
f(`foo bar:~""`, `foo`)
f(`foo bar:~".+"`, `foo bar:*`)
// seq filter
f(`seq()`, `seq()`)
@@ -1799,6 +1855,20 @@ func TestParseQuery_Failure(t *testing.T) {
f(`eq_field(foo`)
f(`eq_field(foo,`)
// invalid le_field
f(`le_field(`)
f(`le_field(foo bar)`)
f(`le_field(foo, bar)`)
f(`le_field(foo`)
f(`le_field(foo,`)
// invalid lt_field
f(`lt_field(`)
f(`lt_field(foo bar)`)
f(`lt_field(foo, bar)`)
f(`lt_field(foo`)
f(`lt_field(foo,`)
// invalid exact
f(`exact(`)
f(`exact(f, b)`)

Some files were not shown because too many files have changed in this diff Show More