diff --git a/public/app/features/correlations/utils.test.ts b/public/app/features/correlations/utils.test.ts index a42e6fd9688..f182b3c85c3 100644 --- a/public/app/features/correlations/utils.test.ts +++ b/public/app/features/correlations/utils.test.ts @@ -1,15 +1,17 @@ -import { DataFrame, DataSourceInstanceSettings, FieldType, toDataFrame } from '@grafana/data'; +import { DataFrame, DataFrameType, DataSourceInstanceSettings, FieldType, toDataFrame } from '@grafana/data'; +import { config } from '@grafana/runtime'; import { CorrelationData } from './useCorrelations'; import { attachCorrelationsToDataFrames } from './utils'; describe('correlations utils', () => { it('attaches correlations defined in the configuration', () => { + config.featureToggles.lokiLogsDataplane = false; const { testDataFrames, correlations, refIdMap, prometheus, elastic } = setup(); attachCorrelationsToDataFrames(testDataFrames, correlations, refIdMap); - // Loki line (no links) - expect(testDataFrames[0].fields[0].config.links).toHaveLength(0); + // Loki line + expect(testDataFrames[0].fields[0].config.links).toHaveLength(1); // Loki traceId (linked to Prometheus and Elastic) expect(testDataFrames[0].fields[1].config.links).toHaveLength(2); expect(testDataFrames[0].fields[1].config.links).toMatchObject([ @@ -68,10 +70,29 @@ describe('correlations utils', () => { // Prometheus value (linked to Elastic) expect(testDataFrames[2].fields[0].config.links).toHaveLength(1); }); + + it('changes the config field if loki dataplane is being used and the correlation is pointing to the legacy body field (Line)', () => { + const originalDataplaneState = config.featureToggles.lokiLogsDataplane; + config.featureToggles.lokiLogsDataplane = true; + const { correlations, refIdMap } = setup(); + const testDataFrame = toDataFrame({ + name: 'Loki Logs', + refId: 'Loki Query', + fields: [ + { name: 'timestamp', values: [], type: FieldType.time }, + { name: 'body', values: [], type: FieldType.string }, + { name: 'traceId', values: [], type: FieldType.string }, + ], + meta: { type: DataFrameType.LogLines }, + }); + const dataFrameOut = attachCorrelationsToDataFrames([testDataFrame], [correlations[3]], refIdMap); + expect(dataFrameOut[0].fields[1].config.links).toHaveLength(1); + config.featureToggles.lokiLogsDataplane = originalDataplaneState; + }); }); function setup() { - const loki = { uid: 'loki-uid', name: 'loki' } as DataSourceInstanceSettings; + const loki = { uid: 'loki-uid', name: 'loki', meta: { id: 'loki' } } as DataSourceInstanceSettings; const elastic = { uid: 'elastic-uid', name: 'elastic' } as DataSourceInstanceSettings; const prometheus = { uid: 'prometheus-uid', name: 'prometheus' } as DataSourceInstanceSettings; @@ -86,15 +107,15 @@ function setup() { name: 'Loki Logs', refId: 'Loki Query', fields: [ - { name: 'line', values: [] }, - { name: 'traceId', values: [] }, + { name: 'Line', values: [], type: FieldType.string }, + { name: 'traceId', values: [], type: FieldType.string }, ], }), toDataFrame({ name: 'Elastic Logs', refId: 'Elastic Query', fields: [ - { name: 'line', values: [] }, + { name: 'Line', values: [] }, { name: 'traceId', values: [] }, ], }), @@ -134,7 +155,16 @@ function setup() { config: { field: 'value', target: { expr: 'target Elastic query' } }, provisioned: false, }, + { + uid: 'loki-to-loki', + label: 'logs to logs', + source: loki, + target: loki, + type: 'query', + config: { field: 'Line', target: { expr: 'target loki query' } }, + provisioned: false, + }, ]; - return { testDataFrames, correlations, refIdMap, prometheus, elastic }; + return { testDataFrames, correlations, refIdMap, loki, prometheus, elastic }; } diff --git a/public/app/features/correlations/utils.ts b/public/app/features/correlations/utils.ts index d9719c77e64..f7778bb16bb 100644 --- a/public/app/features/correlations/utils.ts +++ b/public/app/features/correlations/utils.ts @@ -1,10 +1,11 @@ import { lastValueFrom } from 'rxjs'; import { DataFrame, DataLinkConfigOrigin } from '@grafana/data'; -import { createMonitoringLogger, getBackendSrv, getDataSourceSrv } from '@grafana/runtime'; +import { config, createMonitoringLogger, getBackendSrv, getDataSourceSrv } from '@grafana/runtime'; import { ExploreItemState } from 'app/types'; import { formatValueName } from '../explore/PrometheusListView/ItemLabels'; +import { parseLogsFrame } from '../logs/logsFrame'; import { CreateCorrelationParams, CreateCorrelationResponse } from './types'; import { @@ -43,7 +44,7 @@ export const attachCorrelationsToDataFrames = ( } const sourceCorrelations = correlations.filter((correlation) => correlation.source.uid === dataSourceUid); - decorateDataFrameWithInternalDataLinks(dataFrame, sourceCorrelations); + decorateDataFrameWithInternalDataLinks(dataFrame, fixLokiDataplaneFields(sourceCorrelations, dataFrame)); }); return dataFrames; @@ -83,6 +84,27 @@ const decorateDataFrameWithInternalDataLinks = (dataFrame: DataFrame, correlatio }); }; +/* +If a correlation was made based on the log line field prior to the loki data plane, they would use the field "Line" + +Change it to use whatever the body field name is post-loki data plane +*/ +const fixLokiDataplaneFields = (correlations: CorrelationData[], dataFrame: DataFrame) => { + return correlations.map((correlation) => { + if ( + correlation.source.meta?.id === 'loki' && + config.featureToggles.lokiLogsDataplane === true && + correlation.config.field === 'Line' + ) { + const logsFrame = parseLogsFrame(dataFrame); + if (logsFrame != null && logsFrame.bodyField.name !== undefined) { + correlation.config.field = logsFrame?.bodyField.name; + } + } + return correlation; + }); +}; + export const getCorrelationsBySourceUIDs = async (sourceUIDs: string[]): Promise => { return lastValueFrom( getBackendSrv().fetch({