mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Logs Panel: Refactor style generation to improve rendering performance (#62599)
* Log row: move level styles to its own provider * Log row message: remove unnecessary extra param from styles * Log rows: parse and pass styles to children * Log row: receive parsed styles props from parent * Log details: receive styles from parent * Revert "Log details: receive styles from parent" This reverts commit 8487482a6f4fdcf5e26896182c5ad3982774eea2. * Log row message: receive styles from parent * Chore: remove unnecessary comment * Log level styles: move common styles out of getLogLevelStyles * Chore: fix TimeZone deprecated import * Log Details: inverse ternary operator for readability Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com> * Log Details: inverse ternary operator for readability Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com> * Chore: apply prettier formatting --------- Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com>
This commit is contained in:
@@ -7,11 +7,9 @@ import { Themeable2, withTheme2 } from '@grafana/ui';
|
|||||||
import { calculateLogsLabelStats, calculateStats } from '../utils';
|
import { calculateLogsLabelStats, calculateStats } from '../utils';
|
||||||
|
|
||||||
import { LogDetailsRow } from './LogDetailsRow';
|
import { LogDetailsRow } from './LogDetailsRow';
|
||||||
import { getLogRowStyles } from './getLogRowStyles';
|
import { getLogLevelStyles, getLogRowStyles } from './getLogRowStyles';
|
||||||
import { getAllFields } from './logParser';
|
import { getAllFields } from './logParser';
|
||||||
|
|
||||||
//Components
|
|
||||||
|
|
||||||
export interface Props extends Themeable2 {
|
export interface Props extends Themeable2 {
|
||||||
row: LogRowModel;
|
row: LogRowModel;
|
||||||
showDuplicates: boolean;
|
showDuplicates: boolean;
|
||||||
@@ -66,7 +64,8 @@ class UnThemedLogDetails extends PureComponent<Props> {
|
|||||||
getFieldLinks,
|
getFieldLinks,
|
||||||
wrapLogMessage,
|
wrapLogMessage,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const style = getLogRowStyles(theme, row.logLevel);
|
const rowStyles = getLogRowStyles(theme);
|
||||||
|
const levelStyles = getLogLevelStyles(theme, row.logLevel);
|
||||||
const styles = getStyles(theme);
|
const styles = getStyles(theme);
|
||||||
const labels = row.labels ? row.labels : {};
|
const labels = row.labels ? row.labels : {};
|
||||||
const labelsAvailable = Object.keys(labels).length > 0;
|
const labelsAvailable = Object.keys(labels).length > 0;
|
||||||
@@ -77,19 +76,21 @@ class UnThemedLogDetails extends PureComponent<Props> {
|
|||||||
const linksAvailable = links && links.length > 0;
|
const linksAvailable = links && links.length > 0;
|
||||||
|
|
||||||
// If logs with error, we are not showing the level color
|
// If logs with error, we are not showing the level color
|
||||||
const levelClassName = cx(!hasError && [style.logsRowLevel, styles.logsRowLevelDetails]);
|
const levelClassName = hasError
|
||||||
|
? ''
|
||||||
|
: `${levelStyles.logsRowLevelColor} ${rowStyles.logsRowLevel} ${styles.logsRowLevelDetails}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr className={cx(className, styles.logDetails)}>
|
<tr className={cx(className, styles.logDetails)}>
|
||||||
{showDuplicates && <td />}
|
{showDuplicates && <td />}
|
||||||
<td className={levelClassName} aria-label="Log level" />
|
<td className={levelClassName} aria-label="Log level" />
|
||||||
<td colSpan={4}>
|
<td colSpan={4}>
|
||||||
<div className={style.logDetailsContainer}>
|
<div className={rowStyles.logDetailsContainer}>
|
||||||
<table className={style.logDetailsTable}>
|
<table className={rowStyles.logDetailsTable}>
|
||||||
<tbody>
|
<tbody>
|
||||||
{(labelsAvailable || fieldsAvailable) && (
|
{(labelsAvailable || fieldsAvailable) && (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={100} className={style.logDetailsHeading} aria-label="Fields">
|
<td colSpan={100} className={rowStyles.logDetailsHeading} aria-label="Fields">
|
||||||
Fields
|
Fields
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -138,7 +139,7 @@ class UnThemedLogDetails extends PureComponent<Props> {
|
|||||||
|
|
||||||
{linksAvailable && (
|
{linksAvailable && (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={100} className={style.logDetailsHeading} aria-label="Data Links">
|
<td colSpan={100} className={rowStyles.logDetailsHeading} aria-label="Data Links">
|
||||||
Links
|
Links
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { cx, css } from '@emotion/css';
|
import { cx } from '@emotion/css';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -6,16 +6,15 @@ import {
|
|||||||
LinkModel,
|
LinkModel,
|
||||||
LogRowModel,
|
LogRowModel,
|
||||||
LogsSortOrder,
|
LogsSortOrder,
|
||||||
TimeZone,
|
|
||||||
DataQueryResponse,
|
DataQueryResponse,
|
||||||
dateTimeFormat,
|
dateTimeFormat,
|
||||||
GrafanaTheme2,
|
|
||||||
CoreApp,
|
CoreApp,
|
||||||
DataFrame,
|
DataFrame,
|
||||||
DataSourceWithLogsContextSupport,
|
DataSourceWithLogsContextSupport,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { reportInteraction } from '@grafana/runtime';
|
import { reportInteraction } from '@grafana/runtime';
|
||||||
import { styleMixins, withTheme2, Themeable2, Icon, Tooltip } from '@grafana/ui';
|
import { TimeZone } from '@grafana/schema';
|
||||||
|
import { withTheme2, Themeable2, Icon, Tooltip } from '@grafana/ui';
|
||||||
|
|
||||||
import { checkLogsError, escapeUnescapedString } from '../utils';
|
import { checkLogsError, escapeUnescapedString } from '../utils';
|
||||||
|
|
||||||
@@ -30,9 +29,7 @@ import {
|
|||||||
} from './LogRowContextProvider';
|
} from './LogRowContextProvider';
|
||||||
import { LogRowMessage } from './LogRowMessage';
|
import { LogRowMessage } from './LogRowMessage';
|
||||||
import { LogRowMessageDisplayedFields } from './LogRowMessageDisplayedFields';
|
import { LogRowMessageDisplayedFields } from './LogRowMessageDisplayedFields';
|
||||||
import { getLogRowStyles } from './getLogRowStyles';
|
import { getLogLevelStyles, LogRowStyles } from './getLogRowStyles';
|
||||||
|
|
||||||
//Components
|
|
||||||
|
|
||||||
interface Props extends Themeable2 {
|
interface Props extends Themeable2 {
|
||||||
row: LogRowModel;
|
row: LogRowModel;
|
||||||
@@ -61,6 +58,7 @@ interface Props extends Themeable2 {
|
|||||||
onClickHideField?: (key: string) => void;
|
onClickHideField?: (key: string) => void;
|
||||||
onLogRowHover?: (row?: LogRowModel) => void;
|
onLogRowHover?: (row?: LogRowModel) => void;
|
||||||
toggleContextIsOpen?: () => void;
|
toggleContextIsOpen?: () => void;
|
||||||
|
styles: LogRowStyles;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@@ -68,24 +66,6 @@ interface State {
|
|||||||
showDetails: boolean;
|
showDetails: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStyles = (theme: GrafanaTheme2) => {
|
|
||||||
return {
|
|
||||||
topVerticalAlign: css`
|
|
||||||
label: topVerticalAlign;
|
|
||||||
margin-top: -${theme.spacing(0.9)};
|
|
||||||
margin-left: -${theme.spacing(0.25)};
|
|
||||||
`,
|
|
||||||
detailsOpen: css`
|
|
||||||
&:hover {
|
|
||||||
background-color: ${styleMixins.hoverColor(theme.colors.background.primary, theme)};
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
errorLogRow: css`
|
|
||||||
label: erroredLogRow;
|
|
||||||
color: ${theme.colors.text.secondary};
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/**
|
/**
|
||||||
* Renders a log line.
|
* Renders a log line.
|
||||||
*
|
*
|
||||||
@@ -171,14 +151,14 @@ class UnThemedLogRow extends PureComponent<Props, State> {
|
|||||||
onLogRowHover,
|
onLogRowHover,
|
||||||
app,
|
app,
|
||||||
scrollElement,
|
scrollElement,
|
||||||
|
styles,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { showDetails, showContext } = this.state;
|
const { showDetails, showContext } = this.state;
|
||||||
const style = getLogRowStyles(theme, row.logLevel);
|
const levelStyles = getLogLevelStyles(theme, row.logLevel);
|
||||||
const styles = getStyles(theme);
|
|
||||||
const { errorMessage, hasError } = checkLogsError(row);
|
const { errorMessage, hasError } = checkLogsError(row);
|
||||||
const logRowBackground = cx(style.logsRow, {
|
const logRowBackground = cx(styles.logsRow, {
|
||||||
[styles.errorLogRow]: hasError,
|
[styles.errorLogRow]: hasError,
|
||||||
[style.contextBackground]: showContext,
|
[styles.contextBackground]: showContext,
|
||||||
});
|
});
|
||||||
|
|
||||||
const processedRow =
|
const processedRow =
|
||||||
@@ -199,25 +179,25 @@ class UnThemedLogRow extends PureComponent<Props, State> {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{showDuplicates && (
|
{showDuplicates && (
|
||||||
<td className={style.logsRowDuplicates}>
|
<td className={styles.logsRowDuplicates}>
|
||||||
{processedRow.duplicates && processedRow.duplicates > 0 ? `${processedRow.duplicates + 1}x` : null}
|
{processedRow.duplicates && processedRow.duplicates > 0 ? `${processedRow.duplicates + 1}x` : null}
|
||||||
</td>
|
</td>
|
||||||
)}
|
)}
|
||||||
<td className={cx({ [style.logsRowLevel]: !hasError })}>
|
<td className={hasError ? '' : `${levelStyles.logsRowLevelColor} ${styles.logsRowLevel}`}>
|
||||||
{hasError && (
|
{hasError && (
|
||||||
<Tooltip content={`Error: ${errorMessage}`} placement="right" theme="error">
|
<Tooltip content={`Error: ${errorMessage}`} placement="right" theme="error">
|
||||||
<Icon className={style.logIconError} name="exclamation-triangle" size="xs" />
|
<Icon className={styles.logIconError} name="exclamation-triangle" size="xs" />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
{enableLogDetails && (
|
{enableLogDetails && (
|
||||||
<td title={showDetails ? 'Hide log details' : 'See log details'} className={style.logsRowToggleDetails}>
|
<td title={showDetails ? 'Hide log details' : 'See log details'} className={styles.logsRowToggleDetails}>
|
||||||
<Icon className={styles.topVerticalAlign} name={showDetails ? 'angle-down' : 'angle-right'} />
|
<Icon className={styles.topVerticalAlign} name={showDetails ? 'angle-down' : 'angle-right'} />
|
||||||
</td>
|
</td>
|
||||||
)}
|
)}
|
||||||
{showTime && <td className={style.logsRowLocalTime}>{this.renderTimeStamp(row.timeEpochMs)}</td>}
|
{showTime && <td className={styles.logsRowLocalTime}>{this.renderTimeStamp(row.timeEpochMs)}</td>}
|
||||||
{showLabels && processedRow.uniqueLabels && (
|
{showLabels && processedRow.uniqueLabels && (
|
||||||
<td className={style.logsRowLabels}>
|
<td className={styles.logsRowLabels}>
|
||||||
<LogLabels labels={processedRow.uniqueLabels} />
|
<LogLabels labels={processedRow.uniqueLabels} />
|
||||||
</td>
|
</td>
|
||||||
)}
|
)}
|
||||||
@@ -247,6 +227,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
|
|||||||
app={app}
|
app={app}
|
||||||
scrollElement={scrollElement}
|
scrollElement={scrollElement}
|
||||||
logsSortOrder={logsSortOrder}
|
logsSortOrder={logsSortOrder}
|
||||||
|
styles={styles}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,27 +1,25 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
import { cx } from '@emotion/css';
|
||||||
import memoizeOne from 'memoize-one';
|
import memoizeOne from 'memoize-one';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import Highlighter from 'react-highlight-words';
|
import Highlighter from 'react-highlight-words';
|
||||||
import tinycolor from 'tinycolor2';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
LogRowModel,
|
LogRowModel,
|
||||||
findHighlightChunksInText,
|
findHighlightChunksInText,
|
||||||
GrafanaTheme2,
|
|
||||||
LogsSortOrder,
|
LogsSortOrder,
|
||||||
CoreApp,
|
CoreApp,
|
||||||
DataSourceWithLogsContextSupport,
|
DataSourceWithLogsContextSupport,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { withTheme2, Themeable2, IconButton, Tooltip } from '@grafana/ui';
|
import { IconButton, Tooltip } from '@grafana/ui';
|
||||||
|
|
||||||
import { LogMessageAnsi } from './LogMessageAnsi';
|
import { LogMessageAnsi } from './LogMessageAnsi';
|
||||||
import { LogRowContext } from './LogRowContext';
|
import { LogRowContext } from './LogRowContext';
|
||||||
import { LogRowContextQueryErrors, HasMoreContextRows, LogRowContextRows } from './LogRowContextProvider';
|
import { LogRowContextQueryErrors, HasMoreContextRows, LogRowContextRows } from './LogRowContextProvider';
|
||||||
import { getLogRowStyles } from './getLogRowStyles';
|
import { LogRowStyles } from './getLogRowStyles';
|
||||||
|
|
||||||
export const MAX_CHARACTERS = 100000;
|
export const MAX_CHARACTERS = 100000;
|
||||||
|
|
||||||
interface Props extends Themeable2 {
|
interface Props {
|
||||||
row: LogRowModel;
|
row: LogRowModel;
|
||||||
hasMoreContextRows?: HasMoreContextRows;
|
hasMoreContextRows?: HasMoreContextRows;
|
||||||
contextIsOpen: boolean;
|
contextIsOpen: boolean;
|
||||||
@@ -39,67 +37,9 @@ interface Props extends Themeable2 {
|
|||||||
updateLimit?: () => void;
|
updateLimit?: () => void;
|
||||||
runContextQuery?: () => void;
|
runContextQuery?: () => void;
|
||||||
logsSortOrder?: LogsSortOrder | null;
|
logsSortOrder?: LogsSortOrder | null;
|
||||||
|
styles: LogRowStyles;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStyles = (theme: GrafanaTheme2, showContextButton: boolean, isInExplore: boolean) => {
|
|
||||||
const outlineColor = tinycolor(theme.components.dashboard.background).setAlpha(0.7).toRgbString();
|
|
||||||
|
|
||||||
return {
|
|
||||||
positionRelative: css`
|
|
||||||
label: positionRelative;
|
|
||||||
position: relative;
|
|
||||||
`,
|
|
||||||
rowWithContext: css`
|
|
||||||
label: rowWithContext;
|
|
||||||
z-index: 1;
|
|
||||||
outline: 9999px solid ${outlineColor};
|
|
||||||
display: inherit;
|
|
||||||
`,
|
|
||||||
horizontalScroll: css`
|
|
||||||
label: horizontalScroll;
|
|
||||||
white-space: pre;
|
|
||||||
`,
|
|
||||||
contextNewline: css`
|
|
||||||
display: block;
|
|
||||||
margin-left: 0px;
|
|
||||||
`,
|
|
||||||
rowMenu: css`
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex-direction: row;
|
|
||||||
align-content: flex-end;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
align-items: center;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: auto;
|
|
||||||
height: ${theme.spacing(4.5)};
|
|
||||||
background: ${theme.colors.background.primary};
|
|
||||||
box-shadow: ${theme.shadows.z3};
|
|
||||||
padding: ${theme.spacing(0, 0, 0, 0.5)};
|
|
||||||
z-index: 100;
|
|
||||||
visibility: hidden;
|
|
||||||
width: ${showContextButton ? theme.spacing(10) : theme.spacing(5)};
|
|
||||||
`,
|
|
||||||
logRowMenuCell: css`
|
|
||||||
position: absolute;
|
|
||||||
right: ${!isInExplore ? '40px' : `calc(75px + ${theme.spacing()} + ${showContextButton ? '80px' : '40px'})`};
|
|
||||||
margin-top: -${theme.spacing(0.125)};
|
|
||||||
`,
|
|
||||||
logLine: css`
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
diplay: inline;
|
|
||||||
font-family: ${theme.typography.fontFamilyMonospace};
|
|
||||||
font-size: ${theme.typography.bodySmall.fontSize};
|
|
||||||
letter-spacing: ${theme.typography.bodySmall.letterSpacing};
|
|
||||||
text-align: left;
|
|
||||||
padding: 0;
|
|
||||||
user-select: text;
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function renderLogMessage(
|
function renderLogMessage(
|
||||||
hasAnsi: boolean,
|
hasAnsi: boolean,
|
||||||
entry: string,
|
entry: string,
|
||||||
@@ -137,7 +77,7 @@ const restructureLog = memoizeOne((line: string, prettifyLogMessage: boolean): s
|
|||||||
return line;
|
return line;
|
||||||
});
|
});
|
||||||
|
|
||||||
class UnThemedLogRowMessage extends PureComponent<Props> {
|
export class LogRowMessage extends PureComponent<Props> {
|
||||||
logRowRef: React.RefObject<HTMLTableCellElement> = React.createRef();
|
logRowRef: React.RefObject<HTMLTableCellElement> = React.createRef();
|
||||||
|
|
||||||
onContextToggle = (e: React.SyntheticEvent<HTMLElement>) => {
|
onContextToggle = (e: React.SyntheticEvent<HTMLElement>) => {
|
||||||
@@ -159,7 +99,6 @@ class UnThemedLogRowMessage extends PureComponent<Props> {
|
|||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
row,
|
row,
|
||||||
theme,
|
|
||||||
errors,
|
errors,
|
||||||
hasMoreContextRows,
|
hasMoreContextRows,
|
||||||
updateLimit,
|
updateLimit,
|
||||||
@@ -174,24 +113,23 @@ class UnThemedLogRowMessage extends PureComponent<Props> {
|
|||||||
logsSortOrder,
|
logsSortOrder,
|
||||||
showContextToggle,
|
showContextToggle,
|
||||||
getLogRowContextUi,
|
getLogRowContextUi,
|
||||||
|
styles,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const style = getLogRowStyles(theme, row.logLevel);
|
|
||||||
const { hasAnsi, raw } = row;
|
const { hasAnsi, raw } = row;
|
||||||
const restructuredEntry = restructureLog(raw, prettifyLogMessage);
|
const restructuredEntry = restructureLog(raw, prettifyLogMessage);
|
||||||
const shouldShowContextToggle = showContextToggle ? showContextToggle(row) : false;
|
const shouldShowContextToggle = showContextToggle ? showContextToggle(row) : false;
|
||||||
const styles = getStyles(theme, shouldShowContextToggle, app === CoreApp.Explore);
|
const inExplore = app === CoreApp.Explore;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{
|
{
|
||||||
// When context is open, the position has to be NOT relative. // Setting the postion as inline-style to
|
// When context is open, the position has to be NOT relative. // Setting the postion as inline-style to
|
||||||
// overwrite the more sepecific style definition from `style.logsRowMessage`.
|
// overwrite the more sepecific style definition from `styles.logsRowMessage`.
|
||||||
}
|
}
|
||||||
<td
|
<td
|
||||||
ref={this.logRowRef}
|
ref={this.logRowRef}
|
||||||
style={contextIsOpen ? { position: 'unset' } : undefined}
|
style={contextIsOpen ? { position: 'unset' } : undefined}
|
||||||
className={style.logsRowMessage}
|
className={styles.logsRowMessage}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
@@ -218,13 +156,24 @@ class UnThemedLogRowMessage extends PureComponent<Props> {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<button className={cx(styles.logLine, styles.positionRelative, { [styles.rowWithContext]: contextIsOpen })}>
|
<button className={cx(styles.logLine, styles.positionRelative, { [styles.rowWithContext]: contextIsOpen })}>
|
||||||
{renderLogMessage(hasAnsi, restructuredEntry, row.searchWords, style.logsRowMatchHighLight)}
|
{renderLogMessage(hasAnsi, restructuredEntry, row.searchWords, styles.logsRowMatchHighLight)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
{showRowMenu && (
|
{showRowMenu && (
|
||||||
<td className={cx('log-row-menu-cell', styles.logRowMenuCell)}>
|
<td
|
||||||
<span className={cx('log-row-menu', styles.rowMenu)} onClick={(e) => e.stopPropagation()}>
|
className={cx('log-row-menu-cell', styles.logRowMenuCell, {
|
||||||
|
[styles.logRowMenuCellDefaultPosition]: !inExplore,
|
||||||
|
[styles.logRowMenuCellExplore]: inExplore && !shouldShowContextToggle,
|
||||||
|
[styles.logRowMenuCellExploreWithContextButton]: inExplore && shouldShowContextToggle,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={cx('log-row-menu', styles.rowMenu, {
|
||||||
|
[styles.rowMenuWithContextButton]: shouldShowContextToggle,
|
||||||
|
})}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
{shouldShowContextToggle && (
|
{shouldShowContextToggle && (
|
||||||
<Tooltip placement="top" content={'Show context'}>
|
<Tooltip placement="top" content={'Show context'}>
|
||||||
<IconButton size="md" name="gf-show-context" onClick={this.onShowContextClick} />
|
<IconButton size="md" name="gf-show-context" onClick={this.onShowContextClick} />
|
||||||
@@ -240,6 +189,3 @@ class UnThemedLogRowMessage extends PureComponent<Props> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LogRowMessage = withTheme2(UnThemedLogRowMessage);
|
|
||||||
LogRowMessage.displayName = 'LogRowMessage';
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
|
|||||||
getLogRowContextUi,
|
getLogRowContextUi,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { renderAll, contextIsOpen } = this.state;
|
const { renderAll, contextIsOpen } = this.state;
|
||||||
const { logsRowsTable } = getLogRowStyles(theme);
|
const styles = getLogRowStyles(theme);
|
||||||
const dedupedRows = deduplicatedRows ? deduplicatedRows : logRows;
|
const dedupedRows = deduplicatedRows ? deduplicatedRows : logRows;
|
||||||
const hasData = logRows && logRows.length > 0;
|
const hasData = logRows && logRows.length > 0;
|
||||||
const dedupCount = dedupedRows
|
const dedupCount = dedupedRows
|
||||||
@@ -151,7 +151,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
|
|||||||
const getRowContext = this.props.getRowContext ? this.props.getRowContext : () => Promise.resolve([]);
|
const getRowContext = this.props.getRowContext ? this.props.getRowContext : () => Promise.resolve([]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table className={logsRowsTable}>
|
<table className={styles.logsRowsTable}>
|
||||||
<tbody>
|
<tbody>
|
||||||
{hasData &&
|
{hasData &&
|
||||||
firstRows.map((row, index) => (
|
firstRows.map((row, index) => (
|
||||||
@@ -182,6 +182,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
|
|||||||
onLogRowHover={onLogRowHover}
|
onLogRowHover={onLogRowHover}
|
||||||
app={app}
|
app={app}
|
||||||
scrollElement={scrollElement}
|
scrollElement={scrollElement}
|
||||||
|
styles={styles}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{hasData &&
|
{hasData &&
|
||||||
@@ -214,6 +215,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
|
|||||||
onLogRowHover={onLogRowHover}
|
onLogRowHover={onLogRowHover}
|
||||||
app={app}
|
app={app}
|
||||||
scrollElement={scrollElement}
|
scrollElement={scrollElement}
|
||||||
|
styles={styles}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{hasData && !renderAll && (
|
{hasData && !renderAll && (
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
|
import tinycolor from 'tinycolor2';
|
||||||
|
|
||||||
import { GrafanaTheme2, LogLevel } from '@grafana/data';
|
import { GrafanaTheme2, LogLevel } from '@grafana/data';
|
||||||
import { styleMixins } from '@grafana/ui';
|
import { styleMixins } from '@grafana/ui';
|
||||||
|
|
||||||
export const getLogRowStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => {
|
export const getLogLevelStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => {
|
||||||
let logColor = theme.isLight ? theme.v1.palette.gray5 : theme.v1.palette.gray2;
|
let logColor = theme.isLight ? theme.v1.palette.gray5 : theme.v1.palette.gray2;
|
||||||
const hoverBgColor = styleMixins.hoverColor(theme.colors.background.secondary, theme);
|
|
||||||
|
|
||||||
switch (logLevel) {
|
switch (logLevel) {
|
||||||
case LogLevel.crit:
|
case LogLevel.crit:
|
||||||
case LogLevel.critical:
|
case LogLevel.critical:
|
||||||
@@ -32,6 +31,32 @@ export const getLogRowStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
logsRowLevelColor: css`
|
||||||
|
&::after {
|
||||||
|
background-color: ${logColor};
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getLogRowStyles = (theme: GrafanaTheme2) => {
|
||||||
|
const hoverBgColor = styleMixins.hoverColor(theme.colors.background.secondary, theme);
|
||||||
|
const contextOutlineColor = tinycolor(theme.components.dashboard.background).setAlpha(0.7).toRgbString();
|
||||||
|
return {
|
||||||
|
logsRowLevel: css`
|
||||||
|
label: logs-row__level;
|
||||||
|
max-width: ${theme.spacing(1.25)};
|
||||||
|
cursor: default;
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
bottom: 1px;
|
||||||
|
width: 3px;
|
||||||
|
left: ${theme.spacing(0.5)};
|
||||||
|
}
|
||||||
|
`,
|
||||||
logsRowMatchHighLight: css`
|
logsRowMatchHighLight: css`
|
||||||
label: logs-row__match-highlight;
|
label: logs-row__match-highlight;
|
||||||
background: inherit;
|
background: inherit;
|
||||||
@@ -81,21 +106,6 @@ export const getLogRowStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => {
|
|||||||
width: 4em;
|
width: 4em;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
`,
|
`,
|
||||||
logsRowLevel: css`
|
|
||||||
label: logs-row__level;
|
|
||||||
max-width: ${theme.spacing(1.25)};
|
|
||||||
cursor: default;
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 1px;
|
|
||||||
bottom: 1px;
|
|
||||||
width: 3px;
|
|
||||||
left: ${theme.spacing(0.5)};
|
|
||||||
background-color: ${logColor};
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
logIconError: css`
|
logIconError: css`
|
||||||
color: ${theme.colors.warning.main};
|
color: ${theme.colors.warning.main};
|
||||||
`,
|
`,
|
||||||
@@ -174,5 +184,86 @@ export const getLogRowStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => {
|
|||||||
background-color: ${hoverBgColor};
|
background-color: ${hoverBgColor};
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
// Log row
|
||||||
|
topVerticalAlign: css`
|
||||||
|
label: topVerticalAlign;
|
||||||
|
margin-top: -${theme.spacing(0.9)};
|
||||||
|
margin-left: -${theme.spacing(0.25)};
|
||||||
|
`,
|
||||||
|
detailsOpen: css`
|
||||||
|
&:hover {
|
||||||
|
background-color: ${styleMixins.hoverColor(theme.colors.background.primary, theme)};
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
errorLogRow: css`
|
||||||
|
label: erroredLogRow;
|
||||||
|
color: ${theme.colors.text.secondary};
|
||||||
|
`,
|
||||||
|
// Log Row Message
|
||||||
|
positionRelative: css`
|
||||||
|
label: positionRelative;
|
||||||
|
position: relative;
|
||||||
|
`,
|
||||||
|
rowWithContext: css`
|
||||||
|
label: rowWithContext;
|
||||||
|
z-index: 1;
|
||||||
|
outline: 9999px solid ${contextOutlineColor};
|
||||||
|
display: inherit;
|
||||||
|
`,
|
||||||
|
horizontalScroll: css`
|
||||||
|
label: horizontalScroll;
|
||||||
|
white-space: pre;
|
||||||
|
`,
|
||||||
|
contextNewline: css`
|
||||||
|
display: block;
|
||||||
|
margin-left: 0px;
|
||||||
|
`,
|
||||||
|
rowMenu: css`
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
flex-direction: row;
|
||||||
|
align-content: flex-end;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: auto;
|
||||||
|
height: ${theme.spacing(4.5)};
|
||||||
|
background: ${theme.colors.background.primary};
|
||||||
|
box-shadow: ${theme.shadows.z3};
|
||||||
|
padding: ${theme.spacing(0, 0, 0, 0.5)};
|
||||||
|
z-index: 100;
|
||||||
|
visibility: hidden;
|
||||||
|
width: ${theme.spacing(5)};
|
||||||
|
`,
|
||||||
|
rowMenuWithContextButton: css`
|
||||||
|
width: ${theme.spacing(10)};
|
||||||
|
`,
|
||||||
|
logRowMenuCell: css`
|
||||||
|
position: absolute;
|
||||||
|
margin-top: -${theme.spacing(0.125)};
|
||||||
|
`,
|
||||||
|
logRowMenuCellDefaultPosition: css`
|
||||||
|
right: 40px;
|
||||||
|
`,
|
||||||
|
logRowMenuCellExplore: css`
|
||||||
|
right: calc(115px + ${theme.spacing(1)});
|
||||||
|
`,
|
||||||
|
logRowMenuCellExploreWithContextButton: css`
|
||||||
|
right: calc(155px + ${theme.spacing(1)});
|
||||||
|
`,
|
||||||
|
logLine: css`
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
diplay: inline;
|
||||||
|
font-family: ${theme.typography.fontFamilyMonospace};
|
||||||
|
font-size: ${theme.typography.bodySmall.fontSize};
|
||||||
|
letter-spacing: ${theme.typography.bodySmall.letterSpacing};
|
||||||
|
text-align: left;
|
||||||
|
padding: 0;
|
||||||
|
user-select: text;
|
||||||
|
`,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LogRowStyles = ReturnType<typeof getLogRowStyles>;
|
||||||
|
|||||||
Reference in New Issue
Block a user