2025-07-10 22:54:16 +08:00
|
|
|
import { Observable, of } from 'rxjs';
|
|
|
|
|
import { map } from 'rxjs/operators';
|
2022-04-22 21:33:13 +08:00
|
|
|
|
2020-03-25 19:25:39 +08:00
|
|
|
import {
|
|
|
|
|
DataQueryRequest,
|
|
|
|
|
DataQueryResponse,
|
2021-03-02 20:59:35 +08:00
|
|
|
DataSourceInstanceSettings,
|
2021-10-07 03:39:14 +08:00
|
|
|
DataSourceJsonData,
|
2020-04-02 19:34:16 +08:00
|
|
|
FieldType,
|
2021-03-02 20:59:35 +08:00
|
|
|
MutableDataFrame,
|
2022-06-16 15:17:38 +08:00
|
|
|
ScopedVars,
|
2025-04-23 17:01:40 +08:00
|
|
|
toDataFrame,
|
2020-03-25 19:25:39 +08:00
|
|
|
} from '@grafana/data';
|
2025-04-23 17:01:40 +08:00
|
|
|
import { createNodeGraphFrames, NodeGraphOptions, SpanBarOptions } from '@grafana/o11y-ds-frontend';
|
2025-07-10 22:54:16 +08:00
|
|
|
import { DataSourceWithBackend, getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
2022-04-22 21:33:13 +08:00
|
|
|
|
2023-07-31 23:13:48 +08:00
|
|
|
import { TraceIdTimeParamsOptions } from './configuration/TraceIdTimeParams';
|
2021-03-31 23:56:15 +08:00
|
|
|
import { createGraphFrames } from './graphTransform';
|
2025-07-10 22:54:16 +08:00
|
|
|
import { createTraceFrame } from './responseTransform';
|
2021-05-11 16:38:10 +08:00
|
|
|
import { JaegerQuery } from './types';
|
2020-03-25 19:25:39 +08:00
|
|
|
|
2021-10-07 03:39:14 +08:00
|
|
|
export interface JaegerJsonData extends DataSourceJsonData {
|
|
|
|
|
nodeGraph?: NodeGraphOptions;
|
2023-07-31 23:13:48 +08:00
|
|
|
traceIdTimeParams?: TraceIdTimeParamsOptions;
|
2021-10-07 03:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
2025-01-24 20:37:36 +08:00
|
|
|
export class JaegerDatasource extends DataSourceWithBackend<JaegerQuery, JaegerJsonData> {
|
2021-07-30 00:07:07 +08:00
|
|
|
uploadedJson: string | ArrayBuffer | null = null;
|
2021-10-07 03:39:14 +08:00
|
|
|
nodeGraph?: NodeGraphOptions;
|
2023-07-31 23:13:48 +08:00
|
|
|
traceIdTimeParams?: TraceIdTimeParamsOptions;
|
2022-07-06 15:14:03 +08:00
|
|
|
spanBar?: SpanBarOptions;
|
2021-10-07 03:39:14 +08:00
|
|
|
constructor(
|
2025-07-10 22:54:16 +08:00
|
|
|
instanceSettings: DataSourceInstanceSettings<JaegerJsonData>,
|
2022-06-16 15:17:38 +08:00
|
|
|
private readonly templateSrv: TemplateSrv = getTemplateSrv()
|
2021-10-07 03:39:14 +08:00
|
|
|
) {
|
2020-03-25 19:25:39 +08:00
|
|
|
super(instanceSettings);
|
2021-10-07 03:39:14 +08:00
|
|
|
this.nodeGraph = instanceSettings.jsonData.nodeGraph;
|
2023-07-31 23:13:48 +08:00
|
|
|
this.traceIdTimeParams = instanceSettings.jsonData.traceIdTimeParams;
|
2020-03-25 19:25:39 +08:00
|
|
|
}
|
|
|
|
|
|
2023-11-06 19:28:44 +08:00
|
|
|
async metadataRequest(url: string, params?: Record<string, unknown>) {
|
2025-07-10 22:54:16 +08:00
|
|
|
return await this.getResource(url, params);
|
2020-03-25 19:25:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
query(options: DataQueryRequest<JaegerQuery>): Observable<DataQueryResponse> {
|
2020-04-02 19:34:16 +08:00
|
|
|
// At this moment we expect only one target. In case we somehow change the UI to be able to show multiple
|
|
|
|
|
// traces at one we need to change this.
|
2021-11-23 22:02:07 +08:00
|
|
|
const target: JaegerQuery = options.targets[0];
|
2021-05-11 16:38:10 +08:00
|
|
|
if (!target) {
|
2021-03-02 20:59:35 +08:00
|
|
|
return of({ data: [emptyTraceDataFrame] });
|
2020-04-02 19:34:16 +08:00
|
|
|
}
|
2021-03-02 20:59:35 +08:00
|
|
|
|
2021-07-30 00:07:07 +08:00
|
|
|
if (target.queryType === 'upload') {
|
|
|
|
|
if (!this.uploadedJson) {
|
|
|
|
|
return of({ data: [] });
|
|
|
|
|
}
|
2021-08-26 00:08:46 +08:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const traceData = JSON.parse(this.uploadedJson as string).data[0];
|
2021-10-07 03:39:14 +08:00
|
|
|
let data = [createTraceFrame(traceData)];
|
|
|
|
|
if (this.nodeGraph?.enabled) {
|
|
|
|
|
data.push(...createGraphFrames(traceData));
|
|
|
|
|
}
|
|
|
|
|
return of({ data });
|
2021-08-26 00:08:46 +08:00
|
|
|
} catch (error) {
|
2022-08-11 23:23:19 +08:00
|
|
|
return of({ error: { message: 'The JSON file uploaded is not in a valid Jaeger format' }, data: [] });
|
2021-08-26 00:08:46 +08:00
|
|
|
}
|
2021-07-30 00:07:07 +08:00
|
|
|
}
|
|
|
|
|
|
2025-07-10 22:54:16 +08:00
|
|
|
return super.query({ ...options, targets: [target] }).pipe(
|
2021-03-02 20:59:35 +08:00
|
|
|
map((response) => {
|
2025-07-10 22:54:16 +08:00
|
|
|
// If the node graph is enabled and the query is a trace ID query, add the node graph frames to the response
|
|
|
|
|
if (this.nodeGraph?.enabled && !target.queryType) {
|
|
|
|
|
return addNodeGraphFramesToResponse(response);
|
|
|
|
|
}
|
|
|
|
|
return response;
|
2021-03-02 20:59:35 +08:00
|
|
|
})
|
|
|
|
|
);
|
2020-03-25 19:25:39 +08:00
|
|
|
}
|
|
|
|
|
|
2022-06-16 15:17:38 +08:00
|
|
|
interpolateVariablesInQueries(queries: JaegerQuery[], scopedVars: ScopedVars): JaegerQuery[] {
|
|
|
|
|
if (!queries || queries.length === 0) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return queries.map((query) => {
|
|
|
|
|
return {
|
|
|
|
|
...query,
|
|
|
|
|
datasource: this.getRef(),
|
2025-04-09 20:13:46 +08:00
|
|
|
...this.applyTemplateVariables(query, scopedVars),
|
2022-06-16 15:17:38 +08:00
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 20:13:46 +08:00
|
|
|
applyTemplateVariables(query: JaegerQuery, scopedVars: ScopedVars) {
|
2022-06-16 15:17:38 +08:00
|
|
|
let expandedQuery = { ...query };
|
|
|
|
|
|
|
|
|
|
if (query.tags && this.templateSrv.containsTemplate(query.tags)) {
|
|
|
|
|
expandedQuery = {
|
|
|
|
|
...query,
|
|
|
|
|
tags: this.templateSrv.replace(query.tags, scopedVars),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...expandedQuery,
|
|
|
|
|
service: this.templateSrv.replace(query.service ?? '', scopedVars),
|
|
|
|
|
operation: this.templateSrv.replace(query.operation ?? '', scopedVars),
|
|
|
|
|
minDuration: this.templateSrv.replace(query.minDuration ?? '', scopedVars),
|
|
|
|
|
maxDuration: this.templateSrv.replace(query.maxDuration ?? '', scopedVars),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-06 19:28:44 +08:00
|
|
|
async testDatasource() {
|
2025-07-10 22:54:16 +08:00
|
|
|
return await super.testDatasource();
|
2020-03-25 19:25:39 +08:00
|
|
|
}
|
|
|
|
|
|
2020-04-25 00:23:31 +08:00
|
|
|
getQueryDisplayText(query: JaegerQuery) {
|
2021-05-11 16:38:10 +08:00
|
|
|
return query.query || '';
|
2020-04-25 00:23:31 +08:00
|
|
|
}
|
2020-04-02 19:34:16 +08:00
|
|
|
}
|
|
|
|
|
|
2021-03-02 20:59:35 +08:00
|
|
|
const emptyTraceDataFrame = new MutableDataFrame({
|
|
|
|
|
fields: [
|
|
|
|
|
{
|
|
|
|
|
name: 'trace',
|
|
|
|
|
type: FieldType.trace,
|
|
|
|
|
values: [],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
meta: {
|
|
|
|
|
preferredVisualisationType: 'trace',
|
2021-09-08 21:04:27 +08:00
|
|
|
custom: {
|
|
|
|
|
traceFormat: 'jaeger',
|
|
|
|
|
},
|
2021-03-02 20:59:35 +08:00
|
|
|
},
|
|
|
|
|
});
|
2025-04-23 17:01:40 +08:00
|
|
|
|
|
|
|
|
export function addNodeGraphFramesToResponse(response: DataQueryResponse): DataQueryResponse {
|
|
|
|
|
if (!response.data || response.data.length === 0) {
|
|
|
|
|
return response;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert the first frame to a DataFrame for node graph processing
|
|
|
|
|
const frame = toDataFrame(response.data[0]);
|
|
|
|
|
// Add the node graph frames to the response
|
|
|
|
|
const data = response.data.concat(createNodeGraphFrames(frame));
|
|
|
|
|
return {
|
|
|
|
|
...response,
|
|
|
|
|
data,
|
|
|
|
|
};
|
|
|
|
|
}
|