Tempo: TraceQL editor bug fixes (#60414)

* Set width of common columns between trace and span rows

* Better syntax highlighting for non string constants

* Apply variables to traceql query

* Fix test
This commit is contained in:
Andre Pereira 2023-01-02 14:23:50 +00:00 committed by GitHub
parent b179ac91a2
commit 950f357175
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 66 additions and 20 deletions

View File

@ -13,7 +13,13 @@ import {
MutableDataFrame,
PluginType,
} from '@grafana/data';
import { BackendDataSourceResponse, FetchResponse, setBackendSrv, setDataSourceSrv } from '@grafana/runtime';
import {
BackendDataSourceResponse,
FetchResponse,
setBackendSrv,
setDataSourceSrv,
TemplateSrv,
} from '@grafana/runtime';
import config from 'app/core/config';
import {
@ -49,7 +55,8 @@ describe('Tempo data source', () => {
beforeEach(() => (console.error = consoleErrorMock));
it('returns empty response when traceId is empty', async () => {
const ds = new TempoDatasource(defaultSettings);
const templateSrv: TemplateSrv = { replace: jest.fn() } as unknown as TemplateSrv;
const ds = new TempoDatasource(defaultSettings, templateSrv);
const response = await lastValueFrom(
ds.query({ targets: [{ refId: 'refid1', queryType: 'traceql', query: '' } as Partial<TempoQuery>] } as any),
{ defaultValue: 'empty' }

View File

@ -175,7 +175,8 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
}
if (targets.traceql?.length) {
try {
const queryValue = targets.traceql[0].query;
const appliedQuery = this.applyVariables(targets.traceql[0], options.scopedVars);
const queryValue = appliedQuery?.query || '';
const hexOnlyRegex = /^[0-9A-Fa-f]*$/;
// Check whether this is a trace ID or traceQL query by checking if it only contains hex characters
if (queryValue.trim().match(hexOnlyRegex)) {

View File

@ -131,15 +131,15 @@ describe('createTableFrameFromTraceQlQuery()', () => {
expect(frame.fields[0].values.get(0)).toBe('b1586c3c8c34d');
expect(frame.fields[0].config.unit).toBe('string');
expect(frame.fields[0].values).toBeInstanceOf(ArrayVector);
// Trace name field
expect(frame.fields[1].name).toBe('traceName');
expect(frame.fields[1].type).toBe('string');
expect(frame.fields[1].values.get(0)).toBe('lb HTTP Client');
expect(frame.fields[1].values).toBeInstanceOf(ArrayVector);
// Start time field
expect(frame.fields[2].name).toBe('startTime');
expect(frame.fields[1].name).toBe('startTime');
expect(frame.fields[1].type).toBe('string');
expect(frame.fields[1].values.get(1)).toBe('2022-01-27 22:56:06');
expect(frame.fields[1].values).toBeInstanceOf(ArrayVector);
// Trace name field
expect(frame.fields[2].name).toBe('traceName');
expect(frame.fields[2].type).toBe('string');
expect(frame.fields[2].values.get(1)).toBe('2022-01-27 22:56:06');
expect(frame.fields[2].values.get(0)).toBe('lb HTTP Client');
expect(frame.fields[2].values).toBeInstanceOf(ArrayVector);
// Duration field
expect(frame.fields[3].name).toBe('traceDuration');

View File

@ -630,6 +630,9 @@ export function createTableFrameFromTraceQlQuery(
config: {
unit: 'string',
displayNameFromDS: 'Trace ID',
custom: {
width: 200,
},
links: [
{
title: 'Trace: ${__value.raw}',
@ -646,9 +649,28 @@ export function createTableFrameFromTraceQlQuery(
],
},
},
{
name: 'startTime',
type: FieldType.string,
config: {
displayNameFromDS: 'Start time',
custom: {
width: 200,
},
},
},
{ name: 'traceName', type: FieldType.string, config: { displayNameFromDS: 'Name' } },
{ name: 'startTime', type: FieldType.string, config: { displayNameFromDS: 'Start time' } },
{ name: 'traceDuration', type: FieldType.number, config: { displayNameFromDS: 'Duration', unit: 'ms' } },
{
name: 'traceDuration',
type: FieldType.number,
config: {
displayNameFromDS: 'Duration',
unit: 'ms',
custom: {
width: 120,
},
},
},
],
meta: {
preferredVisualisationType: 'table',
@ -710,6 +732,9 @@ const traceSubFrame = (
config: {
unit: 'string',
displayNameFromDS: 'Span ID',
custom: {
width: 200,
},
links: [
{
title: 'Span: ${__value.raw}',
@ -731,21 +756,32 @@ const traceSubFrame = (
],
},
},
{
name: 'spanStartTime',
type: FieldType.string,
config: {
displayNameFromDS: 'Start time',
custom: {
width: 200,
},
},
},
{
name: 'name',
type: FieldType.string,
config: { displayNameFromDS: 'Name', custom: { hidden: !hasNameAttribute } },
},
{
name: 'spanStartTime',
type: FieldType.string,
config: { displayNameFromDS: 'Start time' },
},
...Object.values(spanDynamicAttrs),
{
name: 'duration',
type: FieldType.number,
config: { displayNameFromDS: 'Duration', unit: 'ns' },
config: {
displayNameFromDS: 'Duration',
unit: 'ns',
custom: {
width: 120,
},
},
},
],
meta: {

View File

@ -26,9 +26,9 @@ const intrinsics = ['duration', 'name', 'status', 'parent'];
const scopes: string[] = ['resource', 'span'];
const booleans = ['false', 'true'];
const keywords = intrinsics.concat(scopes);
const keywords = intrinsics.concat(scopes).concat(booleans);
const statusValues = ['ok', 'unset', 'error', 'false', 'true'];
export const language = {
ignoreCase: false,
@ -37,6 +37,7 @@ export const language = {
keywords,
operators,
statusValues,
// we include these common regular expressions
symbols: /[=><!~?:&|+\-*\/^%]+/,
@ -62,6 +63,7 @@ export const language = {
{
cases: {
'@keywords': 'type',
'@statusValues': 'type.identifier',
'@default': 'identifier',
},
},