diff --git a/x-pack/plugins/fleet/common/constants/locators.ts b/x-pack/plugins/fleet/common/constants/locators.ts
index daa00bcae46e0..cca0687a172d8 100644
--- a/x-pack/plugins/fleet/common/constants/locators.ts
+++ b/x-pack/plugins/fleet/common/constants/locators.ts
@@ -8,6 +8,7 @@
export const LOCATORS_IDS = {
APM_LOCATOR: 'APM_LOCATOR',
DASHBOARD_APP: 'DASHBOARD_APP_LOCATOR',
+ DISCOVER_APP_LOCATOR: 'DISCOVER_APP_LOCATOR',
} as const;
// Dashboards ids
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx
index 7824b8abd2a5c..78e32727212c9 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx
@@ -12,8 +12,6 @@ import { createFleetTestRendererMock } from '../../../../../../../mock';
import { AgentLogsUI } from './agent_logs';
-jest.mock('../../../../../../../hooks/use_authz');
-
jest.mock('@kbn/kibana-utils-plugin/public', () => {
return {
...jest.requireActual('@kbn/kibana-utils-plugin/public'),
@@ -28,6 +26,13 @@ jest.mock('@kbn/logs-shared-plugin/public', () => {
LogStream: () =>
,
};
});
+jest.mock('@kbn/logs-shared-plugin/common', () => {
+ return {
+ getLogsLocatorsFromUrlService: jest.fn().mockReturnValue({
+ logsLocator: { getRedirectUrl: jest.fn(() => 'https://discover-redirect-url') },
+ }),
+ };
+});
jest.mock('@kbn/shared-ux-link-redirect-app', () => {
return {
@@ -52,6 +57,13 @@ jest.mock('../../../../../hooks', () => {
...jest.requireActual('../../../../../hooks'),
useLink: jest.fn(),
useStartServices: jest.fn(),
+ useAuthz: jest.fn(),
+ useDiscoverLocator: jest.fn().mockImplementation(() => {
+ return {
+ id: 'DISCOVER_APP_LOCATOR',
+ getRedirectUrl: jest.fn().mockResolvedValue('app/discover/logs/someview'),
+ };
+ }),
};
});
@@ -62,6 +74,7 @@ describe('AgentLogsUI', () => {
jest.mocked(useAuthz).mockReturnValue({
fleet: {
allAgents: true,
+ readAgents: true,
},
} as any);
});
@@ -100,34 +113,36 @@ describe('AgentLogsUI', () => {
},
},
},
- http: {
- basePath: {
- prepend: (url: string) => 'http://localhost:5620' + url,
+ share: {
+ url: {
+ locators: {
+ get: () => ({
+ useUrl: () => 'https://locator.url',
+ }),
+ },
},
},
- cloud: {
- isServerlessEnabled,
- },
});
};
- it('should render Open in Logs UI if capabilities not set', () => {
+ it('should render Open in Logs button if privileges are set', () => {
mockStartServices();
const result = renderComponent();
expect(result.getByTestId('viewInLogsBtn')).toHaveAttribute(
'href',
- `http://localhost:5620/app/logs/stream?logPosition=(end%3A'2023-20-04T14%3A20%3A00.340Z'%2Cstart%3A'2023-20-04T14%3A00%3A00.340Z'%2CstreamLive%3A!f)&logFilter=(expression%3A'elastic_agent.id%3Aagent1%20and%20(data_stream.dataset%3Aelastic_agent)%20and%20(log.level%3Ainfo%20or%20log.level%3Aerror)'%2Ckind%3Akuery)`
+ `https://discover-redirect-url`
);
});
- it('should render Open in Discover if serverless enabled', () => {
- mockStartServices(true);
+ it('should not render Open in Logs button if privileges are not set', () => {
+ jest.mocked(useAuthz).mockReturnValue({
+ fleet: {
+ readAgents: false,
+ },
+ } as any);
+ mockStartServices();
const result = renderComponent();
- const viewInDiscover = result.getByTestId('viewInDiscoverBtn');
- expect(viewInDiscover).toHaveAttribute(
- 'href',
- `http://localhost:5620/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:'2023-20-04T14:00:00.340Z',to:'2023-20-04T14:20:00.340Z'))&_a=(columns:!(event.dataset,message),index:'logs-*',query:(language:kuery,query:'elastic_agent.id:agent1 and (data_stream.dataset:elastic_agent) and (log.level:info or log.level:error)'))`
- );
+ expect(result.queryByTestId('viewInLogsBtn')).not.toBeInTheDocument();
});
it('should show log level dropdown with correct value', () => {
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx
index 34cc206967d62..5a9bfecd22144 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx
@@ -35,7 +35,7 @@ import { LogLevelFilter } from './filter_log_level';
import { LogQueryBar } from './query_bar';
import { buildQuery } from './build_query';
import { SelectLogLevel } from './select_log_level';
-import { ViewLogsButton } from './view_logs_button';
+import { ViewLogsButton, getFormattedRange } from './view_logs_button';
const WrapperFlexGroup = styled(EuiFlexGroup)`
height: 100%;
@@ -112,9 +112,8 @@ const AgentPolicyLogsNotEnabledCallout: React.FunctionComponent<{ agentPolicy: A
export const AgentLogsUI: React.FunctionComponent = memo(
({ agent, agentPolicy, state }) => {
- const { data, application, cloud } = useStartServices();
+ const { data, application } = useStartServices();
const { update: updateState } = AgentLogsUrlStateHelper.useTransitions();
- const isLogsUIAvailable = !cloud?.isServerlessEnabled;
// Util to convert date expressions (returned by datepicker) to timestamps (used by LogStream)
const getDateRangeTimestamps = useCallback(
@@ -321,10 +320,9 @@ export const AgentLogsUI: React.FunctionComponent = memo(
}}
>
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/view_logs_button.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/view_logs_button.tsx
index 762c34ad7bc36..7b859596987c0 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/view_logs_button.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/view_logs_button.tsx
@@ -5,81 +5,61 @@
* 2.0.
*/
-import url from 'url';
-import { stringify } from 'querystring';
-
import React, { useMemo } from 'react';
-import { encode } from '@kbn/rison';
import { EuiButton } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
-import { useStartServices } from '../../../../../hooks';
+import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
+
+import moment from 'moment';
+
+import { useDiscoverLocator, useStartServices, useAuthz } from '../../../../../hooks';
interface ViewLogsProps {
- viewInLogs: boolean;
logStreamQuery: string;
- startTime: string;
- endTime: string;
+ startTime: number;
+ endTime: number;
}
+export const getFormattedRange = (date: string) => new Date(date).getTime();
+
/*
- Button that takes to the Logs view Ui when that is available, otherwise fallback to the Discover UI
- The urls are built using same logStreamQuery (provided by a prop), startTime and endTime, ensuring that they'll both will target same log lines
+ Button that takes to the Logs view UI or the Discover logs, depending on what's available
+ If none is available, don't display the button at all
*/
export const ViewLogsButton: React.FunctionComponent = ({
- viewInLogs,
logStreamQuery,
startTime,
endTime,
}) => {
- const { http } = useStartServices();
+ const discoverLocator = useDiscoverLocator();
- // Generate URL to pass page state to Logs UI
- const viewInLogsUrl = useMemo(
- () =>
- http.basePath.prepend(
- url.format({
- pathname: '/app/logs/stream',
- search: stringify({
- logPosition: encode({
- start: startTime,
- end: endTime,
- streamLive: false,
- }),
- logFilter: encode({
- expression: logStreamQuery,
- kind: 'kuery',
- }),
- }),
- })
- ),
- [http.basePath, startTime, endTime, logStreamQuery]
- );
+ const { share } = useStartServices();
+ const { logsLocator } = getLogsLocatorsFromUrlService(share.url);
+ const authz = useAuthz();
- const viewInDiscoverUrl = useMemo(() => {
- const index = 'logs-*';
- const query = encode({
- query: logStreamQuery,
- language: 'kuery',
+ const logsUrl = useMemo(() => {
+ const now = moment().toISOString();
+ const oneDayAgo = moment().subtract(1, 'day').toISOString();
+ const defaultStartTime = getFormattedRange(oneDayAgo);
+ const defaultEndTime = getFormattedRange(now);
+
+ return logsLocator.getRedirectUrl({
+ time: endTime ? endTime : defaultEndTime,
+ timeRange: {
+ startTime: startTime ? startTime : defaultStartTime,
+ endTime: endTime ? endTime : defaultEndTime,
+ },
+ filter: logStreamQuery,
});
- return http.basePath.prepend(
- `/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:'${startTime}',to:'${endTime}'))&_a=(columns:!(event.dataset,message),index:'${index}',query:${query})`
- );
- }, [logStreamQuery, http.basePath, startTime, endTime]);
+ }, [endTime, logStreamQuery, logsLocator, startTime]);
- return viewInLogs ? (
-
+ return authz.fleet.readAgents && (logsLocator || discoverLocator) ? (
+
- ) : (
-
-
-
- );
+ ) : null;
};
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/index.test.tsx
index 433cd687208fc..c649b3829a41e 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/index.test.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/index.test.tsx
@@ -11,7 +11,7 @@ import { act, render, fireEvent } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { useActionStatus } from '../../hooks';
-import { useGetAgentPolicies, useStartServices } from '../../../../../hooks';
+import { useGetAgentPolicies, useStartServices, useAuthz } from '../../../../../hooks';
import { AgentActivityFlyout } from '.';
@@ -25,6 +25,15 @@ jest.mock('@kbn/shared-ux-link-redirect-app', () => ({
const mockUseActionStatus = useActionStatus as jest.Mock;
const mockUseGetAgentPolicies = useGetAgentPolicies as jest.Mock;
const mockUseStartServices = useStartServices as jest.Mock;
+const mockedUseAuthz = useAuthz as jest.Mock;
+
+jest.mock('@kbn/logs-shared-plugin/common', () => {
+ return {
+ getLogsLocatorsFromUrlService: jest.fn().mockReturnValue({
+ logsLocator: { getRedirectUrl: jest.fn(() => 'https://discover-redirect-url') },
+ }),
+ };
+});
describe('AgentActivityFlyout', () => {
const mockOnClose = jest.fn();
@@ -65,7 +74,22 @@ describe('AgentActivityFlyout', () => {
docLinks: { links: { fleet: { upgradeElasticAgent: 'https://elastic.co' } } },
application: { navigateToUrl: jest.fn() },
http: { basePath: { prepend: jest.fn() } },
+ share: {
+ url: {
+ locators: {
+ get: () => ({
+ useUrl: () => 'https://locator.url',
+ }),
+ },
+ },
+ },
});
+ mockedUseAuthz.mockReturnValue({
+ fleet: {
+ readAgents: true,
+ allAgents: true,
+ },
+ } as any);
});
beforeEach(() => {
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.test.tsx
index b5018f812da4e..e8f73eae3a2b9 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.test.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.test.tsx
@@ -12,7 +12,7 @@ import { I18nProvider } from '@kbn/i18n-react';
import type { ActionStatus } from '../../../../../../../common/types';
-import { useStartServices } from '../../../../hooks';
+import { useStartServices, useAuthz } from '../../../../hooks';
import { ViewErrors } from './view_errors';
@@ -21,6 +21,13 @@ jest.mock('../../../../hooks', () => {
...jest.requireActual('../../../../hooks'),
useLink: jest.fn(),
useStartServices: jest.fn(),
+ useAuthz: jest.fn(),
+ useDiscoverLocator: jest.fn().mockImplementation(() => {
+ return {
+ id: 'DISCOVER_APP_LOCATOR',
+ getRedirectUrl: jest.fn().mockResolvedValue('app/discover/logs/someview'),
+ };
+ }),
};
});
@@ -32,6 +39,14 @@ jest.mock('@kbn/shared-ux-link-redirect-app', () => ({
},
}));
+jest.mock('@kbn/logs-shared-plugin/common', () => {
+ return {
+ getLogsLocatorsFromUrlService: jest.fn().mockReturnValue({
+ logsLocator: { getRedirectUrl: jest.fn(() => 'https://discover-redirect-url') },
+ }),
+ };
+});
+
const mockStartServices = (isServerlessEnabled?: boolean) => {
mockUseStartServices.mockReturnValue({
application: {},
@@ -47,18 +62,27 @@ const mockStartServices = (isServerlessEnabled?: boolean) => {
},
},
},
- http: {
- basePath: {
- prepend: (url: string) => 'http://localhost:5620' + url,
+ share: {
+ url: {
+ locators: {
+ get: () => ({
+ useUrl: () => 'https://locator.url',
+ }),
+ },
},
},
- cloud: {
- isServerlessEnabled,
- },
});
};
describe('ViewErrors', () => {
+ beforeEach(() => {
+ jest.mocked(useAuthz).mockReturnValue({
+ fleet: {
+ allAgents: true,
+ readAgents: true,
+ },
+ } as any);
+ });
const renderComponent = (action: ActionStatus) => {
return render(
@@ -67,7 +91,7 @@ describe('ViewErrors', () => {
);
};
- it('should render error message with btn to Logs view if serverless not enabled', () => {
+ it('should render error message with btn to Logs view', () => {
mockStartServices();
const result = renderComponent({
actionId: 'action1',
@@ -82,15 +106,32 @@ describe('ViewErrors', () => {
const errorText = result.getByTestId('errorText');
expect(errorText.textContent).toEqual('Agent agent1 is not upgradeable');
+ });
+
+ it('should render open in Logs button if correct privileges are set', () => {
+ mockStartServices();
+ const result = renderComponent({
+ actionId: 'action1',
+ latestErrors: [
+ {
+ agentId: 'agent1',
+ error: 'Agent agent1 is not upgradeable',
+ timestamp: '2023-03-06T14:51:24.709Z',
+ },
+ ],
+ } as any);
const viewErrorBtn = result.getByTestId('viewInLogsBtn');
- expect(viewErrorBtn.getAttribute('href')).toEqual(
- `http://localhost:5620/app/logs/stream?logPosition=(end%3A'2023-03-06T14%3A56%3A24.709Z'%2Cstart%3A'2023-03-06T14%3A46%3A24.709Z'%2CstreamLive%3A!f)&logFilter=(expression%3A'elastic_agent.id%3Aagent1%20and%20(data_stream.dataset%3Aelastic_agent)%20and%20(log.level%3Aerror)'%2Ckind%3Akuery)`
- );
+ expect(viewErrorBtn.getAttribute('href')).toEqual(`https://discover-redirect-url`);
});
- it('should render error message with btn to Discover view if serverless enabled', () => {
- mockStartServices(true);
+ it('should not render open in Logs button if privileges are not set', () => {
+ jest.mocked(useAuthz).mockReturnValue({
+ fleet: {
+ readAgents: false,
+ },
+ } as any);
+ mockStartServices();
const result = renderComponent({
actionId: 'action1',
latestErrors: [
@@ -102,12 +143,6 @@ describe('ViewErrors', () => {
],
} as any);
- const errorText = result.getByTestId('errorText');
- expect(errorText.textContent).toEqual('Agent agent1 is not upgradeable');
-
- const viewErrorBtn = result.getByTestId('viewInDiscoverBtn');
- expect(viewErrorBtn.getAttribute('href')).toEqual(
- `http://localhost:5620/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:'2023-03-06T14:46:24.709Z',to:'2023-03-06T14:56:24.709Z'))&_a=(columns:!(event.dataset,message),index:'logs-*',query:(language:kuery,query:'elastic_agent.id:agent1 and (data_stream.dataset:elastic_agent) and (log.level:error)'))`
- );
+ expect(result.queryByTestId('viewInLogsBtn')).not.toBeInTheDocument();
});
});
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx
index 4d43c9a60a618..e73d7778d1405 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx
@@ -17,7 +17,10 @@ import { i18n } from '@kbn/i18n';
import type { ActionErrorResult } from '../../../../../../../common/types';
import { buildQuery } from '../../agent_details_page/components/agent_logs/build_query';
-import { ViewLogsButton } from '../../agent_details_page/components/agent_logs/view_logs_button';
+import {
+ ViewLogsButton,
+ getFormattedRange,
+} from '../../agent_details_page/components/agent_logs/view_logs_button';
import type { ActionStatus } from '../../../../types';
import { useStartServices } from '../../../../hooks';
@@ -30,11 +33,12 @@ const TruncatedEuiText = styled(EuiText)`
export const ViewErrors: React.FunctionComponent<{ action: ActionStatus }> = ({ action }) => {
const coreStart = useStartServices();
- const isLogsUIAvailable = !coreStart.cloud?.isServerlessEnabled;
- const getLogsButton = (agentId: string, timestamp: string, viewInLogs: boolean) => {
- const startTime = moment(timestamp).subtract(5, 'm').toISOString();
- const endTime = moment(timestamp).add(5, 'm').toISOString();
+ const getLogsButton = (agentId: string, timestamp: string) => {
+ const start = moment(timestamp).subtract(5, 'm').toISOString();
+ const end = moment(timestamp).add(5, 'm').toISOString();
+ const startTime = getFormattedRange(start);
+ const endTime = getFormattedRange(end);
const logStreamQuery = buildQuery({
agentId,
@@ -43,12 +47,7 @@ export const ViewErrors: React.FunctionComponent<{ action: ActionStatus }> = ({
userQuery: '',
});
return (
-
+
);
};
@@ -86,7 +85,7 @@ export const ViewErrors: React.FunctionComponent<{ action: ActionStatus }> = ({
const errorItem = (action.latestErrors ?? []).find((item) => item.agentId === agentId);
return (
- {getLogsButton(agentId, errorItem!.timestamp, !!isLogsUIAvailable)}
+ {getLogsButton(agentId, errorItem!.timestamp)}
);
},
diff --git a/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx b/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx
index 26668c4062981..09a101ef85b8f 100644
--- a/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx
+++ b/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx
@@ -17,6 +17,7 @@ export const CustomLogsAssetsExtension: PackageAssetsComponent = () => {
const { http, cloud } = useStartServices();
const isLogsUIAvailable = !cloud?.isServerlessEnabled;
// if logs ui is not available, link to discover
+ // TODO: move away from hardcoded link and use locators instead
const logStreamUrl = isLogsUIAvailable
? http.basePath.prepend('/app/logs/stream')
: http.basePath.prepend('/app/discover');
diff --git a/x-pack/plugins/fleet/public/hooks/use_locator.ts b/x-pack/plugins/fleet/public/hooks/use_locator.ts
index a3fed97679456..25a673b694670 100644
--- a/x-pack/plugins/fleet/public/hooks/use_locator.ts
+++ b/x-pack/plugins/fleet/public/hooks/use_locator.ts
@@ -21,3 +21,7 @@ export function useLocator(
export function useDashboardLocator() {
return useLocator(LOCATORS_IDS.DASHBOARD_APP);
}
+
+export function useDiscoverLocator() {
+ return useLocator(LOCATORS_IDS.DISCOVER_APP_LOCATOR);
+}
diff --git a/x-pack/plugins/fleet/tsconfig.json b/x-pack/plugins/fleet/tsconfig.json
index 8986527bed977..b45bd90010b42 100644
--- a/x-pack/plugins/fleet/tsconfig.json
+++ b/x-pack/plugins/fleet/tsconfig.json
@@ -64,7 +64,6 @@
"@kbn/utility-types-jest",
"@kbn/es-query",
"@kbn/ui-theme",
- "@kbn/rison",
"@kbn/config-schema",
"@kbn/telemetry-plugin",
"@kbn/task-manager-plugin",
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index 00eb8d11923b2..76b86d0e4ebcf 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -17675,7 +17675,6 @@
"xpack.fleet.agentLogs.downloadLink": "télécharger",
"xpack.fleet.agentLogs.logDisabledCallOutTitle": "La collecte de logs est désactivée",
"xpack.fleet.agentLogs.logLevelSelectText": "Niveau du log",
- "xpack.fleet.agentLogs.openInDiscoverUiLinkText": "Ouvrir dans Discover",
"xpack.fleet.agentLogs.openInLogsUiLinkText": "Ouvrir dans Logs",
"xpack.fleet.agentLogs.searchPlaceholderText": "Rechercher dans les logs…",
"xpack.fleet.agentLogs.selectLogLevel.errorTitleText": "Erreur lors de la mise à jour du niveau de logging de l'agent",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 7778a86693d86..b804c21299587 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -17653,7 +17653,6 @@
"xpack.fleet.agentLogs.downloadLink": "ダウンロード",
"xpack.fleet.agentLogs.logDisabledCallOutTitle": "ログ収集は無効です",
"xpack.fleet.agentLogs.logLevelSelectText": "ログレベル",
- "xpack.fleet.agentLogs.openInDiscoverUiLinkText": "Discoverで開く",
"xpack.fleet.agentLogs.openInLogsUiLinkText": "ログで開く",
"xpack.fleet.agentLogs.searchPlaceholderText": "ログを検索…",
"xpack.fleet.agentLogs.selectLogLevel.errorTitleText": "エージェントログレベルの更新エラー",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 0257b4d2830a4..a99b98be1df3e 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -17682,7 +17682,6 @@
"xpack.fleet.agentLogs.downloadLink": "下载",
"xpack.fleet.agentLogs.logDisabledCallOutTitle": "日志收集已禁用",
"xpack.fleet.agentLogs.logLevelSelectText": "日志级别",
- "xpack.fleet.agentLogs.openInDiscoverUiLinkText": "在 Discover 中打开",
"xpack.fleet.agentLogs.openInLogsUiLinkText": "在日志中打开",
"xpack.fleet.agentLogs.searchPlaceholderText": "搜索日志……",
"xpack.fleet.agentLogs.selectLogLevel.errorTitleText": "更新代理日志记录级别时出错",