Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[APM] Explicitly set environment for cross-service links #87481

Merged
merged 10 commits into from
Jan 15, 2021
Merged
24 changes: 24 additions & 0 deletions x-pack/plugins/apm/common/environment_filter_values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,27 @@ export const ENVIRONMENT_NOT_DEFINED = {
export function getEnvironmentLabel(environment: string) {
return environmentLabels[environment] || environment;
}

// returns the environment url param that should be used
// based on the requested environment. If the requested
// environment is different from the URL parameter, we'll
// return ENVIRONMENT_ALL. If it's not, we'll just return
// the current environment URL param
export function getNextEnvironmentUrlParam({
requestedEnvironment,
currentEnvironmentUrlParam,
}: {
requestedEnvironment?: string;
currentEnvironmentUrlParam?: string;
}) {
const normalizedRequestedEnvironment =
requestedEnvironment || ENVIRONMENT_NOT_DEFINED.value;
const normalizedQueryEnvironment =
currentEnvironmentUrlParam || ENVIRONMENT_ALL.value;

if (normalizedRequestedEnvironment === normalizedQueryEnvironment) {
return currentEnvironmentUrlParam;
}

return ENVIRONMENT_ALL.value;
}
sorenlouv marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { EuiButton, EuiFlexItem, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { getNextEnvironmentUrlParam } from '../../../../../common/environment_filter_values';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { Transaction as ITransaction } from '../../../../../typings/es_schemas/ui/transaction';
import { TransactionDetailLink } from '../../../shared/Links/apm/transaction_detail_link';
Expand All @@ -20,8 +21,9 @@ export const MaybeViewTraceLink = ({
waterfall: IWaterfall;
}) => {
const {
urlParams: { latencyAggregationType },
urlParams: { environment, latencyAggregationType },
} = useUrlParams();

const viewFullTraceButtonLabel = i18n.translate(
'xpack.apm.transactionDetails.viewFullTraceButtonLabel',
{
Expand Down Expand Up @@ -73,6 +75,11 @@ export const MaybeViewTraceLink = ({

// the user is viewing a zoomed in version of the trace. Link to the full trace
} else {
const nextEnvironment = getNextEnvironmentUrlParam({
requestedEnvironment: rootTransaction?.service.environment,
currentEnvironmentUrlParam: environment,
});

return (
<EuiFlexItem grow={false}>
<TransactionDetailLink
Expand All @@ -81,6 +88,7 @@ export const MaybeViewTraceLink = ({
traceId={rootTransaction.trace.id}
transactionName={rootTransaction.transaction.name}
transactionType={rootTransaction.transaction.type}
environment={nextEnvironment}
latencyAggregationType={latencyAggregationType}
>
<EuiButton iconType="apmTrace">{viewFullTraceButtonLabel}</EuiButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { i18n } from '@kbn/i18n';
import React from 'react';
import { useUrlParams } from '../../../../../../context/url_params_context/use_url_params';
import { getNextEnvironmentUrlParam } from '../../../../../../../common/environment_filter_values';
import {
SERVICE_NAME,
TRANSACTION_NAME,
Expand All @@ -22,13 +23,18 @@ interface Props {

export function FlyoutTopLevelProperties({ transaction }: Props) {
const {
urlParams: { latencyAggregationType },
urlParams: { environment, latencyAggregationType },
} = useUrlParams();

if (!transaction) {
return null;
}

const nextEnvironment = getNextEnvironmentUrlParam({
requestedEnvironment: transaction.service.environment,
currentEnvironmentUrlParam: environment,
});

const stickyProperties = [
{
label: i18n.translate('xpack.apm.transactionDetails.serviceLabel', {
Expand All @@ -38,6 +44,7 @@ export function FlyoutTopLevelProperties({ transaction }: Props) {
val: (
<ServiceOrTransactionsOverviewLink
serviceName={transaction.service.name}
environment={nextEnvironment}
>
{transaction.service.name}
</ServiceOrTransactionsOverviewLink>
Expand All @@ -56,6 +63,7 @@ export function FlyoutTopLevelProperties({ transaction }: Props) {
traceId={transaction.trace.id}
transactionName={transaction.transaction.name}
transactionType={transaction.transaction.type}
environment={nextEnvironment}
latencyAggregationType={latencyAggregationType}
>
{transaction.transaction.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { i18n } from '@kbn/i18n';
import React from 'react';
import { useUrlParams } from '../../../../../../../context/url_params_context/use_url_params';
import { getNextEnvironmentUrlParam } from '../../../../../../../../common/environment_filter_values';
import {
SERVICE_NAME,
SPAN_NAME,
Expand All @@ -26,8 +27,14 @@ interface Props {

export function StickySpanProperties({ span, transaction }: Props) {
const {
urlParams: { latencyAggregationType },
urlParams: { environment, latencyAggregationType },
} = useUrlParams();

const nextEnvironment = getNextEnvironmentUrlParam({
requestedEnvironment: transaction?.service.environment,
currentEnvironmentUrlParam: environment,
});

const spanName = span.span.name;
const transactionStickyProperties = transaction
? [
Expand All @@ -39,6 +46,7 @@ export function StickySpanProperties({ span, transaction }: Props) {
val: (
<ServiceOrTransactionsOverviewLink
serviceName={transaction.service.name}
environment={nextEnvironment}
>
{transaction.service.name}
</ServiceOrTransactionsOverviewLink>
Expand All @@ -60,6 +68,7 @@ export function StickySpanProperties({ span, transaction }: Props) {
traceId={transaction.trace.id}
transactionName={transaction.transaction.name}
transactionType={transaction.transaction.type}
environment={nextEnvironment}
latencyAggregationType={latencyAggregationType}
>
{transaction.transaction.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values';
import {
ENVIRONMENT_ALL,
getNextEnvironmentUrlParam,
} from '../../../../../common/environment_filter_values';
import {
asMillisecondDuration,
asPercent,
Expand All @@ -40,6 +43,10 @@ interface Props {
}

export function ServiceOverviewDependenciesTable({ serviceName }: Props) {
const {
urlParams: { start, end, environment },
} = useUrlParams();

const columns: Array<EuiBasicTableColumn<ServiceDependencyItem>> = [
{
field: 'name',
Expand All @@ -64,7 +71,13 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) {
</EuiFlexItem>
<EuiFlexItem>
{item.type === 'service' ? (
<ServiceOverviewLink serviceName={item.serviceName}>
<ServiceOverviewLink
serviceName={item.serviceName}
environment={getNextEnvironmentUrlParam({
requestedEnvironment: item.environment,
currentEnvironmentUrlParam: environment,
})}
>
{item.name}
</ServiceOverviewLink>
) : (
Expand Down Expand Up @@ -154,10 +167,6 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) {
},
];

const {
urlParams: { start, end, environment },
} = useUrlParams();

const { data = [], status } = useFetcher(() => {
if (!start || !end) {
return;
Expand Down
20 changes: 14 additions & 6 deletions x-pack/plugins/apm/public/components/shared/Links/apm/APMLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,24 @@ export const PERSISTENT_APM_PARAMS: Array<keyof APMQueryParams> = [
/**
* Hook to get a link for a path with persisted filters
*/
export function useAPMHref(
path: string,
persistentFilters: Array<keyof APMQueryParams> = []
) {
export function useAPMHref({
path,
persistedFilters,
query,
}: {
path: string;
persistedFilters?: Array<keyof APMQueryParams>;
query?: APMQueryParams;
}) {
const { urlParams } = useUrlParams();
const { basePath } = useApmPluginContext().core.http;
const { search } = useLocation();
const query = pickKeys(urlParams as APMQueryParams, ...persistentFilters);
const nextQuery = {
...pickKeys(urlParams as APMQueryParams, ...(persistedFilters ?? [])),
...query,
};

return getAPMHref({ basePath, path, query, search });
return getAPMHref({ basePath, path, query: nextQuery, search });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea destructuring useAPMHref 👍

As I mentioned to @cauemarcondes in another PR, I don't think getAPMHref should take both query and search (the latter is essentially just a serialised version of the former). But that can wait until 7.12.

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ const persistedFilters: Array<keyof APMQueryParams> = [
];

export function useErrorOverviewHref(serviceName: string) {
return useAPMHref(`/services/${serviceName}/errors`, persistedFilters);
return useAPMHref({
path: `/services/${serviceName}/errors`,
persistedFilters,
});
}

interface Props extends APMLinkExtendProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ const persistedFilters: Array<keyof APMQueryParams> = [
];

export function useMetricOverviewHref(serviceName: string) {
return useAPMHref(`/services/${serviceName}/metrics`, persistedFilters);
return useAPMHref({
path: `/services/${serviceName}/metrics`,
persistedFilters,
});
}

interface Props extends APMLinkExtendProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import React from 'react';
import { APMLinkExtendProps, useAPMHref } from './APMLink';

export function useServiceMapHref(serviceName?: string) {
const pathFor = serviceName
const path = serviceName
? `/services/${serviceName}/service-map`
: '/service-map';
return useAPMHref(pathFor);
return useAPMHref({ path });
}

interface ServiceMapLinkProps extends APMLinkExtendProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ const persistedFilters: Array<keyof APMQueryParams> = [
];

export function useServiceNodeOverviewHref(serviceName: string) {
return useAPMHref(`/services/${serviceName}/nodes`, persistedFilters);
return useAPMHref({
path: `/services/${serviceName}/nodes`,
persistedFilters,
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ const persistedFilters: Array<keyof APMQueryParams> = [
];

export function useTraceOverviewHref() {
return useAPMHref('/traces', persistedFilters);
return useAPMHref({ path: '/traces', persistedFilters });
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ import { useAPMHref } from './APMLink';
const persistedFilters: Array<keyof APMQueryParams> = ['host', 'agentName'];

export function useServiceInventoryHref() {
return useAPMHref('/services', persistedFilters);
return useAPMHref({ path: '/services', persistedFilters });
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,34 @@ import { APMLinkExtendProps, useAPMHref } from './APMLink';

interface ServiceOverviewLinkProps extends APMLinkExtendProps {
serviceName: string;
environment?: string;
}

const persistedFilters: Array<keyof APMQueryParams> = [
'latencyAggregationType',
];

export function useServiceOverviewHref(serviceName: string) {
return useAPMHref(`/services/${serviceName}/overview`, persistedFilters);
export function useServiceOverviewHref(
serviceName: string,
environment?: string
) {
const query = environment
? {
environment,
}
: {};
return useAPMHref({
path: `/services/${serviceName}/overview`,
persistedFilters,
query,
});
}

export function ServiceOverviewLink({
serviceName,
environment,
...rest
}: ServiceOverviewLinkProps) {
const href = useServiceOverviewHref(serviceName);
const href = useServiceOverviewHref(serviceName, environment);
return <EuiLink href={href} {...rest} />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,28 @@ const persistedFilters: Array<keyof APMQueryParams> = [
'latencyAggregationType',
];

export function useServiceOrTransactionsOverviewHref(serviceName: string) {
return useAPMHref(`/services/${serviceName}`, persistedFilters);
export function useServiceOrTransactionsOverviewHref(
serviceName: string,
environment?: string
) {
const query = environment ? { environment } : {};
return useAPMHref({
path: `/services/${serviceName}`,
persistedFilters,
query,
});
}

interface Props extends APMLinkExtendProps {
serviceName: string;
environment?: string;
}

export function ServiceOrTransactionsOverviewLink({
serviceName,
environment,
...rest
}: Props) {
const href = useServiceOrTransactionsOverviewHref(serviceName);
const href = useServiceOrTransactionsOverviewHref(serviceName, environment);
return <EuiLink href={href} {...rest} />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import React from 'react';
import { useLocation } from 'react-router-dom';
import { EuiLink } from '@elastic/eui';
import { pickBy, identity } from 'lodash';
import { getAPMHref, APMLinkExtendProps } from './APMLink';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { pickKeys } from '../../../../../common/utils/pick_keys';
Expand All @@ -20,6 +21,7 @@ interface Props extends APMLinkExtendProps {
transactionName: string;
transactionType: string;
latencyAggregationType?: string;
environment?: string;
}

const persistedFilters: Array<keyof APMQueryParams> = [
Expand All @@ -34,6 +36,7 @@ export function TransactionDetailLink({
transactionName,
transactionType,
latencyAggregationType,
environment,
...rest
}: Props) {
const { urlParams } = useUrlParams();
Expand All @@ -47,8 +50,8 @@ export function TransactionDetailLink({
transactionId,
transactionName,
transactionType,
...(latencyAggregationType ? { latencyAggregationType } : {}),
...pickKeys(urlParams as APMQueryParams, ...persistedFilters),
...pickBy({ latencyAggregationType, environment }, identity),
},
search: location.search,
});
Expand Down
Loading