= {}) {
return render(
diff --git a/public/app/features/logs/components/panel/LogList.tsx b/public/app/features/logs/components/panel/LogList.tsx
index d2e43f0512a..1986a9d2e57 100644
--- a/public/app/features/logs/components/panel/LogList.tsx
+++ b/public/app/features/logs/components/panel/LogList.tsx
@@ -31,7 +31,7 @@ import { LogListContextProvider, LogListState, useLogListContext } from './LogLi
import { LogListControls } from './LogListControls';
import { LOG_LIST_SEARCH_HEIGHT, LogListSearch } from './LogListSearch';
import { LogListSearchContextProvider, useLogListSearchContext } from './LogListSearchContext';
-import { preProcessLogs, LogListModel } from './processing';
+import { preProcessLogs, LogListModel, getLevelsFromLogs } from './processing';
import { useKeyBindings } from './useKeyBindings';
import { usePopoverMenu } from './usePopoverMenu';
import { LogLineVirtualization, getLogLineSize, LogFieldDimension, ScrollToLogsEvent } from './virtualization';
@@ -417,6 +417,8 @@ const LogListComponent = ({
[debouncedScrollToItem, filteredLogs]
);
+ const logLevels = useMemo(() => getLevelsFromLogs(processedLogs), [processedLogs]);
+
if (!containerElement || listHeight == null) {
// Wait for container to be rendered
return null;
@@ -424,7 +426,7 @@ const LogListComponent = ({
return (
- {showControls && }
+ {showControls && }
{detailsMode === 'sidebar' && showDetails.length > 0 && (
{
expect(onLogOptionsChange).toHaveBeenCalledWith('dedupStrategy', LogsDedupStrategy.numbers);
});
- test('Sets level filters', async () => {
+ test('Sets all level filters if not provided', async () => {
const onLogOptionsChange = jest.fn();
render(
@@ -258,6 +258,25 @@ describe('LogListControls', () => {
expect(onLogOptionsChange).toHaveBeenCalledWith('filterLevels', ['error']);
});
+ test('Sets all level filters from provided levels', async () => {
+ const onLogOptionsChange = jest.fn();
+ render(
+
+
+
+ );
+ await userEvent.click(screen.getByLabelText(FILTER_LEVELS_LABEL_COPY));
+ expect(await screen.findByText('All levels')).toBeVisible();
+ expect(screen.getByText('Info')).toBeVisible();
+ expect(screen.queryByText('Debug')).not.toBeInTheDocument();
+ expect(screen.queryByText('Trace')).not.toBeInTheDocument();
+ expect(screen.queryByText('Warning')).not.toBeInTheDocument();
+ expect(screen.queryByText('Error')).not.toBeInTheDocument();
+ expect(screen.getByText('Critical')).toBeVisible();
+ await userEvent.click(screen.getByText('Critical'));
+ expect(onLogOptionsChange).toHaveBeenCalledWith('filterLevels', ['critical']);
+ });
+
test('Controls timestamp visibility', async () => {
const onLogOptionsChange = jest.fn();
render(
diff --git a/public/app/features/logs/components/panel/LogListControls.tsx b/public/app/features/logs/components/panel/LogListControls.tsx
index 18c905a02c9..0f7074c7972 100644
--- a/public/app/features/logs/components/panel/LogListControls.tsx
+++ b/public/app/features/logs/components/panel/LogListControls.tsx
@@ -27,6 +27,7 @@ import { ScrollToLogsEvent } from './virtualization';
type Props = {
eventBus: EventBus;
visualisationType?: LogsVisualisationType;
+ logLevels?: LogLevel[];
};
const DEDUP_OPTIONS = [
@@ -46,7 +47,7 @@ const FILTER_LEVELS: LogLevel[] = [
LogLevel.unknown,
];
-export const LogListControls = ({ eventBus, visualisationType = 'logs' }: Props) => {
+export const LogListControls = ({ eventBus, logLevels = FILTER_LEVELS, visualisationType = 'logs' }: Props) => {
const {
app,
controlsExpanded,
@@ -56,6 +57,7 @@ export const LogListControls = ({ eventBus, visualisationType = 'logs' }: Props)
fontSize,
forceEscape,
hasUnescapedContent,
+ logOptionsStorageKey,
prettifyJSON,
setControlsExpanded,
setDedupStrategy,
@@ -73,7 +75,6 @@ export const LogListControls = ({ eventBus, visualisationType = 'logs' }: Props)
sortOrder,
syntaxHighlighting,
wrapLogMessage,
- logOptionsStorageKey,
} = useLogListContext();
const { hideSearch, searchVisible, showSearch } = useLogListSearchContext();
@@ -209,7 +210,7 @@ export const LogListControls = ({ eventBus, visualisationType = 'logs' }: Props)
label={t('logs.logs-controls.display-level-all', 'All levels')}
onClick={() => onFilterLevelClick()}
/>
- {FILTER_LEVELS.map((level) => (
+ {logLevels.map((level) => (
),
- [filterLevels, onFilterLevelClick, styles.menuItemActive]
+ [filterLevels, logLevels, onFilterLevelClick, styles.menuItemActive]
);
const downloadMenu = useMemo(
diff --git a/public/app/features/logs/components/panel/processing.ts b/public/app/features/logs/components/panel/processing.ts
index 0c8559d5f47..98a0cf6a00c 100644
--- a/public/app/features/logs/components/panel/processing.ts
+++ b/public/app/features/logs/components/panel/processing.ts
@@ -327,3 +327,11 @@ function countNewLines(log: string, limit = Infinity) {
}
return count;
}
+
+export function getLevelsFromLogs(logs: LogListModel[]) {
+ const levels = new Set();
+ for (const log of logs) {
+ levels.add(log.logLevel);
+ }
+ return Array.from(levels).filter((level) => level != null);
+}