Prometheus: Add metadata to metrics in Metrics browser (#34708)

* Prometheus: Add metadata to metrics in Metrics browser

- use the available metadata to enhance the tooltip on metric items in the metrics browser
- added meta info for histogram metrics (was missing before)
- also added one for ALERTS

* fix test
This commit is contained in:
David
2021-05-28 14:51:06 +02:00
committed by GitHub
parent 886f6fc55b
commit 2205464a8d
4 changed files with 79 additions and 8 deletions

View File

@@ -17,6 +17,7 @@ export interface Props extends Omit<HTMLAttributes<HTMLElement>, 'onClick'> {
searchTerm?: string; searchTerm?: string;
value?: string; value?: string;
facets?: number; facets?: number;
title?: string;
onClick?: OnLabelClick; onClick?: OnLabelClick;
} }
@@ -24,7 +25,7 @@ export interface Props extends Omit<HTMLAttributes<HTMLElement>, 'onClick'> {
* TODO #33976: Create a common, shared component with public/app/plugins/datasource/loki/components/LokiLabel.tsx * TODO #33976: Create a common, shared component with public/app/plugins/datasource/loki/components/LokiLabel.tsx
*/ */
export const Label = forwardRef<HTMLElement, Props>( export const Label = forwardRef<HTMLElement, Props>(
({ name, value, hidden, facets, onClick, className, loading, searchTerm, active, style, ...rest }, ref) => { ({ name, value, hidden, facets, onClick, className, loading, searchTerm, active, style, title, ...rest }, ref) => {
const theme = useTheme2(); const theme = useTheme2();
const styles = getLabelStyles(theme); const styles = getLabelStyles(theme);
const searchWords = searchTerm ? [searchTerm] : []; const searchWords = searchTerm ? [searchTerm] : [];
@@ -46,7 +47,7 @@ export const Label = forwardRef<HTMLElement, Props>(
ref={ref} ref={ref}
onClick={onLabelClick} onClick={onLabelClick}
style={style} style={style}
title={text} title={title || text}
role="option" role="option"
aria-selected={!!active} aria-selected={!!active}
className={cx( className={cx(

View File

@@ -36,6 +36,7 @@ interface BrowserState {
interface FacettableValue { interface FacettableValue {
name: string; name: string;
selected?: boolean; selected?: boolean;
details?: string;
} }
export interface SelectableLabel { export interface SelectableLabel {
@@ -385,7 +386,19 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
rawValues = rawValues.slice(0, MAX_VALUE_COUNT); rawValues = rawValues.slice(0, MAX_VALUE_COUNT);
this.setState({ error }); this.setState({ error });
} }
const values: FacettableValue[] = rawValues.map((value) => ({ name: value })); const values: FacettableValue[] = [];
const { metricsMetadata } = languageProvider;
for (const labelValue of rawValues) {
const value: FacettableValue = { name: labelValue };
// Adding type/help text to metrics
if (name === METRIC_LABEL && metricsMetadata) {
const meta = metricsMetadata[labelValue]?.[0];
if (meta) {
value.details = `(${meta.type}) ${meta.help}`;
}
}
values.push(value);
}
this.updateLabelState(name, { values, loading: false }); this.updateLabelState(name, { values, loading: false });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@@ -498,6 +511,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
<PromLabel <PromLabel
name={metrics!.name} name={metrics!.name}
value={value?.name} value={value?.name}
title={value.details}
active={value?.selected} active={value?.selected}
onClick={this.onClickMetric} onClick={this.onClickMetric}
searchTerm={metricSearchTerm} searchTerm={metricSearchTerm}

View File

@@ -72,15 +72,24 @@ describe('parseSelector()', () => {
}); });
describe('fixSummariesMetadata', () => { describe('fixSummariesMetadata', () => {
it('returns empty metadata', () => { const synthetics = {
expect(fixSummariesMetadata({})).toEqual({}); ALERTS: [
{
type: 'counter',
help:
'Time series showing pending and firing alerts. The sample value is set to 1 as long as the alert is in the indicated active (pending or firing) state.',
},
],
};
it('returns only synthetics on empty metadata', () => {
expect(fixSummariesMetadata({})).toEqual({ ...synthetics });
}); });
it('returns unchanged metadata if no summary is present', () => { it('returns unchanged metadata if no summary is present', () => {
const metadata = { const metadata = {
foo: [{ type: 'not_a_summary', help: 'foo help' }], foo: [{ type: 'not_a_summary', help: 'foo help' }],
}; };
expect(fixSummariesMetadata(metadata)).toEqual(metadata); expect(fixSummariesMetadata(metadata)).toEqual({ ...metadata, ...synthetics });
}); });
it('returns metadata with added count and sum for a summary', () => { it('returns metadata with added count and sum for a summary', () => {
@@ -94,7 +103,24 @@ describe('fixSummariesMetadata', () => {
bar_count: [{ type: 'counter', help: 'Count of events that have been observed for the base metric (bar help)' }], bar_count: [{ type: 'counter', help: 'Count of events that have been observed for the base metric (bar help)' }],
bar_sum: [{ type: 'counter', help: 'Total sum of all observed values for the base metric (bar help)' }], bar_sum: [{ type: 'counter', help: 'Total sum of all observed values for the base metric (bar help)' }],
}; };
expect(fixSummariesMetadata(metadata)).toEqual(expected); expect(fixSummariesMetadata(metadata)).toEqual({ ...expected, ...synthetics });
});
it('returns metadata with added bucket/count/sum for a histogram', () => {
const metadata = {
foo: [{ type: 'not_a_histogram', help: 'foo help' }],
bar: [{ type: 'histogram', help: 'bar help' }],
};
const expected = {
foo: [{ type: 'not_a_histogram', help: 'foo help' }],
bar: [{ type: 'histogram', help: 'bar help' }],
bar_bucket: [{ type: 'counter', help: 'Cumulative counters for the observation buckets (bar help)' }],
bar_count: [
{ type: 'counter', help: 'Count of events that have been observed for the histogram metric (bar help)' },
],
bar_sum: [{ type: 'counter', help: 'Total sum of all observed values for the histogram metric (bar help)' }],
};
expect(fixSummariesMetadata(metadata)).toEqual({ ...expected, ...synthetics });
}); });
}); });

View File

@@ -176,6 +176,26 @@ export function fixSummariesMetadata(metadata: PromMetricsMetadata): PromMetrics
const summaryMetadata: PromMetricsMetadata = {}; const summaryMetadata: PromMetricsMetadata = {};
for (const metric in metadata) { for (const metric in metadata) {
const item = metadata[metric][0]; const item = metadata[metric][0];
if (item.type === 'histogram') {
summaryMetadata[`${metric}_bucket`] = [
{
type: 'counter',
help: `Cumulative counters for the observation buckets (${item.help})`,
},
];
summaryMetadata[`${metric}_count`] = [
{
type: 'counter',
help: `Count of events that have been observed for the histogram metric (${item.help})`,
},
];
summaryMetadata[`${metric}_sum`] = [
{
type: 'counter',
help: `Total sum of all observed values for the histogram metric (${item.help})`,
},
];
}
if (item.type === 'summary') { if (item.type === 'summary') {
summaryMetadata[`${metric}_count`] = [ summaryMetadata[`${metric}_count`] = [
{ {
@@ -191,7 +211,17 @@ export function fixSummariesMetadata(metadata: PromMetricsMetadata): PromMetrics
]; ];
} }
} }
return { ...metadata, ...summaryMetadata }; // Synthetic series
const syntheticMetadata: PromMetricsMetadata = {};
syntheticMetadata['ALERTS'] = [
{
type: 'counter',
help:
'Time series showing pending and firing alerts. The sample value is set to 1 as long as the alert is in the indicated active (pending or firing) state.',
},
];
return { ...metadata, ...summaryMetadata, ...syntheticMetadata };
} }
export function roundMsToMin(milliseconds: number): number { export function roundMsToMin(milliseconds: number): number {