Skip to content

Commit

Permalink
Logs Panel: Display error message when logs fail to load (#1079)
Browse files Browse the repository at this point in the history
* feat(LogsPanelScene): display error message when logs fail to load

* Update src/Components/ServiceScene/LogsPanelError.tsx

Co-authored-by: Sven Grossmann <[email protected]>

* feat(LogsPanelScene): collapse log volume on error

* fix(LogsPanelScene): respect collapsed status of logs volume

---------

Co-authored-by: Sven Grossmann <[email protected]>
  • Loading branch information
matyax and svennergr authored Feb 18, 2025
1 parent 965bbdc commit adc3c8f
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 6 deletions.
32 changes: 32 additions & 0 deletions src/Components/ServiceScene/LogsPanelError.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';
import { GrotError } from 'Components/GrotError';
import { Button } from '@grafana/ui';

interface Props {
clearFilters(): void;
error: string;
}

export const LogsPanelError = ({ clearFilters, error }: Props) => {
return (
<GrotError>
<div>
<p>
<strong>No logs found.</strong>
</p>
<p>{getMessageFromError(error)}</p>
<Button variant="secondary" onClick={clearFilters}>
Clear filters
</Button>
</div>
</GrotError>
);
};

function getMessageFromError(error: string) {
if (error.includes('parse error')) {
return 'Logs could not be retrieved due to invalid filter parameters. Please review your filters and try again.';
}

return 'Logs could not be retrieved. Please review your filters or try a different time range.';
}
40 changes: 36 additions & 4 deletions src/Components/ServiceScene/LogsPanelScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
SceneQueryRunner,
VizPanel,
} from '@grafana/scenes';
import { DataFrame, getValueFormat, LogRowModel } from '@grafana/data';
import { getLogOption, setDisplayedFields } from '../../services/store';
import { DataFrame, getValueFormat, LoadingState, LogRowModel, PanelData } from '@grafana/data';
import { getLogOption, getLogsVolumeOption, setDisplayedFields } from '../../services/store';
import React, { MouseEvent } from 'react';
import { LogsListScene } from './LogsListScene';
import { LoadingPlaceholder, useStyles2 } from '@grafana/ui';
Expand All @@ -37,9 +37,13 @@ import { narrowLogsSortOrder } from '../../services/narrowing';
import { logger } from '../../services/logger';
import { LogsSortOrder } from '@grafana/schema';
import { getPrettyQueryExpr } from 'services/scenes';
import { LogsPanelError } from './LogsPanelError';
import { clearVariables } from 'services/variableHelpers';

interface LogsPanelSceneState extends SceneObjectState {
body?: VizPanel<Options>;
error?: string;
logsVolumeCollapsedByError?: boolean;
sortOrder?: LogsSortOrder;
wrapLogMessage?: boolean;
}
Expand All @@ -53,6 +57,7 @@ export class LogsPanelScene extends SceneObjectBase<LogsPanelSceneState> {
super({
sortOrder: getLogsPanelSortOrderFromStore(),
wrapLogMessage: Boolean(getLogOption<boolean>('wrapLogMessage', false)),
error: undefined,
...state,
});

Expand Down Expand Up @@ -121,6 +126,11 @@ export class LogsPanelScene extends SceneObjectBase<LogsPanelSceneState> {
const serviceScene = sceneGraph.getAncestor(this, ServiceScene);
this._subs.add(
serviceScene.subscribeToState((newState, prevState) => {
if (newState.$data?.state.data?.state === LoadingState.Error) {
this.handleLogsError(newState.$data?.state.data);
} else if (this.state.error) {
this.clearLogsError();
}
if (newState.logsCount !== prevState.logsCount) {
if (!this.state.body) {
this.setState({
Expand All @@ -140,6 +150,27 @@ export class LogsPanelScene extends SceneObjectBase<LogsPanelSceneState> {
);
}

handleLogsError(data: PanelData) {
const logsVolumeCollapsedByError = this.state.logsVolumeCollapsedByError ?? !getLogsVolumeOption('collapsed');

const error = data.errors?.length ? data.errors[0].message : data.error?.message;
this.setState({ error, logsVolumeCollapsedByError });

if (logsVolumeCollapsedByError) {
const logsVolume = sceneGraph.findByKeyAndType(this, logsVolumePanelKey, LogsVolumePanel);
logsVolume.state.panel?.setState({ collapsed: true });
}
}

clearLogsError() {
if (this.state.logsVolumeCollapsedByError) {
const logsVolume = sceneGraph.findByKeyAndType(this, logsVolumePanelKey, LogsVolumePanel);
logsVolume.state.panel?.setState({ collapsed: false });
}

this.setState({ error: undefined, logsVolumeCollapsedByError: undefined });
}

onClickShowField = (field: string) => {
const parent = this.getParentScene();
const index = parent.state.displayedFields.indexOf(field);
Expand Down Expand Up @@ -402,12 +433,13 @@ export class LogsPanelScene extends SceneObjectBase<LogsPanelSceneState> {
}

public static Component = ({ model }: SceneComponentProps<LogsPanelScene>) => {
const { body } = model.useState();
const { body, error } = model.useState();
const styles = useStyles2(getPanelWrapperStyles);
if (body) {
return (
<span className={styles.panelWrapper}>
<body.Component model={body} />
{!error && <body.Component model={body} />}
{error && <LogsPanelError error={error} clearFilters={() => clearVariables(body)} />}
</span>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Components/ServiceScene/LogsVolumePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export class LogsVolumePanel extends SceneObjectBase<LogsVolumePanelState> {
.setUnit('short')
.setMenu(new PanelMenu({ investigationOptions: { labelName: 'level' } }))
.setCollapsible(true)
.setCollapsed(Boolean(getLogsVolumeOption('collapsed')))
.setCollapsed(getLogsVolumeOption('collapsed'))
.setHeaderActions(new LogsVolumeActions({}))
// 11.5
// .setShowMenuAlways(true)
Expand Down
2 changes: 1 addition & 1 deletion src/services/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ export function setLogsVolumeOption(option: 'collapsed', value: string | undefin
}

export function getLogsVolumeOption(option: 'collapsed') {
return localStorage.getItem(`${LOGS_VOLUME_LOCALSTORAGE_KEY}.${option}`);
return Boolean(localStorage.getItem(`${LOGS_VOLUME_LOCALSTORAGE_KEY}.${option}`));
}

// Log visualization options
Expand Down

0 comments on commit adc3c8f

Please sign in to comment.