From a5ece0f0cb882b1e3e6e994e36fa5ab93072a6ef Mon Sep 17 00:00:00 2001 From: Matias Chomicki Date: Thu, 19 Dec 2024 18:03:37 +0100 Subject: [PATCH 1/3] feat(LogsPanelScene): issue queries in forward or backward direction depending on sort --- .../ServiceScene/LogsPanelScene.tsx | 12 +++++++- src/services/datasource.ts | 30 ++++++++++++++----- src/services/lokiQuery.ts | 7 +++++ 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/Components/ServiceScene/LogsPanelScene.tsx b/src/Components/ServiceScene/LogsPanelScene.tsx index a94cf1bd..41a90ceb 100644 --- a/src/Components/ServiceScene/LogsPanelScene.tsx +++ b/src/Components/ServiceScene/LogsPanelScene.tsx @@ -5,6 +5,7 @@ import { sceneGraph, SceneObjectBase, SceneObjectState, + SceneQueryRunner, VizPanel, } from '@grafana/scenes'; import { DataFrame, getValueFormat, LogRowModel } from '@grafana/data'; @@ -22,7 +23,7 @@ import { CopyLinkButton } from './CopyLinkButton'; import { getLogsPanelSortOrder, LogOptionsScene } from './LogOptionsScene'; import { LogsVolumePanel, logsVolumePanelKey } from './LogsVolumePanel'; import { getPanelWrapperStyles, PanelMenu } from '../Panels/PanelMenu'; -import { ServiceScene } from './ServiceScene'; +import { LOGS_PANEL_QUERY_REFID, ServiceScene } from './ServiceScene'; interface LogsPanelSceneState extends SceneObjectState { body?: VizPanel; @@ -104,6 +105,15 @@ export class LogsPanelScene extends SceneObjectBase { if (!this.state.body) { return; } + if ('sortOrder' in options) { + const serviceScene = sceneGraph.getAncestor(this, ServiceScene); + const runners = sceneGraph.findDescendents(serviceScene, SceneQueryRunner); + runners.forEach((runner) => { + if (runner.isActive && runner.state.queries[0]?.refId === LOGS_PANEL_QUERY_REFID) { + runner.runQueries(); + } + }); + } this.state.body.onOptionsChange(options); } diff --git a/src/services/datasource.ts b/src/services/datasource.ts index ee46c0bb..028a99ec 100644 --- a/src/services/datasource.ts +++ b/src/services/datasource.ts @@ -10,7 +10,7 @@ import { } from '@grafana/data'; import { config, DataSourceWithBackend, getDataSourceSrv } from '@grafana/runtime'; import { RuntimeDataSource, sceneUtils } from '@grafana/scenes'; -import { DataQuery } from '@grafana/schema'; +import { DataQuery, LogsSortOrder } from '@grafana/schema'; import { Observable, Subscriber } from 'rxjs'; import { getDataSource } from './scenes'; import { getPrimaryLabelFromUrl } from './routing'; @@ -19,11 +19,13 @@ import { FIELDS_TO_REMOVE, LABELS_TO_REMOVE, sortLabelsByCardinality } from './f import { SERVICE_NAME } from './variables'; import { runShardSplitQuery } from './shardQuerySplitting'; import { requestSupportsSharding } from './logql'; -import { LokiDatasource, LokiQuery } from './lokiQuery'; +import { LokiDatasource, LokiQuery, LokiQueryDirection } from './lokiQuery'; import { SceneDataQueryRequest, SceneDataQueryResourceRequest, VolumeRequestProps } from './datasourceTypes'; import { logger } from './logger'; import { PLUGIN_ID } from './plugin'; import { sanitizeStreamSelector } from './query'; +import { LOGS_PANEL_QUERY_REFID } from 'Components/ServiceScene/ServiceScene'; +import { getLogsPanelSortOrder } from 'Components/ServiceScene/LogOptionsScene'; export const WRAPPED_LOKI_DS_UID = 'wrapped-loki-ds-uid'; @@ -141,11 +143,13 @@ export class WrappedLokiDatasource extends RuntimeDataSource { const updatedRequest = { ...request, - targets: ds.interpolateVariablesInQueries(request.targets, request.scopedVars).map((target) => ({ - ...target, - resource: undefined, - expr: sanitizeStreamSelector(target.expr), - })), + targets: this.applyQueryDirection( + ds.interpolateVariablesInQueries(request.targets, request.scopedVars).map((target) => ({ + ...target, + resource: undefined, + expr: sanitizeStreamSelector(target.expr), + })) + ), }; // Query the datasource and return either observable or promise @@ -266,6 +270,18 @@ export class WrappedLokiDatasource extends RuntimeDataSource { return { interpolatedTarget, expression }; } + private applyQueryDirection(targets: LokiQuery[]) { + const sortOrder = getLogsPanelSortOrder(); + return targets.map((target) => { + if (target.refId !== LOGS_PANEL_QUERY_REFID) { + return target; + } + target.direction = + sortOrder === LogsSortOrder.Descending ? LokiQueryDirection.Backward : LokiQueryDirection.Forward; + return target; + }); + } + private async getDetectedLabels( request: DataQueryRequest, ds: LokiDatasource, diff --git a/src/services/lokiQuery.ts b/src/services/lokiQuery.ts index d04c2402..936af53c 100644 --- a/src/services/lokiQuery.ts +++ b/src/services/lokiQuery.ts @@ -3,6 +3,12 @@ import { DataSourceRef } from '@grafana/schema'; import { DataSourceWithBackend } from '@grafana/runtime'; import { DataSourceJsonData } from '@grafana/data'; +export enum LokiQueryDirection { + Backward = 'backward', + Forward = 'forward', + Scan = 'scan', +} + export type LokiQuery = { refId: string; queryType?: LokiQueryType; @@ -13,6 +19,7 @@ export type LokiQuery = { splitDuration?: string; datasource?: DataSourceRef; maxLines?: number; + direction?: LokiQueryDirection; }; export type LokiQueryType = 'instant' | 'range' | 'stream' | string; From b1794368a7e58d3f66617c6121b45746bdec35fc Mon Sep 17 00:00:00 2001 From: Matias Chomicki Date: Fri, 20 Dec 2024 16:10:12 +0100 Subject: [PATCH 2/3] fix(LogsPanelScene): improve query rerunning --- src/Components/ServiceScene/LogsPanelScene.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Components/ServiceScene/LogsPanelScene.tsx b/src/Components/ServiceScene/LogsPanelScene.tsx index 41a90ceb..fa4b278b 100644 --- a/src/Components/ServiceScene/LogsPanelScene.tsx +++ b/src/Components/ServiceScene/LogsPanelScene.tsx @@ -23,7 +23,7 @@ import { CopyLinkButton } from './CopyLinkButton'; import { getLogsPanelSortOrder, LogOptionsScene } from './LogOptionsScene'; import { LogsVolumePanel, logsVolumePanelKey } from './LogsVolumePanel'; import { getPanelWrapperStyles, PanelMenu } from '../Panels/PanelMenu'; -import { LOGS_PANEL_QUERY_REFID, ServiceScene } from './ServiceScene'; +import { ServiceScene } from './ServiceScene'; interface LogsPanelSceneState extends SceneObjectState { body?: VizPanel; @@ -106,13 +106,12 @@ export class LogsPanelScene extends SceneObjectBase { return; } if ('sortOrder' in options) { - const serviceScene = sceneGraph.getAncestor(this, ServiceScene); - const runners = sceneGraph.findDescendents(serviceScene, SceneQueryRunner); - runners.forEach((runner) => { - if (runner.isActive && runner.state.queries[0]?.refId === LOGS_PANEL_QUERY_REFID) { - runner.runQueries(); - } - }); + const $data = sceneGraph.getData(this); + const queryRunner = + $data instanceof SceneQueryRunner ? $data : sceneGraph.findDescendents($data, SceneQueryRunner)[0]; + if (queryRunner) { + queryRunner.runQueries(); + } } this.state.body.onOptionsChange(options); } From 228d8dcd6d9b482f0123779ac4b71c5913dcd2e0 Mon Sep 17 00:00:00 2001 From: Matias Chomicki Date: Mon, 6 Jan 2025 13:48:42 +0100 Subject: [PATCH 3/3] test(sortOrder): update content expectation --- tests/exploreServicesBreakDown.spec.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/exploreServicesBreakDown.spec.ts b/tests/exploreServicesBreakDown.spec.ts index d09b9b2b..a74d8a64 100644 --- a/tests/exploreServicesBreakDown.spec.ts +++ b/tests/exploreServicesBreakDown.spec.ts @@ -1092,10 +1092,6 @@ test.describe('explore services breakdown page', () => { // Scroll the whole page to the bottom so the whole logs panel is visible await explorePage.scrollToBottom(); - // The logs panel keeps the lines in the viewport the same, but will scroll us down - await expect(firstRow).not.toBeInViewport(); - await expect(page.getByText(newestLogContent)).toBeInViewport(); - // assert timestamps are ASC (oldest first) expect(new Date(await firstRowTimeCell.textContent()).valueOf()).toBeLessThanOrEqual( new Date(await secondRowTimeCell.textContent()).valueOf()