From 1a7567d8c75f404554e191ae5fe1fc515fdfd5dd Mon Sep 17 00:00:00 2001 From: Connor Lindsey Date: Thu, 6 Jan 2022 07:09:31 -0700 Subject: [PATCH] Tempo: Filter available service graph filter values to most relevant options (#43728) * Restrict service graph filter tag values to labels from service graph metrics --- .../variables/adhoc/picker/AdHocFilter.tsx | 5 +++++ .../adhoc/picker/AdHocFilterBuilder.tsx | 13 ++++++++++-- .../variables/adhoc/picker/AdHocFilterKey.tsx | 21 ++++++++++++------- .../adhoc/picker/AdHocFilterRenderer.tsx | 9 +++++++- .../datasource/prometheus/datasource.ts | 16 +++++++++++--- .../tempo/QueryEditor/ServiceGraphSection.tsx | 7 +++++++ 6 files changed, 58 insertions(+), 13 deletions(-) diff --git a/public/app/features/variables/adhoc/picker/AdHocFilter.tsx b/public/app/features/variables/adhoc/picker/AdHocFilter.tsx index 98895638ef6..ca072d118ea 100644 --- a/public/app/features/variables/adhoc/picker/AdHocFilter.tsx +++ b/public/app/features/variables/adhoc/picker/AdHocFilter.tsx @@ -12,6 +12,9 @@ interface Props { addFilter: (filter: AdHocVariableFilter) => void; removeFilter: (index: number) => void; changeFilter: (index: number, newFilter: AdHocVariableFilter) => void; + // Passes options to the datasources getTagKeys(options?: any) method + // which is called to fetch the available filter key options in AdHocFilterKey.tsx + getTagKeysOptions?: any; } /** @@ -51,6 +54,7 @@ export class AdHocFilter extends PureComponent { datasource={this.props.datasource!} appendBefore={filters.length > 0 ? : null} onCompleted={this.appendFilterToVariable} + getTagKeysOptions={this.props.getTagKeysOptions} /> ); @@ -75,6 +79,7 @@ export class AdHocFilter extends PureComponent { onKeyChange={this.onChange(index, 'key')} onOperatorChange={this.onChange(index, 'operator')} onValueChange={this.onChange(index, 'value')} + getTagKeysOptions={this.props.getTagKeysOptions} /> ); diff --git a/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx b/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx index 907897b6cc6..a968b523754 100644 --- a/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx +++ b/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx @@ -8,9 +8,10 @@ interface Props { datasource: DataSourceRef; onCompleted: (filter: AdHocVariableFilter) => void; appendBefore?: React.ReactNode; + getTagKeysOptions?: any; } -export const AdHocFilterBuilder: FC = ({ datasource, appendBefore, onCompleted }) => { +export const AdHocFilterBuilder: FC = ({ datasource, appendBefore, onCompleted, getTagKeysOptions }) => { const [key, setKey] = useState(null); const [operator, setOperator] = useState('='); @@ -44,7 +45,14 @@ export const AdHocFilterBuilder: FC = ({ datasource, appendBefore, onComp ); if (key === null) { - return ; + return ( + + ); } return ( @@ -57,6 +65,7 @@ export const AdHocFilterBuilder: FC = ({ datasource, appendBefore, onComp onKeyChange={onKeyChanged} onOperatorChange={onOperatorChanged} onValueChange={onValueChanged} + getTagKeysOptions={getTagKeysOptions} /> ); diff --git a/public/app/features/variables/adhoc/picker/AdHocFilterKey.tsx b/public/app/features/variables/adhoc/picker/AdHocFilterKey.tsx index e8437be3065..a99afca4cde 100644 --- a/public/app/features/variables/adhoc/picker/AdHocFilterKey.tsx +++ b/public/app/features/variables/adhoc/picker/AdHocFilterKey.tsx @@ -7,12 +7,13 @@ interface Props { datasource: DataSourceRef; filterKey: string | null; onChange: (item: SelectableValue) => void; + getTagKeysOptions?: any; } const MIN_WIDTH = 90; -export const AdHocFilterKey: FC = ({ datasource, onChange, filterKey }) => { - const loadKeys = () => fetchFilterKeys(datasource); - const loadKeysWithRemove = () => fetchFilterKeysWithRemove(datasource); +export const AdHocFilterKey: FC = ({ datasource, onChange, filterKey, getTagKeysOptions }) => { + const loadKeys = () => fetchFilterKeys(datasource, getTagKeysOptions); + const loadKeysWithRemove = () => fetchFilterKeysWithRemove(datasource, getTagKeysOptions); if (filterKey === null) { return ( @@ -51,18 +52,24 @@ const plusSegment: ReactElement = ( ); -const fetchFilterKeys = async (datasource: DataSourceRef): Promise>> => { +const fetchFilterKeys = async ( + datasource: DataSourceRef, + getTagKeysOptions?: any +): Promise>> => { const ds = await getDatasourceSrv().get(datasource); if (!ds || !ds.getTagKeys) { return []; } - const metrics = await ds.getTagKeys(); + const metrics = await ds.getTagKeys(getTagKeysOptions); return metrics.map((m) => ({ label: m.text, value: m.text })); }; -const fetchFilterKeysWithRemove = async (datasource: DataSourceRef): Promise>> => { - const keys = await fetchFilterKeys(datasource); +const fetchFilterKeysWithRemove = async ( + datasource: DataSourceRef, + getTagKeysOptions?: any +): Promise>> => { + const keys = await fetchFilterKeys(datasource, getTagKeysOptions); return [REMOVE_VALUE, ...keys]; }; diff --git a/public/app/features/variables/adhoc/picker/AdHocFilterRenderer.tsx b/public/app/features/variables/adhoc/picker/AdHocFilterRenderer.tsx index 63ace211bf6..a3664125f57 100644 --- a/public/app/features/variables/adhoc/picker/AdHocFilterRenderer.tsx +++ b/public/app/features/variables/adhoc/picker/AdHocFilterRenderer.tsx @@ -12,6 +12,7 @@ interface Props { onOperatorChange: (item: SelectableValue) => void; onValueChange: (item: SelectableValue) => void; placeHolder?: string; + getTagKeysOptions?: any; } export const AdHocFilterRenderer: FC = ({ @@ -21,10 +22,16 @@ export const AdHocFilterRenderer: FC = ({ onOperatorChange, onValueChange, placeHolder, + getTagKeysOptions, }) => { return ( <> - +
diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 6b3c8ed0e64..92436f8a266 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -790,9 +790,19 @@ export class PrometheusDatasource ); } - async getTagKeys() { - const result = await this.metadataRequest('/api/v1/labels'); - return result?.data?.data?.map((value: any) => ({ text: value })) ?? []; + async getTagKeys(options?: any) { + if (options?.series) { + // Get tags for the provided series only + const seriesLabels: Array> = await Promise.all( + options.series.map((series: string) => this.languageProvider.fetchSeriesLabels(series)) + ); + const uniqueLabels = [...new Set(...seriesLabels.map((value) => Object.keys(value)))]; + return uniqueLabels.map((value: any) => ({ text: value })); + } else { + // Get all tags + const result = await this.metadataRequest('/api/v1/labels'); + return result?.data?.data?.map((value: any) => ({ text: value })) ?? []; + } } async getTagValues(options: { key?: string } = {}) { diff --git a/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx b/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx index 6b9884e15ab..99471de6846 100644 --- a/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx +++ b/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx @@ -44,6 +44,13 @@ export function ServiceGraphSection({ { onChange({ ...query,