mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
0fa983ad8e
commit
a8424f4831
@ -37,6 +37,11 @@ const defaultLogRow = {
|
|||||||
type: FieldType.time,
|
type: FieldType.time,
|
||||||
values: [0],
|
values: [0],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'labelTypes',
|
||||||
|
type: FieldType.other,
|
||||||
|
values: [{ bar: 'I', foo: 'S', xyz: 'I' }],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
labels: { bar: 'baz', foo: 'uniqueParsedLabel', xyz: 'abc' },
|
labels: { bar: 'baz', foo: 'uniqueParsedLabel', xyz: 'abc' },
|
||||||
@ -75,7 +80,7 @@ describe('LogContextProvider', () => {
|
|||||||
);
|
);
|
||||||
expect(logContextProvider.getInitContextFilters).toBeCalled();
|
expect(logContextProvider.getInitContextFilters).toBeCalled();
|
||||||
expect(logContextProvider.getInitContextFilters).toHaveBeenCalledWith(
|
expect(logContextProvider.getInitContextFilters).toHaveBeenCalledWith(
|
||||||
{ bar: 'baz', foo: 'uniqueParsedLabel', xyz: 'abc' },
|
expect.objectContaining({ labels: { bar: 'baz', foo: 'uniqueParsedLabel', xyz: 'abc' } }),
|
||||||
{ expr: '{bar="baz"}', refId: 'A' },
|
{ expr: '{bar="baz"}', refId: 'A' },
|
||||||
{
|
{
|
||||||
from: dateTime(defaultLogRow.timeEpochMs),
|
from: dateTime(defaultLogRow.timeEpochMs),
|
||||||
@ -399,7 +404,7 @@ describe('LogContextProvider', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it('should correctly create contextFilters', async () => {
|
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([
|
expect(result.contextFilters).toEqual([
|
||||||
{ enabled: true, nonIndexed: false, label: 'bar', value: 'baz' },
|
{ enabled: true, nonIndexed: false, label: 'bar', value: 'baz' },
|
||||||
{ enabled: false, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' },
|
{ enabled: false, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' },
|
||||||
@ -409,28 +414,29 @@ describe('LogContextProvider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty contextFilters if no query', async () => {
|
it('should return empty contextFilters if no query', async () => {
|
||||||
const filters = (await logContextProvider.getInitContextFilters(defaultLogRow.labels, undefined))
|
const filters = (await logContextProvider.getInitContextFilters(defaultLogRow, undefined)).contextFilters;
|
||||||
.contextFilters;
|
|
||||||
expect(filters).toEqual([]);
|
expect(filters).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty contextFilters if no labels', async () => {
|
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([]);
|
expect(filters).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call fetchSeriesLabels if parser', async () => {
|
it('should call fetchSeriesLabels if parser', async () => {
|
||||||
await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithParser);
|
await logContextProvider.getInitContextFilters(defaultLogRow, queryWithParser);
|
||||||
expect(defaultLanguageProviderMock.fetchSeriesLabels).toBeCalled();
|
expect(defaultLanguageProviderMock.fetchSeriesLabels).toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call fetchSeriesLabels with given time range', async () => {
|
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 });
|
expect(defaultLanguageProviderMock.fetchSeriesLabels).toBeCalledWith(`{bar="baz"}`, { timeRange });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call `languageProvider.start` if no parser with given time range', async () => {
|
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);
|
expect(defaultLanguageProviderMock.start).toBeCalledWith(timeRange);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -442,7 +448,7 @@ describe('LogContextProvider', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it('should correctly create contextFilters', async () => {
|
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([
|
expect(result.contextFilters).toEqual([
|
||||||
{ enabled: true, nonIndexed: false, label: 'bar', value: 'baz' },
|
{ enabled: true, nonIndexed: false, label: 'bar', value: 'baz' },
|
||||||
{ enabled: false, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' },
|
{ enabled: false, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' },
|
||||||
@ -452,13 +458,14 @@ describe('LogContextProvider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty contextFilters if no query', async () => {
|
it('should return empty contextFilters if no query', async () => {
|
||||||
const filters = (await logContextProvider.getInitContextFilters(defaultLogRow.labels, undefined))
|
const filters = (await logContextProvider.getInitContextFilters(defaultLogRow, undefined)).contextFilters;
|
||||||
.contextFilters;
|
|
||||||
expect(filters).toEqual([]);
|
expect(filters).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty contextFilters if no labels', async () => {
|
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([]);
|
expect(filters).toEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -477,7 +484,7 @@ describe('LogContextProvider', () => {
|
|||||||
selectedExtractedLabels: ['foo'],
|
selectedExtractedLabels: ['foo'],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const result = await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithParser);
|
const result = await logContextProvider.getInitContextFilters(defaultLogRow, queryWithParser);
|
||||||
expect(result.contextFilters).toEqual([
|
expect(result.contextFilters).toEqual([
|
||||||
{ enabled: false, nonIndexed: false, label: 'bar', value: 'baz' }, // disabled real label
|
{ enabled: false, nonIndexed: false, label: 'bar', value: 'baz' }, // disabled real label
|
||||||
{ enabled: true, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' }, // enabled parsed label
|
{ enabled: true, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' }, // enabled parsed label
|
||||||
@ -494,7 +501,7 @@ describe('LogContextProvider', () => {
|
|||||||
selectedExtractedLabels: ['foo'],
|
selectedExtractedLabels: ['foo'],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const result = await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithParser);
|
const result = await logContextProvider.getInitContextFilters(defaultLogRow, queryWithParser);
|
||||||
expect(result.contextFilters).toEqual([
|
expect(result.contextFilters).toEqual([
|
||||||
{ enabled: true, nonIndexed: false, label: 'bar', value: 'baz' }, // enabled real label
|
{ enabled: true, nonIndexed: false, label: 'bar', value: 'baz' }, // enabled real label
|
||||||
{ enabled: false, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' },
|
{ enabled: false, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' },
|
||||||
@ -511,7 +518,7 @@ describe('LogContextProvider', () => {
|
|||||||
selectedExtractedLabels: ['foo', 'new'],
|
selectedExtractedLabels: ['foo', 'new'],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const result = await logContextProvider.getInitContextFilters(defaultLogRow.labels, queryWithParser);
|
const result = await logContextProvider.getInitContextFilters(defaultLogRow, queryWithParser);
|
||||||
expect(result.contextFilters).toEqual([
|
expect(result.contextFilters).toEqual([
|
||||||
{ enabled: false, nonIndexed: false, label: 'bar', value: 'baz' },
|
{ enabled: false, nonIndexed: false, label: 'bar', value: 'baz' },
|
||||||
{ enabled: true, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' },
|
{ enabled: true, nonIndexed: true, label: 'foo', value: 'uniqueParsedLabel' },
|
||||||
|
@ -16,11 +16,10 @@ import {
|
|||||||
dateTime,
|
dateTime,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { LabelParser, LabelFilter, LineFilters, PipelineStage, Logfmt, Json } from '@grafana/lezer-logql';
|
import { LabelParser, LabelFilter, LineFilters, PipelineStage, Logfmt, Json } from '@grafana/lezer-logql';
|
||||||
import { Labels } from '@grafana/schema';
|
|
||||||
|
|
||||||
import { LokiContextUi } from './components/LokiContextUi';
|
import { LokiContextUi } from './components/LokiContextUi';
|
||||||
import { LokiDatasource, makeRequest, REF_ID_STARTER_LOG_ROW_CONTEXT } from './datasource';
|
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 { addLabelToQuery, addParserToQuery } from './modifyQuery';
|
||||||
import {
|
import {
|
||||||
getNodePositionsFromQuery,
|
getNodePositionsFromQuery,
|
||||||
@ -61,7 +60,7 @@ export class LogContextProvider {
|
|||||||
// to use the cached filters, we need to reinitialize them.
|
// to use the cached filters, we need to reinitialize them.
|
||||||
if (this.cachedContextFilters.length === 0 || !cacheFilters) {
|
if (this.cachedContextFilters.length === 0 || !cacheFilters) {
|
||||||
const filters = (
|
const filters = (
|
||||||
await this.getInitContextFilters(row.labels, origQuery, {
|
await this.getInitContextFilters(row, origQuery, {
|
||||||
from: dateTime(row.timeEpochMs),
|
from: dateTime(row.timeEpochMs),
|
||||||
to: dateTime(row.timeEpochMs),
|
to: dateTime(row.timeEpochMs),
|
||||||
raw: { 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 (
|
getInitContextFilters = async (
|
||||||
labels: Labels,
|
row: LogRowModel,
|
||||||
query?: LokiQuery,
|
query?: LokiQuery,
|
||||||
timeRange?: TimeRange
|
timeRange?: TimeRange
|
||||||
): Promise<{ contextFilters: ContextFilter[]; preservedFiltersApplied: boolean }> => {
|
): Promise<{ contextFilters: ContextFilter[]; preservedFiltersApplied: boolean }> => {
|
||||||
let preservedFiltersApplied = false;
|
let preservedFiltersApplied = false;
|
||||||
if (!query || isEmpty(labels)) {
|
if (!query || isEmpty(row.labels)) {
|
||||||
return { contextFilters: [], preservedFiltersApplied };
|
return { contextFilters: [], preservedFiltersApplied };
|
||||||
}
|
}
|
||||||
|
const rowLabels = row.labels;
|
||||||
|
|
||||||
// 1. First we need to get all labels from the log row's label
|
// 1. First we need to get all labels from the log row's label
|
||||||
// and correctly set parsed and not parsed labels
|
// and correctly set parsed and not parsed labels
|
||||||
@ -338,12 +338,12 @@ export class LogContextProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const contextFilters: ContextFilter[] = [];
|
const contextFilters: ContextFilter[] = [];
|
||||||
Object.entries(labels).forEach(([label, value]) => {
|
Object.entries(rowLabels).forEach(([label, value]) => {
|
||||||
const filter: ContextFilter = {
|
const filter: ContextFilter = {
|
||||||
label,
|
label,
|
||||||
value: value,
|
value: value,
|
||||||
enabled: allLabels.includes(label),
|
enabled: allLabels.includes(label),
|
||||||
nonIndexed: !allLabels.includes(label),
|
nonIndexed: getLabelTypeFromFrame(label, row.dataFrame, row.rowIndex) !== LabelType.Indexed,
|
||||||
};
|
};
|
||||||
|
|
||||||
contextFilters.push(filter);
|
contextFilters.push(filter);
|
||||||
|
@ -122,7 +122,7 @@ describe('LokiContextUi', () => {
|
|||||||
render(<LokiContextUi {...props} />);
|
render(<LokiContextUi {...props} />);
|
||||||
|
|
||||||
await waitFor(() => {
|
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),
|
from: dateTime(props.row.timeEpochMs),
|
||||||
to: dateTime(props.row.timeEpochMs),
|
to: dateTime(props.row.timeEpochMs),
|
||||||
raw: { from: dateTime(props.row.timeEpochMs), to: dateTime(props.row.timeEpochMs) },
|
raw: { from: dateTime(props.row.timeEpochMs), to: dateTime(props.row.timeEpochMs) },
|
||||||
|
@ -205,7 +205,7 @@ export function LokiContextUi(props: LokiContextUiProps) {
|
|||||||
|
|
||||||
useAsync(async () => {
|
useAsync(async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const initContextFilters = await logContextProvider.getInitContextFilters(row.labels, origQuery, {
|
const initContextFilters = await logContextProvider.getInitContextFilters(row, origQuery, {
|
||||||
from: dateTime(row.timeEpochMs),
|
from: dateTime(row.timeEpochMs),
|
||||||
to: dateTime(row.timeEpochMs),
|
to: dateTime(row.timeEpochMs),
|
||||||
raw: { from: dateTime(row.timeEpochMs), to: dateTime(row.timeEpochMs) },
|
raw: { from: dateTime(row.timeEpochMs), to: dateTime(row.timeEpochMs) },
|
||||||
|
Loading…
Reference in New Issue
Block a user