mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Logs: Log samples not being ordered correctly (#64097)
* fix log samples being unsorted and multiple results when chunking * use `SortDirection` enum * changed to `sortDataFrame` to support other datasources than loki * update tests * change capitalization
This commit is contained in:
parent
d61bcdf4ca
commit
2076282064
@ -15,6 +15,7 @@ import {
|
||||
LogsMetaKind,
|
||||
LogsVolumeType,
|
||||
MutableDataFrame,
|
||||
sortDataFrame,
|
||||
toDataFrame,
|
||||
} from '@grafana/data';
|
||||
|
||||
@ -1345,14 +1346,14 @@ describe('logs sample', () => {
|
||||
const resultAFrame1 = createFrame([{ app: 'app01' }], [100, 200, 300], ['line 1', 'line 2', 'line 3']);
|
||||
const resultAFrame2 = createFrame(
|
||||
[{ app: 'app01', level: 'error' }],
|
||||
[100, 200, 300],
|
||||
[400, 500, 600],
|
||||
['line 4', 'line 5', 'line 6']
|
||||
);
|
||||
|
||||
const resultBFrame1 = createFrame([{ app: 'app02' }], [100, 200, 300], ['line A', 'line B', 'line C']);
|
||||
const resultBFrame1 = createFrame([{ app: 'app02' }], [700, 800, 900], ['line A', 'line B', 'line C']);
|
||||
const resultBFrame2 = createFrame(
|
||||
[{ app: 'app02', level: 'error' }],
|
||||
[100, 200, 300],
|
||||
[1000, 1100, 1200],
|
||||
['line D', 'line E', 'line F']
|
||||
);
|
||||
|
||||
@ -1362,7 +1363,7 @@ describe('logs sample', () => {
|
||||
data: [resultAFrame1, resultAFrame2],
|
||||
},
|
||||
{
|
||||
data: [resultBFrame1, resultBFrame2],
|
||||
data: [resultBFrame1, resultBFrame2, resultAFrame1, resultAFrame2],
|
||||
},
|
||||
]);
|
||||
}
|
||||
@ -1374,14 +1375,17 @@ describe('logs sample', () => {
|
||||
it('returns data', async () => {
|
||||
setup(setupMultipleResults);
|
||||
await expect(logsSampleProvider).toEmitValuesWith((received) => {
|
||||
expect(received).toMatchObject([
|
||||
{ state: LoadingState.Loading, error: undefined, data: [] },
|
||||
{
|
||||
state: LoadingState.Done,
|
||||
error: undefined,
|
||||
data: [resultAFrame1, resultAFrame2, resultBFrame1, resultBFrame2],
|
||||
},
|
||||
]);
|
||||
expect(received).toContainEqual({ state: LoadingState.Loading, error: undefined, data: [] });
|
||||
expect(received).toContainEqual(
|
||||
expect.objectContaining({
|
||||
data: expect.arrayContaining([
|
||||
sortDataFrame(resultAFrame1, 0),
|
||||
sortDataFrame(resultAFrame2, 0),
|
||||
sortDataFrame(resultBFrame1, 0),
|
||||
sortDataFrame(resultBFrame2, 0),
|
||||
]),
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
FieldWithIndex,
|
||||
findCommonLabels,
|
||||
findUniqueLabels,
|
||||
getTimeField,
|
||||
Labels,
|
||||
LoadingState,
|
||||
LogLevel,
|
||||
@ -30,6 +31,7 @@ import {
|
||||
MutableDataFrame,
|
||||
rangeUtil,
|
||||
ScopedVars,
|
||||
sortDataFrame,
|
||||
textUtil,
|
||||
TimeRange,
|
||||
toDataFrame,
|
||||
@ -41,6 +43,7 @@ import { ansicolor, colors } from '@grafana/ui';
|
||||
import { getThemeColor } from 'app/core/utils/colors';
|
||||
|
||||
import { getLogLevel, getLogLevelFromKey, sortInAscendingOrder } from '../features/logs/utils';
|
||||
|
||||
export const LIMIT_LABEL = 'Line limit';
|
||||
export const COMMON_LABELS = 'Common labels';
|
||||
|
||||
@ -798,7 +801,11 @@ export function queryLogsSample<TQuery extends DataQuery, TOptions extends DataS
|
||||
});
|
||||
observer.error(error);
|
||||
} else {
|
||||
rawLogsSample = rawLogsSample.concat(dataQueryResponse.data.map(toDataFrame));
|
||||
rawLogsSample = dataQueryResponse.data.map((dataFrame) => {
|
||||
const frame = toDataFrame(dataFrame);
|
||||
const { timeIndex } = getTimeField(frame);
|
||||
return sortDataFrame(frame, timeIndex);
|
||||
});
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
|
@ -78,7 +78,7 @@ import {
|
||||
isValidQuery,
|
||||
requestSupportsPartitioning,
|
||||
} from './queryUtils';
|
||||
import { sortDataFrameByTime } from './sortDataFrame';
|
||||
import { sortDataFrameByTime, SortDirection } from './sortDataFrame';
|
||||
import { doLokiChannelStream } from './streaming';
|
||||
import { trackQuery } from './tracking';
|
||||
import {
|
||||
@ -686,7 +686,7 @@ export class LokiDatasource
|
||||
const processResults = (result: DataQueryResponse): DataQueryResponse => {
|
||||
const frames: DataFrame[] = result.data;
|
||||
const processedFrames = frames
|
||||
.map((frame) => sortDataFrameByTime(frame, 'DESCENDING'))
|
||||
.map((frame) => sortDataFrameByTime(frame, SortDirection.Descending))
|
||||
.map((frame) => processDataFrame(frame)); // rename fields if needed
|
||||
|
||||
return {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ArrayVector, DataFrame, FieldType } from '@grafana/data';
|
||||
|
||||
import { sortDataFrameByTime } from './sortDataFrame';
|
||||
import { sortDataFrameByTime, SortDirection } from './sortDataFrame';
|
||||
|
||||
const inputFrame: DataFrame = {
|
||||
refId: 'A',
|
||||
@ -29,7 +29,7 @@ const inputFrame: DataFrame = {
|
||||
|
||||
describe('loki sortDataFrame', () => {
|
||||
it('sorts a dataframe ascending', () => {
|
||||
const sortedFrame = sortDataFrameByTime(inputFrame, 'ASCENDING');
|
||||
const sortedFrame = sortDataFrameByTime(inputFrame, SortDirection.Ascending);
|
||||
expect(sortedFrame.length).toBe(5);
|
||||
const timeValues = sortedFrame.fields[0].values.toArray();
|
||||
const lineValues = sortedFrame.fields[1].values.toArray();
|
||||
@ -40,7 +40,7 @@ describe('loki sortDataFrame', () => {
|
||||
expect(tsNsValues).toStrictEqual([`1001000000`, `1002000000`, `1003000000`, `1004000000`, `1005000000`]);
|
||||
});
|
||||
it('sorts a dataframe descending', () => {
|
||||
const sortedFrame = sortDataFrameByTime(inputFrame, 'DESCENDING');
|
||||
const sortedFrame = sortDataFrameByTime(inputFrame, SortDirection.Descending);
|
||||
expect(sortedFrame.length).toBe(5);
|
||||
const timeValues = sortedFrame.fields[0].values.toArray();
|
||||
const lineValues = sortedFrame.fields[1].values.toArray();
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { DataFrame, Field, SortedVector } from '@grafana/data';
|
||||
|
||||
type SortDirection = 'ASCENDING' | 'DESCENDING';
|
||||
export enum SortDirection {
|
||||
Ascending,
|
||||
Descending,
|
||||
}
|
||||
|
||||
// creates the `index` for the sorting.
|
||||
// this is needed by the `SortedVector`.
|
||||
@ -21,7 +24,7 @@ function makeIndex(field: Field<string>, dir: SortDirection): number[] {
|
||||
index[i] = i;
|
||||
}
|
||||
|
||||
const isAsc = dir === 'ASCENDING';
|
||||
const isAsc = dir === SortDirection.Ascending;
|
||||
|
||||
index.sort((a: number, b: number): number => {
|
||||
// we need to answer this question:
|
||||
|
Loading…
Reference in New Issue
Block a user