Skip to content

Commit

Permalink
[APM] Profiling (#91818)
Browse files Browse the repository at this point in the history
  • Loading branch information
dgieselaar authored and kibanamachine committed Feb 22, 2021
1 parent 5668436 commit e0eff5d
Show file tree
Hide file tree
Showing 22 changed files with 1,535 additions and 9 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions x-pack/plugins/apm/common/elasticsearch_fieldnames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,17 @@ export const LCP_FIELD = 'transaction.marks.agent.largestContentfulPaint';
export const TBT_FIELD = 'transaction.experience.tbt';
export const FID_FIELD = 'transaction.experience.fid';
export const CLS_FIELD = 'transaction.experience.cls';

export const PROFILE_ID = 'profile.id';
export const PROFILE_DURATION = 'profile.duration';
export const PROFILE_TOP_ID = 'profile.top.id';
export const PROFILE_STACK = 'profile.stack';

export const PROFILE_SAMPLES_COUNT = 'profile.samples.count';
export const PROFILE_CPU_NS = 'profile.cpu.ns';
export const PROFILE_WALL_US = 'profile.wall.us';

export const PROFILE_ALLOC_OBJECTS = 'profile.alloc_objects.count';
export const PROFILE_ALLOC_SPACE = 'profile.alloc_space.bytes';
export const PROFILE_INUSE_OBJECTS = 'profile.inuse_objects.count';
export const PROFILE_INUSE_SPACE = 'profile.inuse_space.bytes';
1 change: 1 addition & 0 deletions x-pack/plugins/apm/common/processor_event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export enum ProcessorEvent {
error = 'error',
metric = 'metric',
span = 'span',
profile = 'profile',
}
/**
* Processor events that are searchable in the UI via the query bar.
Expand Down
112 changes: 112 additions & 0 deletions x-pack/plugins/apm/common/profiling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* 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 { i18n } from '@kbn/i18n';
import {
PROFILE_ALLOC_OBJECTS,
PROFILE_ALLOC_SPACE,
PROFILE_CPU_NS,
PROFILE_INUSE_OBJECTS,
PROFILE_INUSE_SPACE,
PROFILE_SAMPLES_COUNT,
PROFILE_WALL_US,
} from './elasticsearch_fieldnames';

export enum ProfilingValueType {
wallTime = 'wall_time',
cpuTime = 'cpu_time',
samples = 'samples',
allocObjects = 'alloc_objects',
allocSpace = 'alloc_space',
inuseObjects = 'inuse_objects',
inuseSpace = 'inuse_space',
}

export enum ProfilingValueTypeUnit {
ns = 'ns',
us = 'us',
count = 'count',
bytes = 'bytes',
}

export interface ProfileNode {
id: string;
label: string;
fqn: string;
value: number;
children: string[];
}

const config = {
[ProfilingValueType.wallTime]: {
unit: ProfilingValueTypeUnit.us,
label: i18n.translate(
'xpack.apm.serviceProfiling.valueTypeLabel.wallTime',
{
defaultMessage: 'Wall',
}
),
field: PROFILE_WALL_US,
},
[ProfilingValueType.cpuTime]: {
unit: ProfilingValueTypeUnit.ns,
label: i18n.translate('xpack.apm.serviceProfiling.valueTypeLabel.cpuTime', {
defaultMessage: 'On-CPU',
}),
field: PROFILE_CPU_NS,
},
[ProfilingValueType.samples]: {
unit: ProfilingValueTypeUnit.count,
label: i18n.translate('xpack.apm.serviceProfiling.valueTypeLabel.samples', {
defaultMessage: 'Samples',
}),
field: PROFILE_SAMPLES_COUNT,
},
[ProfilingValueType.allocObjects]: {
unit: ProfilingValueTypeUnit.count,
label: i18n.translate(
'xpack.apm.serviceProfiling.valueTypeLabel.allocObjects',
{
defaultMessage: 'Alloc. objects',
}
),
field: PROFILE_ALLOC_OBJECTS,
},
[ProfilingValueType.allocSpace]: {
unit: ProfilingValueTypeUnit.bytes,
label: i18n.translate(
'xpack.apm.serviceProfiling.valueTypeLabel.allocSpace',
{
defaultMessage: 'Alloc. space',
}
),
field: PROFILE_ALLOC_SPACE,
},
[ProfilingValueType.inuseObjects]: {
unit: ProfilingValueTypeUnit.count,
label: i18n.translate(
'xpack.apm.serviceProfiling.valueTypeLabel.inuseObjects',
{
defaultMessage: 'In-use objects',
}
),
field: PROFILE_INUSE_OBJECTS,
},
[ProfilingValueType.inuseSpace]: {
unit: ProfilingValueTypeUnit.bytes,
label: i18n.translate(
'xpack.apm.serviceProfiling.valueTypeLabel.inuseSpace',
{
defaultMessage: 'In-use space',
}
),
field: PROFILE_INUSE_SPACE,
},
};

export const getValueTypeConfig = (type: ProfilingValueType) => {
return config[type];
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ function ServiceDetailsTransactions(
return <ServiceDetails {...props} tab="transactions" />;
}

function ServiceDetailsProfiling(
props: RouteComponentProps<{ serviceName: string }>
) {
return <ServiceDetails {...props} tab="profiling" />;
}

function SettingsAgentConfiguration(props: RouteComponentProps<{}>) {
return (
<Settings {...props}>
Expand Down Expand Up @@ -307,6 +313,14 @@ export const routes: APMRouteDefinition[] = [
return query.transactionName as string;
},
},
{
exact: true,
path: '/services/:serviceName/profiling',
component: withApmServiceContext(ServiceDetailsProfiling),
breadcrumb: i18n.translate('xpack.apm.breadcrumb.serviceProfilingTitle', {
defaultMessage: 'Profiling',
}),
},
{
exact: true,
path: '/services/:serviceName/service-map',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import { EuiTab } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { ReactNode } from 'react';
import { EuiBetaBadge } from '@elastic/eui';
import { EuiFlexItem } from '@elastic/eui';
import { EuiFlexGroup } from '@elastic/eui';
import { isJavaAgentName, isRumAgentName } from '../../../../common/agent_name';
import { enableServiceOverview } from '../../../../common/ui_settings_keys';
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
Expand All @@ -19,19 +22,21 @@ import { useServiceMapHref } from '../../shared/Links/apm/ServiceMapLink';
import { useServiceNodeOverviewHref } from '../../shared/Links/apm/ServiceNodeOverviewLink';
import { useServiceOverviewHref } from '../../shared/Links/apm/service_overview_link';
import { useTransactionsOverviewHref } from '../../shared/Links/apm/transaction_overview_link';
import { useServiceProfilingHref } from '../../shared/Links/apm/service_profiling_link';
import { MainTabs } from '../../shared/main_tabs';
import { ErrorGroupOverview } from '../error_group_overview';
import { ServiceMap } from '../ServiceMap';
import { ServiceNodeOverview } from '../service_node_overview';
import { ServiceMetrics } from '../service_metrics';
import { ServiceOverview } from '../service_overview';
import { TransactionOverview } from '../transaction_overview';
import { ServiceProfiling } from '../service_profiling';
import { Correlations } from '../correlations';

interface Tab {
key: string;
href: string;
text: string;
text: ReactNode;
render: () => ReactNode;
}

Expand All @@ -43,12 +48,16 @@ interface Props {
| 'nodes'
| 'overview'
| 'service-map'
| 'profiling'
| 'transactions';
}

export function ServiceDetailTabs({ serviceName, tab }: Props) {
const { agentName } = useApmServiceContext();
const { uiSettings } = useApmPluginContext().core;
const {
core: { uiSettings },
config,
} = useApmPluginContext();
const {
urlParams: { latencyAggregationType },
} = useUrlParams();
Expand Down Expand Up @@ -114,6 +123,38 @@ export function ServiceDetailTabs({ serviceName, tab }: Props) {
) : null,
};

const profilingTab = {
key: 'profiling',
href: useServiceProfilingHref({ serviceName }),
text: (
<EuiFlexGroup direction="row" gutterSize="s">
<EuiFlexItem>
{i18n.translate('xpack.apm.serviceDetails.profilingTabLabel', {
defaultMessage: 'Profiling',
})}
</EuiFlexItem>
<EuiFlexItem>
<EuiBetaBadge
label={i18n.translate(
'xpack.apm.serviceDetails.profilingTabExperimentalLabel',
{
defaultMessage: 'Experimental',
}
)}
tooltipContent={i18n.translate(
'xpack.apm.serviceDetails.profilingTabExperimentalDescription',
{
defaultMessage:
'Profiling is highly experimental and for internal use only.',
}
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
),
render: () => <ServiceProfiling serviceName={serviceName} />,
};

const tabs: Tab[] = [transactionsTab, errorsTab];

if (uiSettings.get(enableServiceOverview)) {
Expand All @@ -128,6 +169,10 @@ export function ServiceDetailTabs({ serviceName, tab }: Props) {

tabs.push(serviceMapTab);

if (config.profilingEnabled) {
tabs.push(profilingTab);
}

const selectedTab = tabs.find((serviceTab) => serviceTab.key === tab);

return (
Expand Down
Loading

0 comments on commit e0eff5d

Please sign in to comment.