diff --git a/public/app/features/logs/components/LogRow.tsx b/public/app/features/logs/components/LogRow.tsx index 91ec154e005..163b53f2bec 100644 --- a/public/app/features/logs/components/LogRow.tsx +++ b/public/app/features/logs/components/LogRow.tsx @@ -308,6 +308,7 @@ class UnThemedLogRow extends PureComponent { pinned={this.props.pinned} mouseIsOver={this.state.mouseIsOver} onBlur={this.onMouseLeave} + expanded={this.state.showDetails} /> )} diff --git a/public/app/features/logs/components/LogRowMessage.test.tsx b/public/app/features/logs/components/LogRowMessage.test.tsx index a30448748b1..51ba688c9de 100644 --- a/public/app/features/logs/components/LogRowMessage.test.tsx +++ b/public/app/features/logs/components/LogRowMessage.test.tsx @@ -160,4 +160,41 @@ describe('LogRowMessage', () => { }); }); }); + + describe('For multi-line logs', () => { + const entry = `Line1 +line2 +line3`; + const singleLineEntry = entry.replace(/(\r\n|\n|\r)/g, ''); + it('Displays the original log line when wrapping is enabled', () => { + setup({ + row: createLogRow({ entry, logLevel: LogLevel.error, timeEpochMs: 1546297200000 }), + wrapLogMessage: true, + }); + expect(screen.getByText(/Line1/)).toBeInTheDocument(); + expect(screen.getByText(/line2/)).toBeInTheDocument(); + expect(screen.getByText(/line3/)).toBeInTheDocument(); + expect(screen.queryByText(singleLineEntry)).not.toBeInTheDocument(); + }); + + it('Removes new lines from the original log line when wrapping is disabled', () => { + setup({ + row: createLogRow({ entry, logLevel: LogLevel.error, timeEpochMs: 1546297200000 }), + wrapLogMessage: false, + }); + expect(screen.getByText(singleLineEntry)).toBeInTheDocument(); + }); + + it('Displays the original log line when the line is expanded', () => { + setup({ + row: createLogRow({ entry, logLevel: LogLevel.error, timeEpochMs: 1546297200000 }), + wrapLogMessage: true, + expanded: true, + }); + expect(screen.getByText(/Line1/)).toBeInTheDocument(); + expect(screen.getByText(/line2/)).toBeInTheDocument(); + expect(screen.getByText(/line3/)).toBeInTheDocument(); + expect(screen.queryByText(singleLineEntry)).not.toBeInTheDocument(); + }); + }); }); diff --git a/public/app/features/logs/components/LogRowMessage.tsx b/public/app/features/logs/components/LogRowMessage.tsx index 73e456887c9..841923d3f17 100644 --- a/public/app/features/logs/components/LogRowMessage.tsx +++ b/public/app/features/logs/components/LogRowMessage.tsx @@ -29,6 +29,7 @@ interface Props { styles: LogRowStyles; mouseIsOver: boolean; onBlur: () => void; + expanded?: boolean; } interface LogMessageProps { @@ -58,13 +59,20 @@ const LogMessage = ({ hasAnsi, entry, highlights, styles }: LogMessageProps) => return <>{entry}; }; -const restructureLog = (line: string, prettifyLogMessage: boolean): string => { +const restructureLog = ( + line: string, + prettifyLogMessage: boolean, + wrapLogMessage: boolean, + expanded: boolean +): string => { if (prettifyLogMessage) { try { return JSON.stringify(JSON.parse(line), undefined, 2); - } catch (error) { - return line; - } + } catch (error) {} + } + // With wrapping disabled, we want to turn it into a single-line log entry unless the line is expanded + if (!wrapLogMessage && !expanded) { + line = line.replace(/(\r\n|\n|\r)/g, ''); } return line; }; @@ -84,9 +92,13 @@ export const LogRowMessage = React.memo((props: Props) => { mouseIsOver, onBlur, getRowContextQuery, + expanded, } = props; const { hasAnsi, raw } = row; - const restructuredEntry = useMemo(() => restructureLog(raw, prettifyLogMessage), [raw, prettifyLogMessage]); + const restructuredEntry = useMemo( + () => restructureLog(raw, prettifyLogMessage, wrapLogMessage, Boolean(expanded)), + [raw, prettifyLogMessage, wrapLogMessage, expanded] + ); const shouldShowMenu = useMemo(() => mouseIsOver || pinned, [mouseIsOver, pinned]); return ( <>