mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: Log message line wrapping options for logs (#20360)
This commit is contained in:
parent
2027e1aaee
commit
5a4465a382
@ -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,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user