mirror of
https://github.com/grafana/grafana.git
synced 2026-08-13 06:34:55 -05:00
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:
@@ -189,12 +189,12 @@ describe('LogRowContextModal', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should render 3 lines containing `foo123` with the same ms timestamp', async () => {
|
it('should render 3 lines containing `foo123` with the same ms timestamp', async () => {
|
||||||
const dfBefore = createDataFrame({
|
const dfBeforeNs = createDataFrame({
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'time',
|
name: 'time',
|
||||||
type: FieldType.time,
|
type: FieldType.time,
|
||||||
values: [1689052469935, 1689052469935],
|
values: [1, 1],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'message',
|
name: 'message',
|
||||||
@@ -204,16 +204,16 @@ describe('LogRowContextModal', () => {
|
|||||||
{
|
{
|
||||||
name: 'tsNs',
|
name: 'tsNs',
|
||||||
type: FieldType.string,
|
type: FieldType.string,
|
||||||
values: ['1689052469935083353', '1689052469935083354'],
|
values: ['1', '2'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
const dfNow = createDataFrame({
|
const dfNowNs = createDataFrame({
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'time',
|
name: 'time',
|
||||||
type: FieldType.time,
|
type: FieldType.time,
|
||||||
values: [1689052469935],
|
values: [1],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'message',
|
name: 'message',
|
||||||
@@ -223,16 +223,16 @@ describe('LogRowContextModal', () => {
|
|||||||
{
|
{
|
||||||
name: 'tsNs',
|
name: 'tsNs',
|
||||||
type: FieldType.string,
|
type: FieldType.string,
|
||||||
values: ['1689052469935083354'],
|
values: ['2'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
const dfAfter = createDataFrame({
|
const dfAfterNs = createDataFrame({
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'time',
|
name: 'time',
|
||||||
type: FieldType.time,
|
type: FieldType.time,
|
||||||
values: [1689052469935, 1689052469935],
|
values: [1, 1],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'message',
|
name: 'message',
|
||||||
@@ -242,36 +242,37 @@ describe('LogRowContextModal', () => {
|
|||||||
{
|
{
|
||||||
name: 'tsNs',
|
name: 'tsNs',
|
||||||
type: FieldType.string,
|
type: FieldType.string,
|
||||||
values: ['1689052469935083354', '1689052469935083355'],
|
values: ['2', '3'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
let uniqueRefIdCounter = 1;
|
let uniqueRefIdCounter = 1;
|
||||||
const logs = dataFrameToLogsModel([dfNow]);
|
const logs = dataFrameToLogsModel([dfNowNs]);
|
||||||
const row = logs.rows[0];
|
const row = logs.rows[0];
|
||||||
const getRowContext = jest.fn().mockImplementation(async (_, options) => {
|
const getRowContext = jest.fn().mockImplementation(async (_, options) => {
|
||||||
uniqueRefIdCounter += 1;
|
uniqueRefIdCounter += 1;
|
||||||
const refId = `refid_${uniqueRefIdCounter}`;
|
const refId = `refid_${uniqueRefIdCounter}`;
|
||||||
if (options.direction === LogRowContextQueryDirection.Forward) {
|
if (uniqueRefIdCounter === 2) {
|
||||||
return {
|
return {
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
refId,
|
refId,
|
||||||
...dfBefore,
|
...dfBeforeNs,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
} else {
|
} else if (uniqueRefIdCounter === 3) {
|
||||||
return {
|
return {
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
refId,
|
refId,
|
||||||
...dfAfter,
|
...dfAfterNs,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
return { data: [] };
|
||||||
});
|
});
|
||||||
|
|
||||||
render(
|
render(
|
||||||
@@ -284,8 +285,11 @@ describe('LogRowContextModal', () => {
|
|||||||
logsSortOrder={LogsSortOrder.Descending}
|
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 () => {
|
it('should show a split view button', async () => {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
|
import { partition } from 'lodash';
|
||||||
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||||
import { useAsync } from 'react-use';
|
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
|
generationRef.current += 1; // results from currently running loadMore calls will be ignored
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadMore = async (place: Place): Promise<LogRowModel[]> => {
|
const loadMore = async (place: Place, allRows: LogRowModel[]): 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 refRow = allRows.at(place === 'above' ? 0 : -1);
|
const refRow = allRows.at(place === 'above' ? 0 : -1);
|
||||||
if (refRow == null) {
|
if (refRow == null) {
|
||||||
throw new Error('should never happen. the array always contains at least 1 item (the middle row)');
|
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 maybeLoadMore = async (place: Place) => {
|
||||||
|
const { below, above } = context;
|
||||||
const section = context[place];
|
const section = context[place];
|
||||||
if (section.loadingState === LoadingState.Loading) {
|
if (section.loadingState === LoadingState.Loading) {
|
||||||
return;
|
return;
|
||||||
@@ -317,11 +315,25 @@ export const LogRowContextModal: React.FunctionComponent<LogRowContextModalProps
|
|||||||
|
|
||||||
const currentGen = generationRef.current;
|
const currentGen = generationRef.current;
|
||||||
try {
|
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) {
|
if (currentGen === generationRef.current) {
|
||||||
setSection(place, (section) => ({
|
setContext((c) => ({
|
||||||
rows: place === 'above' ? [...newRows, ...section.rows] : [...section.rows, ...newRows],
|
above: {
|
||||||
loadingState: newRows.length === 0 ? LoadingState.Done : LoadingState.NotStarted,
|
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 {
|
} catch {
|
||||||
|
|||||||
Reference in New Issue
Block a user