grafana_bak/public/app/plugins/datasource/jaeger/dependencyGraphTransform.ts
2025-04-01 10:38:02 +09:00

126 lines
3.2 KiB
TypeScript

import {
DataFrame,
DataQueryResponse,
FieldType,
MutableDataFrame,
NodeGraphDataFrameFieldNames as Fields,
} from '@grafana/data';
import { JaegerServiceDependency } from './types';
interface Node {
[Fields.id]: string;
[Fields.title]: string;
}
interface Edge {
[Fields.id]: string;
[Fields.target]: string;
[Fields.source]: string;
[Fields.mainStat]: number;
}
/**
* Error schema used by the Jaeger dependencies API.
*/
interface JaegerDependenciesResponseError {
code: number;
msg: string;
}
interface JaegerDependenciesResponse {
data?: {
errors?: JaegerDependenciesResponseError[];
data?: JaegerServiceDependency[];
};
}
/**
* Transforms a Jaeger dependencies API response to a Grafana {@link DataQueryResponse}.
* @param response Raw response data from the API proxy.
*/
export function mapJaegerDependenciesResponse(response: JaegerDependenciesResponse): DataQueryResponse {
const errors = response?.data?.errors;
if (errors) {
return {
data: [],
errors: errors.map((e: JaegerDependenciesResponseError) => ({ message: e.msg, status: e.code })),
};
}
const dependencies = response?.data?.data;
if (dependencies) {
return {
data: convertDependenciesToGraph(dependencies),
};
}
return { data: [] };
}
/**
* Converts a list of Jaeger service dependencies to a Grafana {@link DataFrame} array suitable for the node graph panel.
* @param dependencies List of Jaeger service dependencies as returned by the Jaeger dependencies API.
*/
function convertDependenciesToGraph(dependencies: JaegerServiceDependency[]): DataFrame[] {
const servicesByName = new Map<string, Node>();
const edges: Edge[] = [];
for (const dependency of dependencies) {
addServiceNode(dependency.parent, servicesByName);
addServiceNode(dependency.child, servicesByName);
edges.push({
[Fields.id]: dependency.parent + '--' + dependency.child,
[Fields.target]: dependency.child,
[Fields.source]: dependency.parent,
[Fields.mainStat]: dependency.callCount,
});
}
const nodesFrame = new MutableDataFrame({
fields: [
{ name: Fields.id, type: FieldType.string },
{ name: Fields.title, type: FieldType.string },
],
meta: {
preferredVisualisationType: 'nodeGraph',
},
});
const edgesFrame = new MutableDataFrame({
fields: [
{ name: Fields.id, type: FieldType.string },
{ name: Fields.target, type: FieldType.string },
{ name: Fields.source, type: FieldType.string },
{ name: Fields.mainStat, type: FieldType.string, config: { displayName: 'Call count' } },
],
meta: {
preferredVisualisationType: 'nodeGraph',
},
});
for (const node of servicesByName.values()) {
nodesFrame.add(node);
}
for (const edge of edges) {
edgesFrame.add(edge);
}
return [nodesFrame, edgesFrame];
}
/**
* Convenience function to register a service node in the dependency graph.
* @param service Name of the service to register.
* @param servicesByName Map of service nodes keyed name.
*/
function addServiceNode(service: string, servicesByName: Map<string, Node>) {
if (!servicesByName.has(service)) {
servicesByName.set(service, {
[Fields.id]: service,
[Fields.title]: service,
});
}
}