New Logs Panel: Read default font size from storage + add missing unescaped content check + fix mutation (#106755)
* Logs Panel: remove default value to it's taken from local storage code * processing: do not remove newlines, let truncation handle * LogList: check and pass unescaped content to context * LogLine: prevent mutation of searchWords * grammar: use parseFlags * grammar: escape regex
This commit is contained in:
@@ -236,7 +236,7 @@ const DisplayedFields = ({
|
|||||||
const { matchingUids, search } = useLogListSearchContext();
|
const { matchingUids, search } = useLogListSearchContext();
|
||||||
|
|
||||||
const searchWords = useMemo(() => {
|
const searchWords = useMemo(() => {
|
||||||
const searchWords = log.searchWords && log.searchWords[0] ? log.searchWords : [];
|
const searchWords = log.searchWords && log.searchWords[0] ? log.searchWords.slice() : [];
|
||||||
if (search && matchingUids?.includes(log.uid)) {
|
if (search && matchingUids?.includes(log.uid)) {
|
||||||
searchWords.push(search);
|
searchWords.push(search);
|
||||||
}
|
}
|
||||||
@@ -271,7 +271,7 @@ const LogLineBody = ({ log, styles }: { log: LogListModel; styles: LogLineStyles
|
|||||||
const { matchingUids, search } = useLogListSearchContext();
|
const { matchingUids, search } = useLogListSearchContext();
|
||||||
|
|
||||||
const highlight = useMemo(() => {
|
const highlight = useMemo(() => {
|
||||||
const searchWords = log.searchWords && log.searchWords[0] ? log.searchWords : [];
|
const searchWords = log.searchWords && log.searchWords[0] ? log.searchWords.slice() : [];
|
||||||
if (search && matchingUids?.includes(log.uid)) {
|
if (search && matchingUids?.includes(log.uid)) {
|
||||||
searchWords.push(search);
|
searchWords.push(search);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,5 +259,33 @@ describe('LogList', () => {
|
|||||||
|
|
||||||
expect(screen.queryByPlaceholderText('Search in logs')).not.toBeInTheDocument();
|
expect(screen.queryByPlaceholderText('Search in logs')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Does not conflict with search words', async () => {
|
||||||
|
logs = [
|
||||||
|
createLogRow({ uid: '1' }),
|
||||||
|
createLogRow({ uid: '2', entry: '(?i)some text', searchWords: ['some text'] }),
|
||||||
|
];
|
||||||
|
|
||||||
|
render(<LogList {...defaultProps} logs={logs} />);
|
||||||
|
|
||||||
|
expect(screen.queryByPlaceholderText('Search in logs')).not.toBeInTheDocument();
|
||||||
|
expect(screen.getByText('log message 1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('some text')).toBeInTheDocument();
|
||||||
|
|
||||||
|
await userEvent.keyboard('{Control>}{f}{/Control}');
|
||||||
|
|
||||||
|
expect(screen.getByPlaceholderText('Search in logs')).toBeInTheDocument();
|
||||||
|
|
||||||
|
await userEvent.type(screen.getByPlaceholderText('Search in logs'), '(?i)');
|
||||||
|
|
||||||
|
expect(screen.getByText('log message 1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('(?i)')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('some text')).toBeInTheDocument();
|
||||||
|
|
||||||
|
await userEvent.clear(screen.getByPlaceholderText('Search in logs'));
|
||||||
|
|
||||||
|
expect(screen.getByText('log message 1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('some text')).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ export const LogList = ({
|
|||||||
timeZone,
|
timeZone,
|
||||||
wrapLogMessage,
|
wrapLogMessage,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
|
const hasUnescapedContent = useMemo(() => logs.some((log) => log.hasUnescapedContent), [logs]);
|
||||||
return (
|
return (
|
||||||
<LogListContextProvider
|
<LogListContextProvider
|
||||||
app={app}
|
app={app}
|
||||||
@@ -161,6 +162,7 @@ export const LogList = ({
|
|||||||
filterLevels={filterLevels}
|
filterLevels={filterLevels}
|
||||||
fontSize={fontSize}
|
fontSize={fontSize}
|
||||||
getRowContextQuery={getRowContextQuery}
|
getRowContextQuery={getRowContextQuery}
|
||||||
|
hasUnescapedContent={hasUnescapedContent}
|
||||||
isLabelFilterActive={isLabelFilterActive}
|
isLabelFilterActive={isLabelFilterActive}
|
||||||
logs={logs}
|
logs={logs}
|
||||||
logsMeta={logsMeta}
|
logsMeta={logsMeta}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Grammar } from 'prismjs';
|
import { Grammar } from 'prismjs';
|
||||||
|
|
||||||
import { escapeRegex } from '@grafana/data';
|
import { escapeRegex, parseFlags } from '@grafana/data';
|
||||||
|
|
||||||
import { LogListModel } from './processing';
|
import { LogListModel } from './processing';
|
||||||
|
|
||||||
@@ -30,14 +30,26 @@ export const generateTextMatchGrammar = (
|
|||||||
highlightWords: string[] | undefined = [],
|
highlightWords: string[] | undefined = [],
|
||||||
search: string | undefined
|
search: string | undefined
|
||||||
): Grammar => {
|
): Grammar => {
|
||||||
const textMatches = [...highlightWords];
|
/**
|
||||||
|
* See:
|
||||||
|
* - https://github.com/grafana/grafana/blob/96f1582c36f94cf4ac7621b7af86bc9e2ad626fb/public/app/features/logs/components/LogRowMessage.tsx#L67
|
||||||
|
* - https://github.com/grafana/grafana/blob/96f1582c36f94cf4ac7621b7af86bc9e2ad626fb/packages/grafana-data/src/text/text.ts#L12
|
||||||
|
*/
|
||||||
|
const expressions = highlightWords.map((word) => {
|
||||||
|
const { cleaned, flags } = parseFlags(cleanNeedle(word));
|
||||||
|
return new RegExp(`(?:${cleaned})`, flags);
|
||||||
|
});
|
||||||
if (search) {
|
if (search) {
|
||||||
textMatches.push(escapeRegex(search));
|
expressions.push(new RegExp(escapeRegex(search), 'gi'));
|
||||||
}
|
}
|
||||||
if (!textMatches.length) {
|
if (!expressions.length) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
'log-search-match': new RegExp(textMatches.join('|'), 'g'),
|
'log-search-match': expressions,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const cleanNeedle = (needle: string): string => {
|
||||||
|
return needle.replace(/[[{(][\w,.\/:;<=>?:*+]+$/, '');
|
||||||
|
};
|
||||||
|
|||||||
@@ -88,9 +88,7 @@ export class LogListModel implements LogRowModel {
|
|||||||
|
|
||||||
get body(): string {
|
get body(): string {
|
||||||
if (this._body === undefined) {
|
if (this._body === undefined) {
|
||||||
let body = this.collapsed ? this.raw.substring(0, getTruncationLength(null)) : this.raw;
|
this._body = this.collapsed ? this.raw.substring(0, getTruncationLength(null)) : this.raw;
|
||||||
// Turn it into a single-line log entry for the list
|
|
||||||
this._body = body.replace(/(\r\n|\n|\r)/g, '');
|
|
||||||
}
|
}
|
||||||
return this._body;
|
return this._body;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,6 @@ export const plugin = new PanelPlugin<Options>(LogsPanel)
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
defaultValue: 'default',
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user