Compare commits

...

42 Commits

Author SHA1 Message Date
dmitryk-dk
35bd7f37b1 apptest/vmctl: migrate vmctl test for the prometheus migration process
apptest/vmctl: wait until vmctl finish it work

apptest/vmctl: remove unneeded function

apptest/vmctl: fix linter

apptest/vmctl: add vmctl to build for the integration tests

apptest/vmctl: rename file

apptest/vmctl: fix comments

apptest/vmctl: added check of the wait discussed in the comments

apptest/vmctl: compare migrated data with expected response

apptest/vmctl: format expected_response.json
2025-06-02 16:37:02 +02:00
Phuong Le
f5ffbb4e00 logsql: Remove redundant suffix logic (#9022)
1. Add `!lex.isEnd()` to prevent an infinite loop. Although the current
code doesn't trigger this bug, it's a latent issue that could occur if
someone modifies the callers or adds new code paths without proper stop
tokens.
2025-05-27 14:00:37 +02:00
Jose Gómez-Sellés
13d2b0b558 docs/cloud: adapt integrations (#9032)
This PR improves integrations docs in 2 areas:
- Background set to white, avoiding issues when changing to dark mode.
- Height set to avoid blank spaces

### 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**:

- [x] My change adheres to [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/victoriametrics/contributing/).
2025-05-27 10:59:47 +02:00
Evgeny
b83b2bae3b fix for multiple users running tests (testStoragePath ownership issue) (#9015)
### Describe Your Changes

When multiple users run tests on the same instance, the first user
creating a folder will own the testStoragePath, which can lead to issues
accessing this folder for other users. This change will allow us to
create unique folders per user.

```
% ls -ld /usr/tmp/vmalert-unittest/
drwxr-xr-x 2 some_user users 4096 May 12 17:22 /usr/tmp/vmalert-unittest/
...
2025-05-20T13:56:16.488Z        panic   lib/fs/fs.go:132        FATAL: cannot create directory: mkdir /usr/tmp/vmalert-unittest/1747749376488491648: permission denied
panic: FATAL: cannot create directory: mkdir /usr/tmp/vmalert-unittest/1747749376488491648: permission denied
```

### Checklist

The following checks are **mandatory**:

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

---------

Co-authored-by: Hui Wang <haley@victoriametrics.com>
2025-05-27 15:09:56 +08:00
Artem Fetishev
ef84c16f37 Bump VictoriaMetrics version mentioned in docs
Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2025-05-26 13:49:56 +02:00
Artem Fetishev
47391fea3b deployment/docker: Bump VictoriaMetrics version
Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2025-05-26 13:39:08 +02:00
Artem Fetishev
afce8bc320 docs: bump last LTS versions
Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2025-05-26 13:34:53 +02:00
Artem Fetishev
5d18cd3416 docs/CHANGELOG.md: update changelog with LTS release notes
Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2025-05-26 13:30:19 +02:00
hagen1778
65e0b3b86f deployment/dashboards: update PendingDataPoints description
Mention that data is flushed every 5s, not 2s.
Hence, expected pending data points is x5.

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-05-26 10:58:48 +02:00
Artem Fetishev
aa3171cf4b docs/CHANGELOG.md: cut v1.118.0
Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2025-05-23 14:40:22 +02:00
Artem Fetishev
1754ac53cd make vmui-update and make vmui-logs-update
Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2025-05-23 11:21:53 +02:00
hagen1778
5c6af65e48 deployment/dashboards: add panels for PSI metrics
Add panels for CPU, IO and Memory pressure to vmalert, vmagent,
VictoriaMetrics single/cluster and VictoriaLogs single/cluster dashboards.

https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8966
Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-05-22 16:54:52 +02:00
Phuong Le
d8871f56ba lib/logstorage/parse: fix incorrect endTime in AddTimeFilter (#8991)
Fixes https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8985

When using `AddTimeFilter`, it creates a string representation with the
exact same timestamps but doesn't transform the internal end value. This
is different from the `parseFilterTime` function, which makes the
behavior of these two paths different.
2025-05-22 16:45:12 +02:00
Zakhar Bessarab
4d6bc3b5df app/vmselect/prometheus: follow-up after 60e253b
Prevent panic on instant queries when `-search.queryStats.lastQueriesCount=0` is set.

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-05-22 15:50:02 +02:00
Zakhar Bessarab
60e253b387 app/vmselect/prometheus: prevent panic when querying with disabled query stats tracking (#8974)
Previously, querying with disabled tracking would lead to loading nil
value of execution duration. `qs.SeriesFetched` does not need similar
handling as it uses atomic.Int64 and has default value anyway.

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

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
2025-05-22 15:38:15 +02:00
dependabot[bot]
127d6972ac build(deps): bump react-router and react-router-dom in /app/vmui/packages/vmui (#8859)
Bumps
[react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router)
to 7.5.3 and updates ancestor dependency
[react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom).
These dependencies need to be updated together.

Updates `react-router` from 7.5.0 to 7.5.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/releases">react-router's
releases</a>.</em></p>
<blockquote>
<h2>v7.5.3</h2>
<p>See the changelog for release notes: <a
href="https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v753">https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v753</a></p>
<h2>v7.5.2</h2>
<p>See the changelog for release notes: <a
href="https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v752">https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v752</a></p>
<h2>v7.5.1</h2>
<p>See the changelog for release notes: <a
href="https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v751">https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v751</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md">react-router's
changelog</a>.</em></p>
<blockquote>
<h2>7.5.3</h2>
<h3>Patch Changes</h3>
<ul>
<li>Fix bug where bubbled action errors would result in
<code>loaderData</code> being cleared at the handling
<code>ErrorBoundary</code> route (<a
href="https://redirect.github.com/remix-run/react-router/pull/13476">#13476</a>)</li>
<li>Handle redirects from <code>clientLoader.hydrate</code> initial load
executions (<a
href="https://redirect.github.com/remix-run/react-router/pull/13477">#13477</a>)</li>
</ul>
<h2>7.5.2</h2>
<h3>Patch Changes</h3>
<ul>
<li>
<p>Update Single Fetch to also handle the 204 redirects used in
<code>?_data</code> requests in Remix v2 (<a
href="https://redirect.github.com/remix-run/react-router/pull/13364">#13364</a>)</p>
<ul>
<li>This allows applications to return a redirect on <code>.data</code>
requests from outside the scope of React Router (i.e., an
<code>express</code>/<code>hono</code> middleware)</li>
<li>⚠️ Please note that doing so relies on implementation details that
are subject to change without a SemVer major release</li>
<li>This is primarily done to ease upgrading to Single Fetch for
existing Remix v2 applications, but the recommended way to handle this
is redirecting from a route middleware</li>
</ul>
</li>
<li>
<p>Adjust approach for Prerendering/SPA Mode via headers (<a
href="https://redirect.github.com/remix-run/react-router/pull/13453">#13453</a>)</p>
</li>
</ul>
<h2>7.5.1</h2>
<h3>Patch Changes</h3>
<ul>
<li>
<p>Fix single fetch bug where no revalidation request would be made when
navigating upwards to a reused parent route (<a
href="https://redirect.github.com/remix-run/react-router/pull/13253">#13253</a>)</p>
</li>
<li>
<p>When using the object-based <code>route.lazy</code> API, the
<code>HydrateFallback</code> and <code>hydrateFallbackElement</code>
properties are now skipped when lazy loading routes after hydration. (<a
href="https://redirect.github.com/remix-run/react-router/pull/13376">#13376</a>)</p>
<p>If you move the code for these properties into a separate file, you
can use this optimization to avoid downloading unused hydration code.
For example:</p>
<pre lang="ts"><code>createBrowserRouter([
  {
    path: &quot;/show/:showId&quot;,
    lazy: {
loader: async () =&gt; (await
import(&quot;./show.loader.js&quot;)).loader,
Component: async () =&gt; (await
import(&quot;./show.component.js&quot;)).Component,
      HydrateFallback: async () =&gt;
(await import(&quot;./show.hydrate-fallback.js&quot;)).HydrateFallback,
    },
  },
]);
</code></pre>
</li>
<li>
<p>Properly revalidate prerendered paths when param values change (<a
href="https://redirect.github.com/remix-run/react-router/pull/13380">#13380</a>)</p>
</li>
<li>
<p>UNSTABLE: Add a new <code>unstable_runClientMiddleware</code>
argument to <code>dataStrategy</code> to enable middleware execution in
custom <code>dataStrategy</code> implementations (<a
href="https://redirect.github.com/remix-run/react-router/pull/13395">#13395</a>)</p>
</li>
<li>
<p>UNSTABLE: Add better error messaging when <code>getLoadContext</code>
is not updated to return a <code>Map</code>&quot; (<a
href="https://redirect.github.com/remix-run/react-router/pull/13242">#13242</a>)</p>
</li>
<li>
<p>Do not automatically add <code>null</code> to
<code>staticHandler.query()</code> <code>context.loaderData</code> if
routes do not have loaders (<a
href="https://redirect.github.com/remix-run/react-router/pull/13223">#13223</a>)</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9a41029f58"><code>9a41029</code></a>
chore: Update version for release (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/13482">#13482</a>)</li>
<li><a
href="945295b711"><code>945295b</code></a>
chore: Update version for release (pre) (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/13479">#13479</a>)</li>
<li><a
href="501d554cba"><code>501d554</code></a>
Handle redirects from hydrating clientLoaders (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/13477">#13477</a>)</li>
<li><a
href="2a128f1b91"><code>2a128f1</code></a>
Fix cleared loaderData bug on thrown action errors (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/13476">#13476</a>)</li>
<li><a
href="5819e0c45d"><code>5819e0c</code></a>
chore: Update version for release (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/13456">#13456</a>)</li>
<li><a
href="d0cac3395f"><code>d0cac33</code></a>
chore: Update version for release (pre) (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/13454">#13454</a>)</li>
<li><a
href="c84302972a"><code>c843029</code></a>
Adjust approach for prerendering/SPA mode via headers (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/13453">#13453</a>)</li>
<li><a
href="8e4963faec"><code>8e4963f</code></a>
Restore handling of 204 &quot;soft&quot; redirects on data requests (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/13364">#13364</a>)</li>
<li><a
href="ed77157ed5"><code>ed77157</code></a>
update session documentation links (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/13448">#13448</a>)</li>
<li><a
href="4281172339"><code>4281172</code></a>
Missed refactor updates</li>
<li>Additional commits viewable in <a
href="https://github.com/remix-run/react-router/commits/react-router@7.5.3/packages/react-router">compare
view</a></li>
</ul>
</details>
<br />

Updates `react-router-dom` from 7.5.0 to 7.5.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/releases">react-router-dom's
releases</a>.</em></p>
<blockquote>
<h2>react-router-dom-v5-compat@6.4.0-pre.15</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies
<ul>
<li>react-router@6.4.0-pre.15</li>
<li>react-router-dom@6.4.0-pre.15</li>
</ul>
</li>
</ul>
<h2>react-router-dom-v5-compat@6.4.0-pre.11</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies
<ul>
<li>react-router@6.4.0-pre.11</li>
<li>react-router-dom@6.4.0-pre.11</li>
</ul>
</li>
</ul>
<h2>react-router-dom-v5-compat@6.4.0-pre.10</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies
<ul>
<li>react-router@6.4.0-pre.10</li>
<li>react-router-dom@6.4.0-pre.10</li>
</ul>
</li>
</ul>
<h2>react-router-dom-v5-compat@6.4.0-pre.9</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies
<ul>
<li>react-router@6.4.0-pre.9</li>
<li>react-router-dom@6.4.0-pre.9</li>
</ul>
</li>
</ul>
<h2>react-router-dom-v5-compat@6.4.0-pre.8</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies
<ul>
<li>react-router@6.4.0-pre.8</li>
<li>react-router-dom@6.4.0-pre.8</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md">react-router-dom's
changelog</a>.</em></p>
<blockquote>
<h2>7.5.3</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies:
<ul>
<li><code>react-router@7.5.3</code></li>
</ul>
</li>
</ul>
<h2>7.5.2</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies:
<ul>
<li><code>react-router@7.5.2</code></li>
</ul>
</li>
</ul>
<h2>7.5.1</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies:
<ul>
<li><code>react-router@7.5.1</code></li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9a41029f58"><code>9a41029</code></a>
chore: Update version for release (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/13482">#13482</a>)</li>
<li><a
href="945295b711"><code>945295b</code></a>
chore: Update version for release (pre) (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/13479">#13479</a>)</li>
<li><a
href="5819e0c45d"><code>5819e0c</code></a>
chore: Update version for release (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/13456">#13456</a>)</li>
<li><a
href="d0cac3395f"><code>d0cac33</code></a>
chore: Update version for release (pre) (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/13454">#13454</a>)</li>
<li><a
href="5dd7c1580f"><code>5dd7c15</code></a>
chore: Update version for release (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/13422">#13422</a>)</li>
<li><a
href="6ce4a79774"><code>6ce4a79</code></a>
chore: Update version for release (pre) (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/13412">#13412</a>)</li>
<li>See full diff in <a
href="https://github.com/remix-run/react-router/commits/react-router-dom@7.5.3/packages/react-router-dom">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/VictoriaMetrics/VictoriaMetrics/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-22 15:24:52 +02:00
Andrii Chubatiuk
6d7d22f3e6 deployment/docker/victorialogs: add grafana alloy setup (#8908)
### 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 to [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/victoriametrics/contributing/).

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: hagen1778 <roman@victoriametrics.com>
2025-05-22 15:24:29 +02:00
Komei Kamiya
6a4757ad06 deployment: fix compose.yml for victorialogs fluentbit otlp demo (#8987)
### Describe Your Changes

compose.yml does not exist, only compose-base.yml

### Checklist

The following checks are **mandatory**:

- [x] My change adheres to [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/victoriametrics/contributing/).
2025-05-22 15:00:05 +02:00
Dima Shur
ff0632c01e docs: changed typo in histogram_bucket - metricsQL query was in wrong place (#8999)
### Describe Your Changes

MetricsQL code was in wrong place - moved it 5 lines higher

### Checklist

The following checks are **mandatory**:

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

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: hagen1778 <roman@victoriametrics.com>
2025-05-22 14:49:10 +02:00
Phuong Le
134501bf99 docs/relabeling: improve readability (#8633)
This commit re-fines the relabeling cookbok and moves all
relabeling related docs to the same page. 
It also removes duplicated information from vmagent readme.

Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: hagen1778 <roman@victoriametrics.com>
2025-05-22 14:46:06 +02:00
Hui Wang
faa3943a25 deployment-docker: fix vmalert -remoteWrite.url arg (#8986)
vmalert auto adds `/api/v1/write` if `remoteWrite.disablePathAppend` is not specified
2025-05-22 10:47:12 +08:00
Artem Fetishev
b30f4ca12a Release-Guide.md: Update link to enterprise release guide and remove Public Announcement section (#8978)
The link to enterprise release guide now points to the doc in
enterprise-single-node branch instead of enterprise master. This is
because we don't use enterprise master.

Additionally the `Public Announcement` section has been removed because
we don't make public announcements for releases.

Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2025-05-21 11:16:17 +02:00
Zakhar Bessarab
208515dc38 lib/promscrape/discovery/k8s: fix inconsistency with Prometheus for endpointslice discovery
Add missing labels for:
- node name
- endpoint "serving" and "terminating" states

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

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
2025-05-19 17:28:53 +04:00
Jose Gómez-Sellés
9de3e80a4f Docs/cloud: complete deployments section (#8928)
### Describe Your Changes

As planned, we are adding a more structured way of explaining
deployments and tiers.
In this PR the following changes are added:
- The previous tiering section is moved under the deployments
placeholder
- Explanations for users to pick single or cluster 
- Explanations for different parameters
- Re-styling of the docs to look more appealing
- Reorder some hanging docs so the sections are more clearly presented
to the users

### Checklist

The following checks are **mandatory**:

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

---------

Co-authored-by: Alexander Marshalov <_@marshalov.org>
2025-05-19 10:15:45 +02:00
hagen1778
63d8d0c5ac docs: remove link to #filtering as it has conflicts in vmctl doc
Apparently, when the doc was created for vmctl the anchor conflicts
weren't accounted for or weren't a thing yet. Now, various migration modes
have conflicting anchors. This should be addressed in follow-up commits.

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-05-16 21:59:26 +02:00
hagen1778
6b485c4e46 docs: revise Prometheus migration section in vmctl
Improve wording and instructions. It has been a while since the last
time we updated it (more than 4 years!).

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-05-16 21:47:45 +02:00
GitHub Snyk Bot
723e56ac50 [Snyk] Security upgrade vite from 6.2.6 to 6.2.7 (#8866)
![snyk-top-banner](https://res.cloudinary.com/snyk/image/upload/r-d/scm-platform/snyk-pull-requests/pr-banner-default.svg)

### Snyk has created this PR to fix 1 vulnerabilities in the npm
dependencies of this project.

#### Snyk changed the following file(s):

- `app/vmui/packages/vmui/package.json`
- `app/vmui/packages/vmui/package-lock.json`




#### Vulnerabilities that will be fixed with an upgrade:

|  | Issue | Score | 

:-------------------------:|:-------------------------|:-------------------------
![medium
severity](https://res.cloudinary.com/snyk/image/upload/w_20,h_20/v1561977819/icon/m.png
'medium severity') | Directory Traversal
<br/>[SNYK-JS-VITE-9919777](https://snyk.io/vuln/SNYK-JS-VITE-9919777) |
&nbsp;&nbsp;**693**&nbsp;&nbsp;




---

> [!IMPORTANT]
>
> - Check the changes in this PR to ensure they won't cause issues with
your project.
> - Max score is 1000. Note that the real score may have changed since
the PR was raised.
> - This PR was automatically created by Snyk using the credentials of a
real user.

---

**Note:** _You are seeing this because you or someone else with access
to this repository has authorized Snyk to open fix PRs._

For more information: <img
src="https://api.segment.io/v1/pixel/track?data=eyJ3cml0ZUtleSI6InJyWmxZcEdHY2RyTHZsb0lYd0dUcVg4WkFRTnNCOUEwIiwiYW5vbnltb3VzSWQiOiI1ZTlmZjBkYy01MjQ0LTQzMGYtYTc3MS0yMTY1MjdjN2Q1NjEiLCJldmVudCI6IlBSIHZpZXdlZCIsInByb3BlcnRpZXMiOnsicHJJZCI6IjVlOWZmMGRjLTUyNDQtNDMwZi1hNzcxLTIxNjUyN2M3ZDU2MSJ9fQ=="
width="0" height="0"/>
🧐 [View latest project
report](https://app.snyk.io/org/victoriametrics/project/69d9ccbb-b5b1-492f-9f8c-9032dcaf021e?utm_source&#x3D;github&amp;utm_medium&#x3D;referral&amp;page&#x3D;fix-pr)
📜 [Customise PR
templates](https://docs.snyk.io/scan-using-snyk/pull-requests/snyk-fix-pull-or-merge-requests/customize-pr-templates?utm_source=github&utm_content=fix-pr-template)
🛠 [Adjust project
settings](https://app.snyk.io/org/victoriametrics/project/69d9ccbb-b5b1-492f-9f8c-9032dcaf021e?utm_source&#x3D;github&amp;utm_medium&#x3D;referral&amp;page&#x3D;fix-pr/settings)
📚 [Read about Snyk's upgrade
logic](https://docs.snyk.io/scan-with-snyk/snyk-open-source/manage-vulnerabilities/upgrade-package-versions-to-fix-vulnerabilities?utm_source=github&utm_content=fix-pr-template)

---

**Learn how to fix vulnerabilities with free interactive lessons:**

🦉 [Directory
Traversal](https://learn.snyk.io/lesson/directory-traversal/?loc&#x3D;fix-pr)

[//]: #
'snyk:metadata:{"customTemplate":{"variablesUsed":[],"fieldsUsed":[]},"dependencies":[{"name":"vite","from":"6.2.6","to":"6.2.7"}],"env":"prod","issuesToFix":["SNYK-JS-VITE-9919777"],"prId":"5e9ff0dc-5244-430f-a771-216527c7d561","prPublicId":"5e9ff0dc-5244-430f-a771-216527c7d561","packageManager":"npm","priorityScoreList":[693],"projectPublicId":"69d9ccbb-b5b1-492f-9f8c-9032dcaf021e","projectUrl":"https://app.snyk.io/org/victoriametrics/project/69d9ccbb-b5b1-492f-9f8c-9032dcaf021e?utm_source=github&utm_medium=referral&page=fix-pr","prType":"fix","templateFieldSources":{"branchName":"default","commitMessage":"default","description":"default","title":"default"},"templateVariants":["updated-fix-title","priorityScore"],"type":"auto","upgrade":["SNYK-JS-VITE-9919777"],"vulns":["SNYK-JS-VITE-9919777"],"patch":[],"isBreakingChange":false,"remediationStrategy":"vuln"}'

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2025-05-16 16:07:28 +02:00
Andrii Chubatiuk
0a4f7e0958 app/vmui: add command to run vmui with victoriametrics playground env (#8927)
### Describe Your Changes

added command to run vmui locally backed by vm playground

### Checklist

The following checks are **mandatory**:

- [ ] My change adheres to [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/victoriametrics/contributing/).
2025-05-16 16:07:07 +02:00
Artur Minchukou
9eb6796bad app/vmui/logs: properly escape special characters in field values shown in autocomplete suggestions
### Describe Your Changes

Related issue: #8925 

Properly escaped special characters in field values shown in
autocomplete suggestions.

### Checklist

The following checks are **mandatory**:

- [ ] My change adheres to [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/victoriametrics/contributing/).
2025-05-16 16:02:20 +02:00
Artem Fetishev
1916f5be4b lib/storage: make the test pass on systems with 1 CPU (#8949)
The following test produces duplicate per-day index records on a system
with 1 CPU even when data inserted sequentially:

```
GOEXPERIMENT=synctest taskset -c 0 go test ./lib/storage -run=TestStorageAddRowsForVariousDataPatternsConcurrently/perDayIndexes/serial/sameBatchMetrics/sameRowMetrics/sameBatchDates/diffRowDates
```

See: #8654

Make this test pass by relaxing got and want data equality requirement
if the number of CPUs is 1. This is temporary until one insertion corner
case is fixed:
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8948

### 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**:

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

Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2025-05-16 15:54:11 +02:00
hagen1778
4207cb8450 docs: add trailing / to links
See comment 266bceaffd (r157230824)

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-05-16 15:46:37 +02:00
Artur Minchukou
231bfcf4cf app/vmui: add live tailing tab to Victoria Logs (#8882)
### Describe Your Changes

Related issue: #7046 

Changes:
- add JSX automatic runtime import of React, you don't need to import
React anymore in JSX files.
 - add unused imports eslint rule
- add headers to ProcessLiveTailRequest to enable client-side connection
setup
- refactor ExploreLogs: divided the component into several separate
components for better readability and code maintenance
 - add live tailing tab to VictoriaLogs

short demo:


https://github.com/user-attachments/assets/3e5f57ee-8e72-4835-9fc6-35c6f38bc9ef



### Checklist

The following checks are **mandatory**:

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

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: hagen1778 <roman@victoriametrics.com>
2025-05-16 15:37:55 +02:00
Max Kotliar
03ceeb7211 docs: capitalize "Enterprise" in VictoriaMetrics Enterprise phrase (#8950)
### Describe Your Changes

Capitalize "Enterprise" in VictoriaMetrics Enterprise phrase

### Checklist

The following checks are **mandatory**:

- [ ] My change adheres to [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/victoriametrics/contributing/).
2025-05-16 15:17:01 +02:00
Max Kotliar
118a322aa4 docs/victoriametrics/changelog: Improve relabel bug fix changelog message (#8951)
### Describe Your Changes

 Improve relabel bug fix changelog message

### Checklist

The following checks are **mandatory**:

- [ ] My change adheres to [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/victoriametrics/contributing/).
2025-05-16 15:13:05 +02:00
Hui Wang
454ad7a1b4 alerts: improve disk full estimation (#8955)
enhance alerting rule `DiskRunsOutOfSpaceIn3Days` and
`NodeBecomesReadonlyIn3Days` to account for
[deduplication](https://docs.victoriametrics.com/#deduplication) and
[indexDB](https://docs.victoriametrics.com/#indexdb) when calculating
disk consumption rate.

And try bring the `Storage full ETA` panel back.

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: hagen1778 <roman@victoriametrics.com>
2025-05-16 15:11:12 +02:00
hagen1778
266bceaffd docs: demote links used for backward compatibility
Move anchors that were kept only for backward-compatibility reasons
to the bottom of the document. So they don't take extra space in main doc.

Demote anchor level to `h6`, so docs engine will stop rendering in the
right navigation column.

In this way, we still keep the backward compatibility: old links will
continue working. And free space occupied by these link in the main doc.
Thanks to @makasim for the idea.

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-05-16 15:06:55 +02:00
Hui Wang
60322ed491 vmalert: drop duplicate labels when they appear in both the recording… (#8957)
… rule label spec and the expression result

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

---------

Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: hagen1778 <roman@victoriametrics.com>
2025-05-16 13:47:54 +02:00
Andrii Chubatiuk
18f4c1f646 app/vlinsert: return HTTP 202 on successfully ingested Datadog logs (#8958)
### Describe Your Changes

fixes https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8956

### Checklist

The following checks are **mandatory**:

- [ ] My change adheres to [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/victoriametrics/contributing/).
2025-05-16 13:38:46 +02:00
hagen1778
45e6491a8e docs: mention where known issues were resolved
* mention which release got the bugfix
* unify `known issues` message

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2025-05-16 13:35:35 +02:00
f41gh7
0108d5777c docs: release follow-up
* mention new app versions
* add lts releases changelog
2025-05-15 17:40:59 +02:00
Max Kotliar
4fabb459aa changelog: add advice to skip affected versions
Add a note to skip the latest releases, because of the bug in vmagent.
Fixed in https://github.com/VictoriaMetrics/VictoriaMetrics/pull/8941
2025-05-15 17:33:49 +02:00
f41gh7
75623173d4 make linter happy after e2ddf2ba52
Signed-off-by: f41gh7 <nik@victoriametrics.com>
2025-05-15 12:51:56 +02:00
153 changed files with 283793 additions and 6961 deletions

View File

@@ -526,7 +526,7 @@ test-full:
test-full-386:
GOEXPERIMENT=synctest GOARCH=386 go test -coverprofile=coverage.txt -covermode=atomic ./lib/... ./app/...
integration-test: victoria-metrics vmagent vmalert vmauth
integration-test: victoria-metrics vmagent vmalert vmauth vmctl
go test ./apptest/... -skip="^TestCluster.*"
benchmark:

View File

@@ -95,6 +95,7 @@ func datadogLogsIngestion(w http.ResponseWriter, r *http.Request) bool {
// There is no need in updating v2LogsRequestDuration for request errors,
// since their timings are usually much smaller than the timing for successful request parsing.
v2LogsRequestDuration.UpdateDuration(startTime)
w.WriteHeader(http.StatusAccepted)
fmt.Fprintf(w, `{}`)
return true
}

View File

@@ -514,6 +514,11 @@ func ProcessLiveTailRequest(ctx context.Context, w http.ResponseWriter, r *http.
if !ok {
logger.Panicf("BUG: it is expected that http.ResponseWriter (%T) supports http.Flusher interface", w)
}
w.Header().Set("Content-Type", "application/x-ndjson")
w.Header().Set("Access-Control-Allow-Origin", "*")
flusher.Flush()
qOrig := q
for {
q = qOrig.CloneWithTimeFilter(end, start, end)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -35,10 +35,10 @@
<meta property="og:title" content="UI for VictoriaLogs">
<meta property="og:url" content="https://victoriametrics.com/products/victorialogs/">
<meta property="og:description" content="Explore your log data with VictoriaLogs UI">
<script type="module" crossorigin src="./assets/index-DfcWONVQ.js"></script>
<link rel="modulepreload" crossorigin href="./assets/vendor-C-vZmbyg.js">
<script type="module" crossorigin src="./assets/index-DLp5TlUn.js"></script>
<link rel="modulepreload" crossorigin href="./assets/vendor-D8IJGiEn.js">
<link rel="stylesheet" crossorigin href="./assets/vendor-D1GxaB_c.css">
<link rel="stylesheet" crossorigin href="./assets/index-Brup_hCI.css">
<link rel="stylesheet" crossorigin href="./assets/index-C85_NB5q.css">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View File

@@ -22,10 +22,10 @@ var (
relabelConfigPathGlobal = flag.String("remoteWrite.relabelConfig", "", "Optional path to file with relabeling configs, which are applied "+
"to all the metrics before sending them to -remoteWrite.url. See also -remoteWrite.urlRelabelConfig. "+
"The path can point either to local file or to http url. "+
"See https://docs.victoriametrics.com/victoriametrics/vmagent/#relabeling")
"See https://docs.victoriametrics.com/victoriametrics/relabeling/")
relabelConfigPaths = flagutil.NewArrayString("remoteWrite.urlRelabelConfig", "Optional path to relabel configs for the corresponding -remoteWrite.url. "+
"See also -remoteWrite.relabelConfig. The path can point either to local file or to http url. "+
"See https://docs.victoriametrics.com/victoriametrics/vmagent/#relabeling")
"See https://docs.victoriametrics.com/victoriametrics/relabeling/")
usePromCompatibleNaming = flag.Bool("usePromCompatibleNaming", false, "Whether to replace characters unsupported by Prometheus with underscores "+
"in the ingested metric names and label names. For example, foo.bar{a.b='c'} is transformed into foo_bar{a_b='c'} during data ingestion if this flag is set. "+

View File

@@ -13,7 +13,6 @@ import (
"path/filepath"
"reflect"
"sort"
"strconv"
"strings"
"syscall"
"time"
@@ -99,8 +98,11 @@ func UnitTest(files []string, disableGroupLabel bool, externalLabels []string, e
}()
}
// 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))
tmpFolder, err := os.MkdirTemp(os.TempDir(), testStoragePath)
if err != nil {
logger.Fatalf("failed to create tmp dir for tests: %v", err)
}
storagePath = tmpFolder
processFlags()
vminsert.Init()
vmselect.Init()

View File

@@ -258,12 +258,18 @@ func (rr *RecordingRule) toTimeSeries(m datasource.Metric) prompbmarshal.TimeSer
Value: rr.Name,
})
}
// add extra labels configured by user
for k := range rr.Labels {
prevLabel := promrelabel.GetLabelByName(m.Labels, k)
if prevLabel != nil && prevLabel.Value != rr.Labels[k] {
// Rename the prevLabel to "exported_" + label.Name
prevLabel.Name = fmt.Sprintf("exported_%s", prevLabel.Name)
existingLabel := promrelabel.GetLabelByName(m.Labels, k)
if existingLabel != nil { // there is a conflict between extra and existing label
if existingLabel.Value == rr.Labels[k] {
// extra and existing labels are identical - do nothing
continue
}
// preserve existing label by adding "exported_" prefix
existingLabel.Name = fmt.Sprintf("exported_%s", existingLabel.Name)
}
// add extra label
m.Labels = append(m.Labels, prompbmarshal.Label{
Name: k,
Value: rr.Labels[k],

View File

@@ -168,6 +168,7 @@ func TestRecordingRule_Exec(t *testing.T) {
}, [][]datasource.Metric{{
metricWithValueAndLabels(t, 2, "__name__", "foo", "job", "foo"),
metricWithValueAndLabels(t, 1, "__name__", "bar", "job", "bar", "source", "origin"),
metricWithValueAndLabels(t, 1, "__name__", "baz", "job", "baz", "source", "test"),
}}, [][]prompbmarshal.TimeSeries{{
newTimeSeries([]float64{2}, []int64{ts.UnixNano()}, []prompbmarshal.Label{
{
@@ -202,6 +203,21 @@ func TestRecordingRule_Exec(t *testing.T) {
Value: "origin",
},
}),
newTimeSeries([]float64{1}, []int64{ts.UnixNano()},
[]prompbmarshal.Label{
{
Name: "__name__",
Value: "job:foo",
},
{
Name: "job",
Value: "baz",
},
{
Name: "source",
Value: "test",
},
}),
}})
}

View File

@@ -1,215 +0,0 @@
package main
import (
"context"
"fmt"
"log"
"os"
"testing"
"time"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/storage"
"github.com/prometheus/prometheus/tsdb"
"github.com/prometheus/prometheus/tsdb/chunkenc"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/backoff"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/barpool"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/prometheus"
remote_read_integration "github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/testdata/servers_integration_test"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/vm"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/promql"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage"
)
const (
testSnapshot = "./testdata/snapshots/20250118T124506Z-59d1b952d7eaf547"
blockData = "./testdata/snapshots/20250118T124506Z-59d1b952d7eaf547/01JHWQ445Y2P1TDYB05AEKD6MC"
)
// This test simulates close process if user abort it
func TestPrometheusProcessorRun(t *testing.T) {
f := func(startStr, endStr string, numOfSeries int, resultExpected []vm.TimeSeries) {
t.Helper()
dst := remote_read_integration.NewRemoteWriteServer(t)
defer func() {
dst.Close()
}()
dst.Series(resultExpected)
dst.ExpectedSeries(resultExpected)
if err := fillStorage(resultExpected); err != nil {
t.Fatalf("cannot fill storage: %s", err)
}
isSilent = true
defer func() { isSilent = false }()
bf, err := backoff.New(1, 1.8, time.Second*2)
if err != nil {
t.Fatalf("cannot create backoff: %s", err)
}
importerCfg := vm.Config{
Addr: dst.URL(),
Transport: nil,
Concurrency: 1,
Backoff: bf,
}
ctx := context.Background()
importer, err := vm.NewImporter(ctx, importerCfg)
if err != nil {
t.Fatalf("cannot create importer: %s", err)
}
defer importer.Close()
matchName := "__name__"
matchValue := ".*"
filter := prometheus.Filter{
TimeMin: startStr,
TimeMax: endStr,
Label: matchName,
LabelValue: matchValue,
}
runner, err := prometheus.NewClient(prometheus.Config{
Snapshot: testSnapshot,
Filter: filter,
})
if err != nil {
t.Fatalf("cannot create prometheus client: %s", err)
}
p := &prometheusProcessor{
cl: runner,
im: importer,
cc: 1,
}
if err := p.run(); err != nil {
t.Fatalf("run() error: %s", err)
}
collectedTs := dst.GetCollectedTimeSeries()
t.Logf("collected timeseries: %d; expected timeseries: %d", len(collectedTs), len(resultExpected))
if len(collectedTs) != len(resultExpected) {
t.Fatalf("unexpected number of collected time series; got %d; want %d", len(collectedTs), numOfSeries)
}
deleted, err := deleteSeries(matchName, matchValue)
if err != nil {
t.Fatalf("cannot delete series: %s", err)
}
if deleted != numOfSeries {
t.Fatalf("unexpected number of deleted series; got %d; want %d", deleted, numOfSeries)
}
}
processFlags()
vmstorage.Init(promql.ResetRollupResultCacheIfNeeded)
defer func() {
vmstorage.Stop()
if err := os.RemoveAll(storagePath); err != nil {
log.Fatalf("cannot remove %q: %s", storagePath, err)
}
}()
barpool.Disable(true)
defer func() {
barpool.Disable(false)
}()
b, err := tsdb.OpenBlock(nil, blockData, nil, nil)
if err != nil {
t.Fatalf("cannot open block: %s", err)
}
// timestamp is equal to minTime and maxTime from meta.json
ss, err := readBlock(b, 1737204082361, 1737204302539)
if err != nil {
t.Fatalf("cannot read block: %s", err)
}
resultExpected, err := prepareExpectedData(ss)
if err != nil {
t.Fatalf("cannot prepare expected data: %s", err)
}
f("2025-01-18T12:40:00Z", "2025-01-18T12:46:00Z", 2792, resultExpected)
}
func readBlock(b tsdb.BlockReader, timeMin int64, timeMax int64) (storage.SeriesSet, error) {
minTime, maxTime := b.Meta().MinTime, b.Meta().MaxTime
if timeMin != 0 {
minTime = timeMin
}
if timeMax != 0 {
maxTime = timeMax
}
q, err := tsdb.NewBlockQuerier(b, minTime, maxTime)
if err != nil {
return nil, err
}
matchName := "__name__"
matchValue := ".*"
ctx := context.Background()
ss := q.Select(ctx, false, nil, labels.MustNewMatcher(labels.MatchRegexp, matchName, matchValue))
return ss, nil
}
func prepareExpectedData(ss storage.SeriesSet) ([]vm.TimeSeries, error) {
var expectedSeriesSet []vm.TimeSeries
var it chunkenc.Iterator
for ss.Next() {
var name string
var labelPairs []vm.LabelPair
series := ss.At()
for _, label := range series.Labels() {
if label.Name == "__name__" {
name = label.Value
continue
}
labelPairs = append(labelPairs, vm.LabelPair{
Name: label.Name,
Value: label.Value,
})
}
if name == "" {
return nil, fmt.Errorf("failed to find `__name__` label in labelset for block")
}
var timestamps []int64
var values []float64
it = series.Iterator(it)
for {
typ := it.Next()
if typ == chunkenc.ValNone {
break
}
if typ != chunkenc.ValFloat {
// Skip unsupported values
continue
}
t, v := it.At()
timestamps = append(timestamps, t)
values = append(values, v)
}
if err := it.Err(); err != nil {
return nil, err
}
ts := vm.TimeSeries{
Name: name,
LabelPairs: labelPairs,
Timestamps: timestamps,
Values: values,
}
expectedSeriesSet = append(expectedSeriesSet, ts)
}
return expectedSeriesSet, nil
}

View File

@@ -32,9 +32,13 @@ See https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries
{% code
// seriesFetched is string instead of int because of historical reasons.
// It cannot be converted to int without breaking backwards compatibility at vmalert :(
executionDuration := int64(0)
if ed := qs.ExecutionDuration.Load(); ed != nil {
executionDuration = ed.Milliseconds()
}
%}
"seriesFetched": "{%dl qs.SeriesFetched.Load() %}",
"executionTimeMsec": {%dl qs.ExecutionDuration.Load().Milliseconds() %}
"executionTimeMsec": {%dl executionDuration %}
}
{% code
qt.Printf("generate /api/v1/query_range response for series=%d, points=%d", seriesCount, pointsCount)

View File

@@ -64,91 +64,95 @@ func StreamQueryRangeResponse(qw422016 *qt422016.Writer, rs []netstorage.Result,
//line app/vmselect/prometheus/query_range_response.qtpl:33
// seriesFetched is string instead of int because of historical reasons.
// It cannot be converted to int without breaking backwards compatibility at vmalert :(
executionDuration := int64(0)
if ed := qs.ExecutionDuration.Load(); ed != nil {
executionDuration = ed.Milliseconds()
}
//line app/vmselect/prometheus/query_range_response.qtpl:35
//line app/vmselect/prometheus/query_range_response.qtpl:39
qw422016.N().S(`"seriesFetched": "`)
//line app/vmselect/prometheus/query_range_response.qtpl:36
qw422016.N().DL(qs.SeriesFetched.Load())
//line app/vmselect/prometheus/query_range_response.qtpl:36
qw422016.N().S(`","executionTimeMsec":`)
//line app/vmselect/prometheus/query_range_response.qtpl:37
qw422016.N().DL(qs.ExecutionDuration.Load().Milliseconds())
//line app/vmselect/prometheus/query_range_response.qtpl:37
qw422016.N().S(`}`)
//line app/vmselect/prometheus/query_range_response.qtpl:40
qw422016.N().DL(qs.SeriesFetched.Load())
//line app/vmselect/prometheus/query_range_response.qtpl:40
qw422016.N().S(`","executionTimeMsec":`)
//line app/vmselect/prometheus/query_range_response.qtpl:41
qw422016.N().DL(executionDuration)
//line app/vmselect/prometheus/query_range_response.qtpl:41
qw422016.N().S(`}`)
//line app/vmselect/prometheus/query_range_response.qtpl:44
qt.Printf("generate /api/v1/query_range response for series=%d, points=%d", seriesCount, pointsCount)
qtDone()
//line app/vmselect/prometheus/query_range_response.qtpl:43
//line app/vmselect/prometheus/query_range_response.qtpl:47
streamdumpQueryTrace(qw422016, qt)
//line app/vmselect/prometheus/query_range_response.qtpl:43
//line app/vmselect/prometheus/query_range_response.qtpl:47
qw422016.N().S(`}`)
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
}
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
func WriteQueryRangeResponse(qq422016 qtio422016.Writer, rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) {
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
qw422016 := qt422016.AcquireWriter(qq422016)
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
StreamQueryRangeResponse(qw422016, rs, qt, qtDone, qs)
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
qt422016.ReleaseWriter(qw422016)
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
}
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
func QueryRangeResponse(rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) string {
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
qb422016 := qt422016.AcquireByteBuffer()
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
WriteQueryRangeResponse(qb422016, rs, qt, qtDone, qs)
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
qs422016 := string(qb422016.B)
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
qt422016.ReleaseByteBuffer(qb422016)
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
return qs422016
//line app/vmselect/prometheus/query_range_response.qtpl:45
//line app/vmselect/prometheus/query_range_response.qtpl:49
}
//line app/vmselect/prometheus/query_range_response.qtpl:47
//line app/vmselect/prometheus/query_range_response.qtpl:51
func streamqueryRangeLine(qw422016 *qt422016.Writer, r *netstorage.Result) {
//line app/vmselect/prometheus/query_range_response.qtpl:47
//line app/vmselect/prometheus/query_range_response.qtpl:51
qw422016.N().S(`{"metric":`)
//line app/vmselect/prometheus/query_range_response.qtpl:49
//line app/vmselect/prometheus/query_range_response.qtpl:53
streammetricNameObject(qw422016, &r.MetricName)
//line app/vmselect/prometheus/query_range_response.qtpl:49
//line app/vmselect/prometheus/query_range_response.qtpl:53
qw422016.N().S(`,"values":`)
//line app/vmselect/prometheus/query_range_response.qtpl:50
//line app/vmselect/prometheus/query_range_response.qtpl:54
streamvaluesWithTimestamps(qw422016, r.Values, r.Timestamps)
//line app/vmselect/prometheus/query_range_response.qtpl:50
//line app/vmselect/prometheus/query_range_response.qtpl:54
qw422016.N().S(`}`)
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
}
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
func writequeryRangeLine(qq422016 qtio422016.Writer, r *netstorage.Result) {
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
qw422016 := qt422016.AcquireWriter(qq422016)
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
streamqueryRangeLine(qw422016, r)
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
qt422016.ReleaseWriter(qw422016)
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
}
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
func queryRangeLine(r *netstorage.Result) string {
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
qb422016 := qt422016.AcquireByteBuffer()
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
writequeryRangeLine(qb422016, r)
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
qs422016 := string(qb422016.B)
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
qt422016.ReleaseByteBuffer(qb422016)
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
return qs422016
//line app/vmselect/prometheus/query_range_response.qtpl:52
//line app/vmselect/prometheus/query_range_response.qtpl:56
}

View File

@@ -34,9 +34,13 @@ See https://prometheus.io/docs/prometheus/latest/querying/api/#instant-queries
{% code
// seriesFetched is string instead of int because of historical reasons.
// It cannot be converted to int without breaking backwards compatibility at vmalert :(
executionDuration := int64(0)
if ed := qs.ExecutionDuration.Load(); ed != nil {
executionDuration = ed.Milliseconds()
}
%}
"seriesFetched": "{%dl qs.SeriesFetched.Load() %}",
"executionTimeMsec": {%dl qs.ExecutionDuration.Load().Milliseconds() %}
"executionTimeMsec": {%dl executionDuration %}
}
{% code
qt.Printf("generate /api/v1/query response for series=%d", seriesCount)

View File

@@ -74,50 +74,54 @@ func StreamQueryResponse(qw422016 *qt422016.Writer, rs []netstorage.Result, qt *
//line app/vmselect/prometheus/query_response.qtpl:35
// seriesFetched is string instead of int because of historical reasons.
// It cannot be converted to int without breaking backwards compatibility at vmalert :(
executionDuration := int64(0)
if ed := qs.ExecutionDuration.Load(); ed != nil {
executionDuration = ed.Milliseconds()
}
//line app/vmselect/prometheus/query_response.qtpl:37
//line app/vmselect/prometheus/query_response.qtpl:41
qw422016.N().S(`"seriesFetched": "`)
//line app/vmselect/prometheus/query_response.qtpl:38
qw422016.N().DL(qs.SeriesFetched.Load())
//line app/vmselect/prometheus/query_response.qtpl:38
qw422016.N().S(`","executionTimeMsec":`)
//line app/vmselect/prometheus/query_response.qtpl:39
qw422016.N().DL(qs.ExecutionDuration.Load().Milliseconds())
//line app/vmselect/prometheus/query_response.qtpl:39
qw422016.N().S(`}`)
//line app/vmselect/prometheus/query_response.qtpl:42
qw422016.N().DL(qs.SeriesFetched.Load())
//line app/vmselect/prometheus/query_response.qtpl:42
qw422016.N().S(`","executionTimeMsec":`)
//line app/vmselect/prometheus/query_response.qtpl:43
qw422016.N().DL(executionDuration)
//line app/vmselect/prometheus/query_response.qtpl:43
qw422016.N().S(`}`)
//line app/vmselect/prometheus/query_response.qtpl:46
qt.Printf("generate /api/v1/query response for series=%d", seriesCount)
qtDone()
//line app/vmselect/prometheus/query_response.qtpl:45
//line app/vmselect/prometheus/query_response.qtpl:49
streamdumpQueryTrace(qw422016, qt)
//line app/vmselect/prometheus/query_response.qtpl:45
//line app/vmselect/prometheus/query_response.qtpl:49
qw422016.N().S(`}`)
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
}
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
func WriteQueryResponse(qq422016 qtio422016.Writer, rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) {
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
qw422016 := qt422016.AcquireWriter(qq422016)
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
StreamQueryResponse(qw422016, rs, qt, qtDone, qs)
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
qt422016.ReleaseWriter(qw422016)
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
}
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
func QueryResponse(rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) string {
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
qb422016 := qt422016.AcquireByteBuffer()
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
WriteQueryResponse(qb422016, rs, qt, qtDone, qs)
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
qs422016 := string(qb422016.B)
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
qt422016.ReleaseByteBuffer(qb422016)
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
return qs422016
//line app/vmselect/prometheus/query_response.qtpl:47
//line app/vmselect/prometheus/query_response.qtpl:51
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -36,10 +36,10 @@
<meta property="og:title" content="UI for VictoriaMetrics">
<meta property="og:url" content="https://victoriametrics.com/">
<meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data">
<script type="module" crossorigin src="./assets/index-C_-w5pCZ.js"></script>
<link rel="modulepreload" crossorigin href="./assets/vendor-C-vZmbyg.js">
<script type="module" crossorigin src="./assets/index-xmjGcv4-.js"></script>
<link rel="modulepreload" crossorigin href="./assets/vendor-D8IJGiEn.js">
<link rel="stylesheet" crossorigin href="./assets/vendor-D1GxaB_c.css">
<link rel="stylesheet" crossorigin href="./assets/index-Brup_hCI.css">
<link rel="stylesheet" crossorigin href="./assets/index-C85_NB5q.css">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View File

@@ -6,6 +6,7 @@ import path from "node:path";
import { fileURLToPath } from "node:url";
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";
import unusedImports from "eslint-plugin-unused-imports";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
@@ -23,6 +24,7 @@ export default [...compat.extends(
plugins: {
react,
"@typescript-eslint": typescriptEslint,
"unused-imports": unusedImports,
},
languageOptions: {
@@ -59,7 +61,7 @@ export default [...compat.extends(
allowTernary: true
}],
"@typescript-eslint/no-unused-vars": ["warn", {
"@typescript-eslint/no-unused-vars": ["error", {
"argsIgnorePattern": "^_",
"caughtErrors": "none",
"caughtErrorsIgnorePattern": "^_",
@@ -67,6 +69,8 @@ export default [...compat.extends(
"varsIgnorePattern": "^_",
"ignoreRestSiblings": true
}],
"unused-imports/no-unused-imports": "error",
"react/jsx-closing-bracket-location": [1, "line-aligned"],
@@ -85,6 +89,7 @@ export default [...compat.extends(
quotes: ["error", "double"],
semi: ["error", "always"],
"react/prop-types": 0,
"react/react-in-jsx-scope": "off",
},
}];

View File

@@ -23,9 +23,9 @@
"preact": "^10.26.5",
"qs": "^6.14.0",
"react-input-mask": "^2.0.4",
"react-router-dom": "^7.5.0",
"react-router-dom": "^7.6.0",
"uplot": "^1.6.32",
"vite": "^6.2.6",
"vite": "^6.2.7",
"web-vitals": "^4.2.4"
},
"devDependencies": {
@@ -42,6 +42,7 @@
"cross-env": "^7.0.3",
"eslint": "^9.24.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-unused-imports": "^4.1.4",
"globals": "^16.0.0",
"http-proxy-middleware": "^3.0.5",
"jsdom": "^26.1.0",
@@ -2115,12 +2116,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/cookie": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
"license": "MIT"
},
"node_modules/@types/eslint": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
@@ -4199,6 +4194,22 @@
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
}
},
"node_modules/eslint-plugin-unused-imports": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz",
"integrity": "sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0",
"eslint": "^9.0.0 || ^8.0.0"
},
"peerDependenciesMeta": {
"@typescript-eslint/eslint-plugin": {
"optional": true
}
}
},
"node_modules/eslint-scope": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
@@ -6476,15 +6487,13 @@
"license": "MIT"
},
"node_modules/react-router": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.5.0.tgz",
"integrity": "sha512-estOHrRlDMKdlQa6Mj32gIks4J+AxNsYoE0DbTTxiMy2mPzZuWSDU+N85/r1IlNR7kGfznF3VCUlvc5IUO+B9g==",
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz",
"integrity": "sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==",
"license": "MIT",
"dependencies": {
"@types/cookie": "^0.6.0",
"cookie": "^1.0.1",
"set-cookie-parser": "^2.6.0",
"turbo-stream": "2.4.0"
"set-cookie-parser": "^2.6.0"
},
"engines": {
"node": ">=20.0.0"
@@ -6500,12 +6509,12 @@
}
},
"node_modules/react-router-dom": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.5.0.tgz",
"integrity": "sha512-fFhGFCULy4vIseTtH5PNcY/VvDJK5gvOWcwJVHQp8JQcWVr85ENhJ3UpuF/zP1tQOIFYNRJHzXtyhU1Bdgw0RA==",
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.0.tgz",
"integrity": "sha512-DYgm6RDEuKdopSyGOWZGtDfSm7Aofb8CCzgkliTjtu/eDuB0gcsv6qdFhhi8HdtmA+KHkt5MfZ5K2PdzjugYsA==",
"license": "MIT",
"dependencies": {
"react-router": "7.5.0"
"react-router": "7.6.0"
},
"engines": {
"node": ">=20.0.0"
@@ -8012,12 +8021,6 @@
"devOptional": true,
"license": "0BSD"
},
"node_modules/turbo-stream": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
"integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
"license": "ISC"
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -8204,9 +8207,9 @@
"license": "MIT"
},
"node_modules/vite": {
"version": "6.2.6",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.6.tgz",
"integrity": "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==",
"version": "6.2.7",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.7.tgz",
"integrity": "sha512-qg3LkeuinTrZoJHHF94coSaTfIPyBYoywp+ys4qu20oSJFbKMYoIJo0FWJT9q6Vp49l6z9IsJRbHdcGtiKbGoQ==",
"license": "MIT",
"dependencies": {
"esbuild": "^0.25.0",

View File

@@ -20,14 +20,15 @@
"preact": "^10.26.5",
"qs": "^6.14.0",
"react-input-mask": "^2.0.4",
"react-router-dom": "^7.5.0",
"react-router-dom": "^7.6.0",
"uplot": "^1.6.32",
"vite": "^6.2.6",
"vite": "^6.2.7",
"web-vitals": "^4.2.4"
},
"scripts": {
"prestart": "npm run copy-metricsql-docs",
"start": "vite",
"start:playground": "cross-env PLAYGROUND=METRICS npm run start",
"start:logs": "vite --mode victorialogs",
"start:logs:playground": "cross-env PLAYGROUND=LOGS npm run start:logs",
"start:anomaly": "vite --mode vmanomaly",
@@ -66,6 +67,7 @@
"cross-env": "^7.0.3",
"eslint": "^9.24.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-unused-imports": "^4.1.4",
"globals": "^16.0.0",
"http-proxy-middleware": "^3.0.5",
"jsdom": "^26.1.0",

View File

@@ -69,7 +69,7 @@ const LogsQueryEditorAutocomplete: FC<QueryEditorAutocompleteProps> = ({
if (insertType === ContextType.FilterName) {
modifiedInsert += ":";
} else if (contextType === ContextType.FilterValue) {
const insertWithQuotes = value.startsWith("_stream:") ? modifiedInsert : `"${modifiedInsert}"`;
const insertWithQuotes = value.startsWith("_stream:") ? modifiedInsert : `${JSON.stringify(modifiedInsert)}`;
modifiedInsert = `${contextData?.filterName || ""}:${insertWithQuotes}`;
}

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
import React, { FC, useMemo, useRef } from "preact/compat";
import { FC, useMemo, useRef } from "preact/compat";
import { ArrowDropDownIcon } from "../../Icons";
import useBoolean from "../../../../hooks/useBoolean";
import Popper from "../../Popper/Popper";
@@ -10,11 +10,12 @@ interface SelectLimitProps {
limit: number | string;
allowUnlimited?: boolean;
onChange: (val: number) => void;
onOpenSelect?: () => void;
}
const defaultLimits = [10, 25, 50, 100, 250, 500, 1000];
const SelectLimit: FC<SelectLimitProps> = ({ limit, allowUnlimited, onChange }) => {
const SelectLimit: FC<SelectLimitProps> = ({ limit, allowUnlimited, onChange, onOpenSelect }) => {
const { isMobile } = useDeviceDetect();
const buttonRef = useRef<HTMLDivElement>(null);
@@ -28,6 +29,11 @@ const SelectLimit: FC<SelectLimitProps> = ({ limit, allowUnlimited, onChange })
setFalse: handleClose,
} = useBoolean(false);
const handleClickSelect = () => {
toggleOpenList();
if(!openList) onOpenSelect?.();
};
const handleChangeLimit = (n: number) => () => {
onChange(n);
handleClose();
@@ -37,7 +43,7 @@ const SelectLimit: FC<SelectLimitProps> = ({ limit, allowUnlimited, onChange })
<>
<div
className="vm-select-limits-button"
onClick={toggleOpenList}
onClick={handleClickSelect}
ref={buttonRef}
>
<div>

View File

@@ -24,6 +24,7 @@
&_sidebar {
display: grid;
grid-template-columns: 40px auto 1fr;
box-shadow: $color-background-body 0 1px 1px 0px;
}
&_mobile {

View File

@@ -1,4 +1,4 @@
import React, { FC, useMemo } from "preact/compat";
import { FC, useMemo } from "preact/compat";
import { useCallback } from "react";
import dayjs from "dayjs";
import DownloadButton from "../../../components/DownloadButton/DownloadButton";
@@ -7,10 +7,11 @@ import { downloadCSV, downloadJSON } from "../../../utils/file";
import { Logs } from "../../../api/types";
interface DownloadLogsButtonProps {
logs: Logs[];
/** Callback to get logs to download */
getLogs: () => Logs[];
}
const DownloadLogsButton: FC<DownloadLogsButtonProps> = ({ logs }) => {
const DownloadLogsButton: FC<DownloadLogsButtonProps> = ({ getLogs }) => {
const { fileExtensions, getDownloaderByExtension } = useMemo(() => {
const downloadFileOptions: {
extension: string;
@@ -39,12 +40,13 @@ const DownloadLogsButton: FC<DownloadLogsButtonProps> = ({ logs }) => {
return;
}
const logs = getLogs();
const downloader = getDownloaderByExtension(fileExtension);
if (downloader){
const timestamp = dayjs().utc().format(DATE_FILENAME_FORMAT);
downloader(logs, `vmui_logs_${timestamp}.${fileExtension}`);
}
}, [logs]);
}, [getLogs]);
return <DownloadButton
title={"Download logs"}
@@ -53,4 +55,4 @@ const DownloadLogsButton: FC<DownloadLogsButtonProps> = ({ logs }) => {
/>;
};
export default DownloadLogsButton;
export default DownloadLogsButton;

View File

@@ -1,5 +1,5 @@
import React, { FC, useState, useMemo, useRef } from "preact/compat";
import { CodeIcon, ListIcon, TableIcon } from "../../../components/Main/Icons";
import { FC, useRef } from "preact/compat";
import { CodeIcon, ListIcon, TableIcon, PlayIcon } from "../../../components/Main/Icons";
import Tabs from "../../../components/Main/Tabs/Tabs";
import "./style.scss";
import classNames from "classnames";
@@ -7,18 +7,11 @@ import useDeviceDetect from "../../../hooks/useDeviceDetect";
import { Logs } from "../../../api/types";
import useStateSearchParams from "../../../hooks/useStateSearchParams";
import useSearchParamsFromObject from "../../../hooks/useSearchParamsFromObject";
import TableSettings from "../../../components/Table/TableSettings/TableSettings";
import useBoolean from "../../../hooks/useBoolean";
import TableLogs from "./TableLogs";
import GroupLogs from "../GroupLogs/GroupLogs";
import JsonView from "../../../components/Views/JsonView/JsonView";
import LineLoader from "../../../components/Main/LineLoader/LineLoader";
import SelectLimit from "../../../components/Main/Pagination/SelectLimit/SelectLimit";
import DownloadLogsButton from "../DownloadLogsButton/DownloadLogsButton";
const MemoizedTableLogs = React.memo(TableLogs);
const MemoizedGroupLogs = React.memo(GroupLogs);
const MemoizedJsonView = React.memo(JsonView);
import GroupView from "./views/GroupView/GroupView";
import TableView from "./views/TableView/TableView";
import JsonView from "./views/JsonView/JsonView";
import LiveTailingView from "./views/LiveTailingView/LiveTailingView";
export interface ExploreLogBodyProps {
data: Logs[];
@@ -29,44 +22,28 @@ enum DisplayType {
group = "group",
table = "table",
json = "json",
liveTailing = "liveTailing",
}
const tabs = [
{ label: "Group", value: DisplayType.group, icon: <ListIcon/> },
{ label: "Table", value: DisplayType.table, icon: <TableIcon/> },
{ label: "JSON", value: DisplayType.json, icon: <CodeIcon/> },
{ label: "Group", value: DisplayType.group, icon: <ListIcon/>, Component: GroupView },
{ label: "Table", value: DisplayType.table, icon: <TableIcon/>, Component: TableView },
{ label: "JSON", value: DisplayType.json, icon: <CodeIcon/>, Component: JsonView },
{ label: "Live", value: DisplayType.liveTailing, icon: <PlayIcon/>, Component: LiveTailingView },
];
const ExploreLogsBody: FC<ExploreLogBodyProps> = ({ data, isLoading }) => {
const { isMobile } = useDeviceDetect();
const { setSearchParamsFromKeys } = useSearchParamsFromObject();
const groupSettingsRef = useRef<HTMLDivElement>(null);
const [activeTab, setActiveTab] = useStateSearchParams(DisplayType.group, "view");
const [displayColumns, setDisplayColumns] = useState<string[]>([]);
const [rowsPerPage, setRowsPerPage] = useStateSearchParams(1000, "rows_per_page");
const { value: tableCompact, toggle: toggleTableCompact } = useBoolean(false);
const columns = useMemo(() => {
if (!data?.length || activeTab !== DisplayType.table) return [];
const keys = new Set<string>();
for (const item of data) {
for (const key in item) {
keys.add(key);
}
}
return Array.from(keys);
}, [data, activeTab]);
const settingsRef = useRef<HTMLDivElement>(null);
const handleChangeTab = (view: string) => {
setActiveTab(view as DisplayType);
setSearchParamsFromKeys({ view });
};
const handleSetRowsPerPage = (limit: number) => {
setRowsPerPage(limit);
setSearchParamsFromKeys({ rows_per_page: limit });
};
const ActiveTabComponent = tabs.find(tab => tab.value === activeTab)?.Component;
return (
<div
@@ -95,39 +72,16 @@ const ExploreLogsBody: FC<ExploreLogBodyProps> = ({ data, isLoading }) => {
items={tabs}
onChange={handleChangeTab}
/>
<div className="vm-explore-logs-body-header__log-info">
Total logs returned: <b>{data.length}</b>
</div>
</div>
{activeTab === DisplayType.table && (
<div className="vm-explore-logs-body-header__settings">
<SelectLimit
limit={rowsPerPage}
onChange={handleSetRowsPerPage}
/>
<div className="vm-explore-logs-body-header__table-settings">
{data.length > 0 && <DownloadLogsButton logs={data} />}
<TableSettings
columns={columns}
selectedColumns={displayColumns}
onChangeColumns={setDisplayColumns}
tableCompact={tableCompact}
toggleTableCompact={toggleTableCompact}
/>
{activeTab !== DisplayType.liveTailing && (
<div className="vm-explore-logs-body-header__log-info">
Total logs returned: <b>{data.length}</b>
</div>
</div>
)}
{activeTab === DisplayType.group && (
<>
<div
className="vm-explore-logs-body-header__settings"
ref={groupSettingsRef}
/>
</>
)}
{activeTab === DisplayType.json && data.length > 0 && (
<DownloadLogsButton logs={data} />
)}
)}
</div>
<div
className="vm-explore-logs-body-header__settings"
ref={settingsRef}
/>
</div>
<div
@@ -136,29 +90,12 @@ const ExploreLogsBody: FC<ExploreLogBodyProps> = ({ data, isLoading }) => {
"vm-explore-logs-body__table_mobile": isMobile,
})}
>
{!data.length && <div className="vm-explore-logs-body__empty">No logs found</div>}
{!!data.length && (
<>
{activeTab === DisplayType.table && (
<MemoizedTableLogs
logs={data}
displayColumns={displayColumns}
tableCompact={tableCompact}
columns={columns}
rowsPerPage={Number(rowsPerPage)}
/>
)}
{activeTab === DisplayType.group && (
<MemoizedGroupLogs
logs={data}
settingsRef={groupSettingsRef}
/>
)}
{activeTab === DisplayType.json && (
<MemoizedJsonView data={data}/>
)}
</>
)}
{ActiveTabComponent &&
<ActiveTabComponent
data={data}
settingsRef={settingsRef}
/>
}
</div>
</div>
);

View File

@@ -4,7 +4,15 @@
position: relative;
&-header {
background-color: $color-background-block;
z-index: 1;
margin: -$padding-medium 0-$padding-medium 0;
position: sticky;
top: 0;
@media (max-width:1000px) {
top: 51px;
}
&_mobile {
margin: -$padding-global 0-$padding-global 0;
@@ -19,11 +27,6 @@
justify-content: flex-end;
}
&__table-settings {
display: flex;
flex-direction: row;
}
&__log-info {
flex-grow: 1;
text-align: right;

View File

@@ -0,0 +1,6 @@
import { Logs } from "../../../api/types";
export interface ViewProps {
data: Logs[];
settingsRef: React.RefObject<HTMLDivElement>;
}

View File

@@ -0,0 +1,21 @@
import React, { FC } from "preact/compat";
import GroupLogs from "../../../GroupLogs/GroupLogs";
import { ViewProps } from "../../types";
import EmptyLogs from "../components/EmptyLogs/EmptyLogs";
const MemoizedGroupLogs = React.memo(GroupLogs);
const GroupView: FC<ViewProps> = ({ data, settingsRef }) => {
if (!data.length) return <EmptyLogs />;
return (
<>
<MemoizedGroupLogs
logs={data}
settingsRef={settingsRef}
/>
</>
);
};
export default GroupView;

View File

@@ -0,0 +1,33 @@
import React, { FC } from "preact/compat";
import DownloadLogsButton from "../../../DownloadLogsButton/DownloadLogsButton";
import { createPortal } from "preact/compat";
import JsonViewComponent from "../../../../../components/Views/JsonView/JsonView";
import { ViewProps } from "../../types";
import EmptyLogs from "../components/EmptyLogs/EmptyLogs";
import { useCallback } from "react";
const MemoizedJsonView = React.memo(JsonViewComponent);
const JsonView: FC<ViewProps> = ({ data, settingsRef }) => {
const getLogs = useCallback(() => data, [data]);
const renderSettings = () => {
if (!settingsRef.current) return null;
return createPortal(
data.length > 0 && <DownloadLogsButton getLogs={getLogs} />,
settingsRef.current
);
};
if (!data.length) return <EmptyLogs />;
return (
<>
{renderSettings()}
<MemoizedJsonView data={data} />
</>
);
};
export default JsonView;

View File

@@ -0,0 +1,125 @@
import { FC, RefObject, useCallback, useRef } from "preact/compat";
import { createPortal } from "preact/compat";
import DownloadLogsButton from "../../../DownloadLogsButton/DownloadLogsButton";
import Button from "../../../../../components/Main/Button/Button";
import SelectLimit from "../../../../../components/Main/Pagination/SelectLimit/SelectLimit";
import { DeleteIcon, PauseIcon, PlayCircleOutlineIcon, SettingsIcon } from "../../../../../components/Main/Icons";
import Tooltip from "../../../../../components/Main/Tooltip/Tooltip";
import Modal from "../../../../../components/Main/Modal/Modal";
import Switch from "../../../../../components/Main/Switch/Switch";
import useBoolean from "../../../../../hooks/useBoolean";
import { Logs } from "../../../../../api/types";
interface LiveTailingSettingsProps {
settingsRef: RefObject<HTMLDivElement>;
rowsPerPage: number;
handleSetRowsPerPage: (limit: number) => void;
logs: Logs[];
isPaused: boolean;
handleResumeLiveTailing: () => void;
pauseLiveTailing: () => void;
clearLogs: () => void;
isCompactTailingNumber: boolean;
handleSetCompactTailing: (value: boolean) => void;
}
const LiveTailingSettings: FC<LiveTailingSettingsProps> = ({
settingsRef,
rowsPerPage,
handleSetRowsPerPage,
logs,
isPaused,
handleResumeLiveTailing,
pauseLiveTailing,
clearLogs,
isCompactTailingNumber,
handleSetCompactTailing
}) => {
const settingButtonRef = useRef<HTMLDivElement>(null);
const { value: isSettingsOpen, setFalse: closeSettings, setTrue: openSettings } = useBoolean(false);
const getLogs = useCallback(() => logs.map(({ _log_id, ...log }) => log), [logs]);
if (!settingsRef.current) return null;
return createPortal(
<div className="vm-live-tailing-view__settings">
<SelectLimit
limit={rowsPerPage}
onChange={handleSetRowsPerPage}
onOpenSelect={pauseLiveTailing}
/>
<div className="vm-live-tailing-view__settings-buttons">
{logs.length > 0 && <DownloadLogsButton getLogs={getLogs}/>}
{isPaused ? (
<Tooltip
title={"Resume live tailing"}
>
<Button
variant="text"
color="primary"
onClick={handleResumeLiveTailing}
startIcon={<PlayCircleOutlineIcon/>}
ariaLabel={"Resume live tailing"}
/>
</Tooltip>
) : (
<Tooltip
title={"Pause live tailing"}
>
<Button
variant="text"
color="primary"
onClick={pauseLiveTailing}
startIcon={<PauseIcon/>}
ariaLabel={"Pause live tailing"}
/>
</Tooltip>
)}
<Tooltip
title={"Clear logs"}
>
<Button
variant="text"
color="secondary"
onClick={clearLogs}
startIcon={<DeleteIcon/>}
ariaLabel={"Clear logs"}
/>
</Tooltip>
<Tooltip
title={"Settings"}
>
<Button
ref={settingButtonRef}
variant="text"
color="secondary"
onClick={openSettings}
startIcon={<SettingsIcon/>}
ariaLabel={"Settings"}
/>
</Tooltip>
{isSettingsOpen && <Modal
onClose={closeSettings}
title={"Live tailing settings"}
>
<div className="vm-live-tailing-view__settings-modal">
<div className={"vm-live-tailing-view__settings-modal-item"}>
<Switch
label={"Expandable Properties View"}
value={isCompactTailingNumber}
onChange={handleSetCompactTailing}
/>
<span className="vm-group-logs-configurator-item__info">
Switches log display to expandable properties view with additional visualization settings. Please note: when processing large volumes of data, it may increase system response time.
</span>
</div>
</div>
</Modal>}
</div>
</div>,
settingsRef.current
);
};
export default LiveTailingSettings;

View File

@@ -0,0 +1,145 @@
import { FC, useCallback, useEffect, useRef, useState } from "preact/compat";
import { ViewProps } from "../../types";
import useStateSearchParams from "../../../../../hooks/useStateSearchParams";
import useSearchParamsFromObject from "../../../../../hooks/useSearchParamsFromObject";
import "./style.scss";
import { useLiveTailingLogs } from "./useLiveTailingLogs";
import { LOGS_DISPLAY_FIELDS, LOGS_URL_PARAMS } from "../../../../../constants/logs";
import { useMemo } from "react";
import { useSearchParams } from "react-router-dom";
import throttle from "lodash/throttle";
import GroupLogsItem from "../../../GroupLogs/GroupLogsItem";
import LiveTailingSettings from "./LiveTailingSettings";
const SCROLL_THRESHOLD = 100;
const scrollToBottom = () => window.scrollTo({
top: document.documentElement.scrollHeight,
behavior: "instant"
});
const throttledScrollToBottom = throttle(scrollToBottom, 200);
const LiveTailingView: FC<ViewProps> = ({ settingsRef }) => {
const containerRef = useRef<HTMLDivElement>(null);
const [isAtBottom, setIsAtBottom] = useState(true);
const [searchParams] = useSearchParams();
const { setSearchParamsFromKeys } = useSearchParamsFromObject();
const [rowsPerPage, setRowsPerPage] = useStateSearchParams(100, "rows_per_page");
const [query, _setQuery] = useStateSearchParams("*", "query");
const [isCompactTailingStr] = useStateSearchParams(0, "compact_tailing");
const isCompactTailingNumber = Boolean(Number(isCompactTailingStr));
const {
logs,
isPaused,
error,
startLiveTailing,
stopLiveTailing,
pauseLiveTailing,
resumeLiveTailing,
clearLogs
} = useLiveTailingLogs(query, rowsPerPage);
const displayFieldsString = searchParams.get(LOGS_URL_PARAMS.DISPLAY_FIELDS) || LOGS_DISPLAY_FIELDS;
const displayFields = useMemo(() => displayFieldsString.split(","), [displayFieldsString]);
const handleResumeLiveTailing = useCallback(() => {
throttledScrollToBottom();
resumeLiveTailing();
}, [resumeLiveTailing]);
const handleSetRowsPerPage = useCallback((limit: number) => {
setSearchParamsFromKeys({ rows_per_page: limit });
}, [setRowsPerPage, setSearchParamsFromKeys]);
const handleSetCompactTailing = useCallback((value: boolean) => {
setSearchParamsFromKeys({ compact_tailing: Number(value) });
}, [setSearchParamsFromKeys]);
useEffect(() => {
startLiveTailing();
return () => stopLiveTailing();
}, [startLiveTailing, stopLiveTailing]);
useEffect(() => {
const container = containerRef.current;
if (!container) return;
const handleScroll = () => {
const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
const isBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < SCROLL_THRESHOLD;
setIsAtBottom(isBottom);
if (!isBottom && !isPaused) {
pauseLiveTailing();
}
};
document.addEventListener("scroll", handleScroll);
return () => document.removeEventListener("scroll", handleScroll);
}, [isPaused, pauseLiveTailing, resumeLiveTailing]);
useEffect(() => {
if (isAtBottom && !isPaused) {
throttledScrollToBottom();
}
}, [logs, isAtBottom]);
useEffect(() => {
handleResumeLiveTailing();
}, [rowsPerPage]);
if (error) {
return <div className="vm-live-tailing-view__error">{error}</div>;
}
return (
<>
<LiveTailingSettings
settingsRef={settingsRef}
rowsPerPage={rowsPerPage}
handleSetRowsPerPage={handleSetRowsPerPage}
logs={logs}
isPaused={isPaused}
handleResumeLiveTailing={handleResumeLiveTailing}
pauseLiveTailing={pauseLiveTailing}
clearLogs={clearLogs}
isCompactTailingNumber={isCompactTailingNumber}
handleSetCompactTailing={handleSetCompactTailing}
/>
<div
ref={containerRef}
className="vm-live-tailing-view__container"
>
{logs.length === 0
? (<div className="vm-live-tailing-view__empty">Waiting for logs...</div>)
: (<div className="vm-live-tailing-view__logs">
{logs.map(({ _log_id, ...log }, idx) =>
isCompactTailingNumber
? (
<GroupLogsItem
key={_log_id}
log={log}
onItemClick={pauseLiveTailing}
hideGroupButton={true}
displayFields={displayFields}
/>
) : (
<pre
key={idx}
className="vm-live-tailing-view__log-row"
>
{JSON.stringify(log)}
</pre>
)
)}
</div>
)}
</div>
</>
);
};
export default LiveTailingView;

View File

@@ -0,0 +1,76 @@
@use "src/styles/variables" as *;
.vm-live-tailing-view {
&__settings {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
&__settings-modal {
max-width: 500px;
min-width: 300px;
}
&__settings-modal-item {
display: flex;
flex-direction: column;
gap: $padding-small;
}
&__settings-modal-item-info {
font-size: $font-size-small;
color: $color-text-secondary;
line-height: 130%;
}
&__settings-buttons {
display: flex;
align-items: center;
}
&__container {
width: 100%;
height: 100%;
overflow: auto;
padding: $padding-global;
min-height: 200px;
font-family: $font-family-monospace;
}
&__empty {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: $color-text-secondary;
}
&__error {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: $color-error;
}
&__logs {
.vm-group-logs-row {
animation: highlight-fade 1s ease-out forwards;
}
}
&__log-row {
margin-top: $padding-small;
}
}
@keyframes highlight-fade {
0% {
background-color: $color-tropical-blue;
}
100% {
background-color: $color-background-block;
}
}

View File

@@ -0,0 +1,152 @@
import { useCallback, useEffect, useRef, useState } from "preact/compat";
import { ErrorTypes } from "../../../../../types";
import { Logs } from "../../../../../api/types";
import { useAppState } from "../../../../../state/common/StateContext";
import { useSearchParams } from "react-router-dom";
import useBoolean from "../../../../../hooks/useBoolean";
export const useLiveTailingLogs = (query: string, limit: number) => {
const { serverUrl } = useAppState();
const [searchParams] = useSearchParams();
const [logs, setLogs] = useState<Logs[]>([]);
const { value: isPaused, setTrue: pauseLiveTailing, setFalse: resumeLiveTailing } = useBoolean(false);
const [error, setError] = useState<ErrorTypes | string>();
const counterRef = useRef<bigint>(0n);
const abortControllerRef = useRef(new AbortController());
const readerRef = useRef<ReadableStreamDefaultReader<Uint8Array> | null>(null);
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
const bufferRef = useRef<string>("");
const stopLiveTailing = useCallback(() => {
if (readerRef.current) {
readerRef.current.cancel();
readerRef.current = null;
}
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
if (bufferRef.current) {
bufferRef.current = "";
}
abortControllerRef.current.abort();
}, []);
const startLiveTailing = useCallback(async () => {
stopLiveTailing();
abortControllerRef.current = new AbortController();
const { signal } = abortControllerRef.current;
setError(undefined);
setLogs([]);
try {
const tenant = {
AccountID: searchParams.get("accountID") || "0",
ProjectID: searchParams.get("projectID") || "0"
};
const response = await fetch(`${serverUrl}/select/logsql/tail`, {
signal,
method: "POST",
headers: {
...tenant,
},
body: new URLSearchParams({
query: query.trim(),
})
});
if (!response.ok || !response.body) {
const text = await response.text();
setError(text);
setLogs([]);
return false;
}
const reader = response.body.getReader();
readerRef.current = reader;
const processStream = async () => {
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
// Convert the Uint8Array to a string
const chunk = new TextDecoder().decode(value);
bufferRef.current += chunk;
}
} catch (e) {
if (e instanceof Error && e.name !== "AbortError") {
console.error("Stream processing error:", e);
setError(String(e));
}
}
};
processStream();
return true;
} catch (e) {
if (e instanceof Error && e.name !== "AbortError") {
setError(String(e));
console.error(e);
setLogs([]);
}
return false;
}
}, [query, stopLiveTailing]);
useEffect(() => {
if (isPaused) return;
/**
* Process incoming log data at a throttled rate (every 1s)
* This interval-based approach prevents CPU overload by:
* 1. Batching log processing instead of processing each chunk immediately
* 2. Limiting UI updates to a reasonable frequency (1/sec) even when data streams in rapidly
* 3. Reducing performance impact when handling large volumes of incoming logs
* 4. Allowing efficient garbage collection between processing cycles
*/
const timerId = setInterval(() => {
const lines = bufferRef.current.split("\n");
bufferRef.current = lines.pop() || "";
const newLogs = lines
.map(line => {
try {
const parsedLine = line && JSON.parse(line);
parsedLine._log_id = counterRef.current++;
return parsedLine;
} catch (e) {
console.error(`Failed to parse "${line}" to JSON\n`, e);
return null;
}
})
.filter(Boolean) as Logs[];
setLogs(prevLogs => {
const combinedLogs = [...prevLogs, ...newLogs];
return combinedLogs.length > limit ? combinedLogs.slice(-limit) : combinedLogs;
});
}, 1000);
return () => clearInterval(timerId);
}, [limit, isPaused]);
const clearLogs = useCallback(() => {
setLogs([]);
}, []);
return {
logs,
isPaused,
error,
startLiveTailing,
stopLiveTailing,
pauseLiveTailing,
resumeLiveTailing,
clearLogs
};
};

View File

@@ -0,0 +1,80 @@
import React, { FC, useMemo, useState } from "preact/compat";
import DownloadLogsButton from "../../../DownloadLogsButton/DownloadLogsButton";
import { createPortal } from "preact/compat";
import "./style.scss";
import { ViewProps } from "../../types";
import useBoolean from "../../../../../hooks/useBoolean";
import useStateSearchParams from "../../../../../hooks/useStateSearchParams";
import TableLogs from "../../TableLogs";
import SelectLimit from "../../../../../components/Main/Pagination/SelectLimit/SelectLimit";
import TableSettings from "../../../../../components/Table/TableSettings/TableSettings";
import useSearchParamsFromObject from "../../../../../hooks/useSearchParamsFromObject";
import EmptyLogs from "../components/EmptyLogs/EmptyLogs";
import { useCallback } from "react";
const MemoizedTableView = React.memo(TableLogs);
const TableView: FC<ViewProps> = ({ data, settingsRef }) => {
const { setSearchParamsFromKeys } = useSearchParamsFromObject();
const [displayColumns, setDisplayColumns] = useState<string[]>([]);
const [rowsPerPage, setRowsPerPage] = useStateSearchParams(100, "rows_per_page");
const { value: tableCompact, toggle: toggleTableCompact } = useBoolean(false);
const columns = useMemo(() => {
const keys = new Set<string>();
for (const item of data) {
for (const key in item) {
keys.add(key);
}
}
return Array.from(keys);
}, [data]);
const handleSetRowsPerPage = (limit: number) => {
setRowsPerPage(limit);
setSearchParamsFromKeys({ rows_per_page: limit });
};
const getLogs = useCallback(() => data, [data]);
const renderSettings = () => {
if (!settingsRef.current) return null;
return createPortal(
<div className="vm-table-view__settings">
<SelectLimit
limit={rowsPerPage}
onChange={handleSetRowsPerPage}
/>
<div className="vm-table-view__settings-buttons">
{data.length > 0 && <DownloadLogsButton getLogs={getLogs} />}
<TableSettings
columns={columns}
selectedColumns={displayColumns}
onChangeColumns={setDisplayColumns}
tableCompact={tableCompact}
toggleTableCompact={toggleTableCompact}
/>
</div>
</div>,
settingsRef.current
);
};
if (!data.length) return <EmptyLogs />;
return (
<>
{renderSettings()}
<MemoizedTableView
logs={data}
displayColumns={displayColumns}
tableCompact={tableCompact}
columns={columns}
rowsPerPage={Number(rowsPerPage)}
/>
</>
);
};
export default TableView;

View File

@@ -0,0 +1,10 @@
@use "src/styles/variables" as *;
.vm-table-view {
&__settings,
&__settings-buttons {
display: flex;
align-items: center;
gap: $padding-small;
}
}

View File

@@ -0,0 +1,10 @@
import { FC } from "preact/compat";
import "./style.scss";
const EmptyLogs: FC = () => {
return (
<div className="vm-explore-logs-body__empty">No logs found</div>
);
};
export default EmptyLogs;

View File

@@ -0,0 +1,12 @@
@use "src/styles/variables" as *;
.vm-explore-logs-body {
&__empty {
display: flex;
align-items: center;
justify-content: center;
min-height: 120px;
color: $color-text-disabled;
text-align: center;
}
}

View File

@@ -96,6 +96,8 @@ const GroupLogs: FC<Props> = ({ logs, settingsRef }) => {
window.scrollTo({ top: 0 });
};
const getLogs = useCallback(() => logs, [logs]);
useEffect(() => {
setExpandGroups(new Array(groupData.length).fill(!isMobile));
}, [groupData]);
@@ -162,7 +164,7 @@ const GroupLogs: FC<Props> = ({ logs, settingsRef }) => {
ariaLabel={expandAll ? "Collapse All" : "Expand All"}
/>
</Tooltip>
<DownloadLogsButton logs={logs} />
<DownloadLogsButton getLogs={getLogs} />
<GroupLogsConfigurators logs={logs}/>
</div>
), settingsRef.current)}

View File

@@ -1,4 +1,4 @@
import React, { FC, memo, useCallback, useEffect, useState } from "preact/compat";
import { FC, memo, useCallback, useEffect, useState } from "preact/compat";
import Tooltip from "../../../components/Main/Tooltip/Tooltip";
import Button from "../../../components/Main/Button/Button";
import { CopyIcon, StorageIcon, VisibilityIcon } from "../../../components/Main/Icons";
@@ -9,9 +9,10 @@ import { LOGS_GROUP_BY, LOGS_URL_PARAMS } from "../../../constants/logs";
interface Props {
field: string;
value: string;
hideGroupButton?: boolean;
}
const GroupLogsFieldRow: FC<Props> = ({ field, value }) => {
const GroupLogsFieldRow: FC<Props> = ({ field, value, hideGroupButton }) => {
const copyToClipboard = useCopyToClipboard();
const [searchParams, setSearchParams] = useSearchParams();
@@ -75,20 +76,22 @@ const GroupLogsFieldRow: FC<Props> = ({ field, value }) => {
size="small"
startIcon={isSelectedField ? <VisibilityIcon/> : <VisibilityIcon/>}
onClick={handleSelectDisplayField}
ariaLabel="copy to clipboard"
/>
</Tooltip>
<Tooltip title={isGroupByField ? "Ungroup this field" : "Group by this field"}>
<Button
className="vm-group-logs-row-fields-item-controls__button"
variant="text"
color={isGroupByField ? "secondary" : "gray"}
size="small"
startIcon={<StorageIcon/>}
onClick={handleSelectGroupBy}
ariaLabel="copy to clipboard"
ariaLabel={isSelectedField ? "Hide this field" : "Show this field instead of the message"}
/>
</Tooltip>
{!hideGroupButton && (
<Tooltip title={isGroupByField ? "Ungroup this field" : "Group by this field"}>
<Button
className="vm-group-logs-row-fields-item-controls__button"
variant="text"
color={isGroupByField ? "secondary" : "gray"}
size="small"
startIcon={<StorageIcon/>}
onClick={handleSelectGroupBy}
ariaLabel={isGroupByField ? "Ungroup this field" : "Group by this field"}
/>
</Tooltip>
)}
</div>
</td>
<td className="vm-group-logs-row-fields-item__key">{field}</td>

View File

@@ -8,9 +8,10 @@ import { getFromStorage } from "../../../utils/storage";
interface Props {
log: Logs;
hideGroupButton?: boolean;
}
const GroupLogsFields: FC<Props> = ({ log }) => {
const GroupLogsFields: FC<Props> = ({ log, hideGroupButton }) => {
const sortedFields = useMemo(() => {
return Object.entries(log)
.sort(([aKey], [bKey]) => aKey.localeCompare(bKey));
@@ -41,6 +42,7 @@ const GroupLogsFields: FC<Props> = ({ log }) => {
key={key}
field={key}
value={value}
hideGroupButton={hideGroupButton}
/>
))}
</tbody>

View File

@@ -18,9 +18,11 @@ import GroupLogsFields from "./GroupLogsFields";
interface Props {
log: Logs;
displayFields?: string[];
hideGroupButton?: boolean;
onItemClick?: (log: Logs) => void;
}
const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"], onItemClick, hideGroupButton }) => {
const {
value: isOpenFields,
toggle: toggleOpenFields,
@@ -75,6 +77,11 @@ const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
}
};
const handleClick = () => {
toggleOpenFields();
onItemClick?.(log);
};
useEventListener("storage", handleUpdateStage);
return (
@@ -84,7 +91,7 @@ const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
"vm-group-logs-row-content": true,
"vm-group-logs-row-content_interactive": !disabledHovers,
})}
onClick={toggleOpenFields}
onClick={handleClick}
>
{hasFields && (
<div
@@ -123,7 +130,10 @@ const GroupLogsItem: FC<Props> = ({ log, displayFields = ["_msg"] }) => {
))}
</div>
</div>
{hasFields && isOpenFields && <GroupLogsFields log={log}/>}
{hasFields && isOpenFields && <GroupLogsFields
hideGroupButton={hideGroupButton}
log={log}
/>}
</div>
);
};

View File

@@ -101,7 +101,7 @@ const Relabel: FC = () => {
<a
className="vm-link vm-link_with-icon"
target="_blank"
href="https://docs.victoriametrics.com/victoriametrics/vmagent/#relabeling"
href="https://docs.victoriametrics.com/victoriametrics/relabeling/"
rel="help noreferrer"
>
<WikiIcon/>

View File

@@ -20,7 +20,9 @@
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"jsxImportSource": "preact",
"downlevelIteration": true,
"noUnusedLocals": true,
"paths": {
"react": ["./node_modules/preact/compat/"],
"react/jsx-runtime": ["./node_modules/preact/jsx-runtime"],

View File

@@ -8,6 +8,28 @@ const getProxy = (): Record<string, ProxyOptions> | undefined => {
const playground = process.env.PLAYGROUND;
switch (playground) {
case "METRICS": {
return {
"^/vmalert/.*": {
target: "https://play.victoriametrics.com",
changeOrigin: true,
configure: (proxy) => {
proxy.on("error", (err) => {
console.error("[proxy error]", err.message);
});
}
},
"^/api/.*": {
target: "https://play.victoriametrics.com/select/0/prometheus/",
changeOrigin: true,
configure: (proxy) => {
proxy.on("error", (err) => {
console.error("[proxy error]", err.message);
});
}
}
};
}
case "LOGS": {
return {
"^/select/.*": {

View File

@@ -31,6 +31,7 @@ type app struct {
binary string
flags []string
process *os.Process
wait bool
}
// appOptions holds the optional configuration of an app, such as default flags
@@ -38,6 +39,7 @@ type app struct {
type appOptions struct {
defaultFlags map[string]string
extractREs []*regexp.Regexp
wait bool
}
// startApp starts an instance of an app using the app binary file path and
@@ -73,6 +75,7 @@ func startApp(instance string, binary string, flags []string, opts *appOptions)
binary: binary,
flags: flags,
process: cmd.Process,
wait: opts.wait,
}
go app.processOutput("stdout", stdout, app.writeToStderr)
@@ -92,7 +95,11 @@ func startApp(instance string, binary string, flags []string, opts *appOptions)
return nil, nil, err
}
return app, extracts, nil
if app.wait {
err = cmd.Wait()
}
return app, extracts, err
}
// setDefaultFlags adds flags with default values to `flags` if it does not
@@ -112,9 +119,12 @@ func setDefaultFlags(flags []string, defaultFlags map[string]string) []string {
return flags
}
// stop sends the app process a SIGINT signal and waits until it terminates
// Stop sends the app process a SIGINT signal and waits until it terminates
// gracefully.
func (app *app) Stop() {
if app.wait {
return
}
if err := app.process.Signal(os.Interrupt); err != nil {
log.Fatalf("Could not send SIGINT signal to %s process: %v", app.instance, err)
}

View File

@@ -7,8 +7,9 @@ import (
"testing"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
"github.com/google/go-cmp/cmp"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
)
// TestCase holds the state and defines clean-up procedure common for all test
@@ -251,6 +252,18 @@ func (tc *TestCase) MustStartCluster(opts *ClusterOptions) PrometheusWriteQuerie
return &Vmcluster{vminsert, vmselect, []*Vmstorage{vmstorage1, vmstorage2}}
}
// MustStartVmctl is a test helper function that starts an instance of vmctl
func (tc *TestCase) MustStartVmctl(instance string, flags []string) *Vmctl {
tc.t.Helper()
app, err := StartVmctl(instance, flags)
if err != nil {
tc.t.Fatalf("Could not start %s: %v", instance, err)
}
tc.addApp(instance, app)
return app
}
func (tc *TestCase) addApp(instance string, app Stopper) {
if _, alreadyStarted := tc.startedApps[instance]; alreadyStarted {
tc.t.Fatalf("%s has already been started", instance)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
package tests
import (
"fmt"
"io"
"os"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/VictoriaMetrics/VictoriaMetrics/apptest"
)
func TestVmctlPrometheusProtocolToVMSingle(t *testing.T) {
os.RemoveAll(t.Name())
tc := apptest.NewTestCase(t)
defer tc.Stop()
cmpOpt := cmpopts.IgnoreFields(apptest.PrometheusAPIV1QueryResponse{}, "Status", "Data.ResultType")
vmsingleDst := tc.MustStartVmsingle("vmsingle", []string{
"-storageDataPath=" + tc.Dir() + "/vmsingle",
"-retentionPeriod=100y",
})
// test for empty data request
got := vmsingleDst.PrometheusAPIV1Query(t, `{__name__=~".*"}`, apptest.QueryOpts{
Step: "5m",
Time: "2025-01-18T12:45:00Z",
})
want := apptest.NewPrometheusAPIV1QueryResponse(t, `{"data":{"result":[]}}`)
if diff := cmp.Diff(want, got, cmpOpt); diff != "" {
t.Errorf("unexpected response (-want, +got):\n%s", diff)
}
vmAddr := fmt.Sprintf("http://%s/", vmsingleDst.HTTPAddr())
testSnapshot := "./testdata/prometheus/snapshots/20250118T124506Z-59d1b952d7eaf547"
_ = tc.MustStartVmctl("vmctl", []string{
`prometheus`,
`--prom-snapshot=` + testSnapshot,
`--vm-addr=` + vmAddr,
`--disable-progress-bar=true`,
})
vmsingleDst.ForceFlush(t)
// open the expected series response file
file, err := os.Open("./testdata/prometheus/expected_response.json")
if err != nil {
t.Fatalf("cannot open expected series response file: %s", err)
}
defer file.Close()
bytes, err := io.ReadAll(file)
if err != nil {
t.Fatalf("cannot read expected series response file: %s", err)
}
wantResponse := apptest.NewPrometheusAPIV1QueryResponse(t, string(bytes))
wantResponse.Sort()
tc.Assert(&apptest.AssertOptions{
Msg: `unexpected metrics stored on vmsingle via the prometheus protocol`,
Got: func() any {
exported := vmsingleDst.PrometheusAPIV1Export(t, `{__name__=~".*"}`, apptest.QueryOpts{
Start: "2025-01-18T00:45:00Z",
End: "2025-01-18T23:46:00Z",
})
exported.Sort()
return exported
},
Want: &apptest.PrometheusAPIV1QueryResponse{Data: wantResponse.Data},
CmpOpts: []cmp.Option{
cmpopts.IgnoreFields(apptest.PrometheusAPIV1QueryResponse{}, "Status", "Data.ResultType"),
},
})
}

18
apptest/vmctl.go Normal file
View File

@@ -0,0 +1,18 @@
package apptest
// Vmctl holds the state of a vmctl app and provides vmctl-specific functions
type Vmctl struct {
*app
}
// StartVmctl starts an instance of vmctl cli with the given flags
func StartVmctl(instance string, flags []string) (*Vmctl, error) {
app, _, err := startApp(instance, "../../bin/vmctl", flags, &appOptions{wait: true})
if err != nil {
return nil, err
}
return &Vmctl{
app: app,
}, nil
}

View File

@@ -1,50 +1,4 @@
{
"__inputs": [],
"__elements": {},
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "11.5.0"
},
{
"type": "datasource",
"id": "prometheus",
"name": "Prometheus",
"version": "1.0.0"
},
{
"type": "panel",
"id": "stat",
"name": "Stat",
"version": ""
},
{
"type": "panel",
"id": "table",
"name": "Table",
"version": ""
},
{
"type": "panel",
"id": "text",
"name": "Text",
"version": ""
},
{
"type": "panel",
"id": "timeseries",
"name": "Time series",
"version": ""
},
{
"type": "datasource",
"id": "victoriametrics-logs-datasource",
"name": "VictoriaLogs",
"version": "0.16.3"
}
],
"annotations": {
"list": [
{
@@ -92,11 +46,11 @@
}
]
},
"description": "Overview for cluster version of VictoriaLogs v1.18.0 or higher",
"description": "Overview for cluster version of VictoriaLogs v1.22.0 or higher",
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"id": 1,
"links": [],
"panels": [
{
@@ -478,6 +432,10 @@
},
{
"description": "See [latest releases](https://docs.victoriametrics.com/victorialogs/changelog/).",
"fieldConfig": {
"defaults": {},
"overrides": []
},
"gridPos": {
"h": 2,
"w": 4,
@@ -886,6 +844,7 @@
"refId": "A"
}
],
"title": "",
"type": "table"
},
{
@@ -1540,7 +1499,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -1647,7 +1607,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -1780,7 +1741,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 341
"y": 543
},
"id": 62,
"options": {
@@ -1885,7 +1846,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 341
"y": 543
},
"id": 26,
"options": {
@@ -2002,7 +1963,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 405
"y": 607
},
"id": 70,
"options": {
@@ -2102,7 +2063,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 405
"y": 607
},
"id": 71,
"options": {
@@ -2209,7 +2170,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2225,7 +2187,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 342
"y": 150
},
"id": 38,
"options": {
@@ -2266,6 +2228,116 @@
"title": "RSS memory % usage ($instance)",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "$ds"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"links": [],
"mappings": [],
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "percentunit"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 150
},
"id": 44,
"options": {
"legend": {
"calcs": [
"mean",
"lastNotNull",
"max"
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true,
"sortBy": "Last *",
"sortDesc": true
},
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "none"
}
},
"pluginVersion": "11.5.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$ds"
},
"editorMode": "code",
"exemplar": false,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "CPU % usage ($instance)",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
@@ -2317,7 +2389,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2332,8 +2405,8 @@
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 342
"x": 0,
"y": 158
},
"id": 42,
"options": {
@@ -2379,6 +2452,7 @@
"type": "prometheus",
"uid": "$ds"
},
"description": "Shows CPU pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
"fieldConfig": {
"defaults": {
"color": {
@@ -2414,9 +2488,10 @@
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
"mode": "line"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"min": 0,
@@ -2424,25 +2499,22 @@
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
"color": "green",
"value": null
}
]
},
"unit": "percentunit"
"unit": "s"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 350
"x": 12,
"y": 158
},
"id": 44,
"id": 76,
"options": {
"legend": {
"calcs": [
@@ -2459,7 +2531,7 @@
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "none"
"sort": "desc"
}
},
"pluginVersion": "11.5.0",
@@ -2470,17 +2542,153 @@
"uid": "$ds"
},
"editorMode": "code",
"exemplar": false,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"expr": "max(rate(process_pressure_cpu_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
"legendFormat": "__auto",
"intervalFactor": 2,
"legendFormat": "{{job}} - waiting",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(rate(process_pressure_cpu_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"hide": false,
"interval": "",
"intervalFactor": 2,
"legendFormat": "{{job}} - stalled",
"range": true,
"refId": "B"
}
],
"title": "CPU % usage ($instance)",
"title": "CPU pressure",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "$ds"
},
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "line"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "s"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 166
},
"id": 77,
"options": {
"legend": {
"calcs": [
"mean",
"lastNotNull",
"max"
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true,
"sortBy": "Last *",
"sortDesc": true
},
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "desc"
}
},
"pluginVersion": "11.5.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(rate(process_pressure_memory_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
"legendFormat": "{{job}} - waiting",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(rate(process_pressure_memory_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"hide": false,
"interval": "",
"intervalFactor": 2,
"legendFormat": "{{job}} - stalled",
"range": true,
"refId": "B"
}
],
"title": "Memory pressure",
"type": "timeseries"
},
{
@@ -2533,7 +2741,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2562,7 +2771,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 350
"y": 166
},
"id": 52,
"options": {
@@ -2672,7 +2881,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2704,7 +2914,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 358
"y": 174
},
"id": 46,
"options": {
@@ -2797,7 +3007,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2826,7 +3037,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 358
"y": 174
},
"id": 56,
"options": {
@@ -2935,7 +3146,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2951,7 +3163,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 366
"y": 182
},
"id": 50,
"options": {
@@ -2997,7 +3209,7 @@
"type": "prometheus",
"uid": "$ds"
},
"description": "",
"description": "Shows IO pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
"fieldConfig": {
"defaults": {
"color": {
@@ -3033,9 +3245,10 @@
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
"mode": "line"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"min": 0,
@@ -3043,15 +3256,12 @@
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
"color": "green",
"value": null
}
]
},
"unit": "short"
"unit": "s"
},
"overrides": []
},
@@ -3059,9 +3269,9 @@
"h": 8,
"w": 12,
"x": 12,
"y": 366
"y": 182
},
"id": 60,
"id": 78,
"options": {
"legend": {
"calcs": [
@@ -3078,7 +3288,7 @@
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "none"
"sort": "desc"
}
},
"pluginVersion": "11.5.0",
@@ -3089,16 +3299,31 @@
"uid": "$ds"
},
"editorMode": "code",
"expr": "sum(max_over_time(vm_tcplistener_conns{job=~\"$job\", instance=~\"$instance\"}[$__interval])) by(job)",
"expr": "max(rate(process_pressure_io_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"hide": false,
"intervalFactor": 1,
"legendFormat": "__auto",
"interval": "",
"intervalFactor": 2,
"legendFormat": "{{job}} - waiting",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(rate(process_pressure_io_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"hide": false,
"interval": "",
"intervalFactor": 2,
"legendFormat": "{{job}} - stalled",
"range": true,
"refId": "B"
}
],
"title": "TCP connections ($instance)",
"title": "IO pressure",
"type": "timeseries"
},
{
@@ -3152,7 +3377,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -3168,7 +3394,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 374
"y": 190
},
"id": 54,
"options": {
@@ -3260,7 +3486,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -3276,9 +3503,9 @@
"h": 8,
"w": 12,
"x": 12,
"y": 374
"y": 190
},
"id": 58,
"id": 60,
"options": {
"legend": {
"calcs": [
@@ -3306,7 +3533,7 @@
"uid": "$ds"
},
"editorMode": "code",
"expr": "sum(rate(vm_tcplistener_accepts_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by(job)",
"expr": "sum(max_over_time(vm_tcplistener_conns{job=~\"$job\", instance=~\"$instance\"}[$__interval])) by(job)",
"format": "time_series",
"hide": false,
"intervalFactor": 1,
@@ -3315,7 +3542,7 @@
"refId": "A"
}
],
"title": "TCP connections rate ($instance)",
"title": "TCP connections ($instance)",
"type": "timeseries"
},
{
@@ -3370,7 +3597,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -3386,7 +3614,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 382
"y": 198
},
"id": 74,
"options": {
@@ -3431,7 +3659,7 @@
"type": "prometheus",
"uid": "$ds"
},
"description": "Shows the time goroutines have spent in runnable state before actually running. The lower is better.\n\nHigh values or values exceeding the threshold is usually a sign of insufficient CPU resources or CPU throttling. \n\nVerify that service has enough CPU resources. Otherwise, the service could work unreliably with delays in processing.",
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -3467,10 +3695,9 @@
"mode": "none"
},
"thresholdsStyle": {
"mode": "line"
"mode": "off"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"min": 0,
@@ -3478,15 +3705,16 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
"value": 0.1
"value": 80
}
]
},
"unit": "s"
"unit": "short"
},
"overrides": []
},
@@ -3494,9 +3722,9 @@
"h": 8,
"w": 12,
"x": 12,
"y": 382
"y": 198
},
"id": 61,
"id": 58,
"options": {
"legend": {
"calcs": [
@@ -3506,12 +3734,14 @@
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
"showLegend": true,
"sortBy": "Last *",
"sortDesc": true
},
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "desc"
"sort": "none"
}
},
"pluginVersion": "11.5.0",
@@ -3522,16 +3752,16 @@
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(histogram_quantile(0.99, sum(rate(go_sched_latencies_seconds_bucket{job=~\"$job\"}[$__rate_interval])) by (job, instance, le))) by(job)",
"expr": "sum(rate(vm_tcplistener_accepts_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
"hide": false,
"intervalFactor": 1,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Go scheduling latency",
"title": "TCP connections rate ($instance)",
"type": "timeseries"
},
{
@@ -3586,7 +3816,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
}
]
},
@@ -3598,7 +3829,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 390
"y": 206
},
"id": 75,
"options": {
@@ -3637,12 +3868,122 @@
],
"title": "Memory allocations rate",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "$ds"
},
"description": "Shows the time goroutines have spent in runnable state before actually running. The lower is better.\n\nHigh values or values exceeding the threshold is usually a sign of insufficient CPU resources or CPU throttling. \n\nVerify that service has enough CPU resources. Otherwise, the service could work unreliably with delays in processing.",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "line"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 0.1
}
]
},
"unit": "s"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 206
},
"id": 61,
"options": {
"legend": {
"calcs": [
"mean",
"lastNotNull",
"max"
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "desc"
}
},
"pluginVersion": "11.5.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(histogram_quantile(0.99, sum(rate(go_sched_latencies_seconds_bucket{job=~\"$job\"}[$__rate_interval])) by (job, instance, le))) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Go scheduling latency",
"type": "timeseries"
}
],
"title": "Resource usage",
"type": "row"
}
],
"preload": false,
"refresh": "",
"schemaVersion": 40,
"tags": [
@@ -3740,4 +4081,4 @@
"uid": "XqCOFEX4z",
"version": 1,
"weekStart": ""
}
}

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,51 +1,5 @@
{
"__inputs": [],
"__elements": {},
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "11.5.0"
},
{
"type": "datasource",
"id": "victoriametrics-metrics-datasource",
"name": "VictoriaMetrics",
"version": "1.0.0"
},
{
"type": "panel",
"id": "stat",
"name": "Stat",
"version": ""
},
{
"type": "panel",
"id": "table",
"name": "Table",
"version": ""
},
{
"type": "panel",
"id": "text",
"name": "Text",
"version": ""
},
{
"type": "panel",
"id": "timeseries",
"name": "Time series",
"version": ""
},
{
"type": "datasource",
"id": "victoriametrics-logs-datasource",
"name": "VictoriaLogs",
"version": "0.16.3"
}
],
"annotations": {
"list": [
{
@@ -93,11 +47,11 @@
}
]
},
"description": "Overview for cluster version of VictoriaLogs v1.18.0 or higher",
"description": "Overview for cluster version of VictoriaLogs v1.22.0 or higher",
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"id": 1,
"links": [],
"panels": [
{
@@ -479,6 +433,10 @@
},
{
"description": "See [latest releases](https://docs.victoriametrics.com/victorialogs/changelog/).",
"fieldConfig": {
"defaults": {},
"overrides": []
},
"gridPos": {
"h": 2,
"w": 4,
@@ -887,6 +845,7 @@
"refId": "A"
}
],
"title": "",
"type": "table"
},
{
@@ -1541,7 +1500,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -1648,7 +1608,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -1781,7 +1742,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 341
"y": 543
},
"id": 62,
"options": {
@@ -1886,7 +1847,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 341
"y": 543
},
"id": 26,
"options": {
@@ -2003,7 +1964,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 405
"y": 607
},
"id": 70,
"options": {
@@ -2103,7 +2064,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 405
"y": 607
},
"id": 71,
"options": {
@@ -2210,7 +2171,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2226,7 +2188,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 342
"y": 150
},
"id": 38,
"options": {
@@ -2267,6 +2229,116 @@
"title": "RSS memory % usage ($instance)",
"type": "timeseries"
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"links": [],
"mappings": [],
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "percentunit"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 150
},
"id": 44,
"options": {
"legend": {
"calcs": [
"mean",
"lastNotNull",
"max"
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true,
"sortBy": "Last *",
"sortDesc": true
},
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "none"
}
},
"pluginVersion": "11.5.0",
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
"exemplar": false,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "CPU % usage ($instance)",
"type": "timeseries"
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
@@ -2318,7 +2390,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2333,8 +2406,8 @@
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 342
"x": 0,
"y": 158
},
"id": 42,
"options": {
@@ -2380,6 +2453,7 @@
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"description": "Shows CPU pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
"fieldConfig": {
"defaults": {
"color": {
@@ -2415,9 +2489,10 @@
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
"mode": "line"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"min": 0,
@@ -2425,25 +2500,22 @@
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
"color": "green",
"value": null
}
]
},
"unit": "percentunit"
"unit": "s"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 350
"x": 12,
"y": 158
},
"id": 44,
"id": 76,
"options": {
"legend": {
"calcs": [
@@ -2460,7 +2532,7 @@
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "none"
"sort": "desc"
}
},
"pluginVersion": "11.5.0",
@@ -2471,17 +2543,153 @@
"uid": "$ds"
},
"editorMode": "code",
"exemplar": false,
"expr": "max(\n rate(process_cpu_seconds_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n /\n process_cpu_cores_available{job=~\"$job\", instance=~\"$instance\"}\n) by(job)",
"expr": "max(rate(process_pressure_cpu_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
"legendFormat": "__auto",
"intervalFactor": 2,
"legendFormat": "{{job}} - waiting",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(rate(process_pressure_cpu_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"hide": false,
"interval": "",
"intervalFactor": 2,
"legendFormat": "{{job}} - stalled",
"range": true,
"refId": "B"
}
],
"title": "CPU % usage ($instance)",
"title": "CPU pressure",
"type": "timeseries"
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"description": "Shows memory pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "line"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "s"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 166
},
"id": 77,
"options": {
"legend": {
"calcs": [
"mean",
"lastNotNull",
"max"
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true,
"sortBy": "Last *",
"sortDesc": true
},
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "desc"
}
},
"pluginVersion": "11.5.0",
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(rate(process_pressure_memory_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
"legendFormat": "{{job}} - waiting",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(rate(process_pressure_memory_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"hide": false,
"interval": "",
"intervalFactor": 2,
"legendFormat": "{{job}} - stalled",
"range": true,
"refId": "B"
}
],
"title": "Memory pressure",
"type": "timeseries"
},
{
@@ -2534,7 +2742,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2563,7 +2772,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 350
"y": 166
},
"id": 52,
"options": {
@@ -2673,7 +2882,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2705,7 +2915,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 358
"y": 174
},
"id": 46,
"options": {
@@ -2798,7 +3008,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2827,7 +3038,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 358
"y": 174
},
"id": 56,
"options": {
@@ -2936,7 +3147,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -2952,7 +3164,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 366
"y": 182
},
"id": 50,
"options": {
@@ -2998,7 +3210,7 @@
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"description": "",
"description": "Shows IO pressure based on [Pressure Stall Information](https://docs.kernel.org/accounting/psi.html).\n\nThe lower the better.",
"fieldConfig": {
"defaults": {
"color": {
@@ -3034,9 +3246,10 @@
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
"mode": "line"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"min": 0,
@@ -3044,15 +3257,12 @@
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
"color": "green",
"value": null
}
]
},
"unit": "short"
"unit": "s"
},
"overrides": []
},
@@ -3060,9 +3270,9 @@
"h": 8,
"w": 12,
"x": 12,
"y": 366
"y": 182
},
"id": 60,
"id": 78,
"options": {
"legend": {
"calcs": [
@@ -3079,7 +3289,7 @@
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "none"
"sort": "desc"
}
},
"pluginVersion": "11.5.0",
@@ -3090,16 +3300,31 @@
"uid": "$ds"
},
"editorMode": "code",
"expr": "sum(max_over_time(vm_tcplistener_conns{job=~\"$job\", instance=~\"$instance\"}[$__interval])) by(job)",
"expr": "max(rate(process_pressure_io_waiting_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"hide": false,
"intervalFactor": 1,
"legendFormat": "__auto",
"interval": "",
"intervalFactor": 2,
"legendFormat": "{{job}} - waiting",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(rate(process_pressure_io_stalled_seconds_total{job=~\"$job\"}[$__rate_interval])) by (job)",
"format": "time_series",
"hide": false,
"interval": "",
"intervalFactor": 2,
"legendFormat": "{{job}} - stalled",
"range": true,
"refId": "B"
}
],
"title": "TCP connections ($instance)",
"title": "IO pressure",
"type": "timeseries"
},
{
@@ -3153,7 +3378,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -3169,7 +3395,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 374
"y": 190
},
"id": 54,
"options": {
@@ -3261,7 +3487,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -3277,9 +3504,9 @@
"h": 8,
"w": 12,
"x": 12,
"y": 374
"y": 190
},
"id": 58,
"id": 60,
"options": {
"legend": {
"calcs": [
@@ -3307,7 +3534,7 @@
"uid": "$ds"
},
"editorMode": "code",
"expr": "sum(rate(vm_tcplistener_accepts_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by(job)",
"expr": "sum(max_over_time(vm_tcplistener_conns{job=~\"$job\", instance=~\"$instance\"}[$__interval])) by(job)",
"format": "time_series",
"hide": false,
"intervalFactor": 1,
@@ -3316,7 +3543,7 @@
"refId": "A"
}
],
"title": "TCP connections rate ($instance)",
"title": "TCP connections ($instance)",
"type": "timeseries"
},
{
@@ -3371,7 +3598,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
@@ -3387,7 +3615,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 382
"y": 198
},
"id": 74,
"options": {
@@ -3432,7 +3660,7 @@
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"description": "Shows the time goroutines have spent in runnable state before actually running. The lower is better.\n\nHigh values or values exceeding the threshold is usually a sign of insufficient CPU resources or CPU throttling. \n\nVerify that service has enough CPU resources. Otherwise, the service could work unreliably with delays in processing.",
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -3468,10 +3696,9 @@
"mode": "none"
},
"thresholdsStyle": {
"mode": "line"
"mode": "off"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"min": 0,
@@ -3479,15 +3706,16 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
},
{
"color": "red",
"value": 0.1
"value": 80
}
]
},
"unit": "s"
"unit": "short"
},
"overrides": []
},
@@ -3495,9 +3723,9 @@
"h": 8,
"w": 12,
"x": 12,
"y": 382
"y": 198
},
"id": 61,
"id": 58,
"options": {
"legend": {
"calcs": [
@@ -3507,12 +3735,14 @@
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
"showLegend": true,
"sortBy": "Last *",
"sortDesc": true
},
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "desc"
"sort": "none"
}
},
"pluginVersion": "11.5.0",
@@ -3523,16 +3753,16 @@
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(histogram_quantile(0.99, sum(rate(go_sched_latencies_seconds_bucket{job=~\"$job\"}[$__rate_interval])) by (job, instance, le))) by(job)",
"expr": "sum(rate(vm_tcplistener_accepts_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
"hide": false,
"intervalFactor": 1,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Go scheduling latency",
"title": "TCP connections rate ($instance)",
"type": "timeseries"
},
{
@@ -3587,7 +3817,8 @@
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": null
}
]
},
@@ -3599,7 +3830,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 390
"y": 206
},
"id": 75,
"options": {
@@ -3638,12 +3869,122 @@
],
"title": "Memory allocations rate",
"type": "timeseries"
},
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"description": "Shows the time goroutines have spent in runnable state before actually running. The lower is better.\n\nHigh values or values exceeding the threshold is usually a sign of insufficient CPU resources or CPU throttling. \n\nVerify that service has enough CPU resources. Otherwise, the service could work unreliably with delays in processing.",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "line"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 0.1
}
]
},
"unit": "s"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 206
},
"id": 61,
"options": {
"legend": {
"calcs": [
"mean",
"lastNotNull",
"max"
],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "multi",
"sort": "desc"
}
},
"pluginVersion": "11.5.0",
"targets": [
{
"datasource": {
"type": "victoriametrics-metrics-datasource",
"uid": "$ds"
},
"editorMode": "code",
"expr": "max(histogram_quantile(0.99, sum(rate(go_sched_latencies_seconds_bucket{job=~\"$job\"}[$__rate_interval])) by (job, instance, le))) by(job)",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Go scheduling latency",
"type": "timeseries"
}
],
"title": "Resource usage",
"type": "row"
}
],
"preload": false,
"refresh": "",
"schemaVersion": 40,
"tags": [
@@ -3741,4 +4082,4 @@
"uid": "XqCOFEX4z_vm",
"version": 1,
"weekStart": ""
}
}

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

File diff suppressed because it is too large Load Diff

View File

@@ -68,7 +68,7 @@ services:
# VictoriaMetrics instance, a single process responsible for
# scraping, storing metrics and serve read requests.
victoriametrics:
image: victoriametrics/victoria-metrics:v1.117.0
image: victoriametrics/victoria-metrics:v1.118.0
volumes:
- vmdata:/storage
- ./prometheus-vl-cluster.yml:/etc/prometheus/prometheus.yml
@@ -81,7 +81,7 @@ services:
# It proxies query requests from vmalert to either VictoriaMetrics or VictoriaLogs,
# depending on the requested path.
vmauth:
image: victoriametrics/vmauth:v1.117.0
image: victoriametrics/vmauth:v1.118.0
depends_on:
- "victoriametrics"
- "vlselect-1"
@@ -97,7 +97,7 @@ services:
# vmalert executes alerting and recording rules according to given rule type.
vmalert:
image: victoriametrics/vmalert:v1.117.0
image: victoriametrics/vmalert:v1.118.0
depends_on:
- "vmauth"
- "alertmanager"

View File

@@ -49,7 +49,7 @@ services:
# VictoriaMetrics instance, a single process responsible for
# scraping, storing metrics and serve read requests.
victoriametrics:
image: victoriametrics/victoria-metrics:v1.117.0
image: victoriametrics/victoria-metrics:v1.118.0
ports:
- "8428:8428"
volumes:
@@ -64,7 +64,7 @@ services:
# It proxies query requests from vmalert to either VictoriaMetrics or VictoriaLogs,
# depending on the requested path.
vmauth:
image: victoriametrics/vmauth:v1.117.0
image: victoriametrics/vmauth:v1.118.0
depends_on:
- "victoriametrics"
- "victorialogs"
@@ -78,7 +78,7 @@ services:
# vmalert executes alerting and recording rules according to the given rule type.
vmalert:
image: victoriametrics/vmalert:v1.117.0
image: victoriametrics/vmalert:v1.118.0
depends_on:
- "vmauth"
- "alertmanager"

View File

@@ -3,7 +3,7 @@ services:
# It scrapes targets defined in --promscrape.config
# And forward them to --remoteWrite.url
vmagent:
image: victoriametrics/vmagent:v1.117.0
image: victoriametrics/vmagent:v1.118.0
depends_on:
- "vmauth"
ports:
@@ -35,14 +35,14 @@ services:
# vmstorage shards. Each shard receives 1/N of all metrics sent to vminserts,
# where N is number of vmstorages (2 in this case).
vmstorage-1:
image: victoriametrics/vmstorage:v1.117.0-cluster
image: victoriametrics/vmstorage:v1.118.0-cluster
volumes:
- strgdata-1:/storage
command:
- "--storageDataPath=/storage"
restart: always
vmstorage-2:
image: victoriametrics/vmstorage:v1.117.0-cluster
image: victoriametrics/vmstorage:v1.118.0-cluster
volumes:
- strgdata-2:/storage
command:
@@ -52,7 +52,7 @@ services:
# vminsert is ingestion frontend. It receives metrics pushed by vmagent,
# pre-process them and distributes across configured vmstorage shards.
vminsert-1:
image: victoriametrics/vminsert:v1.117.0-cluster
image: victoriametrics/vminsert:v1.118.0-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -61,7 +61,7 @@ services:
- "--storageNode=vmstorage-2:8400"
restart: always
vminsert-2:
image: victoriametrics/vminsert:v1.117.0-cluster
image: victoriametrics/vminsert:v1.118.0-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -73,7 +73,7 @@ services:
# vmselect is a query fronted. It serves read queries in MetricsQL or PromQL.
# vmselect collects results from configured `--storageNode` shards.
vmselect-1:
image: victoriametrics/vmselect:v1.117.0-cluster
image: victoriametrics/vmselect:v1.118.0-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -83,7 +83,7 @@ services:
- "--vmalert.proxyURL=http://vmalert:8880"
restart: always
vmselect-2:
image: victoriametrics/vmselect:v1.117.0-cluster
image: victoriametrics/vmselect:v1.118.0-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -98,7 +98,7 @@ services:
# read requests from Grafana, vmui, vmalert among vmselects.
# It can be used as an authentication proxy.
vmauth:
image: victoriametrics/vmauth:v1.117.0
image: victoriametrics/vmauth:v1.118.0
depends_on:
- "vmselect-1"
- "vmselect-2"
@@ -112,7 +112,7 @@ services:
# vmalert executes alerting and recording rules
vmalert:
image: victoriametrics/vmalert:v1.117.0
image: victoriametrics/vmalert:v1.118.0
depends_on:
- "vmauth"
ports:
@@ -125,7 +125,7 @@ services:
command:
- "--datasource.url=http://vmauth:8427/select/0/prometheus"
- "--remoteRead.url=http://vmauth:8427/select/0/prometheus"
- "--remoteWrite.url=http://vmauth:8427/insert/0/prometheus/api/v1/write"
- "--remoteWrite.url=http://vmauth:8427/insert/0/prometheus"
- "--notifier.url=http://alertmanager:9093/"
- "--rule=/etc/alerts/*.yml"
# display source of alerts in grafana

View File

@@ -3,7 +3,7 @@ services:
# It scrapes targets defined in --promscrape.config
# And forward them to --remoteWrite.url
vmagent:
image: victoriametrics/vmagent:v1.117.0
image: victoriametrics/vmagent:v1.118.0
depends_on:
- "victoriametrics"
ports:
@@ -18,7 +18,7 @@ services:
# VictoriaMetrics instance, a single process responsible for
# storing metrics and serve read requests.
victoriametrics:
image: victoriametrics/victoria-metrics:v1.117.0
image: victoriametrics/victoria-metrics:v1.118.0
ports:
- 8428:8428
- 8089:8089
@@ -54,7 +54,7 @@ services:
# vmalert executes alerting and recording rules
vmalert:
image: victoriametrics/vmalert:v1.117.0
image: victoriametrics/vmalert:v1.118.0
depends_on:
- "victoriametrics"
- "alertmanager"

View File

@@ -11,13 +11,18 @@ groups:
rules:
- alert: DiskRunsOutOfSpaceIn3Days
expr: |
sum(vm_free_disk_space_bytes) without(path) /
(
rate(vm_rows_added_to_storage_total[1d]) * (
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
sum(vm_rows{type!~"indexdb.*"}) without(type)
)
) < 3 * 24 * 3600 > 0
sum(vm_free_disk_space_bytes) without(path) /
(
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
sum(vm_rows{type!~"indexdb.*"}) without(type)
)
+
rate(vm_new_timeseries_created_total[1d]) * (
sum(vm_data_size_bytes{type="indexdb/file"}) /
sum(vm_rows{type="indexdb/file"})
)
) < 3 * 24 * 3600 > 0
for: 30m
labels:
severity: critical
@@ -32,10 +37,15 @@ groups:
expr: |
sum(vm_free_disk_space_bytes - vm_free_disk_space_limit_bytes) without(path) /
(
rate(vm_rows_added_to_storage_total[1d]) * (
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
sum(vm_rows{type!~"indexdb.*"}) without(type)
)
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
sum(vm_rows{type!~"indexdb.*"}) without(type)
)
+
rate(vm_new_timeseries_created_total[1d]) * (
sum(vm_data_size_bytes{type="indexdb/file"}) /
sum(vm_rows{type="indexdb/file"})
)
) < 3 * 24 * 3600 > 0
for: 30m
labels:

View File

@@ -11,13 +11,18 @@ groups:
rules:
- alert: DiskRunsOutOfSpaceIn3Days
expr: |
sum(vm_free_disk_space_bytes) without(path) /
(
rate(vm_rows_added_to_storage_total[1d]) * (
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
sum(vm_rows{type!~"indexdb.*"}) without(type)
)
) < 3 * 24 * 3600 > 0
sum(vm_free_disk_space_bytes) without(path) /
(
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
sum(vm_rows{type!~"indexdb.*"}) without(type)
)
+
rate(vm_new_timeseries_created_total[1d]) * (
sum(vm_data_size_bytes{type="indexdb/file"}) /
sum(vm_rows{type="indexdb/file"})
)
) < 3 * 24 * 3600 > 0
for: 30m
labels:
severity: critical
@@ -32,10 +37,15 @@ groups:
expr: |
sum(vm_free_disk_space_bytes - vm_free_disk_space_limit_bytes) without(path) /
(
rate(vm_rows_added_to_storage_total[1d]) * (
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
sum(vm_rows{type!~"indexdb.*"}) without(type)
)
(rate(vm_rows_added_to_storage_total[1d]) - sum(rate(vm_deduplicated_samples_total[1d])) without (type)) * (
sum(vm_data_size_bytes{type!~"indexdb.*"}) without(type) /
sum(vm_rows{type!~"indexdb.*"}) without(type)
)
+
rate(vm_new_timeseries_created_total[1d]) * (
sum(vm_data_size_bytes{type="indexdb/file"}) /
sum(vm_rows{type="indexdb/file"})
)
) < 3 * 24 * 3600 > 0
for: 30m
labels:

View File

@@ -19,11 +19,11 @@ services:
retries: 10
dd-proxy:
image: docker.io/victoriametrics/vmauth:v1.117.0
image: docker.io/victoriametrics/vmauth:v1.118.0
restart: on-failure
volumes:
- ./:/etc/vmauth
command: -auth.config=/etc/vmauth/vmauth.yaml
command: -auth.config=/etc/vmauth/vmauth.yml
victorialogs:
extends: .victorialogs
@@ -34,7 +34,7 @@ services:
deploy:
replicas: 1
# second replica is needed for HA setup and its replica count is set to 1 in compose-ha.yaml file
# second replica is needed for HA setup and its replica count is set to 1 in compose-ha.yml file
victorialogs-2:
extends: .victorialogs
ports:

View File

@@ -4,26 +4,27 @@ The folder contains examples of [DataDog agent](https://docs.datadoghq.com/agent
* [datadog](./datadog)
## Quick start
To spin-up environment `cd` to any of listed above directories run the following command:
```
```sh
docker compose up -d
```
To shut down the docker-compose environment run the following command:
```
docker compose down
docker compose rm -f
```sh
docker compose down -v
```
The docker compose file contains the following components:
* datadog - Datadog logs collection agent, which is configured to collect and write data to `victorialogs`
* victorialogs - VictoriaLogs log database, which accepts the data from `datadog`
* victoriametrics - VictoriaMetrics metrics database, which collects metrics from `victorialogs` and `datadog`
* victoriametrics - VictoriaMetrics metrics database, collects metrics from `victorialogs` and `datadog`
Querying the data
## Querying
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.

View File

@@ -5,15 +5,16 @@ The folder contains examples of [DataDog serverless](https://docs.datadoghq.com/
* [AWS Lambda](./aws)
* [GCP Cloud Run](./gcp)
## Quick start
To spin-up environment `cd` to any of listed above directories run the following command:
```
```sh
docker compose up -d
```
To shut down the docker-compose environment run the following command:
```
docker compose down
docker compose rm -f
```sh
docker compose down -v
```
The docker compose file contains the following components:
@@ -21,11 +22,11 @@ The docker compose file contains the following components:
* dd-proxy - VMAuth proxy, with path-based routing to `victoriametrics` and `victorialogs`
* lambda - Serverless application with Datadog logs collection extension, which is configured to collect and write data to `victorialogs` and `victoriametrics` via `dd-proxy`
* victorialogs - VictoriaLogs log database, which accepts the data from `datadog`
* victoriametrics - VictoriaMetrics metrics database, which collects metrics from `victorialogs` and `datadog`
* victoriametrics - VictoriaMetrics metrics database, collects metrics from `victorialogs` and `datadog`
Querying the data
## Querying
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.

View File

@@ -1,4 +1,4 @@
FROM golang:1.23-bullseye as aws-lambda-rie
FROM golang:1.24-bullseye as aws-lambda-rie
# Install custom aws-lambda-rie till Telemetry API support is not merged
# https://github.com/aws/aws-lambda-runtime-interface-emulator/pull/137
@@ -26,7 +26,7 @@ RUN \
WORKDIR /var/task
COPY --from=aws-lambda-rie /aws-lambda-rie /var/task/aws-lambda-rie
COPY main.py /var/task/
COPY --from=public.ecr.aws/datadog/lambda-extension:73 /opt/. /opt/
COPY --from=public.ecr.aws/datadog/lambda-extension:78 /opt/. /opt/
ENTRYPOINT ["/var/task/aws-lambda-rie"]
CMD ["/usr/local/bin/python", "-m", "awslambdaric", "main.lambda_handler"]

View File

@@ -1,4 +1,4 @@
FROM python:3.12-bullseye
FROM python:3.13-bullseye
COPY --from=datadog/serverless-init:1 /datadog-init /app/datadog-init
ENV DD_SERVICE=datadog-demo-run-go

View File

@@ -5,30 +5,31 @@ The folder contains examples of [Filebeat](https://www.elastic.co/guide/en/beats
* [syslog](./syslog)
* [elasticsearch](./elasticsearch)
## Quick start
To spin-up environment `cd` to any of listed above directories run the following command:
```
```sh
docker compose up -d
```
To shut down the docker-compose environment run the following command:
```
```sh
docker compose down
docker compose rm -f
```
The docker compose file contains the following components:
* filebeat - logs collection agent configured to collect and write data to `victorialogs`
* victorialogs - logs database, receives data from `filebeat` agent
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `filebeat` for observability purposes
* victoriametrics - metrics database, collects metrics from `victorialogs` and `filebeat` for observability purposes
Querying the data
## Querying
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
Filebeat configuration example can be found below:
- [syslog](./syslog/filebeat.yml)
- [elasticsearch](./elasticsearch/filebeat.yml)
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.

View File

@@ -8,27 +8,28 @@ The folder contains examples of [FluentBit](https://docs.fluentbit.io/manual) in
* [jsonline HA setup](./jsonline-ha)
* [otlp](./otlp)
## Quick start
To spin-up environment `cd` to any of listed above directories run the following command:
```
```sh
docker compose up -d
```
To shut down the docker-compose environment run the following command:
```
docker compose down
docker compose rm -f
```sh
docker compose down -v
```
The docker compose file contains the following components:
* fluentbit - logs collection agent configured to collect and write data to `victorialogs`
* victorialogs - logs database, receives data from `fluentbit` agent
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `fluentbit` for observability purposes
* victoriametrics - metrics database, collects metrics from `victorialogs` and `fluentbit` for observability purposes
Querying the data
## Querying
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
FluentBit configuration example can be found below:
* [datadog](./datadog/fluent-bit.conf)
@@ -37,4 +38,4 @@ FluentBit configuration example can be found below:
* [jsonline HA setup](./jsonline-ha/fluent-bit.conf)
* [otlp](./otlp/fluent-bit.conf)
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.

View File

@@ -1,3 +1,3 @@
include:
- ../compose.yml
- ../compose-base.yml
name: fluentbit-loki

View File

@@ -9,31 +9,32 @@ The folder contains examples of [Fluentd](https://www.fluentd.org/) integration
All required plugins, that should be installed in order to support protocols listed above can be found in a [Dockerfile](./Dockerfile)
## Quick start
To spin-up environment `cd` to any of listed above directories run the following command:
```
```sh
docker compose up -d
```
To shut down the docker-compose environment run the following command:
```
docker compose down
docker compose rm -f
```sh
docker compose down -v
```
The docker compose file contains the following components:
* fluentd - logs collection agent configured to collect and write data to `victorialogs`
* victorialogs - logs database, receives data from `fluentd` agent
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `fluentd` for observability purposes
* victoriametrics - metrics database, collects metrics from `victorialogs` and `fluentd` for observability purposes
Querying the data
## Querying
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
Fluentd configuration example can be found below:
* [loki](./loki/fluent.conf)
* [jsonline](./jsonline/fluent.conf)
* [elasticsearch](./elasticsearch/fluent.conf)
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.

View File

@@ -0,0 +1,34 @@
# Docker compose Grafana Alloy integration with VictoriaLogs
The folder contains examples of [Grafana Alloy](https://grafana.com/docs/alloy/latest/) integration with VictoriaLogs using protocols:
* [loki](./loki)
* [otlp](./otlp)
## Quick start
To spin-up environment `cd` to any of listed above directories run the following command:
```sh
docker compose up -d
```
To shut down the docker-compose environment run the following command:
```sh
docker compose down -v
```
The docker compose file contains the following components:
* alloy - logs collection agent configured to collect and write data to `victorialogs`
* victorialogs - logs database, receives data from `alloy` agent
* victoriametrics - metrics database, collects metrics from `victorialogs` and `alloy` for observability purposes
## Querying
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
Grafana Alloy configuration example can be found below:
* [loki](./loki/config.alloy)
* [otlp](./otlp/config.alloy)
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.

View File

@@ -0,0 +1,16 @@
include:
- ../compose-base.yml
services:
alloy:
image: docker.io/grafana/alloy:latest
restart: on-failure
user: 0:0
volumes:
- ${PWD}/config.alloy:/etc/alloy/config.alloy
- /var/lib/docker/containers:/var/lib/docker/containers
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
victorialogs:
condition: service_healthy
victoriametrics:
condition: service_healthy

View File

@@ -0,0 +1,3 @@
include:
- ../compose-base.yml
name: alloy-loki

View File

@@ -0,0 +1,38 @@
discovery.docker "default" {
host = "unix:///var/run/docker.sock"
refresh_interval = "5s"
}
discovery.relabel "default" {
targets = discovery.docker.default.targets
rule {
source_labels = ["__meta_docker_container_name"]
target_label = "container_name"
}
}
prometheus.exporter.self "default" {}
prometheus.scrape "default" {
targets = prometheus.exporter.self.default.targets
forward_to = [prometheus.remote_write.default.receiver]
}
prometheus.remote_write "default" {
endpoint {
url = "http://victoriametrics:8428/api/v1/write"
}
}
loki.write "default" {
endpoint {
headers = { "VL-Msg-Field" = "msg", "VL-Stream-Fields" = "container_name" }
url = "http://victorialogs:9428/insert/loki/api/v1/push"
}
}
loki.source.docker "default" {
host = "unix:///var/run/docker.sock"
targets = discovery.relabel.default.output
forward_to = [loki.write.default.receiver]
}

View File

@@ -0,0 +1,3 @@
include:
- ../compose-base.yml
name: alloy-otlp

View File

@@ -0,0 +1,47 @@
discovery.docker "default" {
host = "unix:///var/run/docker.sock"
refresh_interval = "5s"
}
discovery.relabel "default" {
targets = discovery.docker.default.targets
rule {
source_labels = ["__meta_docker_container_name"]
target_label = "container_name"
}
}
prometheus.exporter.self "default" {}
prometheus.scrape "default" {
targets = prometheus.exporter.self.default.targets
forward_to = [otelcol.receiver.prometheus.default.receiver]
}
otelcol.receiver.prometheus "default" {
output {
metrics = [otelcol.exporter.otlphttp.default.input]
}
}
otelcol.exporter.otlphttp "default" {
client {
endpoint = "http://victorialogs:9428/insert/opentelemetry"
headers = { "VL-Stream-Fields" = "container_name" }
}
metrics_endpoint = "http://victoriametrics:8428/opentelemetry/v1/metrics"
}
otelcol.receiver.loki "default" {
output {
metrics = [otelcol.exporter.otlphttp.default.input]
logs = [otelcol.exporter.otlphttp.default.input]
traces = [otelcol.exporter.otlphttp.default.input]
}
}
loki.source.docker "default" {
host = "unix:///var/run/docker.sock"
targets = discovery.relabel.default.output
forward_to = [otelcol.receiver.loki.default.receiver]
}

View File

@@ -4,26 +4,27 @@ The folder contains examples of Journald integration with VictoriaLogs using pro
* [journald](./journald)
## Quick start
To spin-up environment `cd` to any of listed above directories run the following command:
```
```sh
docker compose up -d
```
To shut down the docker-compose environment run the following command:
```
docker compose down
docker compose rm -f
```sh
docker compose down -v
```
The docker compose file contains the following components:
* journald - Journald logs collection agent, which is configured to collect and write data to `victorialogs`
* victorialogs - VictoriaLogs log database, which accepts the data from `journald`
* victoriametrics - VictoriaMetrics metrics database, which collects metrics from `victorialogs` and `journald`
* journald - Journald logs collection agent, configured to collect and write data to `victorialogs`
* victorialogs - VictoriaLogs log database, accepts the data from `journald`
* victoriametrics - VictoriaMetrics metrics database, collects metrics from `victorialogs` and `journald`
Querying the data
## Querying
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.

View File

@@ -9,27 +9,28 @@ The folder contains examples of [Logstash](https://www.elastic.co/logstash) inte
All required plugins, that should be installed in order to support protocols listed above can be found in a [Dockerfile](./Dockerfile)
## Quick start
To spin-up environment `cd` to any of listed above directories run the following command:
```
```sh
docker compose up -d
```
To shut down the docker-compose environment run the following command:
```
docker compose down
docker compose rm -f
```sh
docker compose down -v
```
The docker compose file contains the following components:
* logstash - logs collection agent configured to collect and write data to `victorialogs`
* victorialogs - logs database, receives data from `logstash` agent
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `logstash` for observability purposes
* victoriametrics - metrics database, collects metrics from `victorialogs` and `logstash` for observability purposes
Querying the data
## Querying
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
Logstash configuration example can be found below:
* [loki](./loki/pipeline.conf)
@@ -37,4 +38,4 @@ Logstash configuration example can be found below:
* [jsonline HA setup](./jsonline-ha/pipeline.conf)
* [elasticsearch](./elasticsearch/pipeline.conf)
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.

View File

@@ -8,27 +8,28 @@ The folder contains examples of [OpenTelemetry collector](https://opentelemetry.
* [elasticsearch single node](./elasticsearch)
* [elasticsearch HA mode](./elasticsearch-ha/)
## Quick start
To spin-up environment `cd` to any of listed above directories run the following command:
```
```sh
docker compose up -d
```
To shut down the docker-compose environment run the following command:
```
docker compose down
docker compose rm -f
```sh
docker compose down -v
```
The docker compose file contains the following components:
* collector - logs collection agent configured to collect and write data to `victorialogs`
* victorialogs - logs database, receives data from `collector` agent
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `collector` for observability purposes
* victoriametrics - metrics database, collects metrics from `victorialogs` and `collector` for observability purposes
Querying the data
## Querying
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
OpenTelemetry collector configuration example can be found below:
* [loki](./loki/config.yml)
@@ -37,4 +38,4 @@ OpenTelemetry collector configuration example can be found below:
* [elasticsearch single node](./elasticsearch/config.yml)
* [elasticsearch HA mode](./elasticsearch-ha/config.yml)
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.

View File

@@ -4,15 +4,16 @@ The folder contains the example of integration of [Promtail agent](https://grafa
* [loki](./loki)
## Quick start
To spin-up environment `cd` to any of listed above directories run the following command:
```
```sh
docker compose up -d
```
To shut down the docker-compose environment run the following command:
```
docker compose down
docker compose rm -f
```sh
docker compose down -v
```
The docker compose file contains the following components:
@@ -21,12 +22,12 @@ The docker compose file contains the following components:
* victorialogs - logs database, receives data from `promtail` agent
* victoriametrics - metrics database, which collects metrics from `victorialogs` and `promtail` for observability purposes
Querying the data
## Querying
* [vmui](https://docs.victoriametrics.com/victorialogs/querying/#vmui) - a web UI is accessible by `http://localhost:9428/select/vmui`
* for querying the data via command-line please check [these docs](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
* for querying the data via command-line please check [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/#command-line)
Promtail agent configuration example can be found below:
* [loki](./loki/config.yml)
Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.
> Please, note that `_stream_fields` parameter must follow recommended [best practices](https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields) to achieve better performance.

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