mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Fix permalink timerange when multiple logs share a timestamp (#83847)
* Loki: Slide permalink timerange `1ms` to make sure to include line * find previous log with different time * fix test not being agnostic
This commit is contained in:
parent
a7c06d26f1
commit
9f73fb65cd
@ -16,12 +16,22 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { organizeFieldsTransformer } from '@grafana/data/src/transformations/transformers/organize';
|
||||
import { config } from '@grafana/runtime';
|
||||
import store from 'app/core/store';
|
||||
import { extractFieldsTransformer } from 'app/features/transformers/extractFields/extractFields';
|
||||
|
||||
import { Logs } from './Logs';
|
||||
import { visualisationTypeKey } from './utils/logs';
|
||||
import { getMockElasticFrame, getMockLokiFrame } from './utils/testMocks.test';
|
||||
|
||||
jest.mock('app/core/store', () => {
|
||||
return {
|
||||
getBool: jest.fn(),
|
||||
getObject: jest.fn((_a, b) => b),
|
||||
get: jest.fn(),
|
||||
set: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
const reportInteraction = jest.fn();
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
@ -379,7 +389,13 @@ describe('Logs', () => {
|
||||
|
||||
it('should call reportInteraction on permalinkClick', async () => {
|
||||
const panelState = { logs: { id: 'not-included' } };
|
||||
setup({ loading: false, panelState });
|
||||
const rows = [
|
||||
makeLog({ uid: '1', rowId: 'id1', timeEpochMs: 4 }),
|
||||
makeLog({ uid: '2', rowId: 'id2', timeEpochMs: 3 }),
|
||||
makeLog({ uid: '3', rowId: 'id3', timeEpochMs: 2 }),
|
||||
makeLog({ uid: '4', rowId: 'id3', timeEpochMs: 1 }),
|
||||
];
|
||||
setup({ loading: false, panelState, logRows: rows });
|
||||
|
||||
const row = screen.getAllByRole('row');
|
||||
await userEvent.hover(row[0]);
|
||||
@ -396,7 +412,13 @@ describe('Logs', () => {
|
||||
|
||||
it('should call createAndCopyShortLink on permalinkClick - logs', async () => {
|
||||
const panelState: Partial<ExplorePanelsState> = { logs: { id: 'not-included', visualisationType: 'logs' } };
|
||||
setup({ loading: false, panelState });
|
||||
const rows = [
|
||||
makeLog({ uid: '1', rowId: 'id1', timeEpochMs: 1 }),
|
||||
makeLog({ uid: '2', rowId: 'id2', timeEpochMs: 1 }),
|
||||
makeLog({ uid: '3', rowId: 'id3', timeEpochMs: 2 }),
|
||||
makeLog({ uid: '4', rowId: 'id3', timeEpochMs: 2 }),
|
||||
];
|
||||
setup({ loading: false, panelState, logRows: rows });
|
||||
|
||||
const row = screen.getAllByRole('row');
|
||||
await userEvent.hover(row[0]);
|
||||
@ -411,6 +433,34 @@ describe('Logs', () => {
|
||||
);
|
||||
expect(createAndCopyShortLink).toHaveBeenCalledWith(expect.stringMatching('visualisationType%22:%22logs'));
|
||||
});
|
||||
|
||||
it('should call createAndCopyShortLink on permalinkClick - with infinite scrolling', async () => {
|
||||
const featureToggleValue = config.featureToggles.logsInfiniteScrolling;
|
||||
config.featureToggles.logsInfiniteScrolling = true;
|
||||
const rows = [
|
||||
makeLog({ uid: '1', rowId: 'id1', timeEpochMs: 1 }),
|
||||
makeLog({ uid: '2', rowId: 'id2', timeEpochMs: 1 }),
|
||||
makeLog({ uid: '3', rowId: 'id3', timeEpochMs: 2 }),
|
||||
makeLog({ uid: '4', rowId: 'id3', timeEpochMs: 2 }),
|
||||
];
|
||||
|
||||
const panelState: Partial<ExplorePanelsState> = { logs: { id: 'not-included', visualisationType: 'logs' } };
|
||||
setup({ loading: false, panelState, logRows: rows });
|
||||
|
||||
const row = screen.getAllByRole('row');
|
||||
await userEvent.hover(row[3]);
|
||||
|
||||
const linkButton = screen.getByLabelText('Copy shortlink');
|
||||
await userEvent.click(linkButton);
|
||||
|
||||
expect(createAndCopyShortLink).toHaveBeenCalledWith(
|
||||
expect.stringMatching(
|
||||
'range%22:%7B%22from%22:%222019-01-01T10:00:00.000Z%22,%22to%22:%221970-01-01T00:00:00.002Z%22%7D'
|
||||
)
|
||||
);
|
||||
expect(createAndCopyShortLink).toHaveBeenCalledWith(expect.stringMatching('visualisationType%22:%22logs'));
|
||||
config.featureToggles.logsInfiniteScrolling = featureToggleValue;
|
||||
});
|
||||
});
|
||||
|
||||
describe('with table visualisation', () => {
|
||||
@ -441,17 +491,23 @@ describe('Logs', () => {
|
||||
});
|
||||
|
||||
it('should use default state from localstorage - table', async () => {
|
||||
const oldGet = store.get;
|
||||
store.get = jest.fn().mockReturnValue('table');
|
||||
localStorage.setItem(visualisationTypeKey, 'table');
|
||||
setup({});
|
||||
const table = await screen.findByTestId('logRowsTable');
|
||||
expect(table).toBeInTheDocument();
|
||||
store.get = oldGet;
|
||||
});
|
||||
|
||||
it('should use default state from localstorage - logs', async () => {
|
||||
const oldGet = store.get;
|
||||
store.get = jest.fn().mockReturnValue('logs');
|
||||
localStorage.setItem(visualisationTypeKey, 'logs');
|
||||
setup({});
|
||||
const table = await screen.findByTestId('logRows');
|
||||
expect(table).toBeInTheDocument();
|
||||
store.get = oldGet;
|
||||
});
|
||||
|
||||
it('should change visualisation to table on toggle (elastic)', async () => {
|
||||
|
@ -437,6 +437,16 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
||||
};
|
||||
};
|
||||
|
||||
getPreviousLog(row: LogRowModel, allLogs: LogRowModel[]): LogRowModel | null {
|
||||
for (let i = allLogs.indexOf(row) - 1; i >= 0; i--) {
|
||||
if (allLogs[i].timeEpochMs > row.timeEpochMs) {
|
||||
return allLogs[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getPermalinkRange(row: LogRowModel) {
|
||||
const range = {
|
||||
from: new Date(this.props.absoluteRange.from).toISOString(),
|
||||
@ -449,7 +459,7 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
||||
// With infinite scrolling, the time range of the log line can be after the absolute range or beyond the request line limit, so we need to adjust
|
||||
// Look for the previous sibling log, and use its timestamp
|
||||
const allLogs = this.props.logRows.filter((logRow) => logRow.dataFrame.refId === row.dataFrame.refId);
|
||||
const prevLog = allLogs[allLogs.indexOf(row) - 1];
|
||||
const prevLog = this.getPreviousLog(row, allLogs);
|
||||
|
||||
if (row.timeEpochMs > this.props.absoluteRange.to && !prevLog) {
|
||||
// Because there's no sibling and the current `to` is oldest than the log, we have no reference we can use for the interval
|
||||
|
Loading…
Reference in New Issue
Block a user