mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Tempo: Integrate TraceQL API (#56867)
This commit is contained in:
parent
0232927591
commit
84a5ced72a
@ -68,7 +68,7 @@ services:
|
|||||||
|
|
||||||
tempo:
|
tempo:
|
||||||
image: grafana/tempo:latest
|
image: grafana/tempo:latest
|
||||||
command:
|
command:
|
||||||
- --config.file=/etc/tempo.yaml
|
- --config.file=/etc/tempo.yaml
|
||||||
- --search.enabled=true
|
- --search.enabled=true
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -41,6 +41,10 @@ metrics_generator:
|
|||||||
- url: http://prometheus:9090/api/v1/write
|
- url: http://prometheus:9090/api/v1/write
|
||||||
send_exemplars: true
|
send_exemplars: true
|
||||||
|
|
||||||
|
query_frontend:
|
||||||
|
search:
|
||||||
|
max_duration: 0 # allow searches >1h
|
||||||
|
|
||||||
storage:
|
storage:
|
||||||
trace:
|
trace:
|
||||||
backend: local # backend configuration to use
|
backend: local # backend configuration to use
|
||||||
@ -48,6 +52,7 @@ storage:
|
|||||||
bloom_filter_false_positive: .05 # bloom filter false positive rate. lower values create larger filters but fewer false positives
|
bloom_filter_false_positive: .05 # bloom filter false positive rate. lower values create larger filters but fewer false positives
|
||||||
index_downsample_bytes: 1000 # number of bytes per index record
|
index_downsample_bytes: 1000 # number of bytes per index record
|
||||||
encoding: zstd # block encoding/compression. options: none, gzip, lz4-64k, lz4-256k, lz4-1M, lz4, snappy, zstd, s2
|
encoding: zstd # block encoding/compression. options: none, gzip, lz4-64k, lz4-256k, lz4-1M, lz4, snappy, zstd, s2
|
||||||
|
version: vParquet
|
||||||
wal:
|
wal:
|
||||||
path: /tmp/tempo/wal # where to store the the wal locally
|
path: /tmp/tempo/wal # where to store the the wal locally
|
||||||
encoding: snappy # wal encoding/compression. options: none, gzip, lz4-64k, lz4-256k, lz4-1M, lz4, snappy, zstd, s2
|
encoding: snappy # wal encoding/compression. options: none, gzip, lz4-64k, lz4-256k, lz4-1M, lz4, snappy, zstd, s2
|
||||||
|
@ -51,7 +51,6 @@ import {
|
|||||||
createTableFrameFromSearch,
|
createTableFrameFromSearch,
|
||||||
createTableFrameFromTraceQlQuery,
|
createTableFrameFromTraceQlQuery,
|
||||||
} from './resultTransformer';
|
} from './resultTransformer';
|
||||||
import { mockedSearchResponse } from './traceql/mockedSearchResponse';
|
|
||||||
import { SearchQueryParams, TempoQuery, TempoJsonData } from './types';
|
import { SearchQueryParams, TempoQuery, TempoJsonData } from './types';
|
||||||
|
|
||||||
export const DEFAULT_LIMIT = 20;
|
export const DEFAULT_LIMIT = 20;
|
||||||
@ -174,9 +173,21 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
|
|||||||
});
|
});
|
||||||
|
|
||||||
subQueries.push(
|
subQueries.push(
|
||||||
of({
|
this._request('/api/search', {
|
||||||
data: [createTableFrameFromTraceQlQuery(mockedSearchResponse().traces, this.instanceSettings)],
|
q: targets.traceql[0].query,
|
||||||
})
|
limit: options.targets[0].limit,
|
||||||
|
start: 0, // Currently the API doesn't return traces when using the 'From' time selected in Explore
|
||||||
|
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) {
|
} catch (error) {
|
||||||
return of({ error: { message: error instanceof Error ? error.message : 'Unknown error occurred' }, data: [] });
|
return of({ error: { message: error instanceof Error ? error.message : 'Unknown error occurred' }, data: [] });
|
||||||
|
@ -1,14 +1,28 @@
|
|||||||
import { collectorTypes } from '@opentelemetry/exporter-collector';
|
import { collectorTypes } from '@opentelemetry/exporter-collector';
|
||||||
|
|
||||||
import { FieldType, MutableDataFrame, PluginType, DataSourceInstanceSettings, dateTime } from '@grafana/data';
|
import {
|
||||||
|
FieldType,
|
||||||
|
MutableDataFrame,
|
||||||
|
PluginType,
|
||||||
|
DataSourceInstanceSettings,
|
||||||
|
dateTime,
|
||||||
|
ArrayVector,
|
||||||
|
} from '@grafana/data';
|
||||||
|
|
||||||
import { createTableFrame, transformToOTLP, transformFromOTLP, createTableFrameFromSearch } from './resultTransformer';
|
import {
|
||||||
|
createTableFrame,
|
||||||
|
transformToOTLP,
|
||||||
|
transformFromOTLP,
|
||||||
|
createTableFrameFromSearch,
|
||||||
|
createTableFrameFromTraceQlQuery,
|
||||||
|
} from './resultTransformer';
|
||||||
import {
|
import {
|
||||||
badOTLPResponse,
|
badOTLPResponse,
|
||||||
otlpDataFrameToResponse,
|
otlpDataFrameToResponse,
|
||||||
otlpDataFrameFromResponse,
|
otlpDataFrameFromResponse,
|
||||||
otlpResponse,
|
otlpResponse,
|
||||||
tempoSearchResponse,
|
tempoSearchResponse,
|
||||||
|
traceQlResponse,
|
||||||
} from './testResponse';
|
} from './testResponse';
|
||||||
import { TraceSearchMetadata } from './types';
|
import { TraceSearchMetadata } from './types';
|
||||||
|
|
||||||
@ -111,6 +125,45 @@ describe('createTableFrameFromSearch()', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('createTableFrameFromTraceQlQuery()', () => {
|
||||||
|
test('transforms TraceQL response to DataFrame', () => {
|
||||||
|
const frame = createTableFrameFromTraceQlQuery(traceQlResponse.traces, defaultSettings);
|
||||||
|
// Trace ID field
|
||||||
|
expect(frame.fields[0].name).toBe('traceID');
|
||||||
|
expect(frame.fields[0].values.get(0)).toBe('b1586c3c8c34d');
|
||||||
|
expect(frame.fields[0].config.unit).toBe('string');
|
||||||
|
expect(frame.fields[0].values).toBeInstanceOf(ArrayVector);
|
||||||
|
// There should be a traceIdHidden field which is hidden
|
||||||
|
expect(frame.fields[1].name).toBe('traceIdHidden');
|
||||||
|
expect(frame.fields[1].config).toBeDefined();
|
||||||
|
expect(frame.fields[1].config.custom).toStrictEqual({ hidden: true });
|
||||||
|
expect(frame.fields[1].values).toBeInstanceOf(ArrayVector);
|
||||||
|
// Span ID field
|
||||||
|
expect(frame.fields[2].name).toBe('spanID');
|
||||||
|
expect(frame.fields[2].config.unit).toBe('string');
|
||||||
|
expect(frame.fields[2].values).toBeInstanceOf(ArrayVector);
|
||||||
|
// Trace name field
|
||||||
|
expect(frame.fields[3].name).toBe('traceName');
|
||||||
|
expect(frame.fields[3].type).toBe('string');
|
||||||
|
expect(frame.fields[3].values.get(0)).toBe('lb HTTP Client');
|
||||||
|
expect(frame.fields[3].values).toBeInstanceOf(ArrayVector);
|
||||||
|
// Start time field
|
||||||
|
expect(frame.fields[4].name).toBe('startTime');
|
||||||
|
expect(frame.fields[4].type).toBe('string');
|
||||||
|
expect(frame.fields[4].values.get(1)).toBe('2022-10-19 09:03:34');
|
||||||
|
expect(frame.fields[4].values).toBeInstanceOf(ArrayVector);
|
||||||
|
// Duration field
|
||||||
|
expect(frame.fields[5].name).toBe('duration');
|
||||||
|
expect(frame.fields[5].type).toBe('number');
|
||||||
|
expect(frame.fields[5].values.get(2)).toBe(6686000);
|
||||||
|
// There should be a field for each attribute
|
||||||
|
expect(frame.fields[6].name).toBe('http.method');
|
||||||
|
expect(frame.fields[6].values).toBeInstanceOf(ArrayVector);
|
||||||
|
expect(frame.fields[7].name).toBe('service.name');
|
||||||
|
expect(frame.fields[7].values).toBeInstanceOf(ArrayVector);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('transformFromOTLP()', () => {
|
describe('transformFromOTLP()', () => {
|
||||||
// Mock the console error so that running the test suite doesnt throw the error
|
// Mock the console error so that running the test suite doesnt throw the error
|
||||||
const origError = console.error;
|
const origError = console.error;
|
||||||
|
@ -577,7 +577,7 @@ export function createTableFrameFromSearch(data: TraceSearchMetadata[], instance
|
|||||||
},
|
},
|
||||||
{ name: 'traceName', type: FieldType.string, config: { displayNameFromDS: 'Trace name' } },
|
{ name: 'traceName', type: FieldType.string, config: { displayNameFromDS: 'Trace name' } },
|
||||||
{ name: 'startTime', type: FieldType.string, config: { displayNameFromDS: 'Start time' } },
|
{ name: 'startTime', type: FieldType.string, config: { displayNameFromDS: 'Start time' } },
|
||||||
{ name: 'duration', type: FieldType.number, config: { displayNameFromDS: 'Duration', unit: 'ms' } },
|
{ name: 'duration', type: FieldType.number, config: { displayNameFromDS: 'Duration', unit: 'ns' } },
|
||||||
],
|
],
|
||||||
meta: {
|
meta: {
|
||||||
preferredVisualisationType: 'table',
|
preferredVisualisationType: 'table',
|
||||||
@ -609,7 +609,7 @@ function transformToTraceData(data: TraceSearchMetadata) {
|
|||||||
|
|
||||||
const traceStartTime = parseInt(data.startTimeUnixNano!, 10) / 1000000;
|
const traceStartTime = parseInt(data.startTimeUnixNano!, 10) / 1000000;
|
||||||
|
|
||||||
let startTime = dateTimeFormat(traceStartTime);
|
let startTime = !isNaN(traceStartTime) ? dateTimeFormat(traceStartTime) : '';
|
||||||
|
|
||||||
if (Math.abs(differenceInHours(new Date(traceStartTime), Date.now())) <= 1) {
|
if (Math.abs(differenceInHours(new Date(traceStartTime), Date.now())) <= 1) {
|
||||||
startTime = formatDistance(new Date(traceStartTime), Date.now(), {
|
startTime = formatDistance(new Date(traceStartTime), Date.now(), {
|
||||||
@ -621,7 +621,7 @@ function transformToTraceData(data: TraceSearchMetadata) {
|
|||||||
return {
|
return {
|
||||||
traceID: data.traceID,
|
traceID: data.traceID,
|
||||||
startTime: startTime,
|
startTime: startTime,
|
||||||
duration: data.durationMs,
|
duration: data.durationMs?.toString(),
|
||||||
traceName,
|
traceName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -654,12 +654,18 @@ export function createTableFrameFromTraceQlQuery(
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'traceIdHidden',
|
||||||
|
config: {
|
||||||
|
custom: { hidden: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'spanID',
|
name: 'spanID',
|
||||||
type: FieldType.string,
|
type: FieldType.string,
|
||||||
config: {
|
config: {
|
||||||
unit: 'string',
|
unit: 'string',
|
||||||
displayNameFromDS: 'Span',
|
displayNameFromDS: 'Span ID',
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
title: 'Span: ${__value.raw}',
|
title: 'Span: ${__value.raw}',
|
||||||
@ -668,18 +674,18 @@ export function createTableFrameFromTraceQlQuery(
|
|||||||
datasourceUid: instanceSettings.uid,
|
datasourceUid: instanceSettings.uid,
|
||||||
datasourceName: instanceSettings.name,
|
datasourceName: instanceSettings.name,
|
||||||
query: {
|
query: {
|
||||||
query: '${__value.raw}',
|
query: '${__data.fields.traceIdHidden}',
|
||||||
queryType: 'spanId',
|
queryType: 'traceId',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ name: 'traceName', type: FieldType.string, config: { displayNameFromDS: 'Name' } },
|
{ name: 'traceName', type: FieldType.string, config: { displayNameFromDS: 'Trace name' } },
|
||||||
{ name: 'attributes', type: FieldType.string, config: { displayNameFromDS: 'Attributes' } },
|
// { name: 'attributes', type: FieldType.string, config: { displayNameFromDS: 'Attributes' } },
|
||||||
{ name: 'startTime', type: FieldType.string, config: { displayNameFromDS: 'Start time' } },
|
{ name: 'startTime', type: FieldType.string, config: { displayNameFromDS: 'Start time' } },
|
||||||
{ name: 'duration', type: FieldType.number, config: { displayNameFromDS: 'Duration', unit: 'ms' } },
|
{ name: 'duration', type: FieldType.number, config: { displayNameFromDS: 'Duration', unit: 'ns' } },
|
||||||
],
|
],
|
||||||
meta: {
|
meta: {
|
||||||
preferredVisualisationType: 'table',
|
preferredVisualisationType: 'table',
|
||||||
@ -688,57 +694,71 @@ export function createTableFrameFromTraceQlQuery(
|
|||||||
if (!data?.length) {
|
if (!data?.length) {
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
// Show the most recent traces
|
|
||||||
const traceData = data
|
const attributesAdded: string[] = [];
|
||||||
|
|
||||||
|
data.forEach((trace) => {
|
||||||
|
trace.spanSet?.spans.forEach((span) => {
|
||||||
|
span.attributes?.forEach((attr) => {
|
||||||
|
if (!attributesAdded.includes(attr.key)) {
|
||||||
|
frame.addField({ name: attr.key, type: FieldType.string, config: { displayNameFromDS: attr.key } });
|
||||||
|
attributesAdded.push(attr.key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const tableRows = data
|
||||||
|
// Show the most recent traces
|
||||||
.sort((a, b) => parseInt(b?.startTimeUnixNano!, 10) / 1000000 - parseInt(a?.startTimeUnixNano!, 10) / 1000000)
|
.sort((a, b) => parseInt(b?.startTimeUnixNano!, 10) / 1000000 - parseInt(a?.startTimeUnixNano!, 10) / 1000000)
|
||||||
.reduce((list: TraceTableData[], t) => {
|
.reduce((rows: TraceTableData[], trace) => {
|
||||||
const firstSpanSet = t.spanSets?.[0];
|
const traceData: TraceTableData = transformToTraceData(trace);
|
||||||
const trace: TraceTableData = transformToTraceData(t);
|
rows.push(traceData);
|
||||||
trace.attributes = firstSpanSet?.attributes
|
trace.spanSet?.spans.forEach((span) => {
|
||||||
.map((atr) => Object.keys(atr).map((key) => `${key} = ${atr[key]}`))
|
rows.push(transformSpanToTraceData(span, trace.traceID));
|
||||||
.join(', ');
|
});
|
||||||
list.push(trace);
|
return rows;
|
||||||
firstSpanSet?.spans.forEach((span) => list.push(transformSpanToTraceData(span)));
|
|
||||||
return list;
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
for (const trace of traceData) {
|
for (const row of tableRows) {
|
||||||
frame.add(trace);
|
frame.add(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TraceTableData {
|
interface TraceTableData {
|
||||||
|
[key: string]: string | number | undefined; // dynamic attribute name
|
||||||
traceID?: string;
|
traceID?: string;
|
||||||
traceName: string;
|
|
||||||
spanID?: string;
|
spanID?: string;
|
||||||
attributes?: string;
|
//attributes?: string;
|
||||||
startTime: string;
|
startTime?: string;
|
||||||
duration: number;
|
duration?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function transformSpanToTraceData(data: Span): TraceTableData {
|
function transformSpanToTraceData(span: Span, traceID: string): TraceTableData {
|
||||||
const traceStartTime = data.startTimeUnixNano / 1000000;
|
const spanStartTimeUnixMs = parseInt(span.startTimeUnixNano, 10) / 1000000;
|
||||||
const traceEndTime = data.endTimeUnixNano / 1000000;
|
let spanStartTime = dateTimeFormat(spanStartTimeUnixMs);
|
||||||
|
|
||||||
let startTime = dateTimeFormat(traceStartTime);
|
if (Math.abs(differenceInHours(new Date(spanStartTime), Date.now())) <= 1) {
|
||||||
|
spanStartTime = formatDistance(new Date(spanStartTime), Date.now(), {
|
||||||
if (Math.abs(differenceInHours(new Date(traceStartTime), Date.now())) <= 1) {
|
|
||||||
startTime = formatDistance(new Date(traceStartTime), Date.now(), {
|
|
||||||
addSuffix: true,
|
addSuffix: true,
|
||||||
includeSeconds: true,
|
includeSeconds: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const data: TraceTableData = {
|
||||||
traceID: undefined,
|
traceIdHidden: traceID,
|
||||||
traceName: data.name,
|
spanID: span.spanID,
|
||||||
spanID: data.spanId,
|
startTime: spanStartTime,
|
||||||
attributes: data.attributes?.map((atr) => Object.keys(atr).map((key) => `${key} = ${atr[key]}`)).join(', '),
|
duration: span.durationNanos,
|
||||||
startTime,
|
|
||||||
duration: traceEndTime - traceStartTime,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
span.attributes?.forEach((attr) => {
|
||||||
|
data[attr.key] = attr.value.stringValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyDataQueryResponse = {
|
const emptyDataQueryResponse = {
|
||||||
|
@ -2204,6 +2204,273 @@ export const tempoSearchResponse = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const traceQlResponse = {
|
||||||
|
traces: [
|
||||||
|
{
|
||||||
|
traceID: 'b1586c3c8c34d',
|
||||||
|
rootServiceName: 'lb',
|
||||||
|
rootTraceName: 'HTTP Client',
|
||||||
|
spanSet: {
|
||||||
|
spans: [
|
||||||
|
{
|
||||||
|
spanID: '162a4adae63b61f1',
|
||||||
|
startTimeUnixNano: '1666188214303201000',
|
||||||
|
durationNanos: '545000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'db',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spanID: '15991be3a92136e6',
|
||||||
|
startTimeUnixNano: '1666188214300239000',
|
||||||
|
durationNanos: '6686000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'app',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spanID: '5e91b69dc224c240',
|
||||||
|
startTimeUnixNano: '1666188214300647000',
|
||||||
|
durationNanos: '6043000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'app',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spanID: '29f218a50b00c306',
|
||||||
|
startTimeUnixNano: '1666188214297891000',
|
||||||
|
durationNanos: '8365000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'lb',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
matched: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
traceID: '9161e77388f3e',
|
||||||
|
rootServiceName: 'lb',
|
||||||
|
rootTraceName: 'HTTP Client',
|
||||||
|
spanSet: {
|
||||||
|
spans: [
|
||||||
|
{
|
||||||
|
spanID: '3b9a5c222d3ddd8f',
|
||||||
|
startTimeUnixNano: '1666187875397721000',
|
||||||
|
durationNanos: '877000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'db',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spanID: '894d90db6b5807f',
|
||||||
|
startTimeUnixNano: '1666187875393293000',
|
||||||
|
durationNanos: '11073000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'app',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spanID: 'd3284e9c5081aab',
|
||||||
|
startTimeUnixNano: '1666187875393897000',
|
||||||
|
durationNanos: '10133000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'app',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spanID: '454785498fc8b1aa',
|
||||||
|
startTimeUnixNano: '1666187875389957000',
|
||||||
|
durationNanos: '13953000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'lb',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
matched: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
traceID: '480691f7c6f20',
|
||||||
|
rootServiceName: 'lb',
|
||||||
|
rootTraceName: 'HTTP Client',
|
||||||
|
spanSet: {
|
||||||
|
spans: [
|
||||||
|
{
|
||||||
|
spanID: '2ab970c9db57d100',
|
||||||
|
startTimeUnixNano: '1666186467658853000',
|
||||||
|
durationNanos: '436000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'db',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spanID: '3a4070e418857cbd',
|
||||||
|
startTimeUnixNano: '1666186467657066000',
|
||||||
|
durationNanos: '5503000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'app',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spanID: '7ddf87d7a3f864c8',
|
||||||
|
startTimeUnixNano: '1666186467657336000',
|
||||||
|
durationNanos: '5005000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'app',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spanID: '241e9f31609056c5',
|
||||||
|
startTimeUnixNano: '1666186467655299000',
|
||||||
|
durationNanos: '6413000',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'http.method',
|
||||||
|
value: {
|
||||||
|
stringValue: 'GET',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'service.name',
|
||||||
|
value: {
|
||||||
|
stringValue: 'lb',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
matched: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
metrics: {
|
||||||
|
inspectedBlocks: 5,
|
||||||
|
totalBlockBytes: '9092129',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const badOTLPResponse = {
|
export const badOTLPResponse = {
|
||||||
batches: [
|
batches: [
|
||||||
{
|
{
|
||||||
|
@ -12,6 +12,10 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const TempoQueryBuilderOptions = React.memo<Props>(({ onChange, query }) => {
|
export const TempoQueryBuilderOptions = React.memo<Props>(({ onChange, query }) => {
|
||||||
|
if (!query.hasOwnProperty('limit')) {
|
||||||
|
query.limit = DEFAULT_LIMIT;
|
||||||
|
}
|
||||||
|
|
||||||
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) });
|
||||||
};
|
};
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
|
|
||||||
import { SearchResponse, Span, SpanKind, TraceSearchMetadata } from '../types';
|
|
||||||
|
|
||||||
export const mockedSearchResponse = (): SearchResponse => {
|
|
||||||
const traces: TraceSearchMetadata[] = [];
|
|
||||||
const attributes = [
|
|
||||||
{ 'http.status.code': '500' },
|
|
||||||
{ 'http.status.code': '200' },
|
|
||||||
{ 'http.status.code': '404' },
|
|
||||||
{ job: '"test-job"' },
|
|
||||||
{ job: '"main-job"' },
|
|
||||||
{ job: '"long-job"' },
|
|
||||||
{ error: '"lorem ipsum"' },
|
|
||||||
{ error: '"something went wrong"' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const tracesCount = Math.random() * 20 + 20;
|
|
||||||
for (let i = 0; i < tracesCount; i++) {
|
|
||||||
const attr = Math.floor(Math.random() * attributes.length);
|
|
||||||
const startTime = (Date.now() - Math.random() * (i + 1) * 100000) * 1000000;
|
|
||||||
const t: TraceSearchMetadata = {
|
|
||||||
traceID: uuidv4().replace(/-/, '').substring(0, 16),
|
|
||||||
rootServiceName: 'service' + i,
|
|
||||||
rootTraceName: 'trace' + i,
|
|
||||||
startTimeUnixNano: startTime.toString(10),
|
|
||||||
durationMs: Math.random() * 1000,
|
|
||||||
spanSets: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const spanAttributes = [];
|
|
||||||
for (let k = 0; k < Math.random() * 2; k++) {
|
|
||||||
const newAttr = Math.floor(Math.random() * attributes.length);
|
|
||||||
if (newAttr !== attr) {
|
|
||||||
spanAttributes.push(attributes[newAttr]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const spans: Span[] = [];
|
|
||||||
for (let j = 0; j < Math.random() * 3 + 1; j++) {
|
|
||||||
spans.push({
|
|
||||||
traceId: t.traceID,
|
|
||||||
spanId: uuidv4().replace(/-/, '').substring(0, 16),
|
|
||||||
name: uuidv4().replace(/-/, '').substring(0, 6),
|
|
||||||
startTimeUnixNano: startTime,
|
|
||||||
endTimeUnixNano: startTime + Math.random() * 10000000,
|
|
||||||
kind: SpanKind.INTERNAL,
|
|
||||||
attributes: spanAttributes,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
t.spanSets!.push({ spans, attributes: [attributes[attr]] });
|
|
||||||
traces.push(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
traces,
|
|
||||||
metrics: {
|
|
||||||
inspectedTraces: tracesCount,
|
|
||||||
inspectedBytes: 83720,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -56,9 +56,9 @@ export type TraceSearchMetadata = {
|
|||||||
traceID: string;
|
traceID: string;
|
||||||
rootServiceName: string;
|
rootServiceName: string;
|
||||||
rootTraceName: string;
|
rootTraceName: string;
|
||||||
startTimeUnixNano: string;
|
startTimeUnixNano?: string;
|
||||||
durationMs: number;
|
durationMs?: number;
|
||||||
spanSets?: Spanset[];
|
spanSet?: { spans: Span[] };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SearchMetrics = {
|
export type SearchMetrics = {
|
||||||
@ -81,15 +81,16 @@ export enum SpanKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type Span = {
|
export type Span = {
|
||||||
traceId: string;
|
durationNanos: string;
|
||||||
spanId: string;
|
traceId?: string;
|
||||||
|
spanID: string;
|
||||||
traceState?: string;
|
traceState?: string;
|
||||||
parentSpanId?: string;
|
parentSpanId?: string;
|
||||||
name: string;
|
name?: string;
|
||||||
kind: SpanKind;
|
kind?: SpanKind;
|
||||||
startTimeUnixNano: number;
|
startTimeUnixNano: string;
|
||||||
endTimeUnixNano: number;
|
endTimeUnixNano?: string;
|
||||||
attributes?: KeyValue[];
|
attributes?: Array<{ key: string; value: { stringValue: string } }>;
|
||||||
dropped_attributes_count?: number;
|
dropped_attributes_count?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user