Logs: Fix nanosecond partition in log context (#71346)

* add ts partition

* fix setting wrong loadingstate

* improve setContext

* update context and test
This commit is contained in:
Sven Grossmann 2023-07-11 16:20:41 +02:00 committed by GitHub
parent 7fdf855932
commit 9ddba37dbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 25 deletions

View File

@ -189,12 +189,12 @@ describe('LogRowContextModal', () => {
});
it('should render 3 lines containing `foo123` with the same ms timestamp', async () => {
const dfBefore = createDataFrame({
const dfBeforeNs = createDataFrame({
fields: [
{
name: 'time',
type: FieldType.time,
values: [1689052469935, 1689052469935],
values: [1, 1],
},
{
name: 'message',
@ -204,16 +204,16 @@ describe('LogRowContextModal', () => {
{
name: 'tsNs',
type: FieldType.string,
values: ['1689052469935083353', '1689052469935083354'],
values: ['1', '2'],
},
],
});
const dfNow = createDataFrame({
const dfNowNs = createDataFrame({
fields: [
{
name: 'time',
type: FieldType.time,
values: [1689052469935],
values: [1],
},
{
name: 'message',
@ -223,16 +223,16 @@ describe('LogRowContextModal', () => {
{
name: 'tsNs',
type: FieldType.string,
values: ['1689052469935083354'],
values: ['2'],
},
],
});
const dfAfter = createDataFrame({
const dfAfterNs = createDataFrame({
fields: [
{
name: 'time',
type: FieldType.time,
values: [1689052469935, 1689052469935],
values: [1, 1],
},
{
name: 'message',
@ -242,36 +242,37 @@ describe('LogRowContextModal', () => {
{
name: 'tsNs',
type: FieldType.string,
values: ['1689052469935083354', '1689052469935083355'],
values: ['2', '3'],
},
],
});
let uniqueRefIdCounter = 1;
const logs = dataFrameToLogsModel([dfNow]);
const logs = dataFrameToLogsModel([dfNowNs]);
const row = logs.rows[0];
const getRowContext = jest.fn().mockImplementation(async (_, options) => {
uniqueRefIdCounter += 1;
const refId = `refid_${uniqueRefIdCounter}`;
if (options.direction === LogRowContextQueryDirection.Forward) {
if (uniqueRefIdCounter === 2) {
return {
data: [
{
refId,
...dfBefore,
...dfBeforeNs,
},
],
};
} else {
} else if (uniqueRefIdCounter === 3) {
return {
data: [
{
refId,
...dfAfter,
...dfAfterNs,
},
],
};
}
return { data: [] };
});
render(
@ -284,8 +285,11 @@ describe('LogRowContextModal', () => {
logsSortOrder={LogsSortOrder.Descending}
/>
);
// there need to be 2 lines with that message. 1 in before, 1 in now, 1 in after
await waitFor(() => expect(screen.getAllByText('foo123').length).toBe(3));
// there need to be 3 lines with that message. 1 in before, 1 in now, 1 in after
await waitFor(() => {
expect(screen.getAllByText('foo123').length).toBe(3);
});
});
it('should show a split view button', async () => {

View File

@ -1,4 +1,5 @@
import { css, cx } from '@emotion/css';
import { partition } from 'lodash';
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useAsync } from 'react-use';
@ -253,11 +254,7 @@ export const LogRowContextModal: React.FunctionComponent<LogRowContextModalProps
generationRef.current += 1; // results from currently running loadMore calls will be ignored
};
const loadMore = async (place: Place): Promise<LogRowModel[]> => {
const { below, above } = context;
// we consider all the currently existing rows, even the original row,
// this way this array of rows will never be empty
const allRows = [...above.rows, row, ...below.rows];
const loadMore = async (place: Place, allRows: LogRowModel[]): Promise<LogRowModel[]> => {
const refRow = allRows.at(place === 'above' ? 0 : -1);
if (refRow == null) {
throw new Error('should never happen. the array always contains at least 1 item (the middle row)');
@ -305,6 +302,7 @@ export const LogRowContextModal: React.FunctionComponent<LogRowContextModalProps
};
const maybeLoadMore = async (place: Place) => {
const { below, above } = context;
const section = context[place];
if (section.loadingState === LoadingState.Loading) {
return;
@ -317,11 +315,25 @@ export const LogRowContextModal: React.FunctionComponent<LogRowContextModalProps
const currentGen = generationRef.current;
try {
const newRows = await loadMore(place);
// we consider all the currently existing rows, even the original row,
// this way this array of rows will never be empty
const allRows = [...above.rows, row, ...below.rows];
const newRows = await loadMore(place, allRows);
const [older, newer] = partition(newRows, (newRow) => newRow.timeEpochNs > row.timeEpochNs);
const newAbove = logsSortOrder === LogsSortOrder.Ascending ? newer : older;
const newBelow = logsSortOrder === LogsSortOrder.Ascending ? older : newer;
if (currentGen === generationRef.current) {
setSection(place, (section) => ({
rows: place === 'above' ? [...newRows, ...section.rows] : [...section.rows, ...newRows],
loadingState: newRows.length === 0 ? LoadingState.Done : LoadingState.NotStarted,
setContext((c) => ({
above: {
rows: sortLogRows([...newAbove, ...c.above.rows], logsSortOrder),
loadingState: newRows.length === 0 ? LoadingState.Done : LoadingState.NotStarted,
},
below: {
rows: sortLogRows([...c.below.rows, ...newBelow], logsSortOrder),
loadingState: newRows.length === 0 ? LoadingState.Done : LoadingState.NotStarted,
},
}));
}
} catch {