diff --git a/app/vmselect/vmui.go b/app/vmselect/vmui.go index 4d33810f6..44db9c71e 100644 --- a/app/vmselect/vmui.go +++ b/app/vmselect/vmui.go @@ -37,7 +37,7 @@ type panelSettings struct { Unit string `json:"unit,omitempty"` Expr []string `json:"expr"` Alias []string `json:"alias,omitempty"` - ShowLegend bool `json:"showLegend,omitempty"` + ShowLegend *bool `json:"showLegend"` Width int `json:"width,omitempty"` } @@ -107,6 +107,17 @@ func collectDashboardsSettings(path string) ([]byte, error) { if err != nil { return nil, fmt.Errorf("cannot parse file %s: %w", filePath, err) } + + for i := range ds.Rows { + for j := range ds.Rows[i].Panels { + // Set default value for ShowLegend = true if it is not specified + if ds.Rows[i].Panels[j].ShowLegend == nil { + defaultValue := true + ds.Rows[i].Panels[j].ShowLegend = &defaultValue + } + } + } + if len(ds.Rows) > 0 { dss = append(dss, ds) } diff --git a/app/vmui/README.md b/app/vmui/README.md index abaf0a61d..ba743fbaf 100644 --- a/app/vmui/README.md +++ b/app/vmui/README.md @@ -127,15 +127,27 @@ DashboardRow:
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.
From 1 (minimum width) to 12 (full width). | +| Name | Type | Description | +|:------------|:----------:|---------------------------------------------------------------------------------------------------------------:| +| expr* | `string[]` | Data source queries | +| alias | `string[]` | An array of aliases for each expression in `expr`. See [Template Support in alias](#template-support-in-alias) | +| 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.
From 1 (minimum width) to 12 (full width). | + +### Template Support in `alias` + +To create more readable metric names in the legend, you can use constructions like `{{label_name}}`, where `label_name` +is the label's name. +If the label exists in the metric, its value will be substituted in the template. +If the label is missing, the legend will use the default name. + +**Example:** +Metric: `metric{foo="bar",baz="qux"}` +Alias: `{{foo}} - {{baz}}` +Legend: `bar - qux` ### Example json diff --git a/app/vmui/packages/vmui/src/components/Chart/Line/Legend/LegendItem/LegendItem.tsx b/app/vmui/packages/vmui/src/components/Chart/Line/Legend/LegendItem/LegendItem.tsx index f0277f3f6..14c506b57 100644 --- a/app/vmui/packages/vmui/src/components/Chart/Line/Legend/LegendItem/LegendItem.tsx +++ b/app/vmui/packages/vmui/src/components/Chart/Line/Legend/LegendItem/LegendItem.tsx @@ -56,19 +56,23 @@ const LegendItem: FC = ({ legend, onChange, isHeatmap, isAnomal )}
- {legend.freeFormFields["__name__"]} - {!!freeFormFields.length && <>{} - {freeFormFields.map((f, i) => ( - - {f.freeField}{i + 1 < freeFormFields.length && ","} - - ))} - {!!freeFormFields.length && <>}} + {legend.hasAlias ? legend.label : ( + <> + {legend.freeFormFields["__name__"]} + {!!freeFormFields.length && <>{} + {freeFormFields.map((f, i) => ( + + {f.freeField}{i + 1 < freeFormFields.length && ","} + + ))} + {!!freeFormFields.length && <>}} + + )}
{!isHeatmap && showStats && ( diff --git a/app/vmui/packages/vmui/src/hooks/uplot/useLineTooltip.ts b/app/vmui/packages/vmui/src/hooks/uplot/useLineTooltip.ts index f72d5c9c3..4d157fb1a 100644 --- a/app/vmui/packages/vmui/src/hooks/uplot/useLineTooltip.ts +++ b/app/vmui/packages/vmui/src/hooks/uplot/useLineTooltip.ts @@ -64,7 +64,7 @@ const useLineTooltip = ({ u, metrics, series, unit, isAnomalyView }: LineTooltip title: groups.size > 1 && !isAnomalyView ? `Query ${group}` : "", dates: [date ? dayjs(date * 1000).tz().format(DATE_FULL_TIMEZONE_FORMAT) : "-"], value: formatPrettyNumber(value, min, max), - info: getMetricName(metricItem), + info: getMetricName(metricItem, seriesItem), statsFormatted: seriesItem?.statsFormatted, marker: `${seriesItem?.stroke}`, }; diff --git a/app/vmui/packages/vmui/src/types/uplot.ts b/app/vmui/packages/vmui/src/types/uplot.ts index 667f9a4bb..8192303ba 100644 --- a/app/vmui/packages/vmui/src/types/uplot.ts +++ b/app/vmui/packages/vmui/src/types/uplot.ts @@ -23,6 +23,7 @@ export interface SeriesItem extends Series { median: number; forecast?: ForecastType | null; forecastGroup?: string; + hasAlias?: boolean; } export interface HideSeriesArgs { @@ -45,6 +46,7 @@ export interface LegendItemType { freeFormFields: {[key: string]: string}; statsFormatted: SeriesItemStatsFormatted; median: number + hasAlias: boolean; } export interface BarSeriesItem { diff --git a/app/vmui/packages/vmui/src/utils/metric.ts b/app/vmui/packages/vmui/src/utils/metric.ts index 90ec03ab9..298a895ca 100644 --- a/app/vmui/packages/vmui/src/utils/metric.ts +++ b/app/vmui/packages/vmui/src/utils/metric.ts @@ -2,16 +2,23 @@ import { MetricBase } from "../api/types"; export const getNameForMetric = (result: MetricBase, alias?: string, showQueryNum = true): string => { const { __name__, ...freeFormFields } = result.metric; - const name = alias || `${showQueryNum ? `[Query ${result.group}] ` : ""}${__name__ || ""}`; - if (Object.keys(freeFormFields).length == 0) { - if (!name) { - return "value"; - } - return name; + const queryPrefix = showQueryNum ? `[Query ${result.group}] ` : ""; + + if (alias) { + return alias.replace(/\{\{(\w+)}}/g, (_, key) => result.metric[key] || ""); } - return `${name}{${Object.entries(freeFormFields).map(e => - `${e[0]}=${JSON.stringify(e[1])}` - ).join(", ")}}`; + + const name = `${queryPrefix}${__name__ || ""}`; + + if (Object.keys(freeFormFields).length === 0) { + return name || "value"; + } + + const fieldsString = Object.entries(freeFormFields) + .map(([key, value]) => `${key}=${JSON.stringify(value)}`) + .join(", "); + + return `${name}{${fieldsString}}`; }; export const promValueToNumber = (s: string): number => { diff --git a/app/vmui/packages/vmui/src/utils/uplot/helpers.ts b/app/vmui/packages/vmui/src/utils/uplot/helpers.ts index a849ecf6e..ab49672bb 100644 --- a/app/vmui/packages/vmui/src/utils/uplot/helpers.ts +++ b/app/vmui/packages/vmui/src/utils/uplot/helpers.ts @@ -1,5 +1,6 @@ import uPlot from "uplot"; import { MetricResult } from "../../api/types"; +import { SeriesItem } from "../../types"; export const formatTicks = (u: uPlot, ticks: number[], unit = ""): string[] => { const min = ticks[0]; @@ -53,7 +54,11 @@ export const getDashLine = (group: number): number[] => { return group <= 1 ? [] : [group*4, group*1.2]; }; -export const getMetricName = (metricItem: MetricResult) => { +export const getMetricName = (metricItem: MetricResult, seriesItem: SeriesItem) => { + if (seriesItem?.hasAlias && seriesItem?.label) { + return seriesItem.label; + } + const metric = metricItem?.metric || {}; const labelNames = Object.keys(metric).filter(x => x != "__name__"); const labels = labelNames.map(key => `${key}=${JSON.stringify(metric[key])}`); diff --git a/app/vmui/packages/vmui/src/utils/uplot/series.ts b/app/vmui/packages/vmui/src/utils/uplot/series.ts index 58c59e8ac..1c726921a 100644 --- a/app/vmui/packages/vmui/src/utils/uplot/series.ts +++ b/app/vmui/packages/vmui/src/utils/uplot/series.ts @@ -42,10 +42,12 @@ export const getSeriesItemContext = (data: MetricResult[], hideSeries: string[], return (d: MetricResult, i: number): SeriesItem => { const metricInfo = isAnomalyUI ? isForecast(data[i].metric) : null; - const label = isAnomalyUI ? metricInfo?.group || "" : getNameForMetric(d, alias[d.group - 1]); + const aliasValue = alias[d.group - 1]; + const label = isAnomalyUI ? metricInfo?.group || "" : getNameForMetric(d, aliasValue); return { label, + hasAlias: Boolean(aliasValue), dash: getDashSeries(metricInfo), width: getWidthSeries(metricInfo), stroke: getStrokeSeries({ metricInfo, label, isAnomalyUI, colorState }), @@ -88,6 +90,7 @@ export const getLegendItem = (s: SeriesItem, group: number): LegendItemType => ( freeFormFields: s.freeFormFields, statsFormatted: s.statsFormatted, median: s.median, + hasAlias: s.hasAlias || false, }); export const getHideSeries = ({ hideSeries, legend, metaKey, series, isAnomalyView }: HideSeriesArgs): string[] => { diff --git a/docs/VictoriaLogs/CHANGELOG.md b/docs/VictoriaLogs/CHANGELOG.md index 8c9f9aa3f..d80a1dbe0 100644 --- a/docs/VictoriaLogs/CHANGELOG.md +++ b/docs/VictoriaLogs/CHANGELOG.md @@ -18,6 +18,9 @@ according to [these docs](https://docs.victoriametrics.com/victorialogs/quicksta * FEATURE: [web UI](https://docs.victoriametrics.com/victorialogs/querying/#web-ui): add frontend-only pagination for table view. * FEATURE: [web UI](https://docs.victoriametrics.com/victorialogs/querying/#web-ui): improve memory consumption during data processing. This enhancement reduces the overall memory footprint, leading to better performance and stability. * FEATURE: [web UI](https://docs.victoriametrics.com/victorialogs/querying/#web-ui): reduce memory usage across all tabs for improved performance and stability. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7185). +* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add support for template alias in predefined panels. This allows creating more readable metric names in the legend using constructions like `{{label_name}}`, where `label_name` is the name of the label. [See this commit](https://github.com/VictoriaMetrics/VictoriaMetrics/commit/116101da78a4dee8bd7c4ba0e66458fd05a10469#diff-95141489b32468cf852d2705d96eaa48c50a8b1cdd0424a29e7ca289912a6dcbR140-R151) + +* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix for `showLegend` and `alias` flags in predefined panels. [See this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7565) ## [v1.0.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.0.0-victorialogs) diff --git a/docs/changelog/CHANGELOG.md b/docs/changelog/CHANGELOG.md index a57bbe268..b0a138297 100644 --- a/docs/changelog/CHANGELOG.md +++ b/docs/changelog/CHANGELOG.md @@ -22,6 +22,7 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/). * FEATURE: [vmalert](https://docs.victoriametrics.com/vmalert): revert the default value of `-remoteWrite.maxQueueSize` from `1_000_000` to `100_000`. It was bumped in [v1.104.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.104.0), which increases memory usage and is not needed for most setups. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7471). * FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add `Raw Query` tab for displaying raw data. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7024). +* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add support for template alias in predefined panels. This allows creating more readable metric names in the legend using constructions like `{{label_name}}`, where `label_name` is the name of the label. [See this commit](https://github.com/VictoriaMetrics/VictoriaMetrics/commit/116101da78a4dee8bd7c4ba0e66458fd05a10469#diff-95141489b32468cf852d2705d96eaa48c50a8b1cdd0424a29e7ca289912a6dcbR140-R151) * FEATURE: [stream aggregation](https://docs.victoriametrics.com/stream-aggregation/): add `ignore_first_sample_interval` param to [aggregation config](https://docs.victoriametrics.com/stream-aggregation/#stream-aggregation-config). It allows users to control the time interval when aggregation skips sending aggregated samples to avoid unexpected spikes in values. By default, this interval is set to x2 of `staleness_interval`. The new setting is applicable only to `total`, `total_prometheus`, `increase`, `increase_prometheus` and `histogram_bucket` outputs. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7116) for details. Thanks to @iyuroch for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7313). * FEATURE: [vmauth](https://docs.victoriametrics.com/vmauth/): add `dump_request_on_errors` bool setting to [auth config](https://docs.victoriametrics.com/vmauth/#auth-config) for debugging HTTP requests that missed routing rules. This should improve debugability of vmauth settings. * FEATURE: [vmauth](https://docs.victoriametrics.com/vmauth/): add `dryRun` flag to validate configuration. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7505) for details. @@ -32,6 +33,7 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/). * BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent): fix the `resource_group` filter for Azure service discovery on virtual machine scale sets. Previously, this filter did not apply to virtual machine scale sets, causing all virtual machines to be discovered. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7630). * BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/), `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): properly return result for binary operation `^` aka pow at query requests for `NaN` values. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7359) for details. * BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix rendering of isolated data points on the graph that are not connected to other points. +* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix for `showLegend` and `alias` flags in predefined panels. [See this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7565) * BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert): improve the correctness of alert [state restoration](https://docs.victoriametrics.com/vmalert/#alerts-state-on-restarts). Previously, it could result in false-positive alerts if alert was resolved shortly before vmalert restart. * BUGFIX: [vmalert-tool](https://docs.victoriametrics.com/vmalert-tool/): exit immediately with error message if no test file is found under specified `-files`. * BUGFIX: `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): Properly handle [multitenant](https://docs.victoriametrics.com/cluster-victoriametrics/#multitenancy-via-labels) query request errors and correctly perform search for available tenants. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7549) for details. This is follow-up after [v1.106.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.106.1) release changes.