mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-03-21 15:45:01 +00:00
vmui: expression alias (#2495)
* feat: add alias for queries * docs: update docs for predefined dashboards * app/vmselect: `make vmui-update` Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
This commit is contained in:
parent
4176be38c4
commit
c7693e8bc1
20 changed files with 1563 additions and 1828 deletions
|
@ -1,14 +1,14 @@
|
||||||
{
|
{
|
||||||
"files": {
|
"files": {
|
||||||
"main.css": "./static/css/main.d8362c27.css",
|
"main.css": "./static/css/main.d8362c27.css",
|
||||||
"main.js": "./static/js/main.3e17cf70.js",
|
"main.js": "./static/js/main.d58914e5.js",
|
||||||
"static/js/362.1a2113d4.chunk.js": "./static/js/362.1a2113d4.chunk.js",
|
"static/js/362.1f16598a.chunk.js": "./static/js/362.1f16598a.chunk.js",
|
||||||
"static/js/27.939f971b.chunk.js": "./static/js/27.939f971b.chunk.js",
|
"static/js/27.939f971b.chunk.js": "./static/js/27.939f971b.chunk.js",
|
||||||
"static/media/README.md": "./static/media/README.5e5724daf3ee333540a3.md",
|
"static/media/README.md": "./static/media/README.40ebc3a1f4adae949154.md",
|
||||||
"index.html": "./index.html"
|
"index.html": "./index.html"
|
||||||
},
|
},
|
||||||
"entrypoints": [
|
"entrypoints": [
|
||||||
"static/css/main.d8362c27.css",
|
"static/css/main.d8362c27.css",
|
||||||
"static/js/main.3e17cf70.js"
|
"static/js/main.d58914e5.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -1 +1 @@
|
||||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><script defer="defer" src="./static/js/main.3e17cf70.js"></script><link href="./static/css/main.d8362c27.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><script defer="defer" src="./static/js/main.d58914e5.js"></script><link href="./static/css/main.d8362c27.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
|
@ -1 +0,0 @@
|
||||||
"use strict";(self.webpackChunkvmui=self.webpackChunkvmui||[]).push([[362],{8362:function(e,s,u){e.exports=u.p+"static/media/README.5e5724daf3ee333540a3.md"}}]);
|
|
1
app/vmselect/vmui/static/js/362.1f16598a.chunk.js
Normal file
1
app/vmselect/vmui/static/js/362.1f16598a.chunk.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
"use strict";(self.webpackChunkvmui=self.webpackChunkvmui||[]).push([[362],{8362:function(e,a,s){e.exports=s.p+"static/media/README.40ebc3a1f4adae949154.md"}}]);
|
File diff suppressed because one or more lines are too long
2
app/vmselect/vmui/static/js/main.d58914e5.js
Normal file
2
app/vmselect/vmui/static/js/main.d58914e5.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -28,7 +28,7 @@
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @license MUI v5.5.2
|
/** @license MUI v5.6.1
|
||||||
*
|
*
|
||||||
* This source code is licensed under the MIT license found in the
|
* This source code is licensed under the MIT license found in the
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
|
@ -0,0 +1,92 @@
|
||||||
|
### Configuration options
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
DashboardSettings:
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|:----------|:----------------:|---------------------------:|
|
||||||
|
| rows* | `DashboardRow[]` | Sections containing panels |
|
||||||
|
| title | `string` | Dashboard title |
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
DashboardRow:
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|:-----------|:-----------------:|---------------------------:|
|
||||||
|
| panels* | `PanelSettings[]` | List of panels (charts) |
|
||||||
|
| title | `string` | Row title |
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
PanelSettings:
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|:------------|:----------:|--------------------------------------------------------------------------------------:|
|
||||||
|
| expr* | `string[]` | Data source queries |
|
||||||
|
| alias | `string[]` | Expression alias. Matched by index in array |
|
||||||
|
| title | `string` | Panel title |
|
||||||
|
| description | `string` | Additional information about the panel |
|
||||||
|
| unit | `string` | Y-axis unit |
|
||||||
|
| showLegend | `boolean` | If `false`, the legend hide. Default value - `true` |
|
||||||
|
| width | `number` | The number of columns the panel uses.<br/> From 1 (minimum width) to 12 (full width). |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Example json
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"title": "Example",
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"title": "Per-job resource usage",
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"title": "Per-job CPU usage",
|
||||||
|
"width": 6,
|
||||||
|
"expr": [
|
||||||
|
"sum(rate(process_cpu_seconds_total)) by (job)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Per-job RSS usage",
|
||||||
|
"width": 6,
|
||||||
|
"expr": [
|
||||||
|
"sum(process_resident_memory_bytes) by (job)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Per-job disk read",
|
||||||
|
"width": 6,
|
||||||
|
"expr": [
|
||||||
|
"sum(rate(process_io_storage_read_bytes_total)) by (job)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Per-job disk write",
|
||||||
|
"width": 6,
|
||||||
|
"expr": [
|
||||||
|
"sum(rate(process_io_storage_written_bytes_total)) by (job)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Free/used disk space",
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"unit": "MB",
|
||||||
|
"expr": [
|
||||||
|
"sum(vm_data_size_bytes{type!=\"indexdb\"}) / 1024 / 1024",
|
||||||
|
"vm_free_disk_space_bytes / 1024 / 1024"
|
||||||
|
],
|
||||||
|
"alias": [
|
||||||
|
"usage space",
|
||||||
|
"free space"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
|
@ -1,77 +0,0 @@
|
||||||
### Configuration options
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
DashboardSettings:
|
|
||||||
|
|
||||||
| Name | Type | Description |
|
|
||||||
|:----------|:----------------:|---------------------------:|
|
|
||||||
| rows* | `DashboardRow[]` | Sections containing panels |
|
|
||||||
| title | `string` | Dashboard title |
|
|
||||||
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
DashboardRow:
|
|
||||||
|
|
||||||
| Name | Type | Description |
|
|
||||||
|:-----------|:-----------------:|---------------------------:|
|
|
||||||
| panels* | `PanelSettings[]` | List of panels (charts) |
|
|
||||||
| title | `string` | Row title |
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
PanelSettings:
|
|
||||||
|
|
||||||
| Name | Type | Description |
|
|
||||||
|:------------|:----------:|-------------------------------------------------------------------------------------------:|
|
|
||||||
| expr* | `string[]` | Data source queries |
|
|
||||||
| title | `string` | Panel title |
|
|
||||||
| description | `string` | Additional information about the panel |
|
|
||||||
| unit | `string` | Y-axis unit |
|
|
||||||
| showLegend | `boolean` | If `false`, the legend hide. Default value - `true` |
|
|
||||||
| width | `number` | The number of columns the panel uses.<br/> From 1 (minimum width) to 12 (full width). |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Example json
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"title": "Example",
|
|
||||||
"rows": [
|
|
||||||
{
|
|
||||||
"title": "Performance",
|
|
||||||
"panels": [
|
|
||||||
{
|
|
||||||
"title": "Query duration",
|
|
||||||
"description": "The less time it takes is better.\n* `*` - unsupported query path\n* `/write` - insert into VM\n* `/metrics` - query VM system metrics\n* `/query` - query instant values\n* `/query_range` - query over a range of time\n* `/series` - match a certain label set\n* `/label/{}/values` - query a list of label values (variables mostly)",
|
|
||||||
"unit": "ms",
|
|
||||||
"showLegend": false,
|
|
||||||
"expr": [
|
|
||||||
"max(vm_request_duration_seconds{quantile=~\"(0.5|0.99)\"}) by (path, quantile) > 0"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Concurrent flushes on disk",
|
|
||||||
"description": "Shows how many ongoing insertions (not API /write calls) on disk are taking place, where:\n* `max` - equal to number of CPUs;\n* `current` - current number of goroutines busy with inserting rows into underlying storage.\n\nEvery successful API /write call results into flush on disk. However, these two actions are separated and controlled via different concurrency limiters. The `max` on this panel can't be changed and always equal to number of CPUs. \n\nWhen `current` hits `max` constantly, it means storage is overloaded and requires more CPU.\n\n",
|
|
||||||
"expr": [
|
|
||||||
"sum(vm_concurrent_addrows_capacity)",
|
|
||||||
"sum(vm_concurrent_addrows_current)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Troubleshooting",
|
|
||||||
"panels": [
|
|
||||||
{
|
|
||||||
"title": "Churn rate",
|
|
||||||
"description": "Shows the rate and total number of new series created over last 24h.\n\nHigh churn rate tightly connected with database performance and may result in unexpected OOM's or slow queries. It is recommended to always keep an eye on this metric to avoid unexpected cardinality \"explosions\".\n\nThe higher churn rate is, the more resources required to handle it. Consider to keep the churn rate as low as possible.\n\nGood references to read:\n* https://www.robustperception.io/cardinality-is-key\n* https://www.robustperception.io/using-tsdb-analyze-to-investigate-churn-and-cardinality",
|
|
||||||
"expr": [
|
|
||||||
"sum(rate(vm_new_timeseries_created_total[5m]))",
|
|
||||||
"sum(increase(vm_new_timeseries_created_total[24h]))"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
3094
app/vmui/packages/vmui/package-lock.json
generated
3094
app/vmui/packages/vmui/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -14,6 +14,7 @@ export interface GraphViewProps {
|
||||||
period: TimeParams;
|
period: TimeParams;
|
||||||
customStep: CustomStep;
|
customStep: CustomStep;
|
||||||
query: string[];
|
query: string[];
|
||||||
|
alias?: string[],
|
||||||
yaxis: YaxisState;
|
yaxis: YaxisState;
|
||||||
unit?: string;
|
unit?: string;
|
||||||
showLegend?: boolean;
|
showLegend?: boolean;
|
||||||
|
@ -45,7 +46,8 @@ const GraphView: FC<GraphViewProps> = ({
|
||||||
unit,
|
unit,
|
||||||
showLegend= true,
|
showLegend= true,
|
||||||
setYaxisLimits,
|
setYaxisLimits,
|
||||||
setPeriod
|
setPeriod,
|
||||||
|
alias = []
|
||||||
}) => {
|
}) => {
|
||||||
const currentStep = useMemo(() => customStep.enable ? customStep.value : period.step || 1, [period.step, customStep]);
|
const currentStep = useMemo(() => customStep.enable ? customStep.value : period.step || 1, [period.step, customStep]);
|
||||||
|
|
||||||
|
@ -70,7 +72,7 @@ const GraphView: FC<GraphViewProps> = ({
|
||||||
const tempSeries: uPlotSeries[] = [];
|
const tempSeries: uPlotSeries[] = [];
|
||||||
|
|
||||||
data?.forEach((d) => {
|
data?.forEach((d) => {
|
||||||
const seriesItem = getSeriesItem(d, hideSeries);
|
const seriesItem = getSeriesItem(d, hideSeries, alias);
|
||||||
tempSeries.push(seriesItem);
|
tempSeries.push(seriesItem);
|
||||||
tempLegend.push(getLegendItem(seriesItem, d.group));
|
tempLegend.push(getLegendItem(seriesItem, d.group));
|
||||||
let tmpValues = tempValues[d.group];
|
let tmpValues = tempValues[d.group];
|
||||||
|
@ -117,7 +119,7 @@ const GraphView: FC<GraphViewProps> = ({
|
||||||
const tempLegend: LegendItem[] = [];
|
const tempLegend: LegendItem[] = [];
|
||||||
const tempSeries: uPlotSeries[] = [];
|
const tempSeries: uPlotSeries[] = [];
|
||||||
data?.forEach(d => {
|
data?.forEach(d => {
|
||||||
const seriesItem = getSeriesItem(d, hideSeries);
|
const seriesItem = getSeriesItem(d, hideSeries, alias);
|
||||||
tempSeries.push(seriesItem);
|
tempSeries.push(seriesItem);
|
||||||
tempLegend.push(getLegendItem(seriesItem, d.group));
|
tempLegend.push(getLegendItem(seriesItem, d.group));
|
||||||
});
|
});
|
||||||
|
|
|
@ -47,7 +47,7 @@ const Legend: FC<LegendProps> = ({labels, query, onChange}) => {
|
||||||
backgroundColor: `rgba(${hexToRGB(legendItem.color)}, 0.1)`
|
backgroundColor: `rgba(${hexToRGB(legendItem.color)}, 0.1)`
|
||||||
}}/>
|
}}/>
|
||||||
<div className="legendLabel">
|
<div className="legendLabel">
|
||||||
{legendItem.freeFormFields.__name__ || `Query ${legendItem.group} result`}
|
{legendItem.label.replace(/{.+}/gmi, "")}
|
||||||
{!!Object.keys(legendItem.freeFormFields).length && <>
|
{!!Object.keys(legendItem.freeFormFields).length && <>
|
||||||
 {
|
 {
|
||||||
{Object.keys(legendItem.freeFormFields).filter(f => f !== "__name__").map((f) => {
|
{Object.keys(legendItem.freeFormFields).filter(f => f !== "__name__").map((f) => {
|
||||||
|
@ -78,4 +78,4 @@ const Legend: FC<LegendProps> = ({labels, query, onChange}) => {
|
||||||
</>;
|
</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Legend;
|
export default Legend;
|
||||||
|
|
|
@ -99,6 +99,7 @@ const PredefinedDashboard: FC<PredefinedDashboardProps> = ({index, title, panels
|
||||||
description={p.description}
|
description={p.description}
|
||||||
unit={p.unit}
|
unit={p.unit}
|
||||||
expr={p.expr}
|
expr={p.expr}
|
||||||
|
alias={p.alias}
|
||||||
filename={filename}
|
filename={filename}
|
||||||
showLegend={p.showLegend}/>
|
showLegend={p.showLegend}/>
|
||||||
<button style={{...resizerStyle, right: 0}}
|
<button style={{...resizerStyle, right: 0}}
|
||||||
|
|
|
@ -26,7 +26,8 @@ const PredefinedPanels: FC<PredefinedPanelsProps> = ({
|
||||||
unit,
|
unit,
|
||||||
expr,
|
expr,
|
||||||
showLegend,
|
showLegend,
|
||||||
filename
|
filename,
|
||||||
|
alias
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const {time: {period}} = useAppState();
|
const {time: {period}} = useAppState();
|
||||||
|
@ -43,7 +44,7 @@ const PredefinedPanels: FC<PredefinedPanelsProps> = ({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const validExpr = useMemo(() => Array.isArray(expr) && expr.every(q => typeof q === "string"), [expr]);
|
const validExpr = useMemo(() => Array.isArray(expr) && expr.every(q => q), [expr]);
|
||||||
|
|
||||||
const {isLoading, graphData, error} = useFetchQuery({
|
const {isLoading, graphData, error} = useFetchQuery({
|
||||||
predefinedQuery: validExpr ? expr : [],
|
predefinedQuery: validExpr ? expr : [],
|
||||||
|
@ -121,6 +122,7 @@ const PredefinedPanels: FC<PredefinedPanelsProps> = ({
|
||||||
query={expr}
|
query={expr}
|
||||||
yaxis={yaxis}
|
yaxis={yaxis}
|
||||||
unit={unit}
|
unit={unit}
|
||||||
|
alias={alias}
|
||||||
showLegend={showLegend}
|
showLegend={showLegend}
|
||||||
setYaxisLimits={setYaxisLimits}
|
setYaxisLimits={setYaxisLimits}
|
||||||
setPeriod={setPeriod}/>
|
setPeriod={setPeriod}/>
|
||||||
|
|
|
@ -8,7 +8,6 @@ DashboardSettings:
|
||||||
| rows* | `DashboardRow[]` | Sections containing panels |
|
| rows* | `DashboardRow[]` | Sections containing panels |
|
||||||
| title | `string` | Dashboard title |
|
| title | `string` | Dashboard title |
|
||||||
|
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
DashboardRow:
|
DashboardRow:
|
||||||
|
|
||||||
|
@ -20,14 +19,15 @@ DashboardRow:
|
||||||
<br/>
|
<br/>
|
||||||
PanelSettings:
|
PanelSettings:
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|:------------|:----------:|-------------------------------------------------------------------------------------------:|
|
|:------------|:----------:|--------------------------------------------------------------------------------------:|
|
||||||
| expr* | `string[]` | Data source queries |
|
| expr* | `string[]` | Data source queries |
|
||||||
| title | `string` | Panel title |
|
| alias | `string[]` | Expression alias. Matched by index in array |
|
||||||
| description | `string` | Additional information about the panel |
|
| title | `string` | Panel title |
|
||||||
| unit | `string` | Y-axis unit |
|
| description | `string` | Additional information about the panel |
|
||||||
| showLegend | `boolean` | If `false`, the legend hide. Default value - `true` |
|
| unit | `string` | Y-axis unit |
|
||||||
| width | `number` | The number of columns the panel uses.<br/> From 1 (minimum width) to 12 (full width). |
|
| showLegend | `boolean` | If `false`, the legend hide. Default value - `true` |
|
||||||
|
| width | `number` | The number of columns the panel uses.<br/> From 1 (minimum width) to 12 (full width). |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -38,40 +38,55 @@ PanelSettings:
|
||||||
"title": "Example",
|
"title": "Example",
|
||||||
"rows": [
|
"rows": [
|
||||||
{
|
{
|
||||||
"title": "Performance",
|
"title": "Per-job resource usage",
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
"title": "Query duration",
|
"title": "Per-job CPU usage",
|
||||||
"description": "The less time it takes is better.\n* `*` - unsupported query path\n* `/write` - insert into VM\n* `/metrics` - query VM system metrics\n* `/query` - query instant values\n* `/query_range` - query over a range of time\n* `/series` - match a certain label set\n* `/label/{}/values` - query a list of label values (variables mostly)",
|
"width": 6,
|
||||||
"unit": "ms",
|
|
||||||
"showLegend": false,
|
|
||||||
"expr": [
|
"expr": [
|
||||||
"max(vm_request_duration_seconds{quantile=~\"(0.5|0.99)\"}) by (path, quantile) > 0"
|
"sum(rate(process_cpu_seconds_total)) by (job)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Concurrent flushes on disk",
|
"title": "Per-job RSS usage",
|
||||||
"description": "Shows how many ongoing insertions (not API /write calls) on disk are taking place, where:\n* `max` - equal to number of CPUs;\n* `current` - current number of goroutines busy with inserting rows into underlying storage.\n\nEvery successful API /write call results into flush on disk. However, these two actions are separated and controlled via different concurrency limiters. The `max` on this panel can't be changed and always equal to number of CPUs. \n\nWhen `current` hits `max` constantly, it means storage is overloaded and requires more CPU.\n\n",
|
"width": 6,
|
||||||
"expr": [
|
"expr": [
|
||||||
"sum(vm_concurrent_addrows_capacity)",
|
"sum(process_resident_memory_bytes) by (job)"
|
||||||
"sum(vm_concurrent_addrows_current)"
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Per-job disk read",
|
||||||
|
"width": 6,
|
||||||
|
"expr": [
|
||||||
|
"sum(rate(process_io_storage_read_bytes_total)) by (job)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Per-job disk write",
|
||||||
|
"width": 6,
|
||||||
|
"expr": [
|
||||||
|
"sum(rate(process_io_storage_written_bytes_total)) by (job)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Troubleshooting",
|
"title": "Free/used disk space",
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
"title": "Churn rate",
|
"unit": "MB",
|
||||||
"description": "Shows the rate and total number of new series created over last 24h.\n\nHigh churn rate tightly connected with database performance and may result in unexpected OOM's or slow queries. It is recommended to always keep an eye on this metric to avoid unexpected cardinality \"explosions\".\n\nThe higher churn rate is, the more resources required to handle it. Consider to keep the churn rate as low as possible.\n\nGood references to read:\n* https://www.robustperception.io/cardinality-is-key\n* https://www.robustperception.io/using-tsdb-analyze-to-investigate-churn-and-cardinality",
|
|
||||||
"expr": [
|
"expr": [
|
||||||
"sum(rate(vm_new_timeseries_created_total[5m]))",
|
"sum(vm_data_size_bytes{type!=\"indexdb\"}) / 1024 / 1024",
|
||||||
"sum(increase(vm_new_timeseries_created_total[24h]))"
|
"vm_free_disk_space_bytes / 1024 / 1024"
|
||||||
|
],
|
||||||
|
"alias": [
|
||||||
|
"usage space",
|
||||||
|
"free space"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -40,6 +40,7 @@ export interface PanelSettings {
|
||||||
description?: string;
|
description?: string;
|
||||||
unit?: string;
|
unit?: string;
|
||||||
expr: string[];
|
expr: string[];
|
||||||
|
alias?: string[];
|
||||||
showLegend?: boolean;
|
showLegend?: boolean;
|
||||||
width?: number
|
width?: number
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import {MetricBase} from "../api/types";
|
import {MetricBase} from "../api/types";
|
||||||
|
|
||||||
export const getNameForMetric = (result: MetricBase): string => {
|
export const getNameForMetric = (result: MetricBase, alias?: string): string => {
|
||||||
|
const { __name__, ...freeFormFields } = result.metric;
|
||||||
|
const name = alias || __name__ || `Query ${result.group} result`;
|
||||||
|
|
||||||
if (Object.keys(result.metric).length === 0) {
|
if (Object.keys(result.metric).length === 0) {
|
||||||
return `Query ${result.group} result`; // a bit better than just {} for case of aggregation functions
|
return name; // a bit better than just {} for case of aggregation functions
|
||||||
}
|
}
|
||||||
const { __name__: name, ...freeFormFields } = result.metric;
|
|
||||||
return `${name || ""} {${Object.entries(freeFormFields).map(e => `${e[0]}: ${e[1]}`).join(", ")}}`;
|
return `${name} {${Object.entries(freeFormFields).map(e => `${e[0]}: ${e[1]}`).join(", ")}}`;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,8 +9,8 @@ interface SeriesItem extends Series {
|
||||||
freeFormFields: {[key: string]: string};
|
freeFormFields: {[key: string]: string};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSeriesItem = (d: MetricResult, hideSeries: string[]): SeriesItem => {
|
export const getSeriesItem = (d: MetricResult, hideSeries: string[], alias: string[]): SeriesItem => {
|
||||||
const label = getNameForMetric(d);
|
const label = getNameForMetric(d, alias[d.group - 1]);
|
||||||
return {
|
return {
|
||||||
label,
|
label,
|
||||||
dash: getDashLine(d.group),
|
dash: getDashLine(d.group),
|
||||||
|
@ -49,4 +49,4 @@ export const getHideSeries = ({hideSeries, legend, metaKey, series}: HideSeriesA
|
||||||
|
|
||||||
export const includesHideSeries = (label: string, group: string | number, hideSeries: string[]): boolean => {
|
export const includesHideSeries = (label: string, group: string | number, hideSeries: string[]): boolean => {
|
||||||
return hideSeries.includes(`${group}.${label}`);
|
return hideSeries.includes(`${group}.${label}`);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import {SetupTooltip} from "./types";
|
import {SetupTooltip} from "./types";
|
||||||
import {getColorLine,formatPrettyNumber} from "./helpers";
|
import {getColorLine, formatPrettyNumber} from "./helpers";
|
||||||
|
|
||||||
export const setTooltip = ({u, tooltipIdx, metrics, series, tooltip, tooltipOffset, unit = ""}: SetupTooltip): void => {
|
export const setTooltip = ({u, tooltipIdx, metrics, series, tooltip, tooltipOffset, unit = ""}: SetupTooltip): void => {
|
||||||
const {seriesIdx, dataIdx} = tooltipIdx;
|
const {seriesIdx, dataIdx} = tooltipIdx;
|
||||||
|
@ -8,7 +8,8 @@ export const setTooltip = ({u, tooltipIdx, metrics, series, tooltip, tooltipOffs
|
||||||
const dataSeries = u.data[seriesIdx][dataIdx];
|
const dataSeries = u.data[seriesIdx][dataIdx];
|
||||||
const dataTime = u.data[0][dataIdx];
|
const dataTime = u.data[0][dataIdx];
|
||||||
const metric = metrics[seriesIdx - 1]?.metric || {};
|
const metric = metrics[seriesIdx - 1]?.metric || {};
|
||||||
const color = getColorLine(Number(series[seriesIdx].scale || 0), series[seriesIdx].label || "");
|
const selectedSeries = series[seriesIdx];
|
||||||
|
const color = getColorLine(Number(selectedSeries.scale || 0), selectedSeries.label || "");
|
||||||
|
|
||||||
const {width, height} = u.over.getBoundingClientRect();
|
const {width, height} = u.over.getBoundingClientRect();
|
||||||
const top = u.valToPos((dataSeries || 0), series[seriesIdx]?.scale || "1");
|
const top = u.valToPos((dataSeries || 0), series[seriesIdx]?.scale || "1");
|
||||||
|
@ -20,12 +21,13 @@ export const setTooltip = ({u, tooltipIdx, metrics, series, tooltip, tooltipOffs
|
||||||
tooltip.style.display = "grid";
|
tooltip.style.display = "grid";
|
||||||
tooltip.style.top = `${tooltipOffset.top + top + 10 - (overflowY ? tooltipHeight + 10 : 0)}px`;
|
tooltip.style.top = `${tooltipOffset.top + top + 10 - (overflowY ? tooltipHeight + 10 : 0)}px`;
|
||||||
tooltip.style.left = `${tooltipOffset.left + lft + 10 - (overflowX ? tooltipWidth + 20 : 0)}px`;
|
tooltip.style.left = `${tooltipOffset.left + lft + 10 - (overflowX ? tooltipWidth + 20 : 0)}px`;
|
||||||
|
const name = (selectedSeries.label || "").replace(/{.+}/gmi, "");
|
||||||
const date = dayjs(new Date(dataTime * 1000)).format("YYYY-MM-DD HH:mm:ss:SSS (Z)");
|
const date = dayjs(new Date(dataTime * 1000)).format("YYYY-MM-DD HH:mm:ss:SSS (Z)");
|
||||||
const info = Object.keys(metric).filter(k => k !== "__name__").map(k => `<div><b>${k}</b>: ${metric[k]}</div>`).join("");
|
const info = Object.keys(metric).filter(k => k !== "__name__").map(k => `<div><b>${k}</b>: ${metric[k]}</div>`).join("");
|
||||||
const marker = `<div class="u-tooltip__marker" style="background: ${color}"></div>`;
|
const marker = `<div class="u-tooltip__marker" style="background: ${color}"></div>`;
|
||||||
tooltip.innerHTML = `<div>${date}</div>
|
tooltip.innerHTML = `<div>${date}</div>
|
||||||
<div class="u-tooltip-data">
|
<div class="u-tooltip-data">
|
||||||
${marker}${metric.__name__ || ""}: <b class="u-tooltip-data__value">${formatPrettyNumber(dataSeries)}</b> ${unit}
|
${marker}${name}: <b class="u-tooltip-data__value">${formatPrettyNumber(dataSeries)}</b> ${unit}
|
||||||
</div>
|
</div>
|
||||||
<div class="u-tooltip__info">${info}</div>`;
|
<div class="u-tooltip__info">${info}</div>`;
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,4 +38,4 @@ export interface LegendItem {
|
||||||
color: string;
|
color: string;
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
freeFormFields: {[key: string]: string};
|
freeFormFields: {[key: string]: string};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue