Skip to content

Commit

Permalink
Loki Logs volume: Added a query splitting loading indicator to the Lo…
Browse files Browse the repository at this point in the history
…gs Volume graph (#79681)

* Logs volume: distinguish annotations from time series frames

* Update unit tests

* Update unit tests

* Formatting
  • Loading branch information
matyax committed Dec 19, 2023
1 parent 8c76397 commit c58ed41
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 9 deletions.
1 change: 1 addition & 0 deletions public/app/features/explore/Logs/LogsVolumePanel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ function renderPanel(logsVolumeData: DataQueryResponse) {
onHiddenSeriesChanged={() => null}
eventBus={new EventBusSrv()}
allLogsVolumeMaximum={20}
annotations={[]}
/>
);
}
Expand Down
3 changes: 3 additions & 0 deletions public/app/features/explore/Logs/LogsVolumePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
TimeZone,
EventBus,
GrafanaTheme2,
DataFrame,
} from '@grafana/data';
import { Icon, Tooltip, TooltipDisplayMode, useStyles2, useTheme2 } from '@grafana/ui';

Expand All @@ -27,6 +28,7 @@ type Props = {
onLoadLogsVolume: () => void;
onHiddenSeriesChanged: (hiddenSeries: string[]) => void;
eventBus: EventBus;
annotations: DataFrame[];
};

export function LogsVolumePanel(props: Props) {
Expand Down Expand Up @@ -80,6 +82,7 @@ export function LogsVolumePanel(props: Props) {
anchorToZero
yAxisMaximum={allLogsVolumeMaximum}
eventBus={props.eventBus}
annotations={props.annotations}
/>
{extraInfoComponent && <div className={styles.extraInfoContainer}>{extraInfoComponent}</div>}
</div>
Expand Down
9 changes: 8 additions & 1 deletion public/app/features/explore/Logs/LogsVolumePanelList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
AbsoluteTimeRange,
DataFrame,
DataQueryResponse,
DataTopic,
EventBus,
GrafanaTheme2,
LoadingState,
Expand Down Expand Up @@ -49,9 +50,13 @@ export const LogsVolumePanelList = ({
logVolumes,
maximumValue: allLogsVolumeMaximumValue,
maximumRange: allLogsVolumeMaximumRange,
annotations,
} = useMemo(() => {
let maximumValue = -Infinity;
const sorted = sortBy(logsVolumeData?.data || [], 'meta.custom.datasourceName');
const data = logsVolumeData?.data.filter((frame: DataFrame) => frame.meta?.dataTopic !== DataTopic.Annotations);
const annotations =
logsVolumeData?.data.filter((frame: DataFrame) => frame.meta?.dataTopic === DataTopic.Annotations) || [];
const sorted = sortBy(data || [], 'meta.custom.datasourceName');
const grouped = groupBy(sorted, 'meta.custom.datasourceName');
const logVolumes = mapValues(grouped, (value) => {
const mergedData = mergeLogsVolumeDataFrames(value);
Expand All @@ -63,6 +68,7 @@ export const LogsVolumePanelList = ({
maximumValue,
maximumRange,
logVolumes,
annotations,
};
}, [logsVolumeData]);

Expand Down Expand Up @@ -127,6 +133,7 @@ export const LogsVolumePanelList = ({
// TODO: Support filtering level from multiple log levels
onHiddenSeriesChanged={numberOfLogVolumes > 1 ? () => {} : onHiddenSeriesChanged}
eventBus={eventBus}
annotations={annotations}
/>
);
})}
Expand Down
78 changes: 78 additions & 0 deletions public/app/features/logs/logsModel.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Observable } from 'rxjs';

import {
arrayToDataFrame,
DataFrame,
DataQuery,
DataQueryRequest,
DataQueryResponse,
DataTopic,
dateTimeParse,
FieldType,
LoadingState,
Expand Down Expand Up @@ -1282,6 +1284,33 @@ describe('logs volume', () => {
]);
}

function setupLogsVolumeWithAnnotations() {
const resultAFrame1 = createFrame({ app: 'app01' }, [100, 200, 300], [5, 5, 5], 'A');
const loadingFrame = arrayToDataFrame([
{
time: 100,
timeEnd: 200,
isRegion: true,
color: 'rgba(120, 120, 120, 0.1)',
},
]);
loadingFrame.name = 'annotation';
loadingFrame.meta = {
dataTopic: DataTopic.Annotations,
};

datasource = new MockObservableDataSourceApi('loki', [
{
state: LoadingState.Streaming,
data: [resultAFrame1, loadingFrame],
},
{
state: LoadingState.Done,
data: [resultAFrame1],
},
]);
}

function setupErrorResponse() {
datasource = new MockObservableDataSourceApi('loki', [], undefined, 'Error message');
}
Expand Down Expand Up @@ -1363,6 +1392,55 @@ describe('logs volume', () => {
]);
});
});

it('handles annotations in responses', async () => {
setup(setupLogsVolumeWithAnnotations);

const logVolumeCustomMeta: LogsVolumeCustomMetaData = {
sourceQuery: { refId: 'A', target: 'volume query 1' } as DataQuery,
datasourceName: 'loki',
logsVolumeType: LogsVolumeType.FullRange,
absoluteRange: {
from: FROM.valueOf(),
to: TO.valueOf(),
},
};

await expect(volumeProvider).toEmitValuesWith((received) => {
expect(received).toContainEqual({ state: LoadingState.Loading, error: undefined, data: [] });
expect(received).toContainEqual({
state: LoadingState.Streaming,
error: undefined,
data: [
expect.objectContaining({
fields: expect.anything(),
meta: {
custom: logVolumeCustomMeta,
},
}),
expect.objectContaining({
fields: expect.anything(),
meta: {
dataTopic: DataTopic.Annotations,
},
name: 'annotation',
}),
],
});
expect(received).toContainEqual({
state: LoadingState.Done,
error: undefined,
data: [
expect.objectContaining({
fields: expect.anything(),
meta: {
custom: logVolumeCustomMeta,
},
}),
],
});
});
});
});

describe('logs sample', () => {
Expand Down
5 changes: 5 additions & 0 deletions public/app/features/logs/logsModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
DataQueryResponse,
DataSourceApi,
DataSourceJsonData,
DataTopic,
dateTimeFormat,
dateTimeFormatTimeAgo,
DateTimeInput,
Expand Down Expand Up @@ -658,6 +659,10 @@ export function queryLogsVolume<TQuery extends DataQuery, TOptions extends DataS
} else {
const framesByRefId = groupBy(dataQueryResponse.data, 'refId');
logsVolumeData = dataQueryResponse.data.map((dataFrame) => {
// Separate possible annotations from data frames
if (dataFrame.meta?.dataTopic === DataTopic.Annotations) {
return dataFrame;
}
let sourceRefId = dataFrame.refId || '';
if (sourceRefId.startsWith('log-volume-')) {
sourceRefId = sourceRefId.substr('log-volume-'.length);
Expand Down
13 changes: 5 additions & 8 deletions public/app/plugins/datasource/loki/querySplitting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,17 +150,18 @@ export function runSplitGroupedQueries(datasource: LokiDatasource, requests: Lok
return response;
}

export const LOADING_FRAME_NAME = 'loki-splitting-progress';

function updateLoadingFrame(
response: DataQueryResponse,
request: DataQueryRequest<LokiQuery>,
partition: TimeRange[],
requestN: number
): DataQueryResponse {
if (isLogsQuery(request.targets[0].expr) || isLogsVolumeRequest(request)) {
if (isLogsQuery(request.targets[0].expr)) {
return response;
}
const loadingFrameName = 'loki-splitting-progress';
response.data = response.data.filter((frame) => frame.name !== loadingFrameName);
response.data = response.data.filter((frame) => frame.name !== LOADING_FRAME_NAME);

if (requestN <= 1) {
return response;
Expand All @@ -174,7 +175,7 @@ function updateLoadingFrame(
color: 'rgba(120, 120, 120, 0.1)',
},
]);
loadingFrame.name = loadingFrameName;
loadingFrame.name = LOADING_FRAME_NAME;
loadingFrame.meta = {
dataTopic: DataTopic.Annotations,
};
Expand All @@ -184,10 +185,6 @@ function updateLoadingFrame(
return response;
}

function isLogsVolumeRequest(request: DataQueryRequest<LokiQuery>): boolean {
return request.targets.some((target) => target.refId.startsWith('log-volume'));
}

function getNextRequestPointers(requests: LokiGroupedRequest[], requestGroup: number, requestN: number) {
// There's a pending request from the next group:
for (let i = requestGroup + 1; i < requests.length; i++) {
Expand Down

0 comments on commit c58ed41

Please sign in to comment.