Commit 5a4465a3 by Ivana Huckova Committed by GitHub

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

parent 2027e1aa
......@@ -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>
......
......@@ -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}
......
......@@ -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'}
/>
);
......
......@@ -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>
);
}
......
......@@ -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;
......
......@@ -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}
/>
......
......@@ -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}
/>
......
......@@ -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} />
......
......@@ -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,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment