mirror of
https://github.com/grafana/grafana.git
synced 2024-11-27 03:11:01 -06:00
Tempo: TraceQL results as a spans list (#75660)
* Format tempo search results as spans * Thank you test
This commit is contained in:
parent
c08606d2c5
commit
1ce603b9e9
@ -59,6 +59,10 @@ export interface TempoQuery extends common.DataQuery {
|
|||||||
* Defines the maximum number of spans per spanset that are returned from Tempo
|
* Defines the maximum number of spans per spanset that are returned from Tempo
|
||||||
*/
|
*/
|
||||||
spss?: number;
|
spss?: number;
|
||||||
|
/**
|
||||||
|
* The type of the table that is used to display the search results
|
||||||
|
*/
|
||||||
|
tableType?: SearchTableType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultTempoQuery: Partial<TempoQuery> = {
|
export const defaultTempoQuery: Partial<TempoQuery> = {
|
||||||
@ -81,6 +85,14 @@ export enum SearchStreamingState {
|
|||||||
Streaming = 'streaming',
|
Streaming = 'streaming',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the table that is used to display the search results
|
||||||
|
*/
|
||||||
|
export enum SearchTableType {
|
||||||
|
Spans = 'spans',
|
||||||
|
Traces = 'traces',
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* static fields are pre-set in the UI, dynamic fields are added by the user
|
* static fields are pre-set in the UI, dynamic fields are added by the user
|
||||||
*/
|
*/
|
||||||
|
@ -17,6 +17,12 @@ const (
|
|||||||
SearchStreamingStateStreaming SearchStreamingState = "streaming"
|
SearchStreamingStateStreaming SearchStreamingState = "streaming"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Defines values for SearchTableType.
|
||||||
|
const (
|
||||||
|
SearchTableTypeSpans SearchTableType = "spans"
|
||||||
|
SearchTableTypeTraces SearchTableType = "traces"
|
||||||
|
)
|
||||||
|
|
||||||
// Defines values for TempoQueryType.
|
// Defines values for TempoQueryType.
|
||||||
const (
|
const (
|
||||||
TempoQueryTypeClear TempoQueryType = "clear"
|
TempoQueryTypeClear TempoQueryType = "clear"
|
||||||
@ -65,6 +71,9 @@ type DataQuery struct {
|
|||||||
// The state of the TraceQL streaming search query
|
// The state of the TraceQL streaming search query
|
||||||
type SearchStreamingState string
|
type SearchStreamingState string
|
||||||
|
|
||||||
|
// The type of the table that is used to display the search results
|
||||||
|
type SearchTableType string
|
||||||
|
|
||||||
// TempoDataQuery defines model for TempoDataQuery.
|
// TempoDataQuery defines model for TempoDataQuery.
|
||||||
type TempoDataQuery = map[string]any
|
type TempoDataQuery = map[string]any
|
||||||
|
|
||||||
@ -128,6 +137,9 @@ type TempoQuery struct {
|
|||||||
|
|
||||||
// Defines the maximum number of spans per spanset that are returned from Tempo
|
// Defines the maximum number of spans per spanset that are returned from Tempo
|
||||||
Spss *int64 `json:"spss,omitempty"`
|
Spss *int64 `json:"spss,omitempty"`
|
||||||
|
|
||||||
|
// The type of the table that is used to display the search results
|
||||||
|
TableType *SearchTableType `json:"tableType,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TempoQueryType search = Loki search, nativeSearch = Tempo search for backwards compatibility
|
// TempoQueryType search = Loki search, nativeSearch = Tempo search for backwards compatibility
|
||||||
|
@ -49,6 +49,8 @@ composableKinds: DataQuery: {
|
|||||||
filters: [...#TraceqlFilter]
|
filters: [...#TraceqlFilter]
|
||||||
// Filters that are used to query the metrics summary
|
// Filters that are used to query the metrics summary
|
||||||
groupBy?: [...#TraceqlFilter]
|
groupBy?: [...#TraceqlFilter]
|
||||||
|
// The type of the table that is used to display the search results
|
||||||
|
tableType?: #SearchTableType
|
||||||
} @cuetsy(kind="interface") @grafana(TSVeneer="type")
|
} @cuetsy(kind="interface") @grafana(TSVeneer="type")
|
||||||
|
|
||||||
// search = Loki search, nativeSearch = Tempo search for backwards compatibility
|
// search = Loki search, nativeSearch = Tempo search for backwards compatibility
|
||||||
@ -57,6 +59,9 @@ composableKinds: DataQuery: {
|
|||||||
// The state of the TraceQL streaming search query
|
// The state of the TraceQL streaming search query
|
||||||
#SearchStreamingState: "pending" | "streaming" | "done" | "error" @cuetsy(kind="enum")
|
#SearchStreamingState: "pending" | "streaming" | "done" | "error" @cuetsy(kind="enum")
|
||||||
|
|
||||||
|
// The type of the table that is used to display the search results
|
||||||
|
#SearchTableType: "traces" | "spans" @cuetsy(kind="enum")
|
||||||
|
|
||||||
// static fields are pre-set in the UI, dynamic fields are added by the user
|
// static fields are pre-set in the UI, dynamic fields are added by the user
|
||||||
#TraceqlSearchScope: "intrinsic" | "unscoped" | "resource" | "span" @cuetsy(kind="enum")
|
#TraceqlSearchScope: "intrinsic" | "unscoped" | "resource" | "span" @cuetsy(kind="enum")
|
||||||
#TraceqlFilter: {
|
#TraceqlFilter: {
|
||||||
|
@ -56,6 +56,10 @@ export interface TempoQuery extends common.DataQuery {
|
|||||||
* Defines the maximum number of spans per spanset that are returned from Tempo
|
* Defines the maximum number of spans per spanset that are returned from Tempo
|
||||||
*/
|
*/
|
||||||
spss?: number;
|
spss?: number;
|
||||||
|
/**
|
||||||
|
* The type of the table that is used to display the search results
|
||||||
|
*/
|
||||||
|
tableType?: SearchTableType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultTempoQuery: Partial<TempoQuery> = {
|
export const defaultTempoQuery: Partial<TempoQuery> = {
|
||||||
@ -78,6 +82,14 @@ export enum SearchStreamingState {
|
|||||||
Streaming = 'streaming',
|
Streaming = 'streaming',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the table that is used to display the search results
|
||||||
|
*/
|
||||||
|
export enum SearchTableType {
|
||||||
|
Spans = 'spans',
|
||||||
|
Traces = 'traces',
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* static fields are pre-set in the UI, dynamic fields are added by the user
|
* static fields are pre-set in the UI, dynamic fields are added by the user
|
||||||
*/
|
*/
|
||||||
|
@ -60,7 +60,7 @@ import {
|
|||||||
transformTraceList,
|
transformTraceList,
|
||||||
transformFromOTLP as transformFromOTEL,
|
transformFromOTLP as transformFromOTEL,
|
||||||
createTableFrameFromSearch,
|
createTableFrameFromSearch,
|
||||||
createTableFrameFromTraceQlQuery,
|
formatTraceQLResponse,
|
||||||
} from './resultTransformer';
|
} from './resultTransformer';
|
||||||
import { doTempoChannelStream } from './streaming';
|
import { doTempoChannelStream } from './streaming';
|
||||||
import { SearchQueryParams, TempoQuery, TempoJsonData } from './types';
|
import { SearchQueryParams, TempoQuery, TempoJsonData } from './types';
|
||||||
@ -359,7 +359,11 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
|
|||||||
}).pipe(
|
}).pipe(
|
||||||
map((response) => {
|
map((response) => {
|
||||||
return {
|
return {
|
||||||
data: createTableFrameFromTraceQlQuery(response.data.traces, this.instanceSettings),
|
data: formatTraceQLResponse(
|
||||||
|
response.data.traces,
|
||||||
|
this.instanceSettings,
|
||||||
|
targets.traceql[0].tableType
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
catchError((err) => {
|
catchError((err) => {
|
||||||
@ -413,7 +417,11 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
|
|||||||
}).pipe(
|
}).pipe(
|
||||||
map((response) => {
|
map((response) => {
|
||||||
return {
|
return {
|
||||||
data: createTableFrameFromTraceQlQuery(response.data.traces, this.instanceSettings),
|
data: formatTraceQLResponse(
|
||||||
|
response.data.traces,
|
||||||
|
this.instanceSettings,
|
||||||
|
targets.traceqlSearch[0].tableType
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
catchError((err) => {
|
catchError((err) => {
|
||||||
|
@ -157,7 +157,7 @@ describe('createTableFrameFromTraceQlQuery()', () => {
|
|||||||
expect(frame.fields[5].values[0][0].fields[0].values[0]).toBe('b1586c3c8c34d');
|
expect(frame.fields[5].values[0][0].fields[0].values[0]).toBe('b1586c3c8c34d');
|
||||||
expect(frame.fields[5].values[0][0].fields[1].name).toBe('spanID');
|
expect(frame.fields[5].values[0][0].fields[1].name).toBe('spanID');
|
||||||
expect(frame.fields[5].values[0][0].fields[1].values[0]).toBe('162a4adae63b61f1');
|
expect(frame.fields[5].values[0][0].fields[1].values[0]).toBe('162a4adae63b61f1');
|
||||||
expect(frame.fields[5].values[0][0].fields[2].name).toBe('spanStartTime');
|
expect(frame.fields[5].values[0][0].fields[2].name).toBe('time');
|
||||||
expect(frame.fields[5].values[0][0].fields[2].values[0]).toBe(1666188214303.201);
|
expect(frame.fields[5].values[0][0].fields[2].values[0]).toBe(1666188214303.201);
|
||||||
expect(frame.fields[5].values[0][0].fields[4].name).toBe('http.method');
|
expect(frame.fields[5].values[0][0].fields[4].name).toBe('http.method');
|
||||||
expect(frame.fields[5].values[0][0].fields[4].values[0]).toBe('GET');
|
expect(frame.fields[5].values[0][0].fields[4].values[0]).toBe('GET');
|
||||||
@ -170,7 +170,7 @@ describe('createTableFrameFromTraceQlQuery()', () => {
|
|||||||
expect(frame.fields[5].values[1][0].fields[0].values[0]).toBe('9161e77388f3e');
|
expect(frame.fields[5].values[1][0].fields[0].values[0]).toBe('9161e77388f3e');
|
||||||
expect(frame.fields[5].values[1][0].fields[1].name).toBe('spanID');
|
expect(frame.fields[5].values[1][0].fields[1].name).toBe('spanID');
|
||||||
expect(frame.fields[5].values[1][0].fields[1].values[0]).toBe('3b9a5c222d3ddd8f');
|
expect(frame.fields[5].values[1][0].fields[1].values[0]).toBe('3b9a5c222d3ddd8f');
|
||||||
expect(frame.fields[5].values[1][0].fields[2].name).toBe('spanStartTime');
|
expect(frame.fields[5].values[1][0].fields[2].name).toBe('time');
|
||||||
expect(frame.fields[5].values[1][0].fields[2].values[0]).toBe(1666187875397.7212);
|
expect(frame.fields[5].values[1][0].fields[2].values[0]).toBe(1666187875397.7212);
|
||||||
expect(frame.fields[5].values[1][0].fields[4].name).toBe('by(resource.service.name)');
|
expect(frame.fields[5].values[1][0].fields[4].name).toBe('by(resource.service.name)');
|
||||||
expect(frame.fields[5].values[1][0].fields[4].values[0]).toBe('db');
|
expect(frame.fields[5].values[1][0].fields[4].values[0]).toBe('db');
|
||||||
@ -185,7 +185,7 @@ describe('createTableFrameFromTraceQlQuery()', () => {
|
|||||||
expect(frame.fields[5].values[1][1].fields[0].values[0]).toBe('9161e77388f3e');
|
expect(frame.fields[5].values[1][1].fields[0].values[0]).toBe('9161e77388f3e');
|
||||||
expect(frame.fields[5].values[1][1].fields[1].name).toBe('spanID');
|
expect(frame.fields[5].values[1][1].fields[1].name).toBe('spanID');
|
||||||
expect(frame.fields[5].values[1][1].fields[1].values[0]).toBe('894d90db6b5807f');
|
expect(frame.fields[5].values[1][1].fields[1].values[0]).toBe('894d90db6b5807f');
|
||||||
expect(frame.fields[5].values[1][1].fields[2].name).toBe('spanStartTime');
|
expect(frame.fields[5].values[1][1].fields[2].name).toBe('time');
|
||||||
expect(frame.fields[5].values[1][1].fields[2].values[0]).toBe(1666187875393.293);
|
expect(frame.fields[5].values[1][1].fields[2].values[0]).toBe(1666187875393.293);
|
||||||
expect(frame.fields[5].values[1][1].fields[4].name).toBe('by(resource.service.name)');
|
expect(frame.fields[5].values[1][1].fields[4].name).toBe('by(resource.service.name)');
|
||||||
expect(frame.fields[5].values[1][1].fields[4].values[0]).toBe('app');
|
expect(frame.fields[5].values[1][1].fields[4].values[0]).toBe('app');
|
||||||
|
@ -18,6 +18,7 @@ import {
|
|||||||
createTheme,
|
createTheme,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
|
|
||||||
|
import { SearchTableType } from './dataquery.gen';
|
||||||
import { createGraphFrames } from './graphTransform';
|
import { createGraphFrames } from './graphTransform';
|
||||||
import { Span, SpanAttributes, Spanset, TraceSearchMetadata } from './types';
|
import { Span, SpanAttributes, Spanset, TraceSearchMetadata } from './types';
|
||||||
|
|
||||||
@ -564,6 +565,17 @@ function transformToTraceData(data: TraceSearchMetadata) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatTraceQLResponse(
|
||||||
|
data: TraceSearchMetadata[],
|
||||||
|
instanceSettings: DataSourceInstanceSettings,
|
||||||
|
tableType?: SearchTableType
|
||||||
|
) {
|
||||||
|
if (tableType === SearchTableType.Spans) {
|
||||||
|
return createTableFrameFromTraceQlQueryAsSpans(data, instanceSettings);
|
||||||
|
}
|
||||||
|
return createTableFrameFromTraceQlQuery(data, instanceSettings);
|
||||||
|
}
|
||||||
|
|
||||||
export function createTableFrameFromTraceQlQuery(
|
export function createTableFrameFromTraceQlQuery(
|
||||||
data: TraceSearchMetadata[],
|
data: TraceSearchMetadata[],
|
||||||
instanceSettings: DataSourceInstanceSettings
|
instanceSettings: DataSourceInstanceSettings
|
||||||
@ -660,6 +672,147 @@ export function createTableFrameFromTraceQlQuery(
|
|||||||
return [frame];
|
return [frame];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createTableFrameFromTraceQlQueryAsSpans(
|
||||||
|
data: TraceSearchMetadata[],
|
||||||
|
instanceSettings: DataSourceInstanceSettings
|
||||||
|
): DataFrame[] {
|
||||||
|
const spanDynamicAttrs: Record<string, FieldDTO> = {};
|
||||||
|
let hasNameAttribute = false;
|
||||||
|
|
||||||
|
data.forEach(
|
||||||
|
(t) =>
|
||||||
|
t.spanSets?.forEach((ss) => {
|
||||||
|
ss.attributes?.forEach((attr) => {
|
||||||
|
spanDynamicAttrs[attr.key] = {
|
||||||
|
name: attr.key,
|
||||||
|
type: FieldType.string,
|
||||||
|
config: { displayNameFromDS: attr.key },
|
||||||
|
};
|
||||||
|
});
|
||||||
|
ss.spans.forEach((span) => {
|
||||||
|
if (span.name) {
|
||||||
|
hasNameAttribute = true;
|
||||||
|
}
|
||||||
|
span.attributes?.forEach((attr) => {
|
||||||
|
spanDynamicAttrs[attr.key] = {
|
||||||
|
name: attr.key,
|
||||||
|
type: FieldType.string,
|
||||||
|
config: { displayNameFromDS: attr.key },
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const frame = new MutableDataFrame({
|
||||||
|
name: 'Spans',
|
||||||
|
refId: 'traces',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'traceIdHidden',
|
||||||
|
type: FieldType.string,
|
||||||
|
config: {
|
||||||
|
custom: { hidden: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'traceService',
|
||||||
|
type: FieldType.string,
|
||||||
|
config: {
|
||||||
|
displayNameFromDS: 'Trace Service',
|
||||||
|
custom: {
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'traceName',
|
||||||
|
type: FieldType.string,
|
||||||
|
config: {
|
||||||
|
displayNameFromDS: 'Trace Name',
|
||||||
|
custom: {
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'spanID',
|
||||||
|
type: FieldType.string,
|
||||||
|
config: {
|
||||||
|
unit: 'string',
|
||||||
|
displayNameFromDS: 'Span ID',
|
||||||
|
custom: {
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
title: 'Span: ${__value.raw}',
|
||||||
|
url: '',
|
||||||
|
internal: {
|
||||||
|
datasourceUid: instanceSettings.uid,
|
||||||
|
datasourceName: instanceSettings.name,
|
||||||
|
query: {
|
||||||
|
query: '${__data.fields.traceIdHidden}',
|
||||||
|
queryType: 'traceql',
|
||||||
|
},
|
||||||
|
panelsState: {
|
||||||
|
trace: {
|
||||||
|
spanId: '${__value.raw}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'time',
|
||||||
|
type: FieldType.time,
|
||||||
|
config: {
|
||||||
|
displayNameFromDS: 'Start time',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
type: FieldType.string,
|
||||||
|
config: { displayNameFromDS: 'Name', custom: { hidden: !hasNameAttribute } },
|
||||||
|
},
|
||||||
|
...Object.values(spanDynamicAttrs).sort((a, b) => a.name.localeCompare(b.name)),
|
||||||
|
{
|
||||||
|
name: 'duration',
|
||||||
|
type: FieldType.number,
|
||||||
|
config: {
|
||||||
|
displayNameFromDS: 'Duration',
|
||||||
|
unit: 'ns',
|
||||||
|
custom: {
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
meta: {
|
||||||
|
preferredVisualisationType: 'table',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data?.length) {
|
||||||
|
return [frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
data
|
||||||
|
// Show the most recent traces
|
||||||
|
.sort((a, b) => parseInt(b?.startTimeUnixNano!, 10) / 1000000 - parseInt(a?.startTimeUnixNano!, 10) / 1000000)
|
||||||
|
.forEach((trace) => {
|
||||||
|
trace.spanSets?.forEach((spanSet) => {
|
||||||
|
spanSet.spans.forEach((span) => {
|
||||||
|
frame.add(transformSpanToTraceData(span, spanSet, trace));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return [frame];
|
||||||
|
}
|
||||||
|
|
||||||
const traceSubFrame = (
|
const traceSubFrame = (
|
||||||
trace: TraceSearchMetadata,
|
trace: TraceSearchMetadata,
|
||||||
spanSet: Spanset,
|
spanSet: Spanset,
|
||||||
@ -728,7 +881,7 @@ const traceSubFrame = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'spanStartTime',
|
name: 'time',
|
||||||
type: FieldType.time,
|
type: FieldType.time,
|
||||||
config: {
|
config: {
|
||||||
displayNameFromDS: 'Start time',
|
displayNameFromDS: 'Start time',
|
||||||
@ -766,7 +919,7 @@ const traceSubFrame = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
spanSet.spans.forEach((span) => {
|
spanSet.spans.forEach((span) => {
|
||||||
subFrame.add(transformSpanToTraceData(span, spanSet, trace.traceID));
|
subFrame.add(transformSpanToTraceData(span, spanSet, trace));
|
||||||
});
|
});
|
||||||
|
|
||||||
return subFrame;
|
return subFrame;
|
||||||
@ -781,11 +934,15 @@ interface TraceTableData {
|
|||||||
traceDuration?: number;
|
traceDuration?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function transformSpanToTraceData(span: Span, spanSet: Spanset, traceID: string): TraceTableData {
|
function transformSpanToTraceData(span: Span, spanSet: Spanset, trace: TraceSearchMetadata): TraceTableData {
|
||||||
|
const spanStartTimeUnixMs = parseInt(span.startTimeUnixNano, 10) / 1000000;
|
||||||
|
|
||||||
const data: TraceTableData = {
|
const data: TraceTableData = {
|
||||||
traceIdHidden: traceID,
|
traceIdHidden: trace.traceID,
|
||||||
|
traceService: trace.rootServiceName || '',
|
||||||
|
traceName: trace.rootTraceName || '',
|
||||||
spanID: span.spanID,
|
spanID: span.spanID,
|
||||||
spanStartTime: parseInt(span.startTimeUnixNano, 10) / 1000000,
|
time: spanStartTimeUnixMs,
|
||||||
duration: parseInt(span.durationNanos, 10),
|
duration: parseInt(span.durationNanos, 10),
|
||||||
name: span.name,
|
name: span.name,
|
||||||
};
|
};
|
||||||
|
@ -18,7 +18,7 @@ import { getGrafanaLiveSrv } from '@grafana/runtime';
|
|||||||
|
|
||||||
import { SearchStreamingState } from './dataquery.gen';
|
import { SearchStreamingState } from './dataquery.gen';
|
||||||
import { DEFAULT_SPSS, TempoDatasource } from './datasource';
|
import { DEFAULT_SPSS, TempoDatasource } from './datasource';
|
||||||
import { createTableFrameFromTraceQlQuery } from './resultTransformer';
|
import { formatTraceQLResponse } from './resultTransformer';
|
||||||
import { SearchMetrics, TempoJsonData, TempoQuery } from './types';
|
import { SearchMetrics, TempoJsonData, TempoQuery } from './types';
|
||||||
export async function getLiveStreamKey(): Promise<string> {
|
export async function getLiveStreamKey(): Promise<string> {
|
||||||
return uuidv4();
|
return uuidv4();
|
||||||
@ -76,7 +76,7 @@ export function doTempoChannelStream(
|
|||||||
|
|
||||||
frames = [
|
frames = [
|
||||||
metricsDataFrame(metrics, frameState, elapsedTime),
|
metricsDataFrame(metrics, frameState, elapsedTime),
|
||||||
...createTableFrameFromTraceQlQuery(traces, instanceSettings),
|
...formatTraceQLResponse(traces, instanceSettings, query.tableType),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { EditorField, EditorRow } from '@grafana/experimental';
|
import { EditorField, EditorRow } from '@grafana/experimental';
|
||||||
import { AutoSizeInput } from '@grafana/ui';
|
import { AutoSizeInput, RadioButtonGroup } from '@grafana/ui';
|
||||||
import { QueryOptionGroup } from 'app/plugins/datasource/prometheus/querybuilder/shared/QueryOptionGroup';
|
import { QueryOptionGroup } from 'app/plugins/datasource/prometheus/querybuilder/shared/QueryOptionGroup';
|
||||||
|
|
||||||
|
import { SearchTableType } from '../dataquery.gen';
|
||||||
import { DEFAULT_LIMIT, DEFAULT_SPSS } from '../datasource';
|
import { DEFAULT_LIMIT, DEFAULT_SPSS } from '../datasource';
|
||||||
import { TempoQuery } from '../types';
|
import { TempoQuery } from '../types';
|
||||||
|
|
||||||
@ -17,14 +18,25 @@ export const TempoQueryBuilderOptions = React.memo<Props>(({ onChange, query })
|
|||||||
query.limit = DEFAULT_LIMIT;
|
query.limit = DEFAULT_LIMIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!query.hasOwnProperty('tableType')) {
|
||||||
|
query.tableType = SearchTableType.Traces;
|
||||||
|
}
|
||||||
|
|
||||||
const onLimitChange = (e: React.FormEvent<HTMLInputElement>) => {
|
const onLimitChange = (e: React.FormEvent<HTMLInputElement>) => {
|
||||||
onChange({ ...query, limit: parseInt(e.currentTarget.value, 10) });
|
onChange({ ...query, limit: parseInt(e.currentTarget.value, 10) });
|
||||||
};
|
};
|
||||||
const onSpssChange = (e: React.FormEvent<HTMLInputElement>) => {
|
const onSpssChange = (e: React.FormEvent<HTMLInputElement>) => {
|
||||||
onChange({ ...query, spss: parseInt(e.currentTarget.value, 10) });
|
onChange({ ...query, spss: parseInt(e.currentTarget.value, 10) });
|
||||||
};
|
};
|
||||||
|
const onTableTypeChange = (val: SearchTableType) => {
|
||||||
|
onChange({ ...query, tableType: val });
|
||||||
|
};
|
||||||
|
|
||||||
const collapsedInfoList = [`Limit: ${query.limit || DEFAULT_LIMIT}`, `Spans Limit: ${query.spss || DEFAULT_SPSS}`];
|
const collapsedInfoList = [
|
||||||
|
`Limit: ${query.limit || DEFAULT_LIMIT}`,
|
||||||
|
`Spans Limit: ${query.spss || DEFAULT_SPSS}`,
|
||||||
|
`Table Format: ${query.tableType === SearchTableType.Traces ? 'Traces' : 'Spans'}`,
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -52,6 +64,16 @@ export const TempoQueryBuilderOptions = React.memo<Props>(({ onChange, query })
|
|||||||
value={query.spss}
|
value={query.spss}
|
||||||
/>
|
/>
|
||||||
</EditorField>
|
</EditorField>
|
||||||
|
<EditorField label="Table Format" tooltip="How the query data should be displayed in the results table">
|
||||||
|
<RadioButtonGroup
|
||||||
|
options={[
|
||||||
|
{ label: 'Traces', value: SearchTableType.Traces },
|
||||||
|
{ label: 'Spans', value: SearchTableType.Spans },
|
||||||
|
]}
|
||||||
|
value={query.tableType}
|
||||||
|
onChange={onTableTypeChange}
|
||||||
|
/>
|
||||||
|
</EditorField>
|
||||||
</QueryOptionGroup>
|
</QueryOptionGroup>
|
||||||
</EditorRow>
|
</EditorRow>
|
||||||
</>
|
</>
|
||||||
|
Loading…
Reference in New Issue
Block a user