diff --git a/docs/sources/datasources/tempo/configure-tempo-data-source.md b/docs/sources/datasources/tempo/configure-tempo-data-source.md index 157238122f1..24844b82ef3 100644 --- a/docs/sources/datasources/tempo/configure-tempo-data-source.md +++ b/docs/sources/datasources/tempo/configure-tempo-data-source.md @@ -333,6 +333,10 @@ You can choose one of three options: | **Duration** | _(Default)_ Displays the span duration on the span bar row. | | **Tag** | Displays the span tag on the span bar row. You must also specify which tag key to use to get the tag value, such as `component`. | +### Tag limit + +The **Tag limit** setting modifies the max number of tags and tag values to retrieve from Tempo. Default: 5000 + ### Private data source connect [//]: # 'Shared content for authentication section procedure in data sources' diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.tsx index d08b30d1f5f..6e7ace1ca18 100644 --- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.tsx +++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.tsx @@ -8,10 +8,11 @@ import { Alert, HorizontalGroup, InputActionMeta, Select, useStyles2 } from '@gr import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen'; import { TempoDatasource } from '../datasource'; +import { OPTIONS_LIMIT } from '../language_provider'; import { TempoQuery } from '../types'; import InlineSearchField from './InlineSearchField'; -import { maxOptions, withTemplateVariableOptions } from './SearchField'; +import { withTemplateVariableOptions } from './SearchField'; import { replaceAt } from './utils'; interface Props { @@ -46,11 +47,11 @@ export const GroupByField = (props: Props) => { () => (f: TraceqlFilter) => { const tags = datasource!.languageProvider.getMetricsSummaryTags(f.scope); if (tagQuery.length === 0) { - return tags.slice(0, maxOptions); + return tags.slice(0, OPTIONS_LIMIT); } const queryLowerCase = tagQuery.toLowerCase(); - return tags.filter((tag) => tag.toLowerCase().includes(queryLowerCase)).slice(0, maxOptions); + return tags.filter((tag) => tag.toLowerCase().includes(queryLowerCase)).slice(0, OPTIONS_LIMIT); }, [datasource, tagQuery] ); diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.tsx index 2ae3f088f70..18ef602b003 100644 --- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.tsx +++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.tsx @@ -10,16 +10,11 @@ import { Select, HorizontalGroup, useStyles2, InputActionMeta } from '@grafana/u import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen'; import { TempoDatasource } from '../datasource'; +import { OPTIONS_LIMIT } from '../language_provider'; import { operators as allOperators, stringOperators, numberOperators, keywordOperators } from '../traceql/traceql'; import { filterScopedTag, operatorSelectableValue } from './utils'; -const getStyles = () => ({ - dropdown: css({ - boxShadow: 'none', - }), -}); - interface Props { filter: TraceqlFilter; datasource: TempoDatasource; @@ -119,11 +114,11 @@ const SearchField = ({ const tagOptions = useMemo(() => { if (tagQuery.length === 0) { - return formatTagOptions(tags.slice(0, maxOptions), filter.tag); + return formatTagOptions(tags.slice(0, OPTIONS_LIMIT), filter.tag); } const queryLowerCase = tagQuery.toLowerCase(); - const filterdOptions = tags.filter((tag) => tag.toLowerCase().includes(queryLowerCase)).slice(0, maxOptions); + const filterdOptions = tags.filter((tag) => tag.toLowerCase().includes(queryLowerCase)).slice(0, OPTIONS_LIMIT); return formatTagOptions(filterdOptions, filter.tag); }, [filter.tag, tagQuery, tags]); @@ -133,7 +128,7 @@ const SearchField = ({ } if (tagValuesQuery.length === 0) { - return options.slice(0, maxOptions); + return options.slice(0, OPTIONS_LIMIT); } const queryLowerCase = tagValuesQuery.toLowerCase(); @@ -144,7 +139,7 @@ const SearchField = ({ } return false; }) - .slice(0, maxOptions); + .slice(0, OPTIONS_LIMIT); }, [tagValuesQuery, options]); return ( @@ -239,6 +234,8 @@ const SearchField = ({ ); }; +export default SearchField; + /** * Add to a list of options the current template variables. * @@ -250,7 +247,8 @@ export const withTemplateVariableOptions = (options: SelectableValue[] | undefin return [...(options || []), ...templateVariables.map((v) => ({ label: `$${v.name}`, value: `$${v.name}` }))]; }; -// Limit maximum options in select dropdowns for performance reasons -export const maxOptions = 1000; - -export default SearchField; +const getStyles = () => ({ + dropdown: css({ + boxShadow: 'none', + }), +}); diff --git a/public/app/plugins/datasource/tempo/VariableQueryEditor.tsx b/public/app/plugins/datasource/tempo/VariableQueryEditor.tsx index e2a2a28373e..8280b5c4a2e 100644 --- a/public/app/plugins/datasource/tempo/VariableQueryEditor.tsx +++ b/public/app/plugins/datasource/tempo/VariableQueryEditor.tsx @@ -3,8 +3,8 @@ import { useEffect, useMemo, useState } from 'react'; import { DataQuery, SelectableValue } from '@grafana/data'; import { InlineField, InlineFieldRow, InputActionMeta, Select } from '@grafana/ui'; -import { maxOptions } from './SearchTraceQLEditor/SearchField'; import { TempoDatasource } from './datasource'; +import { OPTIONS_LIMIT } from './language_provider'; export enum TempoVariableQueryType { LabelNames, @@ -46,7 +46,7 @@ export const TempoVariableQueryEditor = ({ onChange, query, datasource }: TempoV const options = useMemo(() => { if (labelQuery.length === 0) { - return labelOptions.slice(0, maxOptions); + return labelOptions.slice(0, OPTIONS_LIMIT); } const queryLowerCase = labelQuery.toLowerCase(); @@ -57,7 +57,7 @@ export const TempoVariableQueryEditor = ({ onChange, query, datasource }: TempoV } return false; }) - .slice(0, maxOptions); + .slice(0, OPTIONS_LIMIT); }, [labelQuery, labelOptions]); const onQueryTypeChange = (newType: SelectableValue) => { diff --git a/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx b/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx index 6b128eb0dcc..7602cea1487 100644 --- a/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx +++ b/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx @@ -24,6 +24,7 @@ import { SecureSocksProxySettings, useStyles2, Divider, Stack } from '@grafana/u import { QuerySettings } from './QuerySettings'; import { ServiceGraphSettings } from './ServiceGraphSettings'; import { StreamingSection } from './StreamingSection'; +import { TagLimitSection } from './TagLimitSettings'; import { TraceQLSearchSettings } from './TraceQLSearchSettings'; export type ConfigEditorProps = DataSourcePluginOptionsEditorProps; @@ -118,6 +119,8 @@ const ConfigEditor = ({ options, onOptionsChange }: ConfigEditorProps) => { + + diff --git a/public/app/plugins/datasource/tempo/configuration/TagLimitSettings.tsx b/public/app/plugins/datasource/tempo/configuration/TagLimitSettings.tsx new file mode 100644 index 00000000000..edda2b69462 --- /dev/null +++ b/public/app/plugins/datasource/tempo/configuration/TagLimitSettings.tsx @@ -0,0 +1,71 @@ +import { css } from '@emotion/css'; + +import { + DataSourceJsonData, + DataSourcePluginOptionsEditorProps, + GrafanaTheme2, + updateDatasourcePluginJsonDataOption, +} from '@grafana/data'; +import { ConfigDescriptionLink, ConfigSubSection } from '@grafana/experimental'; +import { InlineField, InlineFieldRow, Input, useStyles2 } from '@grafana/ui'; + +export interface TagLimitOptions extends DataSourceJsonData { + tagLimit?: number; +} + +interface Props extends DataSourcePluginOptionsEditorProps {} + +export default function TagLimitSettings({ options, onOptionsChange }: Props) { + const styles = useStyles2(getStyles); + + return ( +
+ + + + updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'tagLimit', v.currentTarget.value) + } + value={options.jsonData.tagLimit || ''} + width={40} + /> + + +
+ ); +} + +export const TagLimitSection = ({ options, onOptionsChange }: DataSourcePluginOptionsEditorProps) => { + return ( + + } + > + + + ); +}; + +const getStyles = (theme: GrafanaTheme2) => ({ + infoText: css({ + label: 'infoText', + paddingBottom: theme.spacing(2), + color: theme.colors.text.secondary, + }), + row: css({ + label: 'row', + alignItems: 'baseline', + }), +}); diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts index 8d8b0a3e5ee..603e33f1a4c 100644 --- a/public/app/plugins/datasource/tempo/datasource.ts +++ b/public/app/plugins/datasource/tempo/datasource.ts @@ -37,6 +37,7 @@ import { BarGaugeDisplayMode, TableCellDisplayMode, VariableFormatID } from '@gr import { generateQueryFromAdHocFilters, getTagWithoutScope, interpolateFilters } from './SearchTraceQLEditor/utils'; import { TempoVariableQuery, TempoVariableQueryType } from './VariableQueryEditor'; import { PrometheusDatasource, PromQuery } from './_importedDependencies/datasources/prometheus/types'; +import { TagLimitOptions } from './configuration/TagLimitSettings'; import { SearchTableType, TraceqlFilter, TraceqlSearchScope } from './dataquery.gen'; import { defaultTableFilter, @@ -109,6 +110,7 @@ export class TempoDatasource extends DataSourceWithBackend, + public instanceSettings: DataSourceInstanceSettings, private readonly templateSrv: TemplateSrv = getTemplateSrv() ) { super(instanceSettings); diff --git a/public/app/plugins/datasource/tempo/language_provider.ts b/public/app/plugins/datasource/tempo/language_provider.ts index 0691d9b5a83..63639645ef1 100644 --- a/public/app/plugins/datasource/tempo/language_provider.ts +++ b/public/app/plugins/datasource/tempo/language_provider.ts @@ -14,6 +14,12 @@ import { TempoDatasource } from './datasource'; import { intrinsicsV1 } from './traceql/traceql'; import { Scope } from './types'; +// Limit maximum tags retrieved from the backend +export const TAGS_LIMIT = 5000; + +// Limit maximum options in select dropdowns +export const OPTIONS_LIMIT = 1000; + export default class TempoLanguageProvider extends LanguageProvider { datasource: TempoDatasource; tagsV1?: string[]; @@ -40,10 +46,14 @@ export default class TempoLanguageProvider extends LanguageProvider { return this.startTask; }; + getTagsLimit = () => { + return this.datasource.instanceSettings.jsonData?.tagLimit || TAGS_LIMIT; + }; + async fetchTags() { let v1Resp, v2Resp; try { - v2Resp = await this.request('/api/v2/search/tags', []); + v2Resp = await this.request('/api/v2/search/tags', { limit: this.getTagsLimit() }); } catch (error) { v1Resp = await this.request('/api/search/tags', []); } @@ -150,7 +160,9 @@ export default class TempoLanguageProvider extends LanguageProvider { const encodedTag = this.encodeTag(tag); const response = await this.request( `/api/v2/search/tag/${encodedTag}/values`, - query ? { q: getTemplateSrv().replace(query, {}, VariableFormatID.Pipe) } : {} + query + ? { q: getTemplateSrv().replace(query, {}, VariableFormatID.Pipe), limit: this.getTagsLimit() } + : { limit: this.getTagsLimit() } ); let options: Array> = []; if (response && response.tagValues) { diff --git a/public/app/plugins/datasource/tempo/types.ts b/public/app/plugins/datasource/tempo/types.ts index c671a1bf15a..de6c050fb6c 100644 --- a/public/app/plugins/datasource/tempo/types.ts +++ b/public/app/plugins/datasource/tempo/types.ts @@ -16,6 +16,7 @@ export interface TempoJsonData extends DataSourceJsonData { spanBar?: { tag: string; }; + tagLimit?: number; traceQuery?: { timeShiftEnabled?: boolean; spanStartTimeShift?: string;