Tempo: Add links to nodes in Service Graph pointing to Prometheus metrics (#41135)

This commit is contained in:
Andrej Ocenas 2021-11-03 15:56:39 +01:00 committed by GitHub
parent 7f74102bc1
commit 5f27959a5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 10 deletions

View File

@ -97,6 +97,7 @@ describe('Tempo data source', () => {
expect(response.data).toHaveLength(2); expect(response.data).toHaveLength(2);
expect(response.data[0].name).toBe('Nodes'); expect(response.data[0].name).toBe('Nodes');
expect(response.data[0].fields[0].values.length).toBe(3); expect(response.data[0].fields[0].values.length).toBe(3);
expect(response.data[0].fields[0].config.links.length).toBeGreaterThan(0);
expect(response.data[1].name).toBe('Edges'); expect(response.data[1].name).toBe('Edges');
expect(response.data[1].fields[0].values.length).toBe(2); expect(response.data[1].fields[0].values.length).toBe(2);

View File

@ -19,7 +19,7 @@ import Prism from 'prismjs';
import { LokiOptions, LokiQuery } from '../loki/types'; import { LokiOptions, LokiQuery } from '../loki/types';
import { PrometheusDatasource } from '../prometheus/datasource'; import { PrometheusDatasource } from '../prometheus/datasource';
import { PromQuery } from '../prometheus/types'; import { PromQuery } from '../prometheus/types';
import { mapPromMetricsToServiceMap, serviceMapMetrics } from './graphTransform'; import { failedMetric, mapPromMetricsToServiceMap, serviceMapMetrics, totalsMetric } from './graphTransform';
import { import {
transformTrace, transformTrace,
transformTraceList, transformTraceList,
@ -288,14 +288,36 @@ function serviceMapQuery(request: DataQueryRequest<TempoQuery>, datasourceUid: s
throw new Error(errorRes.error!.message); throw new Error(errorRes.error!.message);
} }
const { nodes, edges } = mapPromMetricsToServiceMap(responses, request.range);
nodes.fields[0].config = {
links: [
makePromLink('Total requests', totalsMetric, datasourceUid),
makePromLink('Failed requests', failedMetric, datasourceUid),
],
};
return { return {
data: mapPromMetricsToServiceMap(responses, request.range), data: [nodes, edges],
state: LoadingState.Done, state: LoadingState.Done,
}; };
}) })
); );
} }
function makePromLink(title: string, metric: string, datasourceUid: string) {
return {
url: '',
title,
internal: {
query: {
expr: metric,
} as PromQuery,
datasourceUid,
datasourceName: 'Prometheus',
},
};
}
function makePromServiceMapRequest(options: DataQueryRequest<TempoQuery>): DataQueryRequest<PromQuery> { function makePromServiceMapRequest(options: DataQueryRequest<TempoQuery>): DataQueryRequest<PromQuery> {
return { return {
...options, ...options,

View File

@ -64,7 +64,7 @@ describe('mapPromMetricsToServiceMap', () => {
from: dateTime('2000-01-01T00:00:00'), from: dateTime('2000-01-01T00:00:00'),
to: dateTime('2000-01-01T00:01:00'), to: dateTime('2000-01-01T00:01:00'),
}; };
const [nodes, edges] = mapPromMetricsToServiceMap( const { nodes, edges } = mapPromMetricsToServiceMap(
[{ data: [totalsPromMetric, secondsPromMetric, failedPromMetric] }], [{ data: [totalsPromMetric, secondsPromMetric, failedPromMetric] }],
{ {
...range, ...range,

View File

@ -130,9 +130,9 @@ function findTraceDuration(view: DataFrameView<Row>): number {
return traceEndTime - traceStartTime; return traceEndTime - traceStartTime;
} }
const secondsMetric = 'traces_service_graph_request_server_seconds_sum'; export const secondsMetric = 'traces_service_graph_request_server_seconds_sum';
const totalsMetric = 'traces_service_graph_request_total'; export const totalsMetric = 'traces_service_graph_request_total';
const failedMetric = 'traces_service_graph_request_failed_total'; export const failedMetric = 'traces_service_graph_request_failed_total';
export const serviceMapMetrics = [ export const serviceMapMetrics = [
secondsMetric, secondsMetric,
@ -151,7 +151,10 @@ export const serviceMapMetrics = [
* @param responses * @param responses
* @param range * @param range
*/ */
export function mapPromMetricsToServiceMap(responses: DataQueryResponse[], range: TimeRange): [DataFrame, DataFrame] { export function mapPromMetricsToServiceMap(
responses: DataQueryResponse[],
range: TimeRange
): { nodes: DataFrame; edges: DataFrame } {
const frames = getMetricFrames(responses); const frames = getMetricFrames(responses);
// First just collect data from the metrics into a map with nodes and edges as keys // First just collect data from the metrics into a map with nodes and edges as keys
@ -172,7 +175,7 @@ function createServiceMapDataFrames() {
const nodes = createDF('Nodes', [ const nodes = createDF('Nodes', [
{ name: Fields.id }, { name: Fields.id },
{ name: Fields.title }, { name: Fields.title, config: { displayName: 'Service name' } },
{ name: Fields.mainStat, config: { unit: 'ms/r', displayName: 'Average response time' } }, { name: Fields.mainStat, config: { unit: 'ms/r', displayName: 'Average response time' } },
{ {
name: Fields.secondaryStat, name: Fields.secondaryStat,
@ -289,7 +292,7 @@ function convertToDataFrames(
nodesMap: Record<string, ServiceMapStatistics>, nodesMap: Record<string, ServiceMapStatistics>,
edgesMap: Record<string, EdgeObject>, edgesMap: Record<string, EdgeObject>,
range: TimeRange range: TimeRange
): [DataFrame, DataFrame] { ): { nodes: DataFrame; edges: DataFrame } {
const rangeMs = range.to.valueOf() - range.from.valueOf(); const rangeMs = range.to.valueOf() - range.from.valueOf();
const [nodes, edges] = createServiceMapDataFrames(); const [nodes, edges] = createServiceMapDataFrames();
for (const nodeId of Object.keys(nodesMap)) { for (const nodeId of Object.keys(nodesMap)) {
@ -316,5 +319,5 @@ function convertToDataFrames(
}); });
} }
return [nodes, edges]; return { nodes, edges };
} }