LogContext: Fix structured metadata labels being added as stream selectors (#86825)

* LogContext: Fix structured metadata labels being added as stream selectors

* use row index
This commit is contained in:
Sven Grossmann 2024-04-24 09:00:39 +01:00 committed by GitHub
parent 0fa983ad8e
commit a8424f4831
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 31 additions and 24 deletions

View File

@ -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' },

View File

@ -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);

View File

@ -122,7 +122,7 @@ describe('LokiContextUi', () => {
render(<LokiContextUi {...props} />);
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) },

View File

@ -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) },