mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Tempo: Filter available service graph filter values to most relevant options (#43728)
* Restrict service graph filter tag values to labels from service graph metrics
This commit is contained in:
parent
cb34c47123
commit
1a7567d8c7
@ -12,6 +12,9 @@ interface Props {
|
|||||||
addFilter: (filter: AdHocVariableFilter) => void;
|
addFilter: (filter: AdHocVariableFilter) => void;
|
||||||
removeFilter: (index: number) => void;
|
removeFilter: (index: number) => void;
|
||||||
changeFilter: (index: number, newFilter: AdHocVariableFilter) => 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<Props> {
|
|||||||
datasource={this.props.datasource!}
|
datasource={this.props.datasource!}
|
||||||
appendBefore={filters.length > 0 ? <ConditionSegment label="AND" /> : null}
|
appendBefore={filters.length > 0 ? <ConditionSegment label="AND" /> : null}
|
||||||
onCompleted={this.appendFilterToVariable}
|
onCompleted={this.appendFilterToVariable}
|
||||||
|
getTagKeysOptions={this.props.getTagKeysOptions}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -75,6 +79,7 @@ export class AdHocFilter extends PureComponent<Props> {
|
|||||||
onKeyChange={this.onChange(index, 'key')}
|
onKeyChange={this.onChange(index, 'key')}
|
||||||
onOperatorChange={this.onChange(index, 'operator')}
|
onOperatorChange={this.onChange(index, 'operator')}
|
||||||
onValueChange={this.onChange(index, 'value')}
|
onValueChange={this.onChange(index, 'value')}
|
||||||
|
getTagKeysOptions={this.props.getTagKeysOptions}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
@ -8,9 +8,10 @@ interface Props {
|
|||||||
datasource: DataSourceRef;
|
datasource: DataSourceRef;
|
||||||
onCompleted: (filter: AdHocVariableFilter) => void;
|
onCompleted: (filter: AdHocVariableFilter) => void;
|
||||||
appendBefore?: React.ReactNode;
|
appendBefore?: React.ReactNode;
|
||||||
|
getTagKeysOptions?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdHocFilterBuilder: FC<Props> = ({ datasource, appendBefore, onCompleted }) => {
|
export const AdHocFilterBuilder: FC<Props> = ({ datasource, appendBefore, onCompleted, getTagKeysOptions }) => {
|
||||||
const [key, setKey] = useState<string | null>(null);
|
const [key, setKey] = useState<string | null>(null);
|
||||||
const [operator, setOperator] = useState<string>('=');
|
const [operator, setOperator] = useState<string>('=');
|
||||||
|
|
||||||
@ -44,7 +45,14 @@ export const AdHocFilterBuilder: FC<Props> = ({ datasource, appendBefore, onComp
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (key === null) {
|
if (key === null) {
|
||||||
return <AdHocFilterKey datasource={datasource} filterKey={key} onChange={onKeyChanged} />;
|
return (
|
||||||
|
<AdHocFilterKey
|
||||||
|
datasource={datasource}
|
||||||
|
filterKey={key}
|
||||||
|
onChange={onKeyChanged}
|
||||||
|
getTagKeysOptions={getTagKeysOptions}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -57,6 +65,7 @@ export const AdHocFilterBuilder: FC<Props> = ({ datasource, appendBefore, onComp
|
|||||||
onKeyChange={onKeyChanged}
|
onKeyChange={onKeyChanged}
|
||||||
onOperatorChange={onOperatorChanged}
|
onOperatorChange={onOperatorChanged}
|
||||||
onValueChange={onValueChanged}
|
onValueChange={onValueChanged}
|
||||||
|
getTagKeysOptions={getTagKeysOptions}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
@ -7,12 +7,13 @@ interface Props {
|
|||||||
datasource: DataSourceRef;
|
datasource: DataSourceRef;
|
||||||
filterKey: string | null;
|
filterKey: string | null;
|
||||||
onChange: (item: SelectableValue<string | null>) => void;
|
onChange: (item: SelectableValue<string | null>) => void;
|
||||||
|
getTagKeysOptions?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MIN_WIDTH = 90;
|
const MIN_WIDTH = 90;
|
||||||
export const AdHocFilterKey: FC<Props> = ({ datasource, onChange, filterKey }) => {
|
export const AdHocFilterKey: FC<Props> = ({ datasource, onChange, filterKey, getTagKeysOptions }) => {
|
||||||
const loadKeys = () => fetchFilterKeys(datasource);
|
const loadKeys = () => fetchFilterKeys(datasource, getTagKeysOptions);
|
||||||
const loadKeysWithRemove = () => fetchFilterKeysWithRemove(datasource);
|
const loadKeysWithRemove = () => fetchFilterKeysWithRemove(datasource, getTagKeysOptions);
|
||||||
|
|
||||||
if (filterKey === null) {
|
if (filterKey === null) {
|
||||||
return (
|
return (
|
||||||
@ -51,18 +52,24 @@ const plusSegment: ReactElement = (
|
|||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchFilterKeys = async (datasource: DataSourceRef): Promise<Array<SelectableValue<string>>> => {
|
const fetchFilterKeys = async (
|
||||||
|
datasource: DataSourceRef,
|
||||||
|
getTagKeysOptions?: any
|
||||||
|
): Promise<Array<SelectableValue<string>>> => {
|
||||||
const ds = await getDatasourceSrv().get(datasource);
|
const ds = await getDatasourceSrv().get(datasource);
|
||||||
|
|
||||||
if (!ds || !ds.getTagKeys) {
|
if (!ds || !ds.getTagKeys) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const metrics = await ds.getTagKeys();
|
const metrics = await ds.getTagKeys(getTagKeysOptions);
|
||||||
return metrics.map((m) => ({ label: m.text, value: m.text }));
|
return metrics.map((m) => ({ label: m.text, value: m.text }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchFilterKeysWithRemove = async (datasource: DataSourceRef): Promise<Array<SelectableValue<string>>> => {
|
const fetchFilterKeysWithRemove = async (
|
||||||
const keys = await fetchFilterKeys(datasource);
|
datasource: DataSourceRef,
|
||||||
|
getTagKeysOptions?: any
|
||||||
|
): Promise<Array<SelectableValue<string>>> => {
|
||||||
|
const keys = await fetchFilterKeys(datasource, getTagKeysOptions);
|
||||||
return [REMOVE_VALUE, ...keys];
|
return [REMOVE_VALUE, ...keys];
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,7 @@ interface Props {
|
|||||||
onOperatorChange: (item: SelectableValue<string>) => void;
|
onOperatorChange: (item: SelectableValue<string>) => void;
|
||||||
onValueChange: (item: SelectableValue<string>) => void;
|
onValueChange: (item: SelectableValue<string>) => void;
|
||||||
placeHolder?: string;
|
placeHolder?: string;
|
||||||
|
getTagKeysOptions?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdHocFilterRenderer: FC<Props> = ({
|
export const AdHocFilterRenderer: FC<Props> = ({
|
||||||
@ -21,10 +22,16 @@ export const AdHocFilterRenderer: FC<Props> = ({
|
|||||||
onOperatorChange,
|
onOperatorChange,
|
||||||
onValueChange,
|
onValueChange,
|
||||||
placeHolder,
|
placeHolder,
|
||||||
|
getTagKeysOptions,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AdHocFilterKey datasource={datasource} filterKey={key} onChange={onKeyChange} />
|
<AdHocFilterKey
|
||||||
|
datasource={datasource}
|
||||||
|
filterKey={key}
|
||||||
|
onChange={onKeyChange}
|
||||||
|
getTagKeysOptions={getTagKeysOptions}
|
||||||
|
/>
|
||||||
<div className="gf-form">
|
<div className="gf-form">
|
||||||
<OperatorSegment value={operator} onChange={onOperatorChange} />
|
<OperatorSegment value={operator} onChange={onOperatorChange} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -790,9 +790,19 @@ export class PrometheusDatasource
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTagKeys() {
|
async getTagKeys(options?: any) {
|
||||||
const result = await this.metadataRequest('/api/v1/labels');
|
if (options?.series) {
|
||||||
return result?.data?.data?.map((value: any) => ({ text: value })) ?? [];
|
// Get tags for the provided series only
|
||||||
|
const seriesLabels: Array<Record<string, string[]>> = 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 } = {}) {
|
async getTagValues(options: { key?: string } = {}) {
|
||||||
|
@ -44,6 +44,13 @@ export function ServiceGraphSection({
|
|||||||
<AdHocFilter
|
<AdHocFilter
|
||||||
datasource={{ uid: graphDatasourceUid }}
|
datasource={{ uid: graphDatasourceUid }}
|
||||||
filters={filters}
|
filters={filters}
|
||||||
|
getTagKeysOptions={{
|
||||||
|
series: [
|
||||||
|
'traces_service_graph_request_server_seconds_sum',
|
||||||
|
'traces_service_graph_request_total',
|
||||||
|
'traces_service_graph_request_failed_total',
|
||||||
|
],
|
||||||
|
}}
|
||||||
addFilter={(filter: AdHocVariableFilter) => {
|
addFilter={(filter: AdHocVariableFilter) => {
|
||||||
onChange({
|
onChange({
|
||||||
...query,
|
...query,
|
||||||
|
Loading…
Reference in New Issue
Block a user