mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 08:56:43 -06:00
Add catch around JSON trace upload for more error handling (#38520)
This commit is contained in:
parent
d1b6132302
commit
76ade24f2f
@ -89,6 +89,18 @@ describe('JaegerDatasource', () => {
|
||||
expect(field.values.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should fail on invalid json file upload', async () => {
|
||||
const ds = new JaegerDatasource(defaultSettings);
|
||||
ds.uploadedJson = JSON.stringify({ key: 'value', arr: [] });
|
||||
const response = await lastValueFrom(
|
||||
ds.query({
|
||||
targets: [{ queryType: 'upload', refId: 'A' }],
|
||||
} as any)
|
||||
);
|
||||
expect(response.error?.message).toBeDefined();
|
||||
expect(response.data.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should return search results when the query type is search', async () => {
|
||||
const mock = setupFetchMock({ data: [testResponse] });
|
||||
const ds = new JaegerDatasource(defaultSettings, timeSrvStub);
|
||||
|
@ -58,8 +58,13 @@ export class JaegerDatasource extends DataSourceApi<JaegerQuery> {
|
||||
if (!this.uploadedJson) {
|
||||
return of({ data: [] });
|
||||
}
|
||||
const traceData = JSON.parse(this.uploadedJson as string).data[0];
|
||||
return of({ data: [createTraceFrame(traceData), ...createGraphFrames(traceData)] });
|
||||
|
||||
try {
|
||||
const traceData = JSON.parse(this.uploadedJson as string).data[0];
|
||||
return of({ data: [createTraceFrame(traceData), ...createGraphFrames(traceData)] });
|
||||
} catch (error) {
|
||||
return of({ error: { message: 'JSON is not valid Jaeger format' }, data: [] });
|
||||
}
|
||||
}
|
||||
|
||||
let jaegerQuery = pick(target, ['operation', 'service', 'tags', 'minDuration', 'maxDuration', 'limit']);
|
||||
|
@ -119,6 +119,18 @@ describe('Tempo data source', () => {
|
||||
expect(field.values.length).toBe(6);
|
||||
});
|
||||
|
||||
it('should fail on invalid json file upload', async () => {
|
||||
const ds = new TempoDatasource(defaultSettings);
|
||||
ds.uploadedJson = JSON.stringify(mockInvalidJson);
|
||||
const response = await lastValueFrom(
|
||||
ds.query({
|
||||
targets: [{ queryType: 'upload', refId: 'A' }],
|
||||
} as any)
|
||||
);
|
||||
expect(response.error?.message).toBeDefined();
|
||||
expect(response.data.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should build search query correctly', () => {
|
||||
const ds = new TempoDatasource(defaultSettings);
|
||||
const tempoQuery: TempoQuery = {
|
||||
@ -229,3 +241,36 @@ const secondsPromMetric = new MutableDataFrame({
|
||||
{ name: 'Value #tempo_service_graph_request_server_seconds_sum', values: [10, 40] },
|
||||
],
|
||||
});
|
||||
|
||||
const mockInvalidJson = {
|
||||
batches: [
|
||||
{
|
||||
resource: {
|
||||
attributes: [],
|
||||
},
|
||||
instrumentation_library_spans: [
|
||||
{
|
||||
instrumentation_library: {},
|
||||
spans: [
|
||||
{
|
||||
trace_id: 'AAAAAAAAAABguiq7RPE+rg==',
|
||||
span_id: 'cmteMBAvwNA=',
|
||||
parentSpanId: 'OY8PIaPbma4=',
|
||||
name: 'HTTP GET - root',
|
||||
kind: 'SPAN_KIND_SERVER',
|
||||
startTimeUnixNano: '1627471657255809000',
|
||||
endTimeUnixNano: '1627471657256268000',
|
||||
attributes: [
|
||||
{ key: 'http.status_code', value: { intValue: '200' } },
|
||||
{ key: 'http.method', value: { stringValue: 'GET' } },
|
||||
{ key: 'http.url', value: { stringValue: '/' } },
|
||||
{ key: 'component', value: { stringValue: 'net/http' } },
|
||||
],
|
||||
status: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -115,7 +115,7 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
|
||||
if (this.uploadedJson) {
|
||||
const otelTraceData = JSON.parse(this.uploadedJson as string);
|
||||
if (!otelTraceData.batches) {
|
||||
subQueries.push(of({ error: { message: 'JSON is not valid opentelemetry format' }, data: [] }));
|
||||
subQueries.push(of({ error: { message: 'JSON is not valid OpenTelemetry format' }, data: [] }));
|
||||
} else {
|
||||
subQueries.push(of(transformFromOTEL(otelTraceData.batches)));
|
||||
}
|
||||
|
@ -250,25 +250,28 @@ export function transformFromOTLP(
|
||||
preferredVisualisationType: 'trace',
|
||||
},
|
||||
});
|
||||
|
||||
for (const data of traceData) {
|
||||
const { serviceName, serviceTags } = resourceToProcess(data.resource);
|
||||
for (const librarySpan of data.instrumentationLibrarySpans) {
|
||||
for (const span of librarySpan.spans) {
|
||||
frame.add({
|
||||
traceID: transformBase64IDToHexString(span.traceId),
|
||||
spanID: transformBase64IDToHexString(span.spanId),
|
||||
parentSpanID: transformBase64IDToHexString(span.parentSpanId || ''),
|
||||
operationName: span.name || '',
|
||||
serviceName,
|
||||
serviceTags,
|
||||
startTime: span.startTimeUnixNano! / 1000000,
|
||||
duration: (span.endTimeUnixNano! - span.startTimeUnixNano!) / 1000000,
|
||||
tags: getSpanTags(span, librarySpan.instrumentationLibrary),
|
||||
logs: getLogs(span),
|
||||
} as TraceSpanRow);
|
||||
try {
|
||||
for (const data of traceData) {
|
||||
const { serviceName, serviceTags } = resourceToProcess(data.resource);
|
||||
for (const librarySpan of data.instrumentationLibrarySpans) {
|
||||
for (const span of librarySpan.spans) {
|
||||
frame.add({
|
||||
traceID: transformBase64IDToHexString(span.traceId),
|
||||
spanID: transformBase64IDToHexString(span.spanId),
|
||||
parentSpanID: transformBase64IDToHexString(span.parentSpanId || ''),
|
||||
operationName: span.name || '',
|
||||
serviceName,
|
||||
serviceTags,
|
||||
startTime: span.startTimeUnixNano! / 1000000,
|
||||
duration: (span.endTimeUnixNano! - span.startTimeUnixNano!) / 1000000,
|
||||
tags: getSpanTags(span, librarySpan.instrumentationLibrary),
|
||||
logs: getLogs(span),
|
||||
} as TraceSpanRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
return { error: { message: 'JSON is not valid OpenTelemetry format' }, data: [] };
|
||||
}
|
||||
|
||||
return { data: [frame, ...createGraphFrames(frame)] };
|
||||
|
@ -42,6 +42,18 @@ describe('ZipkinDatasource', () => {
|
||||
expect(field.type).toBe(FieldType.string);
|
||||
expect(field.values.length).toBe(3);
|
||||
});
|
||||
|
||||
it('should fail on invalid json file upload', async () => {
|
||||
const ds = new ZipkinDatasource(defaultSettings);
|
||||
ds.uploadedJson = JSON.stringify({ key: 'value', arr: [] });
|
||||
const response = await lastValueFrom(
|
||||
ds.query({
|
||||
targets: [{ queryType: 'upload', refId: 'A' }],
|
||||
} as any)
|
||||
);
|
||||
expect(response.error?.message).toBeDefined();
|
||||
expect(response.data.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('metadataRequest', () => {
|
||||
|
@ -28,8 +28,13 @@ export class ZipkinDatasource extends DataSourceApi<ZipkinQuery> {
|
||||
if (!this.uploadedJson) {
|
||||
return of({ data: [] });
|
||||
}
|
||||
const traceData = JSON.parse(this.uploadedJson as string);
|
||||
return of(responseToDataQueryResponse({ data: traceData }));
|
||||
|
||||
try {
|
||||
const traceData = JSON.parse(this.uploadedJson as string);
|
||||
return of(responseToDataQueryResponse({ data: traceData }));
|
||||
} catch (error) {
|
||||
return of({ error: { message: 'JSON is not valid Zipkin format' }, data: [] });
|
||||
}
|
||||
}
|
||||
|
||||
if (target.query) {
|
||||
|
Loading…
Reference in New Issue
Block a user