From 209b1848b8602805fbf74f139335ac3cba3ea8c9 Mon Sep 17 00:00:00 2001 From: Andre Pereira Date: Tue, 13 Dec 2022 13:27:45 +0000 Subject: [PATCH] Tempo: Merge Trace ID and TraceQL tabs (#60180) * Remove TraceID tab when TraceQL is enabled. Use TraceQL editor to query for trace IDs by checking whether the content is an hex only string * Highlight valid trace IDs in traceql editor * Update trace and span links to use TraceQL tab when feature flag is enabled * Remove traceqlEditor feature flag. * Remove traceId query type from Tempo and replace it with traceQl --- .../feature-toggles/index.md | 1 - .../src/types/featureToggles.gen.ts | 1 - pkg/services/featuremgmt/registry.go | 5 -- pkg/services/featuremgmt/toggles_gen.go | 4 -- .../prometheus/result_transformer.ts | 2 +- .../tempo/QueryEditor/QueryField.tsx | 34 ++-------- .../datasource/tempo/datasource.test.ts | 8 +-- .../plugins/datasource/tempo/datasource.ts | 68 ++++++++++--------- .../datasource/tempo/resultTransformer.ts | 6 +- .../datasource/tempo/traceql/QueryEditor.tsx | 2 +- .../datasource/tempo/traceql/traceql.ts | 3 + public/app/plugins/datasource/tempo/types.ts | 2 +- 12 files changed, 53 insertions(+), 83 deletions(-) diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index 29e47a4363f..466ab33bea1 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -79,7 +79,6 @@ Alpha features might be changed or removed without prior notice. | `logRequestsInstrumentedAsUnknown` | Logs the path for requests that are instrumented as unknown | | `dataConnectionsConsole` | Enables a new top-level page called Connections. This page is an experiment that provides a better experience when you install and configure data sources and other plugins. | | `topnav` | New top nav and page layouts | -| `traceqlEditor` | Show the TraceQL editor in the explore page | | `flameGraph` | Show the flame graph | | `cloudWatchCrossAccountQuerying` | Use cross-account querying in CloudWatch datasource | | `redshiftAsyncQueryDataSupport` | Enable async query data support for Redshift | diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 9a18e56a2f7..6ec6bbeb3f2 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -66,7 +66,6 @@ export interface FeatureToggles { topnav?: boolean; grpcServer?: boolean; entityStore?: boolean; - traceqlEditor?: boolean; flameGraph?: boolean; cloudWatchCrossAccountQuerying?: boolean; redshiftAsyncQueryDataSupport?: boolean; diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index a1e32e71845..2d0480ec8f9 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -287,11 +287,6 @@ var ( State: FeatureStateAlpha, RequiresDevMode: true, }, - { - Name: "traceqlEditor", - Description: "Show the TraceQL editor in the explore page", - State: FeatureStateAlpha, - }, { Name: "flameGraph", Description: "Show the flame graph", diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 1c9e39d678d..0930a7bf511 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -207,10 +207,6 @@ const ( // SQL-based entity store (requires storage flag also) FlagEntityStore = "entityStore" - // FlagTraceqlEditor - // Show the TraceQL editor in the explore page - FlagTraceqlEditor = "traceqlEditor" - // FlagFlameGraph // Show the flame graph FlagFlameGraph = "flameGraph" diff --git a/public/app/plugins/datasource/prometheus/result_transformer.ts b/public/app/plugins/datasource/prometheus/result_transformer.ts index 875d65dc1f2..9e4159b3b6e 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.ts @@ -354,7 +354,7 @@ function getDataLinks(options: ExemplarTraceIdDestination): DataLink[] { title: options.urlDisplayLabel || `Query with ${dsSettings?.name}`, url: '', internal: { - query: { query: '${__value.raw}', queryType: 'traceId' }, + query: { query: '${__value.raw}', queryType: 'traceql' }, datasourceUid: options.datasourceUid, datasourceName: dsSettings?.name ?? 'Data source not found', }, diff --git a/public/app/plugins/datasource/tempo/QueryEditor/QueryField.tsx b/public/app/plugins/datasource/tempo/QueryEditor/QueryField.tsx index 9903838ee4c..1648378760e 100644 --- a/public/app/plugins/datasource/tempo/QueryEditor/QueryField.tsx +++ b/public/app/plugins/datasource/tempo/QueryEditor/QueryField.tsx @@ -3,13 +3,12 @@ import React from 'react'; import useAsync from 'react-use/lib/useAsync'; import { QueryEditorProps, SelectableValue } from '@grafana/data'; -import { config, reportInteraction } from '@grafana/runtime'; +import { reportInteraction } from '@grafana/runtime'; import { FileDropzone, InlineField, InlineFieldRow, InlineLabel, - QueryField, RadioButtonGroup, Themeable2, withTheme2, @@ -28,7 +27,7 @@ import { getDS } from './utils'; interface Props extends QueryEditorProps, Themeable2 {} -const DEFAULT_QUERY_TYPE: TempoQueryType = 'traceId'; +const DEFAULT_QUERY_TYPE: TempoQueryType = 'traceql'; class TempoQueryFieldComponent extends React.PureComponent { constructor(props: Props) { @@ -77,8 +76,8 @@ class TempoQueryFieldComponent extends React.PureComponent { const graphDatasourceUid = datasource.serviceMap?.datasourceUid; - const queryTypeOptions: Array> = [ - { value: 'traceId', label: 'TraceID' }, + let queryTypeOptions: Array> = [ + { value: 'traceql', label: 'TraceQL' }, { value: 'upload', label: 'JSON File' }, { value: 'serviceMap', label: 'Service Graph' }, ]; @@ -97,10 +96,6 @@ class TempoQueryFieldComponent extends React.PureComponent { } } - if (config.featureToggles.traceqlEditor) { - queryTypeOptions.push({ value: 'traceql', label: 'TraceQL' }); - } - return ( <> @@ -155,27 +150,6 @@ class TempoQueryFieldComponent extends React.PureComponent { /> )} - {query.queryType === 'traceId' && ( - - - { - onChange({ - ...query, - query: val, - queryType: 'traceId', - linkedQuery: undefined, - }); - }} - onBlur={this.props.onBlur} - onRunQuery={this.props.onRunQuery} - placeholder={'Enter a Trace ID (run with Shift+Enter)'} - portalOrigin="tempo" - /> - - - )} {query.queryType === 'serviceMap' && ( )} diff --git a/public/app/plugins/datasource/tempo/datasource.test.ts b/public/app/plugins/datasource/tempo/datasource.test.ts index c49876edafe..49fd3e93362 100644 --- a/public/app/plugins/datasource/tempo/datasource.test.ts +++ b/public/app/plugins/datasource/tempo/datasource.test.ts @@ -51,7 +51,7 @@ describe('Tempo data source', () => { it('returns empty response when traceId is empty', async () => { const ds = new TempoDatasource(defaultSettings); const response = await lastValueFrom( - ds.query({ targets: [{ refId: 'refid1', queryType: 'traceId', query: '' } as Partial] } as any), + ds.query({ targets: [{ refId: 'refid1', queryType: 'traceql', query: '' } as Partial] } as any), { defaultValue: 'empty' } ); expect(response).toBe('empty'); @@ -61,7 +61,7 @@ describe('Tempo data source', () => { function getQuery(): TempoQuery { return { refId: 'x', - queryType: 'traceId', + queryType: 'traceql', linkedQuery: { refId: 'linked', expr: '{instance="$interpolationVar"}', @@ -388,7 +388,7 @@ describe('Tempo data source', () => { raw: { from: '15m', to: 'now' }, }, }, - [{ refId: 'refid1', queryType: 'traceId', query: '' } as TempoQuery] + [{ refId: 'refid1', queryType: 'traceql', query: '' } as TempoQuery] ); expect(request.range.from.unix()).toBe(dateTime(new Date(2022, 8, 13, 15, 58, 0, 0)).unix()); @@ -417,7 +417,7 @@ describe('Tempo data source', () => { raw: { from: '15m', to: 'now' }, }, }, - [{ refId: 'refid1', queryType: 'traceId', query: '' } as TempoQuery] + [{ refId: 'refid1', queryType: 'traceql', query: '' } as TempoQuery] ); expect(request.range.from.unix()).toBe(dateTime(0).unix()); diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts index 733b7fe23d3..98fbcc84fb4 100644 --- a/public/app/plugins/datasource/tempo/datasource.ts +++ b/public/app/plugins/datasource/tempo/datasource.ts @@ -95,7 +95,7 @@ export class TempoDatasource extends DataSourceWithBackend): Observable { const subQueries: Array> = []; const filteredTargets = options.targets.filter((target) => !target.hide); - const targets: { [type: string]: TempoQuery[] } = groupBy(filteredTargets, (t) => t.queryType || 'traceId'); + const targets: { [type: string]: TempoQuery[] } = groupBy(filteredTargets, (t) => t.queryType || 'traceql'); if (targets.clear) { return of({ data: [], state: LoadingState.Done }); @@ -175,28 +175,42 @@ export class TempoDatasource extends DataSourceWithBackend { - return { - data: createTableFrameFromTraceQlQuery(response.data.traces, this.instanceSettings), - }; - }), - catchError((error) => { - return of({ error: { message: error.data.message }, data: [] }); - }) - ) - ); + subQueries.push(this.handleTraceIdQuery(options, targets.traceql)); + } else { + reportInteraction('grafana_traces_traceql_queried', { + datasourceType: 'tempo', + app: options.app ?? '', + query: queryValue ?? '', + }); + subQueries.push( + this._request('/api/search', { + q: queryValue, + limit: options.targets[0].limit, + start: options.range.from.unix(), + end: options.range.to.unix(), + }).pipe( + map((response) => { + return { + data: createTableFrameFromTraceQlQuery(response.data.traces, this.instanceSettings), + }; + }), + catchError((error) => { + return of({ error: { message: error.data.message }, data: [] }); + }) + ) + ); + } } catch (error) { return of({ error: { message: error instanceof Error ? error.message : 'Unknown error occurred' }, data: [] }); } @@ -250,16 +264,6 @@ export class TempoDatasource extends DataSourceWithBackend 0) { - reportInteraction('grafana_traces_traceID_queried', { - datasourceType: 'tempo', - app: options.app ?? '', - query: targets.traceId[0].query ?? '', - }); - - subQueries.push(this.handleTraceIdQuery(options, targets.traceId)); - } - return merge(...subQueries); } diff --git a/public/app/plugins/datasource/tempo/resultTransformer.ts b/public/app/plugins/datasource/tempo/resultTransformer.ts index 4aa8c6fbb4c..25c83da1b1f 100644 --- a/public/app/plugins/datasource/tempo/resultTransformer.ts +++ b/public/app/plugins/datasource/tempo/resultTransformer.ts @@ -567,7 +567,7 @@ export function createTableFrameFromSearch(data: TraceSearchMetadata[], instance datasourceName: instanceSettings.name, query: { query: '${__value.raw}', - queryType: 'traceId', + queryType: 'traceql', }, }, }, @@ -639,7 +639,7 @@ export function createTableFrameFromTraceQlQuery( datasourceName: instanceSettings.name, query: { query: '${__value.raw}', - queryType: 'traceId', + queryType: 'traceql', }, }, }, @@ -719,7 +719,7 @@ const traceSubFrame = ( datasourceName: instanceSettings.name, query: { query: '${__data.fields.traceIdHidden}', - queryType: 'traceId', + queryType: 'traceql', }, panelsState: { trace: { diff --git a/public/app/plugins/datasource/tempo/traceql/QueryEditor.tsx b/public/app/plugins/datasource/tempo/traceql/QueryEditor.tsx index f950c630045..55f77ac41c0 100644 --- a/public/app/plugins/datasource/tempo/traceql/QueryEditor.tsx +++ b/public/app/plugins/datasource/tempo/traceql/QueryEditor.tsx @@ -34,7 +34,7 @@ export function QueryEditor(props: Props) { |<|>=|<=|=~|!~))/, 'tag'], + //trace ID + [/^\s*[0-9A-Fa-f]+\s*$/, 'tag'], + // all keywords have the same color [ /[a-zA-Z_.]\w*/, diff --git a/public/app/plugins/datasource/tempo/types.ts b/public/app/plugins/datasource/tempo/types.ts index 0f1e88fbb2a..1afea44df28 100644 --- a/public/app/plugins/datasource/tempo/types.ts +++ b/public/app/plugins/datasource/tempo/types.ts @@ -37,7 +37,7 @@ export interface TempoJsonData extends DataSourceJsonData { } // search = Loki search, nativeSearch = Tempo search for backwards compatibility -export type TempoQueryType = 'traceql' | 'search' | 'traceId' | 'serviceMap' | 'upload' | 'nativeSearch' | 'clear'; +export type TempoQueryType = 'traceql' | 'search' | 'serviceMap' | 'upload' | 'nativeSearch' | 'clear'; export interface TempoQuery extends DataQuery { query: string;