prometheus: metadata: simplify the metrics-metadata format (#39411)

* prometheus: metadata: simplify the metrics-metadata format

* fixed unit test

* fixed tests
pull/39237/head^2
Gábor Farkas 4 years ago committed by GitHub
parent f1edd0ea08
commit 346a53145c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.tsx
  2. 2
      public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx
  3. 2
      public/app/plugins/datasource/prometheus/language_provider.ts
  4. 43
      public/app/plugins/datasource/prometheus/language_utils.test.ts
  5. 79
      public/app/plugins/datasource/prometheus/language_utils.ts
  6. 2
      public/app/plugins/datasource/prometheus/query_hints.test.ts
  7. 2
      public/app/plugins/datasource/prometheus/query_hints.ts
  8. 2
      public/app/plugins/datasource/prometheus/types.ts

@ -404,7 +404,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
const value: FacettableValue = { name: labelValue }; const value: FacettableValue = { name: labelValue };
// Adding type/help text to metrics // Adding type/help text to metrics
if (name === METRIC_LABEL && metricsMetadata) { if (name === METRIC_LABEL && metricsMetadata) {
const meta = metricsMetadata[labelValue]?.[0]; const meta = metricsMetadata[labelValue];
if (meta) { if (meta) {
value.details = `(${meta.type}) ${meta.help}`; value.details = `(${meta.type}) ${meta.help}`;
} }

@ -86,7 +86,7 @@ const MonacoQueryField = (props: Props) => {
const getAllMetricNames = () => { const getAllMetricNames = () => {
const { metrics, metricsMetadata } = lpRef.current; const { metrics, metricsMetadata } = lpRef.current;
const result = metrics.map((m) => { const result = metrics.map((m) => {
const metaItem = metricsMetadata?.[m]?.[0]; const metaItem = metricsMetadata?.[m];
return { return {
name: m, name: m,
help: metaItem?.help ?? '', help: metaItem?.help ?? '',

@ -53,7 +53,7 @@ export function addHistoryMetadata(item: CompletionItem, history: any[]): Comple
function addMetricsMetadata(metric: string, metadata?: PromMetricsMetadata): CompletionItem { function addMetricsMetadata(metric: string, metadata?: PromMetricsMetadata): CompletionItem {
const item: CompletionItem = { label: metric }; const item: CompletionItem = { label: metric };
if (metadata && metadata[metric]) { if (metadata && metadata[metric]) {
const { type, help } = metadata[metric][0]; const { type, help } = metadata[metric];
item.documentation = `${type.toUpperCase()}: ${help}`; item.documentation = `${type.toUpperCase()}: ${help}`;
} }
return item; return item;

@ -73,23 +73,25 @@ describe('parseSelector()', () => {
describe('fixSummariesMetadata', () => { describe('fixSummariesMetadata', () => {
const synthetics = { const synthetics = {
ALERTS: [ ALERTS: {
{ type: 'counter',
type: 'counter', help:
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.',
'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', () => { it('returns only synthetics on empty metadata', () => {
expect(fixSummariesMetadata({})).toEqual({ ...synthetics }); 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 metadataRaw = {
foo: [{ type: 'not_a_summary', help: 'foo help' }], foo: [{ type: 'not_a_summary', help: 'foo help' }],
}; };
expect(fixSummariesMetadata(metadata)).toEqual({ ...metadata, ...synthetics });
const metadata = {
foo: { type: 'not_a_summary', help: 'foo help' },
};
expect(fixSummariesMetadata(metadataRaw)).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', () => {
@ -98,10 +100,10 @@ describe('fixSummariesMetadata', () => {
bar: [{ type: 'summary', help: 'bar help' }], bar: [{ type: 'summary', help: 'bar help' }],
}; };
const expected = { const expected = {
foo: [{ type: 'not_a_summary', help: 'foo help' }], foo: { type: 'not_a_summary', help: 'foo help' },
bar: [{ type: 'summary', help: 'bar help' }], bar: { type: 'summary', help: 'bar help' },
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, ...synthetics }); expect(fixSummariesMetadata(metadata)).toEqual({ ...expected, ...synthetics });
}); });
@ -112,13 +114,14 @@ describe('fixSummariesMetadata', () => {
bar: [{ type: 'histogram', help: 'bar help' }], bar: [{ type: 'histogram', help: 'bar help' }],
}; };
const expected = { const expected = {
foo: [{ type: 'not_a_histogram', help: 'foo help' }], foo: { type: 'not_a_histogram', help: 'foo help' },
bar: [{ type: 'histogram', help: 'bar help' }], bar: { type: 'histogram', help: 'bar help' },
bar_bucket: [{ type: 'counter', help: 'Cumulative counters for the observation buckets (bar help)' }], bar_bucket: { type: 'counter', help: 'Cumulative counters for the observation buckets (bar help)' },
bar_count: [ bar_count: {
{ type: 'counter', help: 'Count of events that have been observed for the histogram metric (bar help)' }, 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)' }], },
bar_sum: { type: 'counter', help: 'Total sum of all observed values for the histogram metric (bar help)' },
}; };
expect(fixSummariesMetadata(metadata)).toEqual({ ...expected, ...synthetics }); expect(fixSummariesMetadata(metadata)).toEqual({ ...expected, ...synthetics });
}); });

@ -1,4 +1,4 @@
import { PromMetricsMetadata } from './types'; import { PromMetricsMetadata, PromMetricsMetadataItem } from './types';
import { addLabelToQuery } from './add_label_to_query'; import { addLabelToQuery } from './add_label_to_query';
import { SUGGESTIONS_LIMIT } from './language_provider'; import { SUGGESTIONS_LIMIT } from './language_provider';
@ -169,59 +169,56 @@ function addLabelsToExpression(expr: string, invalidLabelsRegexp: RegExp) {
* *
* @param metadata HELP and TYPE metadata from /api/v1/metadata * @param metadata HELP and TYPE metadata from /api/v1/metadata
*/ */
export function fixSummariesMetadata(metadata: PromMetricsMetadata): PromMetricsMetadata { export function fixSummariesMetadata(metadata: { [metric: string]: PromMetricsMetadataItem[] }): PromMetricsMetadata {
if (!metadata) { if (!metadata) {
return metadata; return metadata;
} }
const baseMetadata: PromMetricsMetadata = {};
const summaryMetadata: PromMetricsMetadata = {}; const summaryMetadata: PromMetricsMetadata = {};
for (const metric in metadata) { for (const metric in metadata) {
// NOTE: based on prometheus-documentation, we can receive
// multiple metadata-entries for the given metric, it seems
// it happens when the same metric is on multiple targets
// and their help-text differs
// (https://prometheus.io/docs/prometheus/latest/querying/api/#querying-metric-metadata)
// for now we just use the first entry.
const item = metadata[metric][0]; const item = metadata[metric][0];
baseMetadata[metric] = item;
if (item.type === 'histogram') { if (item.type === 'histogram') {
summaryMetadata[`${metric}_bucket`] = [ summaryMetadata[`${metric}_bucket`] = {
{ type: 'counter',
type: 'counter', help: `Cumulative counters for the observation buckets (${item.help})`,
help: `Cumulative counters for the observation buckets (${item.help})`, };
}, summaryMetadata[`${metric}_count`] = {
]; type: 'counter',
summaryMetadata[`${metric}_count`] = [ help: `Count of events that have been observed for the histogram metric (${item.help})`,
{ };
type: 'counter', summaryMetadata[`${metric}_sum`] = {
help: `Count of events that have been observed for the histogram metric (${item.help})`, type: 'counter',
}, help: `Total sum of all observed values 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`] = {
{ type: 'counter',
type: 'counter', help: `Count of events that have been observed for the base metric (${item.help})`,
help: `Count of events that have been observed for the base metric (${item.help})`, };
}, summaryMetadata[`${metric}_sum`] = {
]; type: 'counter',
summaryMetadata[`${metric}_sum`] = [ help: `Total sum of all observed values for the base metric (${item.help})`,
{ };
type: 'counter',
help: `Total sum of all observed values for the base metric (${item.help})`,
},
];
} }
} }
// Synthetic series // Synthetic series
const syntheticMetadata: PromMetricsMetadata = {}; const syntheticMetadata: PromMetricsMetadata = {};
syntheticMetadata['ALERTS'] = [ syntheticMetadata['ALERTS'] = {
{ type: 'counter',
type: 'counter', help:
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.',
'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 { ...baseMetadata, ...summaryMetadata, ...syntheticMetadata };
return { ...metadata, ...summaryMetadata, ...syntheticMetadata };
} }
export function roundMsToMin(milliseconds: number): number { export function roundMsToMin(milliseconds: number): number {

@ -42,7 +42,7 @@ describe('getQueryHints()', () => {
], ],
}, },
]; ];
const mock: unknown = { languageProvider: { metricsMetadata: { foo: [{ type: 'counter' }] } } }; const mock: unknown = { languageProvider: { metricsMetadata: { foo: { type: 'counter' } } } };
const datasource = mock as PrometheusDatasource; const datasource = mock as PrometheusDatasource;
let hints = getQueryHints('foo', series, datasource); let hints = getQueryHints('foo', series, datasource);

@ -40,7 +40,7 @@ export function getQueryHints(query: string, series?: any[], datasource?: Promet
counterNameMetric = counterNameMetric =
metricMetadataKeys.find((metricName) => { metricMetadataKeys.find((metricName) => {
// Only considering first type information, could be non-deterministic // Only considering first type information, could be non-deterministic
const metadata = metricsMetadata[metricName][0]; const metadata = metricsMetadata[metricName];
if (metadata.type.toLowerCase() === 'counter') { if (metadata.type.toLowerCase() === 'counter') {
const metricRegex = new RegExp(`\\b${metricName}\\b`); const metricRegex = new RegExp(`\\b${metricName}\\b`);
if (query.match(metricRegex)) { if (query.match(metricRegex)) {

@ -50,7 +50,7 @@ export interface PromMetricsMetadataItem {
} }
export interface PromMetricsMetadata { export interface PromMetricsMetadata {
[metric: string]: PromMetricsMetadataItem[]; [metric: string]: PromMetricsMetadataItem;
} }
export interface PromDataSuccessResponse<T = PromData> { export interface PromDataSuccessResponse<T = PromData> {

Loading…
Cancel
Save