From 107075c94fb713ade8f9386edb3745f755f58ba7 Mon Sep 17 00:00:00 2001 From: Dominique Clarke Date: Sun, 26 May 2024 09:36:57 -0400 Subject: [PATCH] [Obs Alerting] View in apm button - add defensive code (#184236) ## Summary Resolves https://github.com/elastic/kibana/issues/184204 The page can break when the share plugin is undefined. This PR adds defensive code to prevent errors when `share` is undefined. ![image](https://github.com/elastic/kibana/assets/11356435/538a73e1-e8b5-4743-8a01-f723695dcf86) ![image](https://github.com/elastic/kibana/assets/11356435/4a3a606e-4aa0-4aed-a644-83cdf3965dbd) ### Testing Generate some mock APM data with ```node scripts/synthtrace.js simple_trace --live``` Create an APM latency rule Wait for the rule to be triggered, then navigate to the alert details page The alert details page should load properly --- .../src/lib/apm/instance.ts | 1 - .../05_transactions_with_errors.test.ts | 7 +-- .../cypress/e2e/errors/error_details.cy.ts | 4 +- .../view_in_apm_button.test.tsx | 49 +++++++++++++++++++ .../view_in_apm_button.tsx | 5 +- .../storage_explorer/indices_stats_helpers.ts | 2 +- 6 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/view_in_apm_button.test.tsx diff --git a/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts b/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts index 991e5e40b6340..4b3cfde40825c 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts @@ -76,7 +76,6 @@ export class Instance extends Entity { return new ApmError({ ...this.fields, 'error.exception': [{ message, ...(type ? { type } : {}) }], - 'error.grouping_name': getErrorGroupingKey(message), 'error.culprit': culprit, }); } diff --git a/packages/kbn-apm-synthtrace/src/test/scenarios/05_transactions_with_errors.test.ts b/packages/kbn-apm-synthtrace/src/test/scenarios/05_transactions_with_errors.test.ts index a8848c1954e40..43b924d9d8a18 100644 --- a/packages/kbn-apm-synthtrace/src/test/scenarios/05_transactions_with_errors.test.ts +++ b/packages/kbn-apm-synthtrace/src/test/scenarios/05_transactions_with_errors.test.ts @@ -60,11 +60,6 @@ describe('transactions with errors', () => { .errors(instance.error({ message: 'test error' }).timestamp(timestamp)) .serialize(); - expect(error['error.grouping_name']).toEqual( - '4274b1899eba687801198c89f64a3fdade080a475c8a54881ba8fa10e7f45691' - ); - expect(error['error.grouping_key']).toMatchInlineSnapshot( - `"4274b1899eba687801198c89f64a3fdade080a475c8a54881ba8fa10e7f45691"` - ); + expect(error['error.grouping_key']).toMatchInlineSnapshot(`"0000000000000000000000test error"`); }); }); diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/errors/error_details.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/errors/error_details.cy.ts index d470202d9f041..e61762629a537 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/errors/error_details.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/errors/error_details.cy.ts @@ -6,6 +6,8 @@ */ import { getErrorGroupingKey } from '@kbn/apm-synthtrace-client/src/lib/apm/instance'; +import { generateLongId } from '@kbn/apm-synthtrace-client/src/lib/utils/generate_id'; + import url from 'url'; import { synthtrace } from '../../../synthtrace'; import { checkA11y } from '../../support/commands'; @@ -69,7 +71,7 @@ describe('Error details', () => { }); describe('when error has data', () => { - const errorGroupingKey = getErrorGroupingKey('Error 1'); + const errorGroupingKey = generateLongId('Error 1'); const errorGroupingKeyShort = errorGroupingKey.slice(0, 5); const errorDetailsPageHref = url.format({ pathname: `/app/apm/services/opbeans-java/errors/${errorGroupingKey}`, diff --git a/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/view_in_apm_button.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/view_in_apm_button.test.tsx new file mode 100644 index 0000000000000..703f4324238ba --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/view_in_apm_button.test.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { render } from '@testing-library/react'; +import { ViewInAPMButton } from './view_in_apm_button'; +import * as apmContext from '../../../../context/apm_plugin/use_apm_plugin_context'; + +describe('ViewInApmButton', () => { + const config = { + serviceName: 'testService', + environment: 'testEnvironment', + transactionName: 'testTransaction', + transactionType: 'testTransactionType', + from: 'now-15m', + to: 'now', + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('hides button when share plugin is not available', () => { + const { queryByText } = render(); + + expect(queryByText('View in APM')).not.toBeInTheDocument(); + }); + + it('reners correctly', () => { + jest.spyOn(apmContext, 'useApmPluginContext').mockReturnValue({ + share: { + url: { + locators: { + // @ts-ignore + get: () => ({ + navigate: jest.fn(), + }), + }, + }, + }, + }); + const { getByText } = render(); + + expect(getByText('View in APM')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/view_in_apm_button.tsx b/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/view_in_apm_button.tsx index ac67359d64568..f8935a4082ded 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/view_in_apm_button.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/view_in_apm_button.tsx @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -/* Error Rate */ import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -29,8 +28,8 @@ export function ViewInAPMButton({ to: string; kuery?: string; }) { - const { share } = useApmPluginContext(); - const serviceNavigator = share.url.locators.get(APM_APP_LOCATOR_ID); + const { share } = useApmPluginContext() || {}; + const serviceNavigator = share?.url?.locators?.get(APM_APP_LOCATOR_ID); if (!serviceNavigator) { return null; diff --git a/x-pack/plugins/observability_solution/apm/server/routes/storage_explorer/indices_stats_helpers.ts b/x-pack/plugins/observability_solution/apm/server/routes/storage_explorer/indices_stats_helpers.ts index 3943f349e55e6..85e3dbfb97ca1 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/storage_explorer/indices_stats_helpers.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/storage_explorer/indices_stats_helpers.ts @@ -74,7 +74,7 @@ export async function getIndicesLifecycleStatus({ filter_path: 'indices.*.phase', }); - return indices; + return indices || {}; } export async function getIndicesInfo({