mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Tempo: Fix type errors that appeared when removing the "any" type from DataQueryResponseData (#75600)
* Tempo: Improving typing of data types * last fix * Fix
This commit is contained in:
parent
7329e2dc62
commit
bf7fae4bd3
@ -193,9 +193,7 @@
|
|||||||
"footer": {
|
"footer": {
|
||||||
"countRows": false,
|
"countRows": false,
|
||||||
"fields": "",
|
"fields": "",
|
||||||
"reducer": [
|
"reducer": ["sum"],
|
||||||
"sum"
|
|
||||||
],
|
|
||||||
"show": false
|
"show": false
|
||||||
},
|
},
|
||||||
"showHeader": true
|
"showHeader": true
|
||||||
|
@ -422,4 +422,4 @@
|
|||||||
"uid": "a3b23921-287d-4f90-9a14-c04228057dfa",
|
"uid": "a3b23921-287d-4f90-9a14-c04228057dfa",
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"weekStart": ""
|
"weekStart": ""
|
||||||
}
|
}
|
||||||
|
@ -232,11 +232,11 @@ describe('Tempo data source', () => {
|
|||||||
expect(response.data).toHaveLength(2);
|
expect(response.data).toHaveLength(2);
|
||||||
const nodesFrame = response.data[0];
|
const nodesFrame = response.data[0];
|
||||||
expect(nodesFrame.name).toBe('Nodes');
|
expect(nodesFrame.name).toBe('Nodes');
|
||||||
expect(nodesFrame.meta.preferredVisualisationType).toBe('nodeGraph');
|
expect(nodesFrame.meta?.preferredVisualisationType).toBe('nodeGraph');
|
||||||
|
|
||||||
const edgesFrame = response.data[1];
|
const edgesFrame = response.data[1];
|
||||||
expect(edgesFrame.name).toBe('Edges');
|
expect(edgesFrame.name).toBe('Edges');
|
||||||
expect(edgesFrame.meta.preferredVisualisationType).toBe('nodeGraph');
|
expect(edgesFrame.meta?.preferredVisualisationType).toBe('nodeGraph');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should build search query correctly', () => {
|
it('should build search query correctly', () => {
|
||||||
@ -486,67 +486,67 @@ describe('Tempo service graph view', () => {
|
|||||||
expect(response.data[0].fields[1].values.length).toBe(2);
|
expect(response.data[0].fields[1].values.length).toBe(2);
|
||||||
expect(response.data[0].fields[1].values[0]).toBe(12.75164671814457);
|
expect(response.data[0].fields[1].values[0]).toBe(12.75164671814457);
|
||||||
expect(response.data[0].fields[1].values[1]).toBe(12.121331111401608);
|
expect(response.data[0].fields[1].values[1]).toBe(12.121331111401608);
|
||||||
expect(response.data[0].fields[1].config.decimals).toBe(2);
|
expect(response.data[0].fields[1]?.config?.decimals).toBe(2);
|
||||||
expect(response.data[0].fields[1].config.links[0].title).toBe('Rate');
|
expect(response.data[0].fields[1]?.config?.links?.[0]?.title).toBe('Rate');
|
||||||
expect(response.data[0].fields[1].config.links[0].internal.query.expr).toBe(
|
expect(response.data[0].fields[1]?.config?.links?.[0]?.internal?.query.expr).toBe(
|
||||||
'sum(rate(traces_spanmetrics_calls_total{span_name="${__data.fields[0]}"}[$__rate_interval]))'
|
'sum(rate(traces_spanmetrics_calls_total{span_name="${__data.fields[0]}"}[$__rate_interval]))'
|
||||||
);
|
);
|
||||||
expect(response.data[0].fields[1].config.links[0].internal.query.range).toBe(true);
|
expect(response.data[0].fields[1]?.config?.links?.[0]?.internal?.query.range).toBe(true);
|
||||||
expect(response.data[0].fields[1].config.links[0].internal.query.exemplar).toBe(true);
|
expect(response.data[0].fields[1]?.config?.links?.[0]?.internal?.query.exemplar).toBe(true);
|
||||||
expect(response.data[0].fields[1].config.links[0].internal.query.instant).toBe(false);
|
expect(response.data[0].fields[1]?.config?.links?.[0]?.internal?.query.instant).toBe(false);
|
||||||
|
|
||||||
expect(response.data[0].fields[2].values.length).toBe(2);
|
expect(response.data[0].fields[2].values.length).toBe(2);
|
||||||
expect(response.data[0].fields[2].values[0]).toBe(12.75164671814457);
|
expect(response.data[0].fields[2].values[0]).toBe(12.75164671814457);
|
||||||
expect(response.data[0].fields[2].values[1]).toBe(12.121331111401608);
|
expect(response.data[0].fields[2].values[1]).toBe(12.121331111401608);
|
||||||
expect(response.data[0].fields[2].config.color.mode).toBe('continuous-BlPu');
|
expect(response.data[0].fields[2]?.config?.color?.mode).toBe('continuous-BlPu');
|
||||||
expect(response.data[0].fields[2].config.custom.cellOptions.mode).toBe(BarGaugeDisplayMode.Lcd);
|
expect(response.data[0].fields[2]?.config?.custom.cellOptions.mode).toBe(BarGaugeDisplayMode.Lcd);
|
||||||
expect(response.data[0].fields[2].config.custom.cellOptions.type).toBe(TableCellDisplayMode.Gauge);
|
expect(response.data[0].fields[2]?.config?.custom.cellOptions.type).toBe(TableCellDisplayMode.Gauge);
|
||||||
expect(response.data[0].fields[2].config.decimals).toBe(3);
|
expect(response.data[0].fields[2]?.config?.decimals).toBe(3);
|
||||||
|
|
||||||
expect(response.data[0].fields[3].name).toBe('Error Rate');
|
expect(response.data[0].fields[3].name).toBe('Error Rate');
|
||||||
expect(response.data[0].fields[3].values.length).toBe(2);
|
expect(response.data[0].fields[3].values.length).toBe(2);
|
||||||
expect(response.data[0].fields[3].values[0]).toBe(3.75164671814457);
|
expect(response.data[0].fields[3].values[0]).toBe(3.75164671814457);
|
||||||
expect(response.data[0].fields[3].values[1]).toBe(3.121331111401608);
|
expect(response.data[0].fields[3].values[1]).toBe(3.121331111401608);
|
||||||
expect(response.data[0].fields[3].config.decimals).toBe(2);
|
expect(response.data[0].fields[3]?.config?.decimals).toBe(2);
|
||||||
expect(response.data[0].fields[3].config.links[0].title).toBe('Error Rate');
|
expect(response.data[0].fields[3]?.config?.links?.[0]?.title).toBe('Error Rate');
|
||||||
expect(response.data[0].fields[3].config.links[0].internal.query.expr).toBe(
|
expect(response.data[0].fields[3]?.config?.links?.[0]?.internal?.query.expr).toBe(
|
||||||
'sum(rate(traces_spanmetrics_calls_total{status_code="STATUS_CODE_ERROR",span_name="${__data.fields[0]}"}[$__rate_interval]))'
|
'sum(rate(traces_spanmetrics_calls_total{status_code="STATUS_CODE_ERROR",span_name="${__data.fields[0]}"}[$__rate_interval]))'
|
||||||
);
|
);
|
||||||
expect(response.data[0].fields[3].config.links[0].internal.query.range).toBe(true);
|
expect(response.data[0].fields[3]?.config?.links?.[0]?.internal?.query.range).toBe(true);
|
||||||
expect(response.data[0].fields[3].config.links[0].internal.query.exemplar).toBe(true);
|
expect(response.data[0].fields[3]?.config?.links?.[0]?.internal?.query.exemplar).toBe(true);
|
||||||
expect(response.data[0].fields[3].config.links[0].internal.query.instant).toBe(false);
|
expect(response.data[0].fields[3]?.config?.links?.[0]?.internal?.query.instant).toBe(false);
|
||||||
|
|
||||||
expect(response.data[0].fields[4].values.length).toBe(2);
|
expect(response.data[0].fields[4].values.length).toBe(2);
|
||||||
expect(response.data[0].fields[4].values[0]).toBe(3.75164671814457);
|
expect(response.data[0].fields[4].values[0]).toBe(3.75164671814457);
|
||||||
expect(response.data[0].fields[4].values[1]).toBe(3.121331111401608);
|
expect(response.data[0].fields[4].values[1]).toBe(3.121331111401608);
|
||||||
expect(response.data[0].fields[4].config.color.mode).toBe('continuous-RdYlGr');
|
expect(response.data[0].fields[4]?.config?.color?.mode).toBe('continuous-RdYlGr');
|
||||||
expect(response.data[0].fields[4].config.custom.cellOptions.mode).toBe(BarGaugeDisplayMode.Lcd);
|
expect(response.data[0].fields[4]?.config?.custom.cellOptions.mode).toBe(BarGaugeDisplayMode.Lcd);
|
||||||
expect(response.data[0].fields[4].config.custom.cellOptions.type).toBe(TableCellDisplayMode.Gauge);
|
expect(response.data[0].fields[4]?.config?.custom.cellOptions.type).toBe(TableCellDisplayMode.Gauge);
|
||||||
expect(response.data[0].fields[4].config.decimals).toBe(3);
|
expect(response.data[0].fields[4]?.config?.decimals).toBe(3);
|
||||||
|
|
||||||
expect(response.data[0].fields[5].name).toBe('Duration (p90)');
|
expect(response.data[0].fields[5].name).toBe('Duration (p90)');
|
||||||
expect(response.data[0].fields[5].values.length).toBe(2);
|
expect(response.data[0].fields[5].values.length).toBe(2);
|
||||||
expect(response.data[0].fields[5].values[0]).toBe('0');
|
expect(response.data[0].fields[5].values[0]).toBe('0');
|
||||||
expect(response.data[0].fields[5].values[1]).toBe(0.12003505696757232);
|
expect(response.data[0].fields[5].values[1]).toBe(0.12003505696757232);
|
||||||
expect(response.data[0].fields[5].config.unit).toBe('s');
|
expect(response.data[0].fields[5]?.config?.unit).toBe('s');
|
||||||
expect(response.data[0].fields[5].config.links[0].title).toBe('Duration');
|
expect(response.data[0].fields[5]?.config?.links?.[0]?.title).toBe('Duration');
|
||||||
expect(response.data[0].fields[5].config.links[0].internal.query.expr).toBe(
|
expect(response.data[0].fields[5]?.config?.links?.[0]?.internal?.query.expr).toBe(
|
||||||
'histogram_quantile(.9, sum(rate(traces_spanmetrics_latency_bucket{span_name="${__data.fields[0]}"}[$__rate_interval])) by (le))'
|
'histogram_quantile(.9, sum(rate(traces_spanmetrics_latency_bucket{span_name="${__data.fields[0]}"}[$__rate_interval])) by (le))'
|
||||||
);
|
);
|
||||||
expect(response.data[0].fields[5].config.links[0].internal.query.range).toBe(true);
|
expect(response.data[0].fields[5]?.config?.links?.[0]?.internal?.query.range).toBe(true);
|
||||||
expect(response.data[0].fields[5].config.links[0].internal.query.exemplar).toBe(true);
|
expect(response.data[0].fields[5]?.config?.links?.[0]?.internal?.query.exemplar).toBe(true);
|
||||||
expect(response.data[0].fields[5].config.links[0].internal.query.instant).toBe(false);
|
expect(response.data[0].fields[5]?.config?.links?.[0]?.internal?.query.instant).toBe(false);
|
||||||
|
|
||||||
expect(response.data[0].fields[6].config.links[0].url).toBe('');
|
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].title).toBe('Tempo');
|
||||||
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.queryType).toBe('traceqlSearch');
|
||||||
expect(response.data[0].fields[6].config.links[0].internal.query.filters[0].value).toBe('${__data.fields[0]}');
|
expect(response.data[0].fields[6]?.config?.links?.[0].internal.query.filters[0].value).toBe('${__data.fields[0]}');
|
||||||
|
|
||||||
// Service graph
|
// Service graph
|
||||||
expect(response.data[1].name).toBe('Nodes');
|
expect(response.data[1].name).toBe('Nodes');
|
||||||
expect(response.data[1].fields[0].values.length).toBe(3);
|
expect(response.data[1].fields[0].values.length).toBe(3);
|
||||||
expect(response.data[1].fields[0].config.links.length).toBeGreaterThan(0);
|
expect(response.data[1].fields[0]?.config?.links?.length).toBeGreaterThan(0);
|
||||||
expect(response.data[1].fields[0].config.links).toEqual(serviceGraphLinks);
|
expect(response.data[1].fields[0]?.config?.links).toEqual(serviceGraphLinks);
|
||||||
|
|
||||||
expect(response.data[2].name).toBe('Edges');
|
expect(response.data[2].name).toBe('Edges');
|
||||||
expect(response.data[2].fields[0].values.length).toBe(2);
|
expect(response.data[2].fields[0].values.length).toBe(2);
|
||||||
@ -804,7 +804,7 @@ describe('Tempo service graph view', () => {
|
|||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'Time',
|
name: 'Time',
|
||||||
type: 'time',
|
type: FieldType.time,
|
||||||
config: {},
|
config: {},
|
||||||
values: [1653828275000, 1653828275000, 1653828275000, 1653828275000, 1653828275000],
|
values: [1653828275000, 1653828275000, 1653828275000, 1653828275000, 1653828275000],
|
||||||
},
|
},
|
||||||
@ -813,12 +813,14 @@ describe('Tempo service graph view', () => {
|
|||||||
config: {
|
config: {
|
||||||
filterable: true,
|
filterable: true,
|
||||||
},
|
},
|
||||||
type: 'string',
|
type: FieldType.string,
|
||||||
values: ['HTTP Client', 'HTTP GET', 'HTTP GET - root', 'HTTP POST', 'HTTP POST - post'],
|
values: ['HTTP Client', 'HTTP GET', 'HTTP GET - root', 'HTTP POST', 'HTTP POST - post'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
values: [],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const objToAlign = {
|
const objToAlign = {
|
||||||
'HTTP GET - root': {
|
'HTTP GET - root': {
|
||||||
value: '0.1234',
|
value: '0.1234',
|
||||||
|
@ -6,13 +6,13 @@ import semver from 'semver';
|
|||||||
import {
|
import {
|
||||||
CoreApp,
|
CoreApp,
|
||||||
DataFrame,
|
DataFrame,
|
||||||
|
DataFrameDTO,
|
||||||
DataQueryRequest,
|
DataQueryRequest,
|
||||||
DataQueryResponse,
|
DataQueryResponse,
|
||||||
DataQueryResponseData,
|
DataQueryResponseData,
|
||||||
DataSourceApi,
|
DataSourceApi,
|
||||||
DataSourceInstanceSettings,
|
DataSourceInstanceSettings,
|
||||||
dateTime,
|
dateTime,
|
||||||
Field,
|
|
||||||
FieldType,
|
FieldType,
|
||||||
isValidGoDuration,
|
isValidGoDuration,
|
||||||
LoadingState,
|
LoadingState,
|
||||||
@ -86,6 +86,17 @@ const featuresToTempoVersion = {
|
|||||||
// This is the last minor version of Tempo that does not expose the endpoint for build information.
|
// This is the last minor version of Tempo that does not expose the endpoint for build information.
|
||||||
const defaultTempoVersion = '2.1.0';
|
const defaultTempoVersion = '2.1.0';
|
||||||
|
|
||||||
|
interface ServiceMapQueryResponse {
|
||||||
|
nodes: DataFrame;
|
||||||
|
edges: DataFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ServiceMapQueryResponseWithRates {
|
||||||
|
rates: Array<DataFrame | DataFrameDTO>;
|
||||||
|
nodes: DataFrame;
|
||||||
|
edges: DataFrame;
|
||||||
|
}
|
||||||
|
|
||||||
export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJsonData> {
|
export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJsonData> {
|
||||||
tracesToLogs?: TraceToLogsOptions;
|
tracesToLogs?: TraceToLogsOptions;
|
||||||
serviceMap?: {
|
serviceMap?: {
|
||||||
@ -783,7 +794,11 @@ function queryPrometheus(request: DataQueryRequest<PromQuery>, datasourceUid: st
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function serviceMapQuery(request: DataQueryRequest<TempoQuery>, datasourceUid: string, tempoDatasourceUid: string) {
|
function serviceMapQuery(
|
||||||
|
request: DataQueryRequest<TempoQuery>,
|
||||||
|
datasourceUid: string,
|
||||||
|
tempoDatasourceUid: string
|
||||||
|
): Observable<ServiceMapQueryResponse> {
|
||||||
const serviceMapRequest = makePromServiceMapRequest(request);
|
const serviceMapRequest = makePromServiceMapRequest(request);
|
||||||
|
|
||||||
return queryPrometheus(serviceMapRequest, datasourceUid).pipe(
|
return queryPrometheus(serviceMapRequest, datasourceUid).pipe(
|
||||||
@ -849,7 +864,8 @@ function serviceMapQuery(request: DataQueryRequest<TempoQuery>, datasourceUid: s
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: [nodes, edges],
|
nodes,
|
||||||
|
edges,
|
||||||
state: LoadingState.Done,
|
state: LoadingState.Done,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@ -858,9 +874,9 @@ function serviceMapQuery(request: DataQueryRequest<TempoQuery>, datasourceUid: s
|
|||||||
|
|
||||||
function rateQuery(
|
function rateQuery(
|
||||||
request: DataQueryRequest<TempoQuery>,
|
request: DataQueryRequest<TempoQuery>,
|
||||||
serviceMapResponse: DataQueryResponse,
|
serviceMapResponse: ServiceMapQueryResponse,
|
||||||
datasourceUid: string
|
datasourceUid: string
|
||||||
) {
|
): Observable<ServiceMapQueryResponseWithRates> {
|
||||||
const serviceMapRequest = makePromServiceMapRequest(request);
|
const serviceMapRequest = makePromServiceMapRequest(request);
|
||||||
serviceMapRequest.targets = makeServiceGraphViewRequest([buildExpr(rateMetric, defaultTableFilter, request)]);
|
serviceMapRequest.targets = makeServiceGraphViewRequest([buildExpr(rateMetric, defaultTableFilter, request)]);
|
||||||
|
|
||||||
@ -872,8 +888,9 @@ function rateQuery(
|
|||||||
throw new Error(getErrorMessage(errorRes.error?.message));
|
throw new Error(getErrorMessage(errorRes.error?.message));
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
data: [responses[0]?.data ?? [], serviceMapResponse.data[0], serviceMapResponse.data[1]],
|
rates: responses[0]?.data ?? [],
|
||||||
state: LoadingState.Done,
|
nodes: serviceMapResponse.nodes,
|
||||||
|
edges: serviceMapResponse.edges,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -883,7 +900,7 @@ function rateQuery(
|
|||||||
// -> which determine the errorRate/duration span_name(s) we need to query
|
// -> which determine the errorRate/duration span_name(s) we need to query
|
||||||
function errorAndDurationQuery(
|
function errorAndDurationQuery(
|
||||||
request: DataQueryRequest<TempoQuery>,
|
request: DataQueryRequest<TempoQuery>,
|
||||||
rateResponse: DataQueryResponse,
|
rateResponse: ServiceMapQueryResponseWithRates,
|
||||||
datasourceUid: string,
|
datasourceUid: string,
|
||||||
tempoDatasourceUid: string
|
tempoDatasourceUid: string
|
||||||
) {
|
) {
|
||||||
@ -892,14 +909,14 @@ function errorAndDurationQuery(
|
|||||||
let durationsBySpanName: string[] = [];
|
let durationsBySpanName: string[] = [];
|
||||||
|
|
||||||
let labels = [];
|
let labels = [];
|
||||||
if (rateResponse.data[0][0] && request.app === CoreApp.Explore) {
|
if (rateResponse.rates[0] && request.app === CoreApp.Explore) {
|
||||||
const spanNameField = rateResponse.data[0][0].fields.find((field: Field) => field.name === 'span_name');
|
const spanNameField = rateResponse.rates[0].fields.find((field) => field.name === 'span_name');
|
||||||
if (spanNameField && spanNameField.values) {
|
if (spanNameField && spanNameField.values) {
|
||||||
labels = spanNameField.values;
|
labels = spanNameField.values;
|
||||||
}
|
}
|
||||||
} else if (rateResponse.data[0]) {
|
} else if (rateResponse.rates) {
|
||||||
rateResponse.data[0].map((df: DataFrame) => {
|
rateResponse.rates.map((df: DataFrame | DataFrameDTO) => {
|
||||||
const spanNameLabels = df.fields.find((field: Field) => field.labels?.['span_name']);
|
const spanNameLabels = df.fields.find((field) => field.labels?.['span_name']);
|
||||||
if (spanNameLabels) {
|
if (spanNameLabels) {
|
||||||
labels.push(spanNameLabels.labels?.['span_name']);
|
labels.push(spanNameLabels.labels?.['span_name']);
|
||||||
}
|
}
|
||||||
@ -941,13 +958,13 @@ function errorAndDurationQuery(
|
|||||||
|
|
||||||
if (serviceGraphView.fields.length === 0) {
|
if (serviceGraphView.fields.length === 0) {
|
||||||
return {
|
return {
|
||||||
data: [rateResponse.data[1], rateResponse.data[2]],
|
data: [rateResponse.nodes, rateResponse.edges],
|
||||||
state: LoadingState.Done,
|
state: LoadingState.Done,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: [serviceGraphView, rateResponse.data[1], rateResponse.data[2]],
|
data: [serviceGraphView, rateResponse.nodes, rateResponse.edges],
|
||||||
state: LoadingState.Done,
|
state: LoadingState.Done,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@ -1078,7 +1095,7 @@ function makePromServiceMapRequest(options: DataQueryRequest<TempoQuery>): DataQ
|
|||||||
|
|
||||||
function getServiceGraphView(
|
function getServiceGraphView(
|
||||||
request: DataQueryRequest<TempoQuery>,
|
request: DataQueryRequest<TempoQuery>,
|
||||||
rateResponse: DataQueryResponse,
|
rateResponse: ServiceMapQueryResponseWithRates,
|
||||||
secondResponse: DataQueryResponse,
|
secondResponse: DataQueryResponse,
|
||||||
errorRateBySpanName: string,
|
errorRateBySpanName: string,
|
||||||
durationsBySpanName: string[],
|
durationsBySpanName: string[],
|
||||||
@ -1086,14 +1103,15 @@ function getServiceGraphView(
|
|||||||
tempoDatasourceUid: string
|
tempoDatasourceUid: string
|
||||||
) {
|
) {
|
||||||
let df: any = { fields: [] };
|
let df: any = { fields: [] };
|
||||||
const rate = rateResponse.data[0]?.filter((x: { refId: string }) => {
|
|
||||||
|
const rate = rateResponse.rates.filter((x) => {
|
||||||
return x.refId === buildExpr(rateMetric, defaultTableFilter, request);
|
return x.refId === buildExpr(rateMetric, defaultTableFilter, request);
|
||||||
});
|
});
|
||||||
const errorRate = secondResponse.data.filter((x) => {
|
const errorRate = secondResponse.data.filter((x) => {
|
||||||
return x.refId === errorRateBySpanName;
|
return x.refId === errorRateBySpanName;
|
||||||
});
|
});
|
||||||
const duration = secondResponse.data.filter((x) => {
|
const duration = secondResponse.data.filter((x) => {
|
||||||
return durationsBySpanName.includes(x.refId);
|
return durationsBySpanName.includes(x.refId ?? '');
|
||||||
});
|
});
|
||||||
|
|
||||||
if (rate.length > 0 && rate[0].fields?.length > 2) {
|
if (rate.length > 0 && rate[0].fields?.length > 2) {
|
||||||
@ -1193,7 +1211,7 @@ function getServiceGraphView(
|
|||||||
if (d.fields.length > 1) {
|
if (d.fields.length > 1) {
|
||||||
const delimiter = d.refId?.includes('span_name=~"') ? 'span_name=~"' : 'span_name="';
|
const delimiter = d.refId?.includes('span_name=~"') ? 'span_name=~"' : 'span_name="';
|
||||||
const name = d.refId?.split(delimiter)[1].split('"}')[0];
|
const name = d.refId?.split(delimiter)[1].split('"}')[0];
|
||||||
durationObj[name] = { value: d.fields[1].values[0] };
|
durationObj[name!] = { value: d.fields[1].values[0] };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (Object.keys(durationObj).length > 0) {
|
if (Object.keys(durationObj).length > 0) {
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
NodeGraphDataFrameFieldNames as Fields,
|
NodeGraphDataFrameFieldNames as Fields,
|
||||||
TimeRange,
|
TimeRange,
|
||||||
FieldType,
|
FieldType,
|
||||||
|
toDataFrame,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
|
|
||||||
import { getNonOverlappingDuration, getStats, makeFrames, makeSpanMap } from '../../../core/utils/tracing';
|
import { getNonOverlappingDuration, getStats, makeFrames, makeSpanMap } from '../../../core/utils/tracing';
|
||||||
@ -189,39 +190,53 @@ function createServiceMapDataFrames() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nodes = createDF('Nodes', [
|
const nodes = createDF('Nodes', [
|
||||||
{ name: Fields.id, type: FieldType.string },
|
{ name: Fields.id, type: FieldType.string, values: [] },
|
||||||
{ name: Fields.title, type: FieldType.string, config: { displayName: 'Service name' } },
|
{ name: Fields.title, type: FieldType.string, config: { displayName: 'Service name' }, values: [] },
|
||||||
{ name: Fields.subTitle, type: FieldType.string, config: { displayName: 'Service namespace' } },
|
{ name: Fields.subTitle, type: FieldType.string, config: { displayName: 'Service namespace' }, values: [] },
|
||||||
{ name: Fields.mainStat, type: FieldType.number, config: { unit: 'ms/r', displayName: 'Average response time' } },
|
{
|
||||||
|
name: Fields.mainStat,
|
||||||
|
type: FieldType.number,
|
||||||
|
config: { unit: 'ms/r', displayName: 'Average response time' },
|
||||||
|
values: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: Fields.secondaryStat,
|
name: Fields.secondaryStat,
|
||||||
type: FieldType.number,
|
type: FieldType.number,
|
||||||
config: { unit: 'r/sec', displayName: 'Requests per second' },
|
config: { unit: 'r/sec', displayName: 'Requests per second' },
|
||||||
|
values: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: Fields.arc + 'success',
|
name: Fields.arc + 'success',
|
||||||
type: FieldType.number,
|
type: FieldType.number,
|
||||||
config: { displayName: 'Success', color: { fixedColor: 'green', mode: FieldColorModeId.Fixed } },
|
config: { displayName: 'Success', color: { fixedColor: 'green', mode: FieldColorModeId.Fixed } },
|
||||||
|
values: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: Fields.arc + 'failed',
|
name: Fields.arc + 'failed',
|
||||||
type: FieldType.number,
|
type: FieldType.number,
|
||||||
config: { displayName: 'Failed', color: { fixedColor: 'red', mode: FieldColorModeId.Fixed } },
|
config: { displayName: 'Failed', color: { fixedColor: 'red', mode: FieldColorModeId.Fixed } },
|
||||||
|
values: [],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const edges = createDF('Edges', [
|
const edges = createDF('Edges', [
|
||||||
{ name: Fields.id, type: FieldType.string },
|
{ name: Fields.id, type: FieldType.string, values: [] },
|
||||||
{ name: Fields.source, type: FieldType.string },
|
{ name: Fields.source, type: FieldType.string, values: [] },
|
||||||
{ name: AdditionalEdgeFields.sourceName, type: FieldType.string },
|
{ name: AdditionalEdgeFields.sourceName, type: FieldType.string, values: [] },
|
||||||
{ name: AdditionalEdgeFields.sourceNamespace, type: FieldType.string },
|
{ name: AdditionalEdgeFields.sourceNamespace, type: FieldType.string, values: [] },
|
||||||
{ name: Fields.target, type: FieldType.string },
|
{ name: Fields.target, type: FieldType.string, values: [] },
|
||||||
{ name: AdditionalEdgeFields.targetName, type: FieldType.string },
|
{ name: AdditionalEdgeFields.targetName, type: FieldType.string, values: [] },
|
||||||
{ name: AdditionalEdgeFields.targetNamespace, type: FieldType.string },
|
{ name: AdditionalEdgeFields.targetNamespace, type: FieldType.string, values: [] },
|
||||||
{ name: Fields.mainStat, type: FieldType.number, config: { unit: 'ms/r', displayName: 'Average response time' } },
|
{
|
||||||
|
name: Fields.mainStat,
|
||||||
|
type: FieldType.number,
|
||||||
|
config: { unit: 'ms/r', displayName: 'Average response time' },
|
||||||
|
values: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: Fields.secondaryStat,
|
name: Fields.secondaryStat,
|
||||||
type: FieldType.number,
|
type: FieldType.number,
|
||||||
config: { unit: 'r/sec', displayName: 'Requests per second' },
|
config: { unit: 'r/sec', displayName: 'Requests per second' },
|
||||||
|
values: [],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -234,8 +249,9 @@ function createServiceMapDataFrames() {
|
|||||||
* @param responses
|
* @param responses
|
||||||
*/
|
*/
|
||||||
function getMetricFrames(responses: DataQueryResponse[]): Record<string, DataFrameView> {
|
function getMetricFrames(responses: DataQueryResponse[]): Record<string, DataFrameView> {
|
||||||
return responses[0].data.reduce<Record<string, DataFrameView>>((acc, frame) => {
|
return responses[0].data.reduce<Record<string, DataFrameView>>((acc, frameDTO) => {
|
||||||
acc[frame.refId] = new DataFrameView(frame);
|
const frame = toDataFrame(frameDTO);
|
||||||
|
acc[frame.refId ?? 'A'] = new DataFrameView(frame);
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ export function createTableFrameFromMetricsSummaryQuery(
|
|||||||
name: `${series.key}`,
|
name: `${series.key}`,
|
||||||
type: FieldType.string,
|
type: FieldType.string,
|
||||||
config: getConfig(series, configQuery, instanceSettings),
|
config: getConfig(series, configQuery, instanceSettings),
|
||||||
|
values: [],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -16,6 +16,8 @@ import {
|
|||||||
createDataFrame,
|
createDataFrame,
|
||||||
getDisplayProcessor,
|
getDisplayProcessor,
|
||||||
createTheme,
|
createTheme,
|
||||||
|
DataFrameDTO,
|
||||||
|
toDataFrame,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
|
|
||||||
import { SearchTableType } from './dataquery.gen';
|
import { SearchTableType } from './dataquery.gen';
|
||||||
@ -23,7 +25,7 @@ import { createGraphFrames } from './graphTransform';
|
|||||||
import { Span, SpanAttributes, Spanset, TraceSearchMetadata } from './types';
|
import { Span, SpanAttributes, Spanset, TraceSearchMetadata } from './types';
|
||||||
|
|
||||||
export function createTableFrame(
|
export function createTableFrame(
|
||||||
logsFrame: DataFrame,
|
logsFrame: DataFrame | DataFrameDTO,
|
||||||
datasourceUid: string,
|
datasourceUid: string,
|
||||||
datasourceName: string,
|
datasourceName: string,
|
||||||
traceRegexs: string[]
|
traceRegexs: string[]
|
||||||
@ -38,6 +40,7 @@ export function createTableFrame(
|
|||||||
width: 200,
|
width: 200,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
values: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'traceID',
|
name: 'traceID',
|
||||||
@ -59,10 +62,12 @@ export function createTableFrame(
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
values: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Message',
|
name: 'Message',
|
||||||
type: FieldType.string,
|
type: FieldType.string,
|
||||||
|
values: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
meta: {
|
meta: {
|
||||||
@ -80,7 +85,7 @@ export function createTableFrame(
|
|||||||
for (let field of logsFrame.fields) {
|
for (let field of logsFrame.fields) {
|
||||||
let hasMatch = false;
|
let hasMatch = false;
|
||||||
if (field.type === FieldType.string) {
|
if (field.type === FieldType.string) {
|
||||||
const values = field.values;
|
const values = field.values!;
|
||||||
for (let i = 0; i < values.length; i++) {
|
for (let i = 0; i < values.length; i++) {
|
||||||
const line = values[i];
|
const line = values[i];
|
||||||
if (line) {
|
if (line) {
|
||||||
@ -88,7 +93,7 @@ export function createTableFrame(
|
|||||||
const match = line.match(traceRegex);
|
const match = line.match(traceRegex);
|
||||||
if (match) {
|
if (match) {
|
||||||
const traceId = match[1];
|
const traceId = match[1];
|
||||||
const time = timeField ? timeField.values[i] : null;
|
const time = timeField ? timeField.values![i] : null;
|
||||||
tableFrame.fields[0].values.push(time);
|
tableFrame.fields[0].values.push(time);
|
||||||
tableFrame.fields[1].values.push(traceId);
|
tableFrame.fields[1].values.push(traceId);
|
||||||
tableFrame.fields[2].values.push(line);
|
tableFrame.fields[2].values.push(line);
|
||||||
@ -226,23 +231,23 @@ export function transformFromOTLP(
|
|||||||
): DataQueryResponse {
|
): DataQueryResponse {
|
||||||
const frame = new MutableDataFrame({
|
const frame = new MutableDataFrame({
|
||||||
fields: [
|
fields: [
|
||||||
{ name: 'traceID', type: FieldType.string },
|
{ name: 'traceID', type: FieldType.string, values: [] },
|
||||||
{ name: 'spanID', type: FieldType.string },
|
{ name: 'spanID', type: FieldType.string, values: [] },
|
||||||
{ name: 'parentSpanID', type: FieldType.string },
|
{ name: 'parentSpanID', type: FieldType.string, values: [] },
|
||||||
{ name: 'operationName', type: FieldType.string },
|
{ name: 'operationName', type: FieldType.string, values: [] },
|
||||||
{ name: 'serviceName', type: FieldType.string },
|
{ name: 'serviceName', type: FieldType.string, values: [] },
|
||||||
{ name: 'kind', type: FieldType.string },
|
{ name: 'kind', type: FieldType.string, values: [] },
|
||||||
{ name: 'statusCode', type: FieldType.number },
|
{ name: 'statusCode', type: FieldType.number, values: [] },
|
||||||
{ name: 'statusMessage', type: FieldType.string },
|
{ name: 'statusMessage', type: FieldType.string, values: [] },
|
||||||
{ name: 'instrumentationLibraryName', type: FieldType.string },
|
{ name: 'instrumentationLibraryName', type: FieldType.string, values: [] },
|
||||||
{ name: 'instrumentationLibraryVersion', type: FieldType.string },
|
{ name: 'instrumentationLibraryVersion', type: FieldType.string, values: [] },
|
||||||
{ name: 'traceState', type: FieldType.string },
|
{ name: 'traceState', type: FieldType.string, values: [] },
|
||||||
{ name: 'serviceTags', type: FieldType.other },
|
{ name: 'serviceTags', type: FieldType.other, values: [] },
|
||||||
{ name: 'startTime', type: FieldType.number },
|
{ name: 'startTime', type: FieldType.number, values: [] },
|
||||||
{ name: 'duration', type: FieldType.number },
|
{ name: 'duration', type: FieldType.number, values: [] },
|
||||||
{ name: 'logs', type: FieldType.other },
|
{ name: 'logs', type: FieldType.other, values: [] },
|
||||||
{ name: 'references', type: FieldType.other },
|
{ name: 'references', type: FieldType.other, values: [] },
|
||||||
{ name: 'tags', type: FieldType.other },
|
{ name: 'tags', type: FieldType.other, values: [] },
|
||||||
],
|
],
|
||||||
meta: {
|
meta: {
|
||||||
preferredVisualisationType: 'trace',
|
preferredVisualisationType: 'trace',
|
||||||
@ -487,7 +492,7 @@ function getOTLPReferences(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function transformTrace(response: DataQueryResponse, nodeGraph = false): DataQueryResponse {
|
export function transformTrace(response: DataQueryResponse, nodeGraph = false): DataQueryResponse {
|
||||||
const frame: DataFrame = response.data[0];
|
const frame = response.data[0];
|
||||||
|
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return emptyDataQueryResponse;
|
return emptyDataQueryResponse;
|
||||||
@ -495,7 +500,7 @@ export function transformTrace(response: DataQueryResponse, nodeGraph = false):
|
|||||||
|
|
||||||
let data = [...response.data];
|
let data = [...response.data];
|
||||||
if (nodeGraph) {
|
if (nodeGraph) {
|
||||||
data.push(...createGraphFrames(frame));
|
data.push(...createGraphFrames(toDataFrame(frame)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -512,6 +517,7 @@ export function createTableFrameFromSearch(data: TraceSearchMetadata[], instance
|
|||||||
{
|
{
|
||||||
name: 'traceID',
|
name: 'traceID',
|
||||||
type: FieldType.string,
|
type: FieldType.string,
|
||||||
|
values: [],
|
||||||
config: {
|
config: {
|
||||||
unit: 'string',
|
unit: 'string',
|
||||||
displayNameFromDS: 'Trace ID',
|
displayNameFromDS: 'Trace ID',
|
||||||
@ -531,10 +537,15 @@ export function createTableFrameFromSearch(data: TraceSearchMetadata[], instance
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ name: 'traceService', type: FieldType.string, config: { displayNameFromDS: 'Trace service' } },
|
{ name: 'traceService', type: FieldType.string, config: { displayNameFromDS: 'Trace service' }, values: [] },
|
||||||
{ name: 'traceName', type: FieldType.string, config: { displayNameFromDS: 'Trace name' } },
|
{ name: 'traceName', type: FieldType.string, config: { displayNameFromDS: 'Trace name' }, values: [] },
|
||||||
{ name: 'startTime', type: FieldType.time, config: { displayNameFromDS: 'Start time' } },
|
{ name: 'startTime', type: FieldType.time, config: { displayNameFromDS: 'Start time' }, values: [] },
|
||||||
{ name: 'traceDuration', type: FieldType.number, config: { displayNameFromDS: 'Duration', unit: 'ms' } },
|
{
|
||||||
|
name: 'traceDuration',
|
||||||
|
type: FieldType.number,
|
||||||
|
config: { displayNameFromDS: 'Duration', unit: 'ms' },
|
||||||
|
values: [],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
meta: {
|
meta: {
|
||||||
preferredVisualisationType: 'table',
|
preferredVisualisationType: 'table',
|
||||||
@ -826,6 +837,7 @@ const traceSubFrame = (
|
|||||||
name: attr.key,
|
name: attr.key,
|
||||||
type: FieldType.string,
|
type: FieldType.string,
|
||||||
config: { displayNameFromDS: attr.key },
|
config: { displayNameFromDS: attr.key },
|
||||||
|
values: [],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
spanSet.spans.forEach((span) => {
|
spanSet.spans.forEach((span) => {
|
||||||
@ -837,6 +849,7 @@ const traceSubFrame = (
|
|||||||
name: attr.key,
|
name: attr.key,
|
||||||
type: FieldType.string,
|
type: FieldType.string,
|
||||||
config: { displayNameFromDS: attr.key },
|
config: { displayNameFromDS: attr.key },
|
||||||
|
values: [],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -849,10 +862,12 @@ const traceSubFrame = (
|
|||||||
config: {
|
config: {
|
||||||
custom: { hidden: true },
|
custom: { hidden: true },
|
||||||
},
|
},
|
||||||
|
values: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'spanID',
|
name: 'spanID',
|
||||||
type: FieldType.string,
|
type: FieldType.string,
|
||||||
|
values: [],
|
||||||
config: {
|
config: {
|
||||||
unit: 'string',
|
unit: 'string',
|
||||||
displayNameFromDS: 'Span ID',
|
displayNameFromDS: 'Span ID',
|
||||||
@ -893,12 +908,14 @@ const traceSubFrame = (
|
|||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
type: FieldType.string,
|
type: FieldType.string,
|
||||||
|
values: [],
|
||||||
config: { displayNameFromDS: 'Name', custom: { hidden: !hasNameAttribute } },
|
config: { displayNameFromDS: 'Name', custom: { hidden: !hasNameAttribute } },
|
||||||
},
|
},
|
||||||
...Object.values(spanDynamicAttrs).sort((a, b) => a.name.localeCompare(b.name)),
|
...Object.values(spanDynamicAttrs).sort((a, b) => a.name.localeCompare(b.name)),
|
||||||
{
|
{
|
||||||
name: 'duration',
|
name: 'duration',
|
||||||
type: FieldType.number,
|
type: FieldType.number,
|
||||||
|
values: [],
|
||||||
config: {
|
config: {
|
||||||
displayNameFromDS: 'Duration',
|
displayNameFromDS: 'Duration',
|
||||||
unit: 'ns',
|
unit: 'ns',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { from, Observable } from 'rxjs';
|
import { from, Observable } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { DataQueryRequest, DataQueryResponse, CustomVariableSupport } from '@grafana/data';
|
import { DataQueryRequest, CustomVariableSupport, MetricFindValue } from '@grafana/data';
|
||||||
|
|
||||||
import { TempoVariableQuery, TempoVariableQueryEditor } from './VariableQueryEditor';
|
import { TempoVariableQuery, TempoVariableQueryEditor } from './VariableQueryEditor';
|
||||||
import { TempoDatasource } from './datasource';
|
import { TempoDatasource } from './datasource';
|
||||||
@ -13,7 +13,7 @@ export class TempoVariableSupport extends CustomVariableSupport<TempoDatasource,
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
query(request: DataQueryRequest<TempoVariableQuery>): Observable<DataQueryResponse> {
|
query(request: DataQueryRequest<TempoVariableQuery>): Observable<{ data: MetricFindValue[] }> {
|
||||||
if (!this.datasource) {
|
if (!this.datasource) {
|
||||||
throw new Error('Datasource not initialized');
|
throw new Error('Datasource not initialized');
|
||||||
}
|
}
|
||||||
|
@ -9,16 +9,16 @@ export function transformResponse(zSpans: ZipkinSpan[]): DataFrame {
|
|||||||
const spanRows = zSpans.map(transformSpan);
|
const spanRows = zSpans.map(transformSpan);
|
||||||
const frame = new MutableDataFrame({
|
const frame = new MutableDataFrame({
|
||||||
fields: [
|
fields: [
|
||||||
{ name: 'traceID', type: FieldType.string },
|
{ name: 'traceID', type: FieldType.string, values: [] },
|
||||||
{ name: 'spanID', type: FieldType.string },
|
{ name: 'spanID', type: FieldType.string, values: [] },
|
||||||
{ name: 'parentSpanID', type: FieldType.string },
|
{ name: 'parentSpanID', type: FieldType.string, values: [] },
|
||||||
{ name: 'operationName', type: FieldType.string },
|
{ name: 'operationName', type: FieldType.string, values: [] },
|
||||||
{ name: 'serviceName', type: FieldType.string },
|
{ name: 'serviceName', type: FieldType.string, values: [] },
|
||||||
{ name: 'serviceTags', type: FieldType.other },
|
{ name: 'serviceTags', type: FieldType.other, values: [] },
|
||||||
{ name: 'startTime', type: FieldType.number },
|
{ name: 'startTime', type: FieldType.number, values: [] },
|
||||||
{ name: 'duration', type: FieldType.number },
|
{ name: 'duration', type: FieldType.number, values: [] },
|
||||||
{ name: 'logs', type: FieldType.other },
|
{ name: 'logs', type: FieldType.other, values: [] },
|
||||||
{ name: 'tags', type: FieldType.other },
|
{ name: 'tags', type: FieldType.other, values: [] },
|
||||||
],
|
],
|
||||||
meta: {
|
meta: {
|
||||||
preferredVisualisationType: 'trace',
|
preferredVisualisationType: 'trace',
|
||||||
|
Loading…
Reference in New Issue
Block a user