diff --git a/public/app/plugins/datasource/loki/LogContextProvider.test.ts b/public/app/plugins/datasource/loki/LogContextProvider.test.ts index 0eb962a89df..7d6216a8b10 100644 --- a/public/app/plugins/datasource/loki/LogContextProvider.test.ts +++ b/public/app/plugins/datasource/loki/LogContextProvider.test.ts @@ -37,6 +37,11 @@ const defaultLogRow = { type: FieldType.time, values: [0], }, + { + name: 'labelTypes', + type: FieldType.other, + values: [{ bar: 'I', foo: 'S', xyz: 'I' }], + }, ], }), labels: { bar: 'baz', foo: 'uniqueParsedLabel', xyz: 'abc' }, @@ -75,7 +80,7 @@ describe('LogContextProvider', () => { ); expect(logContextProvider.getInitContextFilters).toBeCalled(); expect(logContextProvider.getInitContextFilters).toHaveBeenCalledWith( - { bar: 'baz', foo: 'uniqueParsedLabel', xyz: 'abc' }, + expect.objectContaining({ labels: { bar: 'baz', foo: 'uniqueParsedLabel', xyz: 'abc' } }), { expr: '{bar="baz"}', refId: 'A' }, { from: dateTime(defaultLogRow.timeEpochMs), @@ -399,7 +404,7 @@ describe('LogContextProvider', () => { }; it('should correctly create contextFilters', async () => { - const result = await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithoutParser); + const result = await logContextProvider.getInitContextFilters(defaultLogRow, queryWithoutParser); expect(result.contextFilters).toEqual([ { enabled: true, nonIndexed: false, label: 'bar', value: 'baz' }, { enabled: false, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' }, @@ -409,28 +414,29 @@ describe('LogContextProvider', () => { }); it('should return empty contextFilters if no query', async () => { - const filters = (await logContextProvider.getInitContextFilters(defaultLogRow.labels, undefined)) - .contextFilters; + const filters = (await logContextProvider.getInitContextFilters(defaultLogRow, undefined)).contextFilters; expect(filters).toEqual([]); }); it('should return empty contextFilters if no labels', async () => { - const filters = (await logContextProvider.getInitContextFilters({}, queryWithoutParser)).contextFilters; + const filters = ( + await logContextProvider.getInitContextFilters({ labels: [] } as unknown as LogRowModel, queryWithoutParser) + ).contextFilters; expect(filters).toEqual([]); }); it('should call fetchSeriesLabels if parser', async () => { - await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithParser); + await logContextProvider.getInitContextFilters(defaultLogRow, queryWithParser); expect(defaultLanguageProviderMock.fetchSeriesLabels).toBeCalled(); }); it('should call fetchSeriesLabels with given time range', async () => { - await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithParser, timeRange); + await logContextProvider.getInitContextFilters(defaultLogRow, queryWithParser, timeRange); expect(defaultLanguageProviderMock.fetchSeriesLabels).toBeCalledWith(`{bar="baz"}`, { timeRange }); }); it('should call `languageProvider.start` if no parser with given time range', async () => { - await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithoutParser, timeRange); + await logContextProvider.getInitContextFilters(defaultLogRow, queryWithoutParser, timeRange); expect(defaultLanguageProviderMock.start).toBeCalledWith(timeRange); }); }); @@ -442,7 +448,7 @@ describe('LogContextProvider', () => { }; it('should correctly create contextFilters', async () => { - const result = await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithParser); + const result = await logContextProvider.getInitContextFilters(defaultLogRow, queryWithParser); expect(result.contextFilters).toEqual([ { enabled: true, nonIndexed: false, label: 'bar', value: 'baz' }, { enabled: false, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' }, @@ -452,13 +458,14 @@ describe('LogContextProvider', () => { }); it('should return empty contextFilters if no query', async () => { - const filters = (await logContextProvider.getInitContextFilters(defaultLogRow.labels, undefined)) - .contextFilters; + const filters = (await logContextProvider.getInitContextFilters(defaultLogRow, undefined)).contextFilters; expect(filters).toEqual([]); }); it('should return empty contextFilters if no labels', async () => { - const filters = (await logContextProvider.getInitContextFilters({}, queryWithParser)).contextFilters; + const filters = ( + await logContextProvider.getInitContextFilters({ labels: [] } as unknown as LogRowModel, queryWithParser) + ).contextFilters; expect(filters).toEqual([]); }); }); @@ -477,7 +484,7 @@ describe('LogContextProvider', () => { selectedExtractedLabels: ['foo'], }) ); - const result = await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithParser); + const result = await logContextProvider.getInitContextFilters(defaultLogRow, queryWithParser); expect(result.contextFilters).toEqual([ { enabled: false, nonIndexed: false, label: 'bar', value: 'baz' }, // disabled real label { enabled: true, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' }, // enabled parsed label @@ -494,7 +501,7 @@ describe('LogContextProvider', () => { selectedExtractedLabels: ['foo'], }) ); - const result = await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithParser); + const result = await logContextProvider.getInitContextFilters(defaultLogRow, queryWithParser); expect(result.contextFilters).toEqual([ { enabled: true, nonIndexed: false, label: 'bar', value: 'baz' }, // enabled real label { enabled: false, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' }, @@ -511,7 +518,7 @@ describe('LogContextProvider', () => { selectedExtractedLabels: ['foo', 'new'], }) ); - const result = await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithParser); + const result = await logContextProvider.getInitContextFilters(defaultLogRow, queryWithParser); expect(result.contextFilters).toEqual([ { enabled: false, nonIndexed: false, label: 'bar', value: 'baz' }, { enabled: true, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' }, diff --git a/public/app/plugins/datasource/loki/LogContextProvider.ts b/public/app/plugins/datasource/loki/LogContextProvider.ts index e7e45999ddd..ada99fad88c 100644 --- a/public/app/plugins/datasource/loki/LogContextProvider.ts +++ b/public/app/plugins/datasource/loki/LogContextProvider.ts @@ -16,11 +16,10 @@ import { dateTime, } from '@grafana/data'; import { LabelParser, LabelFilter, LineFilters, PipelineStage, Logfmt, Json } from '@grafana/lezer-logql'; -import { Labels } from '@grafana/schema'; import { LokiContextUi } from './components/LokiContextUi'; import { LokiDatasource, makeRequest, REF_ID_STARTER_LOG_ROW_CONTEXT } from './datasource'; -import { escapeLabelValueInExactSelector } from './languageUtils'; +import { escapeLabelValueInExactSelector, getLabelTypeFromFrame } from './languageUtils'; import { addLabelToQuery, addParserToQuery } from './modifyQuery'; import { getNodePositionsFromQuery, @@ -61,7 +60,7 @@ export class LogContextProvider { // to use the cached filters, we need to reinitialize them. if (this.cachedContextFilters.length === 0 || !cacheFilters) { const filters = ( - await this.getInitContextFilters(row.labels, origQuery, { + await this.getInitContextFilters(row, origQuery, { from: dateTime(row.timeEpochMs), to: dateTime(row.timeEpochMs), raw: { from: dateTime(row.timeEpochMs), to: dateTime(row.timeEpochMs) }, @@ -312,14 +311,15 @@ export class LogContextProvider { }; getInitContextFilters = async ( - labels: Labels, + row: LogRowModel, query?: LokiQuery, timeRange?: TimeRange ): Promise<{ contextFilters: ContextFilter[]; preservedFiltersApplied: boolean }> => { let preservedFiltersApplied = false; - if (!query || isEmpty(labels)) { + if (!query || isEmpty(row.labels)) { return { contextFilters: [], preservedFiltersApplied }; } + const rowLabels = row.labels; // 1. First we need to get all labels from the log row's label // and correctly set parsed and not parsed labels @@ -338,12 +338,12 @@ export class LogContextProvider { } const contextFilters: ContextFilter[] = []; - Object.entries(labels).forEach(([label, value]) => { + Object.entries(rowLabels).forEach(([label, value]) => { const filter: ContextFilter = { label, value: value, enabled: allLabels.includes(label), - nonIndexed: !allLabels.includes(label), + nonIndexed: getLabelTypeFromFrame(label, row.dataFrame, row.rowIndex) !== LabelType.Indexed, }; contextFilters.push(filter); diff --git a/public/app/plugins/datasource/loki/components/LokiContextUi.test.tsx b/public/app/plugins/datasource/loki/components/LokiContextUi.test.tsx index 0ba89331811..7d9d7220877 100644 --- a/public/app/plugins/datasource/loki/components/LokiContextUi.test.tsx +++ b/public/app/plugins/datasource/loki/components/LokiContextUi.test.tsx @@ -122,7 +122,7 @@ describe('LokiContextUi', () => { render(); await waitFor(() => { - expect(props.logContextProvider.getInitContextFilters).toHaveBeenCalledWith(props.row.labels, props.origQuery, { + expect(props.logContextProvider.getInitContextFilters).toHaveBeenCalledWith(props.row, props.origQuery, { from: dateTime(props.row.timeEpochMs), to: dateTime(props.row.timeEpochMs), raw: { from: dateTime(props.row.timeEpochMs), to: dateTime(props.row.timeEpochMs) }, diff --git a/public/app/plugins/datasource/loki/components/LokiContextUi.tsx b/public/app/plugins/datasource/loki/components/LokiContextUi.tsx index abea3b584c2..fe181e08ea8 100644 --- a/public/app/plugins/datasource/loki/components/LokiContextUi.tsx +++ b/public/app/plugins/datasource/loki/components/LokiContextUi.tsx @@ -205,7 +205,7 @@ export function LokiContextUi(props: LokiContextUiProps) { useAsync(async () => { setLoading(true); - const initContextFilters = await logContextProvider.getInitContextFilters(row.labels, origQuery, { + const initContextFilters = await logContextProvider.getInitContextFilters(row, origQuery, { from: dateTime(row.timeEpochMs), to: dateTime(row.timeEpochMs), raw: { from: dateTime(row.timeEpochMs), to: dateTime(row.timeEpochMs) },