mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Ingest Manager] UI to configure agent log level (#84112)
This commit is contained in:
parent
fc9c19574e
commit
e4ff981b94
8 changed files with 175 additions and 4 deletions
|
@ -140,6 +140,8 @@ export const agentRouteService = {
|
|||
getBulkUpgradePath: () => AGENT_API_ROUTES.BULK_UPGRADE_PATTERN,
|
||||
getListPath: () => AGENT_API_ROUTES.LIST_PATTERN,
|
||||
getStatusPath: () => AGENT_API_ROUTES.STATUS_PATTERN,
|
||||
getCreateActionPath: (agentId: string) =>
|
||||
AGENT_API_ROUTES.ACTIONS_PATTERN.replace('{agentId}', agentId),
|
||||
};
|
||||
|
||||
export const outputRoutesService = {
|
||||
|
|
|
@ -26,6 +26,8 @@ import {
|
|||
PostBulkAgentUpgradeRequest,
|
||||
PostAgentUpgradeResponse,
|
||||
PostBulkAgentUpgradeResponse,
|
||||
PostNewAgentActionRequest,
|
||||
PostNewAgentActionResponse,
|
||||
} from '../../types';
|
||||
|
||||
type RequestOptions = Pick<Partial<UseRequestConfig>, 'pollIntervalMs'>;
|
||||
|
@ -144,6 +146,19 @@ export function sendPostAgentUpgrade(
|
|||
});
|
||||
}
|
||||
|
||||
export function sendPostAgentAction(
|
||||
agentId: string,
|
||||
body: PostNewAgentActionRequest['body'],
|
||||
options?: RequestOptions
|
||||
) {
|
||||
return sendRequest<PostNewAgentActionResponse>({
|
||||
path: agentRouteService.getCreateActionPath(agentId),
|
||||
method: 'post',
|
||||
body,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
export function sendPostBulkAgentUpgrade(
|
||||
body: PostBulkAgentUpgradeRequest['body'],
|
||||
options?: RequestOptions
|
||||
|
|
|
@ -109,6 +109,17 @@ export const AgentDetailsContent: React.FunctionComponent<{
|
|||
: 'stable'
|
||||
: '-',
|
||||
},
|
||||
{
|
||||
title: i18n.translate('xpack.fleet.agentDetails.logLevel', {
|
||||
defaultMessage: 'Log level',
|
||||
}),
|
||||
description:
|
||||
typeof agent.local_metadata.elastic === 'object' &&
|
||||
typeof agent.local_metadata.elastic.agent === 'object' &&
|
||||
typeof agent.local_metadata.elastic.agent.log_level === 'string'
|
||||
? agent.local_metadata.elastic.agent.log_level
|
||||
: '-',
|
||||
},
|
||||
{
|
||||
title: i18n.translate('xpack.fleet.agentDetails.platformLabel', {
|
||||
defaultMessage: 'Platform',
|
||||
|
|
|
@ -24,3 +24,12 @@ export const DEFAULT_DATE_RANGE = {
|
|||
start: 'now-1d',
|
||||
end: 'now',
|
||||
};
|
||||
|
||||
export const AGENT_LOG_LEVELS = {
|
||||
ERROR: 'error',
|
||||
WARNING: 'warning',
|
||||
INFO: 'info',
|
||||
DEBUG: 'debug',
|
||||
};
|
||||
|
||||
export const DEFAULT_LOG_LEVEL = AGENT_LOG_LEVELS.INFO;
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
import React, { memo, useState, useEffect } from 'react';
|
||||
import { EuiPopover, EuiFilterButton, EuiFilterSelectItem } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { AGENT_LOG_LEVELS, AGENT_LOG_INDEX_PATTERN, LOG_LEVEL_FIELD } from './constants';
|
||||
import { useStartServices } from '../../../../../hooks';
|
||||
import { AGENT_LOG_INDEX_PATTERN, LOG_LEVEL_FIELD } from './constants';
|
||||
|
||||
const LEVEL_VALUES = Object.values(AGENT_LOG_LEVELS);
|
||||
|
||||
export const LogLevelFilter: React.FunctionComponent<{
|
||||
selectedLevels: string[];
|
||||
|
@ -16,13 +18,13 @@ export const LogLevelFilter: React.FunctionComponent<{
|
|||
const { data } = useStartServices();
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [levelValues, setLevelValues] = useState<string[]>([]);
|
||||
const [levelValues, setLevelValues] = useState<string[]>(LEVEL_VALUES);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchValues = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const values = await data.autocomplete.getValueSuggestions({
|
||||
const values: string[] = await data.autocomplete.getValueSuggestions({
|
||||
indexPattern: {
|
||||
title: AGENT_LOG_INDEX_PATTERN,
|
||||
fields: [LOG_LEVEL_FIELD],
|
||||
|
@ -30,7 +32,7 @@ export const LogLevelFilter: React.FunctionComponent<{
|
|||
field: LOG_LEVEL_FIELD,
|
||||
query: '',
|
||||
});
|
||||
setLevelValues(values.sort());
|
||||
setLevelValues([...new Set([...LEVEL_VALUES, ...values.sort()])]);
|
||||
} catch (e) {
|
||||
setLevelValues([]);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ import {
|
|||
EuiButtonEmpty,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import semverGte from 'semver/functions/gte';
|
||||
import semverCoerce from 'semver/functions/coerce';
|
||||
import { RedirectAppLinks } from '../../../../../../../../../../../src/plugins/kibana_react/public';
|
||||
import { TimeRange, esKuery } from '../../../../../../../../../../../src/plugins/data/public';
|
||||
import { LogStream } from '../../../../../../../../../infra/public';
|
||||
|
@ -27,6 +29,7 @@ import { DatasetFilter } from './filter_dataset';
|
|||
import { LogLevelFilter } from './filter_log_level';
|
||||
import { LogQueryBar } from './query_bar';
|
||||
import { buildQuery } from './build_query';
|
||||
import { SelectLogLevel } from './select_log_level';
|
||||
|
||||
const WrapperFlexGroup = styled(EuiFlexGroup)`
|
||||
height: 100%;
|
||||
|
@ -137,6 +140,18 @@ export const AgentLogs: React.FunctionComponent<{ agent: Agent }> = memo(({ agen
|
|||
[logStreamQuery, dateRange.endExpression, dateRange.startExpression, http.basePath]
|
||||
);
|
||||
|
||||
const agentVersion = agent.local_metadata?.elastic?.agent?.version;
|
||||
const isLogLevelSelectionAvailable = useMemo(() => {
|
||||
if (!agentVersion) {
|
||||
return false;
|
||||
}
|
||||
const agentVersionWithPrerelease = semverCoerce(agentVersion)?.version;
|
||||
if (!agentVersionWithPrerelease) {
|
||||
return false;
|
||||
}
|
||||
return semverGte(agentVersionWithPrerelease, '7.11.0');
|
||||
}, [agentVersion]);
|
||||
|
||||
return (
|
||||
<WrapperFlexGroup direction="column" gutterSize="m">
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -213,6 +228,11 @@ export const AgentLogs: React.FunctionComponent<{ agent: Agent }> = memo(({ agen
|
|||
/>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
{isLogLevelSelectionAvailable && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<SelectLogLevel agent={agent} />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</WrapperFlexGroup>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { memo, useState, useCallback } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiSelect, EuiFormLabel, EuiButtonEmpty, EuiFlexItem, EuiFlexGroup } from '@elastic/eui';
|
||||
import { Agent } from '../../../../../types';
|
||||
import { sendPostAgentAction, useStartServices } from '../../../../../hooks';
|
||||
import { AGENT_LOG_LEVELS, DEFAULT_LOG_LEVEL } from './constants';
|
||||
|
||||
const LEVEL_VALUES = Object.values(AGENT_LOG_LEVELS);
|
||||
|
||||
export const SelectLogLevel: React.FC<{ agent: Agent }> = memo(({ agent }) => {
|
||||
const { notifications } = useStartServices();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [agentLogLevel, setAgentLogLevel] = useState(
|
||||
agent.local_metadata?.elastic?.agent?.log_level ?? DEFAULT_LOG_LEVEL
|
||||
);
|
||||
const [selectedLogLevel, setSelectedLogLevel] = useState(agentLogLevel);
|
||||
|
||||
const onClickApply = useCallback(() => {
|
||||
setIsLoading(true);
|
||||
async function send() {
|
||||
try {
|
||||
const res = await sendPostAgentAction(agent.id, {
|
||||
action: {
|
||||
type: 'SETTINGS',
|
||||
data: {
|
||||
log_level: selectedLogLevel,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (res.error) {
|
||||
throw res.error;
|
||||
}
|
||||
setAgentLogLevel(selectedLogLevel);
|
||||
notifications.toasts.addSuccess(
|
||||
i18n.translate('xpack.fleet.agentLogs.selectLogLevel.successText', {
|
||||
defaultMessage: `Changed agent logging level to '{logLevel}'.`,
|
||||
values: {
|
||||
logLevel: selectedLogLevel,
|
||||
},
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
notifications.toasts.addError(error, {
|
||||
title: i18n.translate('xpack.fleet.agentLogs.selectLogLevel.errorTitleText', {
|
||||
defaultMessage: 'Error updating agent logging level',
|
||||
}),
|
||||
});
|
||||
}
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
send();
|
||||
}, [notifications, selectedLogLevel, agent.id]);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="m" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormLabel htmlFor="selectAgentLogLevel">
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.agentLogs.selectLogLevelLabelText"
|
||||
defaultMessage="Agent logging level"
|
||||
/>
|
||||
</EuiFormLabel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSelect
|
||||
disabled={isLoading}
|
||||
compressed={true}
|
||||
id="selectAgentLogLevel"
|
||||
value={selectedLogLevel}
|
||||
onChange={(event) => {
|
||||
setSelectedLogLevel(event.target.value);
|
||||
}}
|
||||
options={LEVEL_VALUES.map((level) => ({ text: level, value: level }))}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
{agentLogLevel !== selectedLogLevel && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
flush="left"
|
||||
size="xs"
|
||||
isLoading={isLoading}
|
||||
disabled={agentLogLevel === selectedLogLevel}
|
||||
iconType="refresh"
|
||||
onClick={onClickApply}
|
||||
>
|
||||
{isLoading ? (
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.agentLogs.updateButtonLoadingText"
|
||||
defaultMessage="Applying changes..."
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.agentLogs.updateButtonText"
|
||||
defaultMessage="Apply changes"
|
||||
/>
|
||||
)}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
});
|
|
@ -67,6 +67,8 @@ export {
|
|||
PutAgentReassignResponse,
|
||||
PostBulkAgentReassignRequest,
|
||||
PostBulkAgentReassignResponse,
|
||||
PostNewAgentActionResponse,
|
||||
PostNewAgentActionRequest,
|
||||
// API schemas - Enrollment API Keys
|
||||
GetEnrollmentAPIKeysResponse,
|
||||
GetEnrollmentAPIKeysRequest,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue