From de0e1b2c5895f220b0231c4c58da8e157ed10bdb Mon Sep 17 00:00:00 2001 From: Andreas Opferkuch Date: Tue, 5 May 2020 18:02:55 +0200 Subject: [PATCH] Prometheus: Add off switch for metric/label name lookup (#24034) * Prometheus: Add off switch for metric/label name lookup This will help users with amounts of metric name data that is too much for a browser to handle. Autocomplete will be disabled and metrics chooser hidden, since obviously both rely on this data. Fixes #22702 * Use onUpdateDatasourceJsonDataOptionChecked ... from `@grafana/data`. Refactor naming to faciliate its use and stick with prop names as passed down from `ConfigEditor`. PLUS: - Rephrase switch label, add a tooltip and reduce the size of the to what "Custom query parameters" originally was. - Change `languageProvider` type in `PromQueryField`. * Put language provider back in Functions and history still work, even when metrics lookup gets disabled. Also: Rewording of setting. * Display a message when lookup got disabled manually * Call property for setting disableMetricsLookup * Show disabled metrics chooser instead of warning --- .../components/PromQueryField.test.tsx | 44 +++++++++++++++ .../prometheus/components/PromQueryField.tsx | 23 ++++---- .../prometheus/configuration/ConfigEditor.tsx | 2 +- .../prometheus/configuration/PromSettings.tsx | 54 +++++++++++-------- .../datasource/prometheus/datasource.ts | 2 + .../prometheus/language_provider.ts | 5 ++ .../plugins/datasource/prometheus/types.ts | 1 + 7 files changed, 100 insertions(+), 31 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx index 5effcdc6c8f..bcfcc8c2320 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx @@ -4,6 +4,9 @@ import RCCascader from 'rc-cascader'; import React from 'react'; import PromQlLanguageProvider, { DEFAULT_LOOKUP_METRICS_THRESHOLD } from '../language_provider'; import PromQueryField, { groupMetricsByPrefix, RECORDING_RULES_GROUP } from './PromQueryField'; +import { ButtonCascader } from '@grafana/ui'; +import { DataSourceInstanceSettings } from '@grafana/data'; +import { PromOptions } from '../types'; describe('PromQueryField', () => { beforeAll(() => { @@ -11,6 +14,47 @@ describe('PromQueryField', () => { window.getSelection = () => {}; }); + it('renders metrics chooser regularly if lookups are not disabled in the datasource settings', () => { + const datasource = ({ + languageProvider: { + start: () => Promise.resolve([]), + }, + } as unknown) as DataSourceInstanceSettings; + + const queryField = mount( + {}} + onChange={() => {}} + history={[]} + /> + ); + + expect(queryField.find(ButtonCascader).length).toBe(1); + }); + + it('renders a disabled metrics chooser if lookups are disabled in datasource settings', () => { + const queryField = mount( + {}} + onChange={() => {}} + history={[]} + /> + ); + + expect( + queryField + .find(ButtonCascader) + .find('button') + .props().disabled + ).toBe(true); + }); + it('refreshes metrics when the data source changes', async () => { const metrics = ['foo', 'bar']; const languageProvider = ({ diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx index ddc96f21015..0b25385c068 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx @@ -25,13 +25,19 @@ const HISTOGRAM_GROUP = '__histograms__'; const PRISM_SYNTAX = 'promql'; export const RECORDING_RULES_GROUP = '__recording_rules__'; -function getChooserText(hasSyntax: boolean, metrics: string[]) { +function getChooserText(metricsLookupDisabled: boolean, hasSyntax: boolean, metrics: string[]) { + if (metricsLookupDisabled) { + return '(Disabled)'; + } + if (!hasSyntax) { return 'Loading metrics...'; } + if (metrics && metrics.length === 0) { return '(No metrics found)'; } + return 'Metrics'; } @@ -250,12 +256,10 @@ class PromQueryField extends React.PureComponent { const { - histogramMetrics, - metrics, - metricsMetadata, - lookupsDisabled, - lookupMetricsThreshold, - } = this.props.datasource.languageProvider; + datasource, + datasource: { languageProvider }, + } = this.props; + const { histogramMetrics, metrics, metricsMetadata, lookupMetricsThreshold } = languageProvider; if (!metrics) { return; @@ -274,7 +278,7 @@ class PromQueryField extends React.PureComponent 0); return ( diff --git a/public/app/plugins/datasource/prometheus/configuration/ConfigEditor.tsx b/public/app/plugins/datasource/prometheus/configuration/ConfigEditor.tsx index b47581d24f4..bfe24d40316 100644 --- a/public/app/plugins/datasource/prometheus/configuration/ConfigEditor.tsx +++ b/public/app/plugins/datasource/prometheus/configuration/ConfigEditor.tsx @@ -16,7 +16,7 @@ export const ConfigEditor = (props: Props) => { onChange={onOptionsChange} /> - + ); }; diff --git a/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx b/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx index f0c2c222745..3acbe5f39c2 100644 --- a/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx +++ b/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx @@ -1,7 +1,11 @@ import React, { SyntheticEvent } from 'react'; import { EventsWithValidation, InlineFormLabel, regexValidation, LegacyForms } from '@grafana/ui'; -const { Select, Input, FormField } = LegacyForms; -import { DataSourceSettings, SelectableValue } from '@grafana/data'; +const { Select, Input, FormField, Switch } = LegacyForms; +import { + SelectableValue, + onUpdateDatasourceJsonDataOptionChecked, + DataSourcePluginOptionsEditorProps, +} from '@grafana/data'; import { PromOptions } from '../types'; const httpOptions = [ @@ -9,13 +13,10 @@ const httpOptions = [ { value: 'POST', label: 'POST' }, ]; -type Props = { - value: DataSourceSettings; - onChange: (value: DataSourceSettings) => void; -}; +type Props = Pick, 'options' | 'onOptionsChange'>; export const PromSettings = (props: Props) => { - const { value, onChange } = props; + const { options, onOptionsChange } = props; return ( <> @@ -28,10 +29,10 @@ export const PromSettings = (props: Props) => { inputEl={ } @@ -47,8 +48,8 @@ export const PromSettings = (props: Props) => { inputEl={ { @@ -119,13 +129,15 @@ export const getValueFromEventItem = (eventItem: SyntheticEvent).value; }; -const onChangeHandler = (key: keyof PromOptions, value: Props['value'], onChange: Props['onChange']) => ( - eventItem: SyntheticEvent | SelectableValue -) => { - onChange({ - ...value, +const onChangeHandler = ( + key: keyof PromOptions, + options: Props['options'], + onOptionsChange: Props['onOptionsChange'] +) => (eventItem: SyntheticEvent | SelectableValue) => { + onOptionsChange({ + ...options, jsonData: { - ...value.jsonData, + ...options.jsonData, [key]: getValueFromEventItem(eventItem), }, }); diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index c8539fe3370..77c6ab39f8a 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -83,6 +83,7 @@ export class PrometheusDatasource extends DataSourceApi queryTimeout: string; httpMethod: string; languageProvider: PrometheusLanguageProvider; + lookupsDisabled: boolean; resultTransformer: ResultTransformer; customQueryParameters: any; @@ -101,6 +102,7 @@ export class PrometheusDatasource extends DataSourceApi this.resultTransformer = new ResultTransformer(templateSrv); this.ruleMappings = {}; this.languageProvider = new PrometheusLanguageProvider(this); + this.lookupsDisabled = instanceSettings.jsonData.disableMetricsLookup; this.customQueryParameters = new URLSearchParams(instanceSettings.jsonData.customQueryParameters); } diff --git a/public/app/plugins/datasource/prometheus/language_provider.ts b/public/app/plugins/datasource/prometheus/language_provider.ts index 78b07d51249..77cb6df0d9f 100644 --- a/public/app/plugins/datasource/prometheus/language_provider.ts +++ b/public/app/plugins/datasource/prometheus/language_provider.ts @@ -112,10 +112,15 @@ export default class PromQlLanguageProvider extends LanguageProvider { }; start = async (): Promise => { + if (this.datasource.lookupsDisabled) { + return []; + } + this.metrics = await this.request('/api/v1/label/__name__/values', []); this.lookupsDisabled = this.metrics.length > this.lookupMetricsThreshold; this.metricsMetadata = await this.request('/api/v1/metadata', {}); this.processHistogramMetrics(this.metrics); + return []; }; diff --git a/public/app/plugins/datasource/prometheus/types.ts b/public/app/plugins/datasource/prometheus/types.ts index 49e20f7a888..d1d103c6a03 100644 --- a/public/app/plugins/datasource/prometheus/types.ts +++ b/public/app/plugins/datasource/prometheus/types.ts @@ -20,6 +20,7 @@ export interface PromOptions extends DataSourceJsonData { httpMethod: string; directUrl: string; customQueryParameters?: string; + disableMetricsLookup?: boolean; } export interface PromQueryRequest extends PromQuery {