mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Visually distinguish error logs for LogQL2 (#28359)
* Loki: Add errored logs and update UI * Update messaging * Add icon and tooltip for errored logs * Update name of variable for more semantic meaning * Add tests * Update test * Refactor, remove unnecessary state * Update packages/grafana-data/src/types/logs.ts * Update packages/grafana-ui/src/components/Logs/LogDetails.tsx Co-authored-by: Giordano Ricci <gio.ricci@grafana.com> Co-authored-by: Giordano Ricci <gio.ricci@grafana.com>
This commit is contained in:
@@ -45,6 +45,12 @@ describe('LogDetails', () => {
|
||||
expect(wrapper.text().includes('key1label1key2label2')).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('when log row has error', () => {
|
||||
it('should not render log level border', () => {
|
||||
const wrapper = setup({ hasError: true }, undefined);
|
||||
expect(wrapper.find({ 'aria-label': 'Log level' }).html()).not.toContain('logs-row__level');
|
||||
});
|
||||
});
|
||||
describe('when row entry has parsable fields', () => {
|
||||
it('should render heading ', () => {
|
||||
const wrapper = setup(undefined, { entry: 'test=successful' });
|
||||
|
||||
@@ -28,6 +28,7 @@ export interface Props extends Themeable {
|
||||
showDuplicates: boolean;
|
||||
getRows: () => LogRowModel[];
|
||||
className?: string;
|
||||
hasError?: boolean;
|
||||
onMouseEnter?: () => void;
|
||||
onMouseLeave?: () => void;
|
||||
onClickFilterLabel?: (key: string, value: string) => void;
|
||||
@@ -70,6 +71,7 @@ class UnThemedLogDetails extends PureComponent<Props> {
|
||||
const {
|
||||
row,
|
||||
theme,
|
||||
hasError,
|
||||
onClickFilterOutLabel,
|
||||
onClickFilterLabel,
|
||||
getRows,
|
||||
@@ -88,6 +90,8 @@ class UnThemedLogDetails extends PureComponent<Props> {
|
||||
const labelsAvailable = Object.keys(labels).length > 0;
|
||||
const fields = getAllFields(row, getFieldLinks);
|
||||
const parsedFieldsAvailable = fields && fields.length > 0;
|
||||
// If logs with error, we are not showing the level color
|
||||
const levelClassName = cx(!hasError && [style.logsRowLevel, styles.logsRowLevelDetails]);
|
||||
|
||||
return (
|
||||
<tr
|
||||
@@ -96,7 +100,7 @@ class UnThemedLogDetails extends PureComponent<Props> {
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
{showDuplicates && <td />}
|
||||
<td className={cx(style.logsRowLevel, styles.logsRowLevelDetails)} />
|
||||
<td className={levelClassName} aria-label="Log level" />
|
||||
<td colSpan={4}>
|
||||
<div className={style.logDetailsContainer}>
|
||||
<table className={style.logDetailsTable}>
|
||||
|
||||
@@ -8,8 +8,10 @@ import {
|
||||
DataQueryResponse,
|
||||
GrafanaTheme,
|
||||
dateTimeFormat,
|
||||
checkLogsError,
|
||||
} from '@grafana/data';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { Tooltip } from '../Tooltip/Tooltip';
|
||||
import { cx, css } from 'emotion';
|
||||
|
||||
import {
|
||||
@@ -72,6 +74,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
label: hoverBackground;
|
||||
background-color: ${bgColor};
|
||||
`,
|
||||
errorLogRow: css`
|
||||
label: erroredLogRow;
|
||||
color: ${theme.colors.textWeak};
|
||||
`,
|
||||
};
|
||||
});
|
||||
/**
|
||||
@@ -160,22 +166,27 @@ class UnThemedLogRow extends PureComponent<Props, State> {
|
||||
const { showDetails, showContext, hasHoverBackground } = this.state;
|
||||
const style = getLogRowStyles(theme, row.logLevel);
|
||||
const styles = getStyles(theme);
|
||||
const hoverBackground = cx(style.logsRow, { [styles.hoverBackground]: hasHoverBackground });
|
||||
const { errorMessage, hasError } = checkLogsError(row);
|
||||
const logRowBackground = cx(style.logsRow, {
|
||||
[styles.hoverBackground]: hasHoverBackground,
|
||||
[styles.errorLogRow]: hasError,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<tr
|
||||
className={hoverBackground}
|
||||
onMouseEnter={this.addHoverBackground}
|
||||
onMouseLeave={this.clearHoverBackground}
|
||||
onClick={this.toggleDetails}
|
||||
>
|
||||
<tr className={logRowBackground} onClick={this.toggleDetails}>
|
||||
{showDuplicates && (
|
||||
<td className={style.logsRowDuplicates}>
|
||||
{row.duplicates && row.duplicates > 0 ? `${row.duplicates + 1}x` : null}
|
||||
</td>
|
||||
)}
|
||||
<td className={style.logsRowLevel} />
|
||||
<td className={cx({ [style.logsRowLevel]: !hasError })}>
|
||||
{hasError && (
|
||||
<Tooltip content={`Error: ${errorMessage}`} placement="right" theme="error">
|
||||
<Icon className={style.logIconError} name="exclamation-triangle" size="sm" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</td>
|
||||
{!allowDetails && (
|
||||
<td title={showDetails ? 'Hide log details' : 'See log details'} className={style.logsRowToggleDetails}>
|
||||
<Icon className={styles.topVerticalAlign} name={showDetails ? 'angle-down' : 'angle-right'} />
|
||||
@@ -207,7 +218,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
|
||||
</tr>
|
||||
{this.state.showDetails && (
|
||||
<LogDetails
|
||||
className={hoverBackground}
|
||||
className={logRowBackground}
|
||||
onMouseEnter={this.addHoverBackground}
|
||||
onMouseLeave={this.clearHoverBackground}
|
||||
showDuplicates={showDuplicates}
|
||||
@@ -218,6 +229,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
|
||||
onClickHideParsedField={onClickHideParsedField}
|
||||
getRows={getRows}
|
||||
row={row}
|
||||
hasError={hasError}
|
||||
showParsedFields={showParsedFields}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -9,6 +9,7 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
|
||||
let logColor = selectThemeVariant({ light: theme.palette.gray5, dark: theme.palette.gray2 }, theme.type);
|
||||
const borderColor = selectThemeVariant({ light: theme.palette.gray5, dark: theme.palette.gray2 }, theme.type);
|
||||
const bgColor = selectThemeVariant({ light: theme.palette.gray5, dark: theme.palette.dark4 }, theme.type);
|
||||
const hoverBgColor = selectThemeVariant({ light: theme.palette.gray7, dark: theme.palette.dark2 }, theme.type);
|
||||
const context = css`
|
||||
label: context;
|
||||
visibility: hidden;
|
||||
@@ -92,7 +93,7 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: ${theme.colors.bodyBg};
|
||||
background: ${hoverBgColor};
|
||||
}
|
||||
`,
|
||||
logsRowDuplicates: css`
|
||||
@@ -116,6 +117,10 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
|
||||
background-color: ${logColor};
|
||||
}
|
||||
`,
|
||||
logIconError: css`
|
||||
color: ${theme.palette.red};
|
||||
margin-left: -5px;
|
||||
`,
|
||||
logsRowToggleDetails: css`
|
||||
label: logs-row-toggle-details__level;
|
||||
position: relative;
|
||||
|
||||
Reference in New Issue
Block a user