Skip to content

Commit

Permalink
[Infra][APM] Fix uptime links display condition in Infra and APM (#18…
Browse files Browse the repository at this point in the history
…1425)

closes [#178714](#178714)

## Summary

This PR changes where link to legacy uptime is displayed to
conditionally show it according to whether the plugin is enabled or not.

<img width="962" alt="image"
src="https://github.com/elastic/kibana/assets/2767137/e2e659ae-bc2e-49a6-a34b-9434f04b4617">

<img width="962" alt="image"
src="https://github.com/elastic/kibana/assets/2767137/4aa487f5-4a61-4387-a9ed-12c9ed624410">


### How to test

The issue and the fix are the same in serverless and stateful

#### APM 
- Run
```
node scripts/synthtrace simple_trace.ts --from=now-15m --to=now --clean --target=http://elastic_serverless:changeme@localhost:9200 --kibana=http://elastic_serverless:changeme@0.0.0.0:5601
```
- Navigate to APM > Traces, click on "Investigate" 
- if `xpack.legacy_uptime.enabled: false` in kibana.yml - "Status"
**should** appear
- if `xpack.legacy_uptime.enabled: false` in kibana.yml - "Status"
**should not** appear
- if `xpack.legacy_uptime.enabled: false` and `xpack.uptime.enabled:
true` in kibana.yml - "Status" **should not** appear
- if `observability:enableLegacyUptimeApp` is switched on in Advanced
settings - "Status" **should** appear

#### Infra 
- Start a local kibana instance pointing to an oblt cluster
- Navigate to Infrastructure, select `Kubernetes Pod` (other asset
types, except hosts, share the same code) in `Show` dropdown
- if `xpack.legacy_uptime.enabled: false` in kibana.yml - the link
should be **enabled**
- if `xpack.legacy_uptime.enabled: false` in kibana.yml - the link to
uptime should be **disabled**
- if `xpack.legacy_uptime.enabled: false` and `xpack.uptime.enabled:
true` in kibana.yml - the link to uptime should be **disabled**
- if `observability:enableLegacyUptimeApp` is switched on in Advanced
settings - the link to uptime should be **enabled**

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
crespocarlos and kibanamachine committed Apr 29, 2024
1 parent 4d55e52 commit 694acf7
Show file tree
Hide file tree
Showing 13 changed files with 167 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ export type ApmFields = Fields<{
span: { id: string };
}>;
'url.original': string;
'url.domain': string;
}> &
ApmApplicationMetricFields &
ExperimentalFields;
Expand Down
3 changes: 3 additions & 0 deletions packages/kbn-apm-synthtrace/src/scenarios/simple_trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ const scenario: Scenario<ApmFields> = async (runOptions) => {
instance
.transaction({ transactionName })
.timestamp(timestamp)
.defaults({
'url.domain': 'foo.bar',
})
.duration(1000)
.success()
.children(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,26 @@ import { IBasePath } from '@kbn/core/public';
import { Transaction } from '../../../../typings/es_schemas/ui/transaction';
import { getSections } from './sections';
import { apmRouter as apmRouterBase, ApmRouter } from '../../routing/apm_route_config';
import {
logsLocatorsMock,
observabilityLogsExplorerLocatorsMock,
} from '../../../context/apm_plugin/mock_apm_plugin_context';
import { logsLocatorsMock } from '../../../context/apm_plugin/mock_apm_plugin_context';
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';

const apmRouter = {
...apmRouterBase,
link: (...args: [any]) => `some-basepath/app/apm${apmRouterBase.link(...args)}`,
} as ApmRouter;

const { allDatasetsLocator } = observabilityLogsExplorerLocatorsMock;
const { nodeLogsLocator, traceLogsLocator } = logsLocatorsMock;
const uptimeLocator = sharePluginMock.createLocator();

const expectLogsLocatorsToBeCalled = () => {
expect(nodeLogsLocator.getRedirectUrl).toBeCalledTimes(3);
expect(traceLogsLocator.getRedirectUrl).toBeCalledTimes(1);
};

const expectUptimeLocatorToBeCalled = () => {
expect(uptimeLocator.getRedirectUrl).toBeCalledTimes(1);
};

describe('Transaction action menu', () => {
const basePath = {
prepend: (url: string) => {
Expand Down Expand Up @@ -60,8 +62,8 @@ describe('Transaction action menu', () => {
basePath,
location,
apmRouter,
allDatasetsLocator,
logsLocators: logsLocatorsMock,
uptimeLocator,
infraLinksAvailable: false,
rangeFrom: 'now-24h',
rangeTo: 'now',
Expand Down Expand Up @@ -110,6 +112,7 @@ describe('Transaction action menu', () => {
},
],
]);
expectUptimeLocatorToBeCalled();
expectLogsLocatorsToBeCalled();
});

Expand All @@ -127,7 +130,7 @@ describe('Transaction action menu', () => {
basePath,
location,
apmRouter,
allDatasetsLocator,
uptimeLocator,
logsLocators: logsLocatorsMock,
infraLinksAvailable: true,
rangeFrom: 'now-24h',
Expand Down Expand Up @@ -195,6 +198,7 @@ describe('Transaction action menu', () => {
},
],
]);
expectUptimeLocatorToBeCalled();
expectLogsLocatorsToBeCalled();
});

Expand All @@ -212,7 +216,7 @@ describe('Transaction action menu', () => {
basePath,
location,
apmRouter,
allDatasetsLocator,
uptimeLocator,
logsLocators: logsLocatorsMock,
infraLinksAvailable: true,
rangeFrom: 'now-24h',
Expand Down Expand Up @@ -280,6 +284,7 @@ describe('Transaction action menu', () => {
},
],
]);
expectUptimeLocatorToBeCalled();
expectLogsLocatorsToBeCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,16 @@ import { Location } from 'history';
import { IBasePath } from '@kbn/core/public';
import { isEmpty, pickBy } from 'lodash';
import moment from 'moment';
import url from 'url';
import type { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
import { LocatorPublic } from '@kbn/share-plugin/common';
import { AllDatasetsLocatorParams } from '@kbn/deeplinks-observability/locators';
import type { ProfilingLocators } from '@kbn/observability-shared-plugin/public';
import { LocatorPublic } from '@kbn/share-plugin/common';
import { SerializableRecord } from '@kbn/utility-types';
import { Environment } from '../../../../common/environment_rt';
import type { Transaction } from '../../../../typings/es_schemas/ui/transaction';
import { getDiscoverHref } from '../links/discover_links/discover_link';
import { getDiscoverQuery } from '../links/discover_links/discover_transaction_link';
import { getInfraHref } from '../links/infra_link';
import { fromQuery } from '../links/url_helpers';
import { SectionRecord, getNonEmptySections, Action } from './sections_helper';
import { HOST_NAME, TRACE_ID } from '../../../../common/es_fields/apm';
import { ApmRouter } from '../../routing/apm_route_config';
Expand All @@ -42,11 +40,11 @@ export const getSections = ({
location,
apmRouter,
infraLinksAvailable,
uptimeLocator,
profilingLocators,
rangeFrom,
rangeTo,
environment,
allDatasetsLocator,
logsLocators,
dataViewId,
}: {
Expand All @@ -55,11 +53,11 @@ export const getSections = ({
location: Location;
apmRouter: ApmRouter;
infraLinksAvailable: boolean;
uptimeLocator?: LocatorPublic<SerializableRecord>;
profilingLocators?: ProfilingLocators;
rangeFrom: string;
rangeTo: string;
environment: Environment;
allDatasetsLocator: LocatorPublic<AllDatasetsLocatorParams>;
logsLocators: ReturnType<typeof getLogsLocatorsFromUrlService>;
dataViewId?: string;
}) => {
Expand All @@ -72,19 +70,16 @@ export const getSections = ({
const time = Math.round(transaction.timestamp.us / 1000);
const infraMetricsQuery = getInfraMetricsQuery(transaction);

const uptimeLink = url.format({
pathname: basePath.prepend('/app/uptime'),
search: `?${fromQuery(
pickBy(
{
dateRangeStart: rangeFrom,
dateRangeEnd: rangeTo,
search: `url.domain:"${transaction.url?.domain}"`,
},
(val) => !isEmpty(val)
)
)}`,
});
const uptimeLink = uptimeLocator?.getRedirectUrl(
pickBy(
{
dateRangeStart: rangeFrom,
dateRangeEnd: rangeTo,
search: `url.domain:"${transaction.url?.domain}"`,
},
(val) => !isEmpty(val)
)
);

// Logs hrefs
const podLogsHref = logsLocators.nodeLogsLocator.getRedirectUrl({
Expand Down Expand Up @@ -231,7 +226,7 @@ export const getSections = ({
defaultMessage: 'Status',
}),
href: uptimeLink,
condition: !!transaction.url?.domain,
condition: !!transaction.url?.domain && !!uptimeLink,
},
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import * as Transactions from './__fixtures__/mock_data';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import * as useAdHocApmDataView from '../../../hooks/use_adhoc_apm_data_view';
import { useProfilingIntegrationSetting } from '../../../hooks/use_profiling_integration_setting';
import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/common';
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';

const apmContextMock = {
...mockApmPluginContextValue,
Expand All @@ -52,6 +54,15 @@ const apmContextMock = {
if (id === TRACE_LOGS_LOCATOR_ID) {
return logsLocatorsMock.traceLogsLocator;
}
if (id === uptimeOverviewLocatorID) {
return {
...sharePluginMock.createLocator(),
getRedirectUrl: jest.fn(
() =>
'http://localhost/basepath/app/uptime?dateRangeStart=now-24h&dateRangeEnd=now&search=url.domain:%22example.com%22'
),
};
}
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,9 @@ import {
import React, { useState } from 'react';
import { useLocation } from 'react-router-dom';
import useAsync from 'react-use/lib/useAsync';
import {
AllDatasetsLocatorParams,
ALL_DATASETS_LOCATOR_ID,
} from '@kbn/deeplinks-observability/locators';
import type { ProfilingLocators } from '@kbn/observability-shared-plugin/public';
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/common';
import { useAnyOfApmParams } from '../../../hooks/use_apm_params';
import { ApmFeatureFlagName } from '../../../../common/apm_feature_flags';
import { Transaction } from '../../../../typings/es_schemas/ui/transaction';
Expand Down Expand Up @@ -124,10 +121,10 @@ function ActionMenuSections({
const apmRouter = useApmRouter();
const { dataView } = useAdHocApmDataView();

const allDatasetsLocator =
share.url.locators.get<AllDatasetsLocatorParams>(ALL_DATASETS_LOCATOR_ID)!;
const logsLocators = getLogsLocatorsFromUrlService(share.url);

const uptimeLocator = share.url.locators.get(uptimeOverviewLocatorID);

const infraLinksAvailable = useApmFeatureFlag(ApmFeatureFlagName.InfraUiAvailable);

const {
Expand All @@ -145,11 +142,11 @@ function ActionMenuSections({
location,
apmRouter,
infraLinksAvailable,
uptimeLocator,
profilingLocators,
rangeFrom,
rangeTo,
environment,
allDatasetsLocator,
logsLocators,
dataViewId: dataView?.id,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
import { findInventoryModel, findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/common';
import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana';
import { AlertFlyout } from '../../../../../alerting/inventory/components/alert_flyout';
import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib';
Expand All @@ -46,6 +47,7 @@ export const NodeContextMenu: React.FC<Props & { theme?: EuiTheme }> = withTheme
const { services } = useKibanaContextForPlugin();
const { application, share } = services;
const { nodeLogsLocator } = getLogsLocatorsFromUrlService(share.url);
const uptimeLocator = share.url.locators.get(uptimeOverviewLocatorID);
const uiCapabilities = application?.capabilities;
// Due to the changing nature of the fields between APM and this UI,
// We need to have some exceptions until 7.0 & ECS is finalized. Reference
Expand All @@ -60,7 +62,8 @@ export const NodeContextMenu: React.FC<Props & { theme?: EuiTheme }> = withTheme
inventoryModel.crosslinkSupport.apm && uiCapabilities?.apm && uiCapabilities?.apm.show;
const showUptimeLink =
inventoryModel.crosslinkSupport.uptime &&
(['pod', 'container'].includes(nodeType) || node.ip);
(['pod', 'container'].includes(nodeType) || node.ip) &&
!!uptimeLocator;
const showCreateAlertLink = uiCapabilities?.infrastructure?.save;

const inventoryId = useMemo(() => {
Expand Down Expand Up @@ -144,7 +147,7 @@ export const NodeContextMenu: React.FC<Props & { theme?: EuiTheme }> = withTheme
defaultMessage: '{inventoryName} in Uptime',
values: { inventoryName: inventoryModel.singularDisplayName },
}),
onClick: () => navigateToUptime(share.url.locators, nodeType, node),
onClick: () => (showUptimeLink ? navigateToUptime({ uptimeLocator, nodeType, node }) : {}),
isDisabled: !showUptimeLink,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
* 2.0.
*/

import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/public';
import { LocatorClient } from '@kbn/share-plugin/common/url_service/locators';
import { LocatorPublic } from '@kbn/share-plugin/common/url_service/locators';
import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
import { SerializableRecord } from '@kbn/utility-types';
import { InfraWaffleMapNode } from '../../../../lib/lib';

export const navigateToUptime = (
locators: LocatorClient,
nodeType: InventoryItemType,
node: InfraWaffleMapNode
) => {
return locators.get(uptimeOverviewLocatorID)!.navigate({ [nodeType]: node.id, ip: node.ip });
export const navigateToUptime = ({
uptimeLocator,
nodeType,
node,
}: {
uptimeLocator: LocatorPublic<SerializableRecord>;
nodeType: InventoryItemType;
node: InfraWaffleMapNode;
}) => {
return uptimeLocator.navigate({ [nodeType]: node.id, ip: node.ip });
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@
*/
import { LocatorPublic } from '@kbn/share-plugin/public';
import { SerializableRecord } from '@kbn/utility-types';
import { uptimeOverviewNavigatorParams } from './overview';
import { monitorDetailNavigatorParams } from './monitor_detail';
import { editMonitorNavigatorParams } from './edit_monitor';
import { syntheticsSettingsNavigatorParams } from './settings';

export const locators: Array<Pick<LocatorPublic<SerializableRecord>, 'id' | 'getLocation'>> = [
uptimeOverviewNavigatorParams,
monitorDetailNavigatorParams,
editMonitorNavigatorParams,
syntheticsSettingsNavigatorParams,
Expand Down

This file was deleted.

0 comments on commit 694acf7

Please sign in to comment.