diff --git a/x-pack/plugins/fleet/common/services/routes.ts b/x-pack/plugins/fleet/common/services/routes.ts index f35b6b3f7de6a..4af3f3beb32be 100644 --- a/x-pack/plugins/fleet/common/services/routes.ts +++ b/x-pack/plugins/fleet/common/services/routes.ts @@ -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 = { diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts index 564e7b225cf45..7bbf621c57894 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts @@ -26,6 +26,8 @@ import { PostBulkAgentUpgradeRequest, PostAgentUpgradeResponse, PostBulkAgentUpgradeResponse, + PostNewAgentActionRequest, + PostNewAgentActionResponse, } from '../../types'; type RequestOptions = Pick, 'pollIntervalMs'>; @@ -144,6 +146,19 @@ export function sendPostAgentUpgrade( }); } +export function sendPostAgentAction( + agentId: string, + body: PostNewAgentActionRequest['body'], + options?: RequestOptions +) { + return sendRequest({ + path: agentRouteService.getCreateActionPath(agentId), + method: 'post', + body, + ...options, + }); +} + export function sendPostBulkAgentUpgrade( body: PostBulkAgentUpgradeRequest['body'], options?: RequestOptions diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details.tsx index 5ce757734e637..1b6ad35cc6424 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details.tsx @@ -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', diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx index e033781a850a0..bbee562edf359 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx @@ -27,6 +27,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%; @@ -213,6 +214,9 @@ export const AgentLogs: React.FunctionComponent<{ agent: Agent }> = memo(({ agen /> + + + ); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/select_log_level.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/select_log_level.tsx new file mode 100644 index 0000000000000..115ff1ab80a59 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/select_log_level.tsx @@ -0,0 +1,116 @@ +/* + * 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, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import semverGte from 'semver/functions/gte'; +import { EuiSelect, EuiFormLabel, EuiButtonEmpty, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; +import { Agent } from '../../../../../types'; +import { sendPostAgentAction, useStartServices } from '../../../../../hooks'; + +export const SelectLogLevel: React.FC<{ agent: Agent }> = memo(({ agent }) => { + const agentVersion = agent.local_metadata?.elastic?.agent?.version; + const isAvailable = useMemo(() => { + return semverGte(agentVersion, '7.11.0'); + }, [agentVersion]); + + const { notifications } = useStartServices(); + const [isLoading, setIsLoading] = useState(false); + const [agentLogLevel, setAgentLogLevel] = useState( + agent.local_metadata?.elastic?.agent?.log_level ?? 'info' + ); + const [selectedLogLevel, setSelectedLogLevel] = useState(agentLogLevel); + + if (!isAvailable) { + return null; + } + + return ( + + + + + + + + { + setSelectedLogLevel(event.target.value); + }} + options={[ + { text: 'error', value: 'error' }, + { text: 'warning', value: 'warning' }, + { text: 'info', value: 'info' }, + { text: 'debug', value: 'debug' }, + ]} + /> + + {agentLogLevel !== selectedLogLevel && ( + + { + 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: 'Error', + }); + } + setIsLoading(false); + } + + send(); + }} + > + {isLoading ? ( + + ) : ( + + )} + + + )} + + ); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/types/index.ts b/x-pack/plugins/fleet/public/applications/fleet/types/index.ts index 78cb355318d40..ded1447954aff 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/types/index.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/types/index.ts @@ -67,6 +67,8 @@ export { PutAgentReassignResponse, PostBulkAgentReassignRequest, PostBulkAgentReassignResponse, + PostNewAgentActionResponse, + PostNewAgentActionRequest, // API schemas - Enrollment API Keys GetEnrollmentAPIKeysResponse, GetEnrollmentAPIKeysRequest,