From 41dbdb536ef0b35d0028f4d39f553b4d2aba9fb0 Mon Sep 17 00:00:00 2001 From: Giorgos Bamparopoulos Date: Fri, 13 Dec 2024 08:53:25 +0000 Subject: [PATCH] [Stack Monitoring] Migrate logs-related components to TypeScript (#203536) A recent [bug](https://github.com/elastic/kibana/issues/199902) that affected some of the pages in Stack Monitoring was caused by changes related to the locators of the logs-related apps. The issue wasn't caught by type checks as the affected area in the monitoring plugin was written in JavaScript. The goal of this PR is to migrate the logs-related components to TypeScript. The stateful environment deployed by this PR includes logs and metrics for stack monitoring. Please make sure to select a larger time range (e.g. last 14 days). --- .../contexts/external_config_context.tsx | 1 + .../{logs.test.js.snap => logs.test.tsx.snap} | 0 ...ason.test.js.snap => reason.test.tsx.snap} | 0 .../components/logs/{index.js => index.tsx} | 0 .../logs/{logs.test.js => logs.test.tsx} | 2 +- .../components/logs/{logs.js => logs.tsx} | 65 ++++++++++++++----- .../logs/{reason.test.js => reason.test.tsx} | 0 .../components/logs/{reason.js => reason.tsx} | 32 ++++++--- .../e2e/playwright/.env | 11 ++++ .../playwright/.playwright/.auth/user.json | 41 ++++++++++++ .../e2e/playwright/.playwright/.last-run.json | 4 ++ .../.playwright/code_snippet_kubernetes.sh | 1 + 12 files changed, 128 insertions(+), 29 deletions(-) rename x-pack/plugins/monitoring/public/components/logs/__snapshots__/{logs.test.js.snap => logs.test.tsx.snap} (100%) rename x-pack/plugins/monitoring/public/components/logs/__snapshots__/{reason.test.js.snap => reason.test.tsx.snap} (100%) rename x-pack/plugins/monitoring/public/components/logs/{index.js => index.tsx} (100%) rename x-pack/plugins/monitoring/public/components/logs/{logs.test.js => logs.test.tsx} (98%) rename x-pack/plugins/monitoring/public/components/logs/{logs.js => logs.tsx} (82%) rename x-pack/plugins/monitoring/public/components/logs/{reason.test.js => reason.test.tsx} (100%) rename x-pack/plugins/monitoring/public/components/logs/{reason.js => reason.tsx} (88%) create mode 100644 x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.env create mode 100644 x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/.auth/user.json create mode 100644 x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/.last-run.json create mode 100644 x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/code_snippet_kubernetes.sh diff --git a/x-pack/plugins/monitoring/public/application/contexts/external_config_context.tsx b/x-pack/plugins/monitoring/public/application/contexts/external_config_context.tsx index e86262defb65..45791507fa72 100644 --- a/x-pack/plugins/monitoring/public/application/contexts/external_config_context.tsx +++ b/x-pack/plugins/monitoring/public/application/contexts/external_config_context.tsx @@ -14,6 +14,7 @@ export interface ExternalConfig { renderReactApp: boolean; staleStatusThresholdSeconds: number; isCcsEnabled: boolean; + logsIndices: string; } export const ExternalConfigContext = createContext({} as ExternalConfig); diff --git a/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap b/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.tsx.snap similarity index 100% rename from x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap rename to x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.tsx.snap diff --git a/x-pack/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap b/x-pack/plugins/monitoring/public/components/logs/__snapshots__/reason.test.tsx.snap similarity index 100% rename from x-pack/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap rename to x-pack/plugins/monitoring/public/components/logs/__snapshots__/reason.test.tsx.snap diff --git a/x-pack/plugins/monitoring/public/components/logs/index.js b/x-pack/plugins/monitoring/public/components/logs/index.tsx similarity index 100% rename from x-pack/plugins/monitoring/public/components/logs/index.js rename to x-pack/plugins/monitoring/public/components/logs/index.tsx diff --git a/x-pack/plugins/monitoring/public/components/logs/logs.test.js b/x-pack/plugins/monitoring/public/components/logs/logs.test.tsx similarity index 98% rename from x-pack/plugins/monitoring/public/components/logs/logs.test.js rename to x-pack/plugins/monitoring/public/components/logs/logs.test.tsx index 50e850400cc0..f103288a2498 100644 --- a/x-pack/plugins/monitoring/public/components/logs/logs.test.js +++ b/x-pack/plugins/monitoring/public/components/logs/logs.test.tsx @@ -29,7 +29,7 @@ const sharePlugin = { }, }, }, -}; +} as unknown as ReturnType; const logs = { enabled: true, diff --git a/x-pack/plugins/monitoring/public/components/logs/logs.js b/x-pack/plugins/monitoring/public/components/logs/logs.tsx similarity index 82% rename from x-pack/plugins/monitoring/public/components/logs/logs.js rename to x-pack/plugins/monitoring/public/components/logs/logs.tsx index ab897423ff05..b17129d90eac 100644 --- a/x-pack/plugins/monitoring/public/components/logs/logs.js +++ b/x-pack/plugins/monitoring/public/components/logs/logs.tsx @@ -8,16 +8,42 @@ import React, { PureComponent, useContext } from 'react'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { upperFirst } from 'lodash'; -import { Legacy } from '../../legacy_shims'; import { EuiBasicTable, EuiTitle, EuiSpacer, EuiText, EuiCallOut, EuiLink } from '@elastic/eui'; -import { formatDateTimeLocal } from '../../../common/formatting'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { Reason } from './reason'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { SharePluginStart } from '@kbn/share-plugin/public'; +import { Reason, type IReason } from './reason'; +import { formatDateTimeLocal } from '../../../common/formatting'; +import { Legacy } from '../../legacy_shims'; import { ExternalConfigContext } from '../../application/contexts/external_config_context'; +import { MonitoringStartServices } from '../../types'; + +interface LogsProps { + logs: { + logs?: Array<{ + timestamp: string; + component: string; + level: string; + type: string; + node: string; + message: string; + }>; + enabled: boolean; + limit: number; + reason?: IReason; + }; + nodeId?: string; + indexUuid?: string; + clusterUuid?: string; +} -const getFormattedDateTimeLocal = (timestamp) => { +interface LogsContentProps extends LogsProps { + sharePlugin: SharePluginStart; + logsIndices: string; +} + +const getFormattedDateTimeLocal = (timestamp: number | Date) => { const timezone = Legacy.shims.uiSettings?.get('dateFormat:tz'); return formatDateTimeLocal(timestamp, timezone); }; @@ -51,7 +77,7 @@ const columns = [ field: 'timestamp', name: columnTimestampTitle, width: '12%', - render: (timestamp) => getFormattedDateTimeLocal(timestamp), + render: (timestamp: number | Date) => getFormattedDateTimeLocal(timestamp), }, { field: 'level', @@ -62,7 +88,7 @@ const columns = [ field: 'type', name: columnTypeTitle, width: '10%', - render: (type) => upperFirst(type), + render: (type: string) => upperFirst(type), }, { field: 'message', @@ -81,7 +107,7 @@ const clusterColumns = [ field: 'timestamp', name: columnTimestampTitle, width: '12%', - render: (timestamp) => getFormattedDateTimeLocal(timestamp), + render: (timestamp: number | Date) => getFormattedDateTimeLocal(timestamp), }, { field: 'level', @@ -92,7 +118,7 @@ const clusterColumns = [ field: 'type', name: columnTypeTitle, width: '10%', - render: (type) => upperFirst(type), + render: (type: string) => upperFirst(type), }, { field: 'message', @@ -111,7 +137,13 @@ const clusterColumns = [ }, ]; -function getDiscoverLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndices) { +function getDiscoverLink( + clusterUuid?: string, + nodeId?: string, + indexUuid?: string, + sharePlugin?: SharePluginStart, + logsIndices?: string +) { const params = []; if (clusterUuid) { params.push(`elasticsearch.cluster.uuid:${clusterUuid}`); @@ -124,13 +156,9 @@ function getDiscoverLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndice } const filter = params.join(' and '); - const discoverLocator = sharePlugin.url.locators.get('DISCOVER_APP_LOCATOR'); + const discoverLocator = sharePlugin?.url.locators.get('DISCOVER_APP_LOCATOR'); - if (!discoverLocator) { - return; - } - - const base = discoverLocator.getRedirectUrl({ + const base = discoverLocator?.getRedirectUrl({ dataViewSpec: { id: logsIndices, title: logsIndices, @@ -144,14 +172,15 @@ function getDiscoverLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndice return base; } -export const Logs = (props) => { +export const Logs = (props: LogsProps) => { const { services: { share }, - } = useKibana(); + } = useKibana(); const externalConfig = useContext(ExternalConfigContext); return ; }; -export class LogsContent extends PureComponent { + +export class LogsContent extends PureComponent { renderLogs() { const { logs: { enabled, logs }, diff --git a/x-pack/plugins/monitoring/public/components/logs/reason.test.js b/x-pack/plugins/monitoring/public/components/logs/reason.test.tsx similarity index 100% rename from x-pack/plugins/monitoring/public/components/logs/reason.test.js rename to x-pack/plugins/monitoring/public/components/logs/reason.test.tsx diff --git a/x-pack/plugins/monitoring/public/components/logs/reason.js b/x-pack/plugins/monitoring/public/components/logs/reason.tsx similarity index 88% rename from x-pack/plugins/monitoring/public/components/logs/reason.js rename to x-pack/plugins/monitoring/public/components/logs/reason.tsx index 4444c818d5cc..82a4f788df98 100644 --- a/x-pack/plugins/monitoring/public/components/logs/reason.js +++ b/x-pack/plugins/monitoring/public/components/logs/reason.tsx @@ -12,7 +12,19 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { Legacy } from '../../legacy_shims'; import { Monospace } from '../metricbeat_migration/instruction_steps/components/monospace/monospace'; -export const Reason = ({ reason }) => { +export interface IReason { + indexPatternExists?: boolean; + indexPatternInTimeRangeExists?: boolean; + typeExists?: boolean; + typeExistsAtAnyTime?: boolean; + usingStructuredLogs?: boolean; + clusterExists?: boolean; + nodeExists?: boolean | null; + indexExists?: boolean; + correctIndexName?: boolean; +} + +export const Reason = ({ reason }: { reason?: IReason }) => { const filebeatUrl = Legacy.shims.docLinks.links.filebeat.installation; const elasticsearchUrl = Legacy.shims.docLinks.links.filebeat.elasticsearchModule; const troubleshootUrl = Legacy.shims.docLinks.links.monitoring.troubleshootKibana; @@ -36,7 +48,7 @@ export const Reason = ({ reason }) => { /> ); - if (false === reason.indexPatternExists) { + if (false === reason?.indexPatternExists) { title = i18n.translate('xpack.monitoring.logs.reason.noIndexPatternTitle', { defaultMessage: 'No log data found', }); @@ -56,8 +68,8 @@ export const Reason = ({ reason }) => { /> ); } else if ( - false === reason.indexPatternInTimeRangeExists || - (false === reason.typeExists && reason.typeExistsAtAnyTime) + false === reason?.indexPatternInTimeRangeExists || + (false === reason?.typeExists && reason.typeExistsAtAnyTime) ) { title = i18n.translate('xpack.monitoring.logs.reason.noIndexPatternInTimePeriodTitle', { defaultMessage: 'No logs for the selected time', @@ -68,7 +80,7 @@ export const Reason = ({ reason }) => { defaultMessage="Use the time filter to adjust your timeframe." /> ); - } else if (false === reason.typeExists) { + } else if (false === reason?.typeExists) { title = i18n.translate('xpack.monitoring.logs.reason.noTypeTitle', { defaultMessage: 'No logs for Elasticsearch', }); @@ -87,7 +99,7 @@ export const Reason = ({ reason }) => { }} /> ); - } else if (false === reason.usingStructuredLogs) { + } else if (false === reason?.usingStructuredLogs) { title = i18n.translate('xpack.monitoring.logs.reason.notUsingStructuredLogsTitle', { defaultMessage: 'No structured logs found', }); @@ -107,7 +119,7 @@ export const Reason = ({ reason }) => { }} /> ); - } else if (false === reason.clusterExists) { + } else if (false === reason?.clusterExists) { title = i18n.translate('xpack.monitoring.logs.reason.noClusterTitle', { defaultMessage: 'No logs for this cluster', }); @@ -126,7 +138,7 @@ export const Reason = ({ reason }) => { }} /> ); - } else if (false === reason.nodeExists) { + } else if (false === reason?.nodeExists) { title = i18n.translate('xpack.monitoring.logs.reason.noNodeTitle', { defaultMessage: 'No logs for this Elasticsearch node', }); @@ -145,7 +157,7 @@ export const Reason = ({ reason }) => { }} /> ); - } else if (false === reason.indexExists) { + } else if (false === reason?.indexExists) { title = i18n.translate('xpack.monitoring.logs.reason.noIndexTitle', { defaultMessage: 'No logs for this index', }); @@ -164,7 +176,7 @@ export const Reason = ({ reason }) => { }} /> ); - } else if (false === reason.correctIndexName) { + } else if (false === reason?.correctIndexName) { title = i18n.translate('xpack.monitoring.logs.reason.correctIndexNameTitle', { defaultMessage: 'Corrupted filebeat index', }); diff --git a/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.env b/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.env new file mode 100644 index 000000000000..79246caa38b7 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.env @@ -0,0 +1,11 @@ +KIBANA_BASE_URL = "http://localhost:5601/ftw" +ELASTICSEARCH_HOST = "http://localhost:9200" +KIBANA_USERNAME = "elastic" +KIBANA_PASSWORD = "changeme" + +# Comment this variable if running against a cloud environment +CLUSTER_ENVIRONMENT = local +# Folder that will contain all the playwright test results +# along with artifacts like code snippets that are +# picked up by Ensemble story on the CI +ARTIFACTS_FOLDER = ./.playwright diff --git a/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/.auth/user.json b/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/.auth/user.json new file mode 100644 index 000000000000..b5a8cb4389c2 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/.auth/user.json @@ -0,0 +1,41 @@ +{ + "cookies": [ + { + "name": "sid", + "value": "Fe26.2**0f6c7b5841cd939b4f7e6042e8e548a61396f6137a16a80468967d75a3c4a15d*3aO-W92cmioNifwGvMIe7w*Js9nTdolngZrFhPjTAihnf4ND08FtNYrODG00EvZrd193yWRvEVQy__7L5FZQtS1sD5LntsQMZO2gy5wPFuBKog0AXKOVIj-kxzIKtIbiUiTdLVZl2kqvmMqpYkhfFwK0SDubaMrypI14odSGRxYzAfGTL7czxDatfNdndIPTYlpkUCKKvJdTBZOQS2H3HbDlzPb71pFl7YPvQSSbdFe0frFIOytodO8JxPj2dsqIpGbZZ9mBfriiF3S6SU1ayR1DjLRMpyL32MLyOrlzJKy_w**b2cea11d4b35aa93dc79e42a09484d199a1fdac7234a01438f7dd2c084387c44*hj1VDxXhtXc4m9sC_vq_Xck3R3E8za4ramNZLcIL5pM", + "domain": "localhost", + "path": "/ftw", + "expires": -1, + "httpOnly": true, + "secure": false, + "sameSite": "Lax" + } + ], + "origins": [ + { + "origin": "http://localhost:5601", + "localStorage": [ + { + "name": "newsfeed.kibana.readStatus", + "value": "{\"235b3e1b48\":false,\"99c40b0db0\":false,\"297e88cb8d\":false}" + }, + { + "name": "analytics", + "value": "{\"reportVersion\":3,\"userAgent\":{\"kibana-user_agent\":{\"key\":\"kibana-user_agent\",\"appName\":\"kibana\",\"type\":\"user_agent\",\"userAgent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36\"}},\"uiCounter\":{\"ebt_counters.client-enqueued_enqueued-Loaded Kibana\":{\"key\":\"ebt_counters.client-enqueued_enqueued-Loaded Kibana\",\"appName\":\"ebt_counters.client\",\"eventName\":\"Loaded Kibana\",\"type\":\"enqueued_enqueued\",\"total\":1},\"ebt_counters.client-enqueued_enqueued-performance_metric\":{\"key\":\"ebt_counters.client-enqueued_enqueued-performance_metric\",\"appName\":\"ebt_counters.client\",\"eventName\":\"performance_metric\",\"type\":\"enqueued_enqueued\",\"total\":2},\"ebt_counters.client-sent_to_shipper_OK-Loaded Kibana\":{\"key\":\"ebt_counters.client-sent_to_shipper_OK-Loaded Kibana\",\"appName\":\"ebt_counters.client\",\"eventName\":\"Loaded Kibana\",\"type\":\"sent_to_shipper_OK\",\"total\":1},\"ebt_counters.client-sent_to_shipper_OK-performance_metric\":{\"key\":\"ebt_counters.client-sent_to_shipper_OK-performance_metric\",\"appName\":\"ebt_counters.client\",\"eventName\":\"performance_metric\",\"type\":\"sent_to_shipper_OK\",\"total\":2}}}" + }, + { + "name": "kibana.security.userAuthType", + "value": "{\"signature\":\"dd4be0630945f1a8be8e10baabf6536c937d053481c09e30a0703b5ce17e1fcd\",\"timestamp\":1733926278035}" + }, + { + "name": "newsfeed.kibana.lastFetch", + "value": "1733926278001" + }, + { + "name": "eui-experimental-theme-enabled", + "value": "true" + } + ] + } + ] +} \ No newline at end of file diff --git a/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/.last-run.json b/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/.last-run.json new file mode 100644 index 000000000000..cbcc1fbac11a --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/.last-run.json @@ -0,0 +1,4 @@ +{ + "status": "passed", + "failedTests": [] +} \ No newline at end of file diff --git a/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/code_snippet_kubernetes.sh b/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/code_snippet_kubernetes.sh new file mode 100644 index 000000000000..04c976eb491f --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/e2e/playwright/.playwright/code_snippet_kubernetes.sh @@ -0,0 +1 @@ +kubectl kustomize https://github.com/elastic/elastic-agent/deploy/kubernetes/elastic-agent-kustomize/default/elastic-agent-standalone\?ref\=v8.16.1 | sed -e 's/JUFQSV9LRVkl/enN3UHRwTUJRbjdEVk1laFpoZXA6ZEtrai1lRnFSUEcwYVhKbHREM2tIUQ==/g' -e "s/%ES_HOST%/http:\/\/localhost:9200/g" -e "s/%ONBOARDING_ID%/af9c9709-52da-45a8-904f-228aa2e61621/g" -e "s/\(docker.elastic.co\/beats\/elastic-agent:\).*$/\18.16.1/g" -e "/{CA_TRUSTED}/c\ " | kubectl apply -f- \ No newline at end of file