diff --git a/public/app/plugins/datasource/tempo/datasource.test.ts b/public/app/plugins/datasource/tempo/datasource.test.ts index 6cbfc3d5963..6d9a086e20d 100644 --- a/public/app/plugins/datasource/tempo/datasource.test.ts +++ b/public/app/plugins/datasource/tempo/datasource.test.ts @@ -25,6 +25,7 @@ import { getRateAlignedValues, makeApmRequest, makeTempoLink, + getFieldConfig, } from './datasource'; import mockJson from './mockJsonResponse.json'; import mockServiceGraph from './mockServiceGraph.json'; @@ -486,6 +487,76 @@ describe('Tempo apm table', () => { expect(builtQuery).toBe('sum(rate(traces_spanmetrics_calls_total{}[$__rate_interval]))'); }); + it('should build link expr correctly', () => { + let datasourceUid = 's4Jvz8Qnk'; + let tempoDatasourceUid = 'EbPO1fYnz'; + let targetField = '__data.fields.target'; + let tempoField = '__data.fields.target'; + let sourceField = '__data.fields.source'; + + let fieldConfig = getFieldConfig(datasourceUid, tempoDatasourceUid, targetField, tempoField, sourceField); + + let resultObj = { + links: [ + { + url: '', + title: 'Request rate', + internal: { + query: { + expr: 'sum by (client, server)(rate(traces_service_graph_request_total{client="${__data.fields.source}",server="${__data.fields.target}"}[$__rate_interval]))', + range: true, + exemplar: true, + instant: false, + }, + datasourceUid: 's4Jvz8Qnk', + datasourceName: '', + }, + }, + { + url: '', + title: 'Request histogram', + internal: { + query: { + expr: 'histogram_quantile(0.9, sum(rate(traces_service_graph_request_server_seconds_bucket{client="${__data.fields.source}",server="${__data.fields.target}"}[$__rate_interval])) by (le, client, server))', + range: true, + exemplar: true, + instant: false, + }, + datasourceUid: 's4Jvz8Qnk', + datasourceName: '', + }, + }, + { + url: '', + title: 'Failed request rate', + internal: { + query: { + expr: 'sum by (client, server)(rate(traces_service_graph_request_failed_total{client="${__data.fields.source}",server="${__data.fields.target}"}[$__rate_interval]))', + range: true, + exemplar: true, + instant: false, + }, + datasourceUid: 's4Jvz8Qnk', + datasourceName: '', + }, + }, + { + url: '', + title: 'View traces', + internal: { + query: { + queryType: 'nativeSearch', + serviceName: '${__data.fields.target}', + }, + datasourceUid: 'EbPO1fYnz', + datasourceName: '', + }, + }, + ], + }; + expect(fieldConfig).toStrictEqual(resultObj); + }); + it('should get rate aligned values correctly', () => { const resp = [ { diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts index dc2640c2951..92fd7f9bdf4 100644 --- a/public/app/plugins/datasource/tempo/datasource.ts +++ b/public/app/plugins/datasource/tempo/datasource.ts @@ -459,29 +459,19 @@ function serviceMapQuery(request: DataQueryRequest, datasourceUid: s } const { nodes, edges } = mapPromMetricsToServiceMap(responses, request.range); - nodes.fields[0].config = { - links: [ - makePromLink( - 'Request rate', - `sum by (client, server)(rate(${totalsMetric}{server="\${__data.fields.id}"}[$__rate_interval]))`, - datasourceUid, - false - ), - makePromLink( - 'Request histogram', - `histogram_quantile(0.9, sum(rate(${histogramMetric}{server="\${__data.fields.id}"}[$__rate_interval])) by (le, client, server))`, - datasourceUid, - false - ), - makePromLink( - 'Failed request rate', - `sum by (client, server)(rate(${failedMetric}{server="\${__data.fields.id}"}[$__rate_interval]))`, - datasourceUid, - false - ), - makeTempoLink('View traces', `\${__data.fields[0]}`, '', tempoDatasourceUid), - ], - }; + nodes.fields[0].config = getFieldConfig( + datasourceUid, + tempoDatasourceUid, + '__data.fields.id', + '__data.fields[0]' + ); + edges.fields[0].config = getFieldConfig( + datasourceUid, + tempoDatasourceUid, + '__data.fields.target', + '__data.fields.target', + '__data.fields.source' + ); return { data: [nodes, edges], @@ -591,6 +581,39 @@ function makePromLink(title: string, expr: string, datasourceUid: string, instan }; } +export function getFieldConfig( + datasourceUid: string, + tempoDatasourceUid: string, + targetField: string, + tempoField: string, + sourceField?: string +) { + sourceField = sourceField ? `client="\${${sourceField}}",` : ''; + return { + links: [ + makePromLink( + 'Request rate', + `sum by (client, server)(rate(${totalsMetric}{${sourceField}server="\${${targetField}}"}[$__rate_interval]))`, + datasourceUid, + false + ), + makePromLink( + 'Request histogram', + `histogram_quantile(0.9, sum(rate(${histogramMetric}{${sourceField}server="\${${targetField}}"}[$__rate_interval])) by (le, client, server))`, + datasourceUid, + false + ), + makePromLink( + 'Failed request rate', + `sum by (client, server)(rate(${failedMetric}{${sourceField}server="\${${targetField}}"}[$__rate_interval]))`, + datasourceUid, + false + ), + makeTempoLink('View traces', `\${${tempoField}}`, '', tempoDatasourceUid), + ], + }; +} + export function makeTempoLink(title: string, serviceName: string, spanName: string, datasourceUid: string) { let query = { queryType: 'nativeSearch' } as TempoQuery; if (serviceName !== '') { diff --git a/public/app/plugins/panel/nodeGraph/useContextMenu.tsx b/public/app/plugins/panel/nodeGraph/useContextMenu.tsx index 3df2c7d37ed..2bbcc48c779 100644 --- a/public/app/plugins/panel/nodeGraph/useContextMenu.tsx +++ b/public/app/plugins/panel/nodeGraph/useContextMenu.tsx @@ -172,8 +172,20 @@ function NodeHeader(props: { node: NodeDatum; nodes: DataFrame }) { function EdgeHeader(props: { edge: EdgeDatum; edges: DataFrame }) { const index = props.edge.dataFrameRowIndex; const fields = getEdgeFields(props.edges); + const styles = getLabelStyles(useTheme()); + const valueSource = fields.source?.values.get(index) || ''; + const valueTarget = fields.target?.values.get(index) || ''; + return (
+ {fields.source && fields.target && ( +
+
Source → Target
+ + {valueSource} → {valueTarget} + +
+ )} {fields.details.map((f) => (