Explore: Log message line wrapping options for logs (#20360)

This commit is contained in:
Ivana Huckova 2019-12-03 13:02:44 +01:00 committed by GitHub
parent 2027e1aaee
commit 5a4465a382
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 95 additions and 40 deletions

View File

@ -22,6 +22,7 @@ interface Props extends Themeable {
row: LogRowModel;
showDuplicates: boolean;
showTime: boolean;
wrapLogMessage: boolean;
timeZone: TimeZone;
allowDetails?: boolean;
getRows: () => LogRowModel[];
@ -93,6 +94,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
showDuplicates,
timeZone,
showTime,
wrapLogMessage,
theme,
getFieldLinks,
} = this.props;
@ -103,6 +105,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
const showDetailsClassName = showDetails
? cx(['fa fa-chevron-down', styles.topVerticalAlign])
: cx(['fa fa-chevron-right', styles.topVerticalAlign]);
return (
<div className={style.logsRow}>
{showDuplicates && (
@ -141,6 +144,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
updateLimit={updateLimit}
context={context}
showContext={showContext}
wrapLogMessage={wrapLogMessage}
onToggleContext={this.toggleContext}
/>
</div>

View File

@ -21,6 +21,7 @@ interface Props extends Themeable {
row: LogRowModel;
hasMoreContextRows?: HasMoreContextRows;
showContext: boolean;
wrapLogMessage: boolean;
errors?: LogRowContextQueryErrors;
context?: LogRowContextRows;
highlighterExpressions?: string[];
@ -57,6 +58,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
label: whiteSpacePreWrap;
white-space: pre-wrap;
`,
horizontalScroll: css`
label: verticalScroll;
white-space: nowrap;
`,
};
});
@ -76,6 +81,7 @@ class UnThemedLogRowMessage extends PureComponent<Props, State> {
updateLimit,
context,
showContext,
wrapLogMessage,
onToggleContext,
} = this.props;
const {} = this.state;
@ -91,7 +97,7 @@ class UnThemedLogRowMessage extends PureComponent<Props, State> {
const styles = getStyles(theme);
return (
<div className={style.logsRowMessage}>
<div className={styles.positionRelative}>
<div className={cx(styles.positionRelative, { [styles.horizontalScroll]: !wrapLogMessage })}>
{showContext && context && (
<LogRowContext
row={row}

View File

@ -14,6 +14,7 @@ describe('LogRows', () => {
dedupStrategy={LogsDedupStrategy.none}
highlighterExpressions={[]}
showTime={false}
wrapLogMessage={true}
timeZone={'utc'}
/>
);
@ -33,6 +34,7 @@ describe('LogRows', () => {
dedupStrategy={LogsDedupStrategy.none}
highlighterExpressions={[]}
showTime={false}
wrapLogMessage={true}
timeZone={'utc'}
previewLimit={1}
/>
@ -61,6 +63,7 @@ describe('LogRows', () => {
dedupStrategy={LogsDedupStrategy.none}
highlighterExpressions={[]}
showTime={false}
wrapLogMessage={true}
timeZone={'utc'}
/>
);
@ -79,6 +82,7 @@ describe('LogRows', () => {
dedupStrategy={LogsDedupStrategy.none}
highlighterExpressions={[]}
showTime={false}
wrapLogMessage={true}
timeZone={'utc'}
/>
);

View File

@ -18,6 +18,7 @@ export interface Props extends Themeable {
dedupStrategy: LogsDedupStrategy;
highlighterExpressions?: string[];
showTime: boolean;
wrapLogMessage: boolean;
timeZone: TimeZone;
rowLimit?: number;
allowDetails?: boolean;
@ -71,6 +72,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
const {
dedupStrategy,
showTime,
wrapLogMessage,
logRows,
deduplicatedRows,
highlighterExpressions,
@ -84,12 +86,14 @@ class UnThemedLogRows extends PureComponent<Props, State> {
getFieldLinks,
} = this.props;
const { renderAll } = this.state;
const { logsRows, logsRowsHorizontalScroll } = getLogRowStyles(theme);
const dedupedRows = deduplicatedRows ? deduplicatedRows : logRows;
const hasData = logRows && logRows.length > 0;
const dedupCount = dedupedRows
? dedupedRows.reduce((sum, row) => (row.duplicates ? sum + row.duplicates : sum), 0)
: 0;
const showDuplicates = dedupStrategy !== LogsDedupStrategy.none && dedupCount > 0;
const horizontalScrollWindow = wrapLogMessage ? '' : logsRowsHorizontalScroll;
// Staged rendering
const processedRows = dedupedRows ? dedupedRows : [];
@ -100,45 +104,48 @@ class UnThemedLogRows extends PureComponent<Props, State> {
// React profiler becomes unusable if we pass all rows to all rows and their labels, using getter instead
const getRows = this.makeGetRows(processedRows);
const getRowContext = this.props.getRowContext ? this.props.getRowContext : () => Promise.resolve([]);
const { logsRows } = getLogRowStyles(theme);
return (
<div className={logsRows}>
{hasData &&
firstRows.map((row, index) => (
<LogRow
key={row.uid}
getRows={getRows}
getRowContext={getRowContext}
highlighterExpressions={highlighterExpressions}
row={row}
showDuplicates={showDuplicates}
showTime={showTime}
timeZone={timeZone}
allowDetails={allowDetails}
onClickFilterLabel={onClickFilterLabel}
onClickFilterOutLabel={onClickFilterOutLabel}
getFieldLinks={getFieldLinks}
/>
))}
{hasData &&
renderAll &&
lastRows.map((row, index) => (
<LogRow
key={row.uid}
getRows={getRows}
getRowContext={getRowContext}
row={row}
showDuplicates={showDuplicates}
showTime={showTime}
timeZone={timeZone}
allowDetails={allowDetails}
onClickFilterLabel={onClickFilterLabel}
onClickFilterOutLabel={onClickFilterOutLabel}
getFieldLinks={getFieldLinks}
/>
))}
{hasData && !renderAll && <span>Rendering {rowCount - previewLimit!} rows...</span>}
<div className={horizontalScrollWindow}>
{hasData &&
firstRows.map((row, index) => (
<LogRow
key={row.uid}
getRows={getRows}
getRowContext={getRowContext}
highlighterExpressions={highlighterExpressions}
row={row}
showDuplicates={showDuplicates}
showTime={showTime}
wrapLogMessage={wrapLogMessage}
timeZone={timeZone}
allowDetails={allowDetails}
onClickFilterLabel={onClickFilterLabel}
onClickFilterOutLabel={onClickFilterOutLabel}
getFieldLinks={getFieldLinks}
/>
))}
{hasData &&
renderAll &&
lastRows.map((row, index) => (
<LogRow
key={row.uid}
getRows={getRows}
getRowContext={getRowContext}
row={row}
showDuplicates={showDuplicates}
showTime={showTime}
wrapLogMessage={wrapLogMessage}
timeZone={timeZone}
allowDetails={allowDetails}
onClickFilterLabel={onClickFilterLabel}
onClickFilterOutLabel={onClickFilterOutLabel}
getFieldLinks={getFieldLinks}
/>
))}
{hasData && !renderAll && <span>Rendering {rowCount - previewLimit!} rows...</span>}
</div>
</div>
);
}

View File

@ -62,6 +62,10 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
table-layout: fixed;
width: 100%;
`,
logsRowsHorizontalScroll: css`
label: logs-rows__horizontal-scroll;
overflow-y: scroll;
`,
context: context,
logsRow: css`
label: logs-row;
@ -130,6 +134,7 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo
display: table-cell;
white-space: nowrap;
width: 12.5em;
padding-right: 1em;
`,
logsRowMessage: css`
label: logs-row__message;

View File

@ -57,11 +57,13 @@ interface Props {
interface State {
showTime: boolean;
wrapLogMessage: boolean;
}
export class Logs extends PureComponent<Props, State> {
state = {
showTime: true,
wrapLogMessage: true,
};
onChangeDedup = (dedup: LogsDedupStrategy) => {
@ -81,6 +83,15 @@ export class Logs extends PureComponent<Props, State> {
}
};
onChangewrapLogMessage = (event?: React.SyntheticEvent) => {
const target = event && (event.target as HTMLInputElement);
if (target) {
this.setState({
wrapLogMessage: target.checked,
});
}
};
onToggleLogLevel = (hiddenRawLevels: string[]) => {
const hiddenLogLevels: LogLevel[] = hiddenRawLevels.map(level => LogLevel[level as LogLevel]);
this.props.onToggleLogLevel(hiddenLogLevels);
@ -123,7 +134,7 @@ export class Logs extends PureComponent<Props, State> {
return null;
}
const { showTime } = this.state;
const { showTime, wrapLogMessage } = this.state;
const { dedupStrategy } = this.props;
const hasData = logRows && logRows.length > 0;
const dedupCount = dedupedRows
@ -164,6 +175,7 @@ export class Logs extends PureComponent<Props, State> {
<div className="logs-panel-options">
<div className="logs-panel-controls">
<Switch label="Time" checked={showTime} onChange={this.onChangeTime} transparent />
<Switch label="Wrap lines" checked={wrapLogMessage} onChange={this.onChangewrapLogMessage} transparent />
<ToggleButtonGroup label="Dedup" transparent={true}>
{Object.keys(LogsDedupStrategy).map((dedupType: string, i) => (
<ToggleButton
@ -202,6 +214,7 @@ export class Logs extends PureComponent<Props, State> {
onClickFilterLabel={onClickFilterLabel}
onClickFilterOutLabel={onClickFilterOutLabel}
showTime={showTime}
wrapLogMessage={wrapLogMessage}
timeZone={timeZone}
getFieldLinks={getFieldLinks}
/>

View File

@ -10,7 +10,7 @@ interface LogsPanelProps extends PanelProps<Options> {}
export const LogsPanel: React.FunctionComponent<LogsPanelProps> = ({
data,
timeZone,
options: { showTime, sortOrder },
options: { showTime, wrapLogMessage, sortOrder },
width,
}) => {
if (!data) {
@ -31,6 +31,7 @@ export const LogsPanel: React.FunctionComponent<LogsPanelProps> = ({
dedupStrategy={LogsDedupStrategy.none}
highlighterExpressions={[]}
showTime={showTime}
wrapLogMessage={wrapLogMessage}
timeZone={timeZone}
allowDetails={true}
/>

View File

@ -20,13 +20,20 @@ export class LogsPanelEditor extends PureComponent<PanelEditorProps<Options>> {
onOptionsChange({ ...options, showTime: !showTime });
};
onTogglewrapLogMessage = () => {
const { options, onOptionsChange } = this.props;
const { wrapLogMessage } = options;
onOptionsChange({ ...options, wrapLogMessage: !wrapLogMessage });
};
onShowValuesChange = (item: SelectableValue<SortOrder>) => {
const { options, onOptionsChange } = this.props;
onOptionsChange({ ...options, sortOrder: item.value });
};
render() {
const { showTime, sortOrder } = this.props.options;
const { showTime, wrapLogMessage, sortOrder } = this.props.options;
const value = sortOrderOptions.filter(option => option.value === sortOrder)[0];
return (
@ -34,6 +41,12 @@ export class LogsPanelEditor extends PureComponent<PanelEditorProps<Options>> {
<PanelOptionsGrid>
<PanelOptionsGroup title="Columns">
<Switch label="Time" labelClass="width-10" checked={showTime} onChange={this.onToggleTime} />
<Switch
label="Wrap lines"
labelClass="width-10"
checked={wrapLogMessage}
onChange={this.onTogglewrapLogMessage}
/>
<div className="gf-form">
<FormLabel>Order</FormLabel>
<Select options={sortOrderOptions} value={value} onChange={this.onShowValuesChange} />

View File

@ -2,10 +2,12 @@ import { SortOrder } from 'app/core/utils/explore';
export interface Options {
showTime: boolean;
wrapLogMessage: boolean;
sortOrder: SortOrder;
}
export const defaults: Options = {
showTime: true,
wrapLogMessage: true,
sortOrder: SortOrder.Descending,
};