Tempo: Fix service graph menu item links (#75748)

* Only call preventDefault if it exists

* Change "View Traces" link to use traceQLSearch instead of the deprecated nativeSearch

* Thank you again test. Update tests

* Update test

* Update betterer

* Type fix

* Small type change

* Update betterer
This commit is contained in:
Andre Pereira 2023-10-09 14:22:39 +01:00 committed by GitHub
parent 4be6a8df78
commit 8bf914ac0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 96 additions and 37 deletions

View File

@ -7027,11 +7027,10 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "10"],
[0, 0, 0, "Do not use any type assertions.", "11"],
[0, 0, 0, "Do not use any type assertions.", "12"],
[0, 0, 0, "Do not use any type assertions.", "13"],
[0, 0, 0, "Unexpected any. Specify a different type.", "13"],
[0, 0, 0, "Unexpected any. Specify a different type.", "14"],
[0, 0, 0, "Unexpected any. Specify a different type.", "15"],
[0, 0, 0, "Unexpected any. Specify a different type.", "16"],
[0, 0, 0, "Unexpected any. Specify a different type.", "17"]
[0, 0, 0, "Unexpected any. Specify a different type.", "16"]
],
"public/app/plugins/datasource/tempo/language_provider.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]

View File

@ -34,7 +34,7 @@ export interface TempoQuery extends common.DataQuery {
/**
* TraceQL query or trace ID
*/
query: string;
query?: string;
/**
* @deprecated Logfmt query to filter traces by their tags. Example: http.status_code=200 error=true
*/

View File

@ -109,7 +109,7 @@ type TempoQuery struct {
MinDuration *string `json:"minDuration,omitempty"`
// TraceQL query or trace ID
Query string `json:"query"`
Query *string `json:"query,omitempty"`
// Specify the query flavor
// TODO make this required and give it a default

View File

@ -28,7 +28,11 @@ func (s *Service) getTrace(ctx context.Context, pCtx backend.PluginContext, quer
return nil, err
}
request, err := s.createRequest(ctx, dsInfo, model.Query, query.TimeRange.From.Unix(), query.TimeRange.To.Unix())
if model.Query == nil || *model.Query == "" {
return result, fmt.Errorf("trace id is required")
}
request, err := s.createRequest(ctx, dsInfo, *model.Query, query.TimeRange.From.Unix(), query.TimeRange.To.Unix())
if err != nil {
return result, err
}
@ -50,7 +54,7 @@ func (s *Service) getTrace(ctx context.Context, pCtx backend.PluginContext, quer
}
if resp.StatusCode != http.StatusOK {
result.Error = fmt.Errorf("failed to get trace with id: %s Status: %s Body: %s", model.Query, resp.Status, string(body))
result.Error = fmt.Errorf("failed to get trace with id: %v Status: %s Body: %s", model.Query, resp.Status, string(body))
return result, nil
}

View File

@ -90,7 +90,6 @@ describe('SearchField', () => {
});
const filter: TraceqlFilter = {
id: 'test1',
value: 'old',
valueType: 'string',
tag: 'test-tag',
};

View File

@ -81,6 +81,9 @@ const SearchField = ({
setError,
query,
]);
if (filter.value && options && !options.find((o) => o === filter.value)) {
options.push({ label: filter.value.toString(), value: filter.value.toString(), type: filter.valueType });
}
useEffect(() => {
if (Array.isArray(filter.value) && filter.value.length > 1 && filter.operator !== '=~') {

View File

@ -27,7 +27,7 @@ composableKinds: DataQuery: {
schema: {
#TempoQuery: common.DataQuery & {
// TraceQL query or trace ID
query: string
query?: string
// @deprecated Logfmt query to filter traces by their tags. Example: http.status_code=200 error=true
search?: string
// @deprecated Query traces by service name

View File

@ -31,7 +31,7 @@ export interface TempoQuery extends common.DataQuery {
/**
* TraceQL query or trace ID
*/
query: string;
query?: string;
/**
* @deprecated Logfmt query to filter traces by their tags. Example: http.status_code=200 error=true
*/

View File

@ -539,8 +539,8 @@ describe('Tempo service graph view', () => {
expect(response.data[0].fields[6].config.links[0].url).toBe('');
expect(response.data[0].fields[6].config.links[0].title).toBe('Tempo');
expect(response.data[0].fields[6].config.links[0].internal.query.queryType).toBe('nativeSearch');
expect(response.data[0].fields[6].config.links[0].internal.query.spanName).toBe('${__data.fields[0]}');
expect(response.data[0].fields[6].config.links[0].internal.query.queryType).toBe('traceqlSearch');
expect(response.data[0].fields[6].config.links[0].internal.query.filters[0].value).toBe('${__data.fields[0]}');
// Service graph
expect(response.data[1].name).toBe('Nodes');
@ -683,8 +683,18 @@ describe('Tempo service graph view', () => {
title: 'View traces',
internal: {
query: {
queryType: 'nativeSearch',
serviceName: '${__data.fields.target}',
refId: 'A',
queryType: 'traceqlSearch',
filters: [
{
id: 'service-name',
operator: '=',
scope: 'resource',
tag: 'service.name',
value: '${__data.fields.target}',
valueType: 'string',
},
],
},
datasourceUid: 'EbPO1fYnz',
datasourceName: '',
@ -764,8 +774,18 @@ describe('Tempo service graph view', () => {
title: 'View traces',
internal: {
query: {
queryType: 'nativeSearch',
serviceName: '${__data.fields.target}',
queryType: 'traceqlSearch',
refId: 'A',
filters: [
{
id: 'service-name',
operator: '=',
scope: 'resource',
tag: 'service.name',
value: '${__data.fields.target}',
valueType: 'string',
},
],
},
datasourceUid: 'EbPO1fYnz',
datasourceName: '',
@ -842,8 +862,18 @@ describe('Tempo service graph view', () => {
title: 'Tempo',
internal: {
query: {
queryType: 'nativeSearch',
spanName: '"${__data.fields[0]}"',
queryType: 'traceqlSearch',
refId: 'A',
filters: [
{
id: 'span-name',
operator: '=',
scope: 'span',
tag: 'name',
value: '"${__data.fields[0]}"',
valueType: 'string',
},
],
},
datasourceUid: 'gdev-tempo',
datasourceName: 'Tempo',
@ -1169,8 +1199,18 @@ const serviceGraphLinks = [
title: 'View traces',
internal: {
query: {
queryType: 'nativeSearch',
serviceName: '${__data.fields[0]}',
refId: 'A',
queryType: 'traceqlSearch',
filters: [
{
id: 'service-name',
operator: '=',
scope: 'resource',
tag: 'service.name',
value: '${__data.fields[0]}',
valueType: 'string',
},
],
} as TempoQuery,
datasourceUid: 'gdev-tempo',
datasourceName: 'Tempo',

View File

@ -1,4 +1,4 @@
import { identity, pick, pickBy, groupBy, startCase } from 'lodash';
import { groupBy, identity, pick, pickBy, startCase } from 'lodash';
import { EMPTY, from, lastValueFrom, merge, Observable, of, throwError } from 'rxjs';
import { catchError, concatMap, map, mergeMap, toArray } from 'rxjs/operators';
import semver from 'semver';
@ -20,13 +20,13 @@ import {
ScopedVars,
} from '@grafana/data';
import {
config,
BackendSrvRequest,
config,
DataSourceWithBackend,
getBackendSrv,
getTemplateSrv,
reportInteraction,
TemplateSrv,
getTemplateSrv,
} from '@grafana/runtime';
import { BarGaugeDisplayMode, TableCellDisplayMode, VariableFormatID } from '@grafana/schema';
import { NodeGraphOptions } from 'app/core/components/NodeGraphSettings';
@ -43,27 +43,27 @@ import { generateQueryFromFilters } from './SearchTraceQLEditor/utils';
import { TempoVariableQuery, TempoVariableQueryType } from './VariableQueryEditor';
import { TraceqlFilter, TraceqlSearchScope } from './dataquery.gen';
import {
defaultTableFilter,
durationMetric,
errorRateMetric,
failedMetric,
histogramMetric,
mapPromMetricsToServiceMap,
rateMetric,
serviceMapMetrics,
totalsMetric,
rateMetric,
durationMetric,
errorRateMetric,
defaultTableFilter,
} from './graphTransform';
import TempoLanguageProvider from './language_provider';
import { createTableFrameFromMetricsSummaryQuery, emptyResponse, MetricsSummary } from './metricsSummary';
import {
createTableFrameFromSearch,
transformFromOTLP as transformFromOTEL,
transformTrace,
transformTraceList,
transformFromOTLP as transformFromOTEL,
createTableFrameFromSearch,
formatTraceQLResponse,
} from './resultTransformer';
import { doTempoChannelStream } from './streaming';
import { SearchQueryParams, TempoQuery, TempoJsonData } from './types';
import { SearchQueryParams, TempoJsonData, TempoQuery } from './types';
import { getErrorMessage } from './utils';
import { TempoVariableSupport } from './variables';
@ -608,7 +608,7 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
handleTraceIdQuery(options: DataQueryRequest<TempoQuery>, targets: TempoQuery[]): Observable<DataQueryResponse> {
const validTargets = targets
.filter((t) => t.query)
.map((t): TempoQuery => ({ ...t, query: t.query.trim(), queryType: 'traceId' }));
.map((t): TempoQuery => ({ ...t, query: t.query?.trim(), queryType: 'traceId' }));
if (!validTargets.length) {
return EMPTY;
}
@ -713,7 +713,7 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
}
return result.join(', ');
}
return query.query;
return query.query ?? '';
}
buildSearchQuery(query: TempoQuery, timeRange?: { startTime: number; endTime?: number }): SearchQueryParams {
@ -1025,12 +1025,26 @@ export function getFieldConfig(
}
export function makeTempoLink(title: string, serviceName: string, spanName: string, datasourceUid: string) {
let query = { queryType: 'nativeSearch' } as TempoQuery;
let query: TempoQuery = { refId: 'A', queryType: 'traceqlSearch', filters: [] };
if (serviceName !== '') {
query.serviceName = serviceName;
query.filters.push({
id: 'service-name',
scope: TraceqlSearchScope.Resource,
tag: 'service.name',
value: serviceName,
operator: '=',
valueType: 'string',
});
}
if (spanName !== '') {
query.spanName = spanName;
query.filters.push({
id: 'span-name',
scope: TraceqlSearchScope.Span,
tag: 'name',
value: spanName,
operator: '=',
valueType: 'string',
});
}
return {

View File

@ -31,7 +31,7 @@ export function QueryEditor(props: Props) {
</InlineLabel>
<TraceQLEditor
placeholder="Enter a TraceQL query or trace ID (run with Shift+Enter)"
value={query.query}
value={query.query || ''}
onChange={onEditorChange}
datasource={props.datasource}
onRunQuery={props.onRunQuery}

View File

@ -86,6 +86,6 @@ export const onDashboardLoadedHandler = ({
}
};
const hasTemplateVariables = (val: string): boolean => {
const hasTemplateVariables = (val?: string): boolean => {
return getTemplateSrv().containsTemplate(val);
};