From d3a0c72a95eb3d58c3097e5ae69250f19ce35a6b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cau=C3=AA=20Marcondes?=
<55978943+cauemarcondes@users.noreply.github.com>
Date: Tue, 13 Jul 2021 12:33:32 -0400
Subject: [PATCH] [APM] Add telemetry to track usage of the agent config to
fleet synchronisation feature (#105297)
* removing telemetry hook from pages
* adding telemetry to schema and agent config
---
.../Settings/agent_configurations/index.tsx | 4 ---
.../Settings/schema/confirm_switch_modal.tsx | 9 ++++-
.../app/error_group_details/index.tsx | 4 ---
.../app/error_group_overview/index.tsx | 7 ----
.../app/service_inventory/index.tsx | 8 -----
.../components/app/service_map/index.tsx | 4 ---
.../components/app/service_overview/index.tsx | 4 ---
.../components/app/trace_overview/index.tsx | 4 ---
.../app/transaction_details/index.tsx | 4 ---
.../app/transaction_overview/index.tsx | 3 --
.../public/components/routing/app_root.tsx | 24 ++++++++++----
.../components/routing/telemetry_wrapper.tsx | 33 +++++++++++++++++++
...c_agent_configs_to_apm_package_policies.ts | 9 +++++
.../server/routes/register_routes/index.ts | 12 ++++---
.../routes/settings/agent_configuration.ts | 6 ++--
x-pack/plugins/apm/server/routes/typings.ts | 6 ++++
16 files changed, 84 insertions(+), 57 deletions(-)
create mode 100644 x-pack/plugins/apm/public/components/routing/telemetry_wrapper.tsx
diff --git a/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/index.tsx
index 1ca7f46a0b26f..32c93e43175df 100644
--- a/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/index.tsx
@@ -18,7 +18,6 @@ import { i18n } from '@kbn/i18n';
import { isEmpty } from 'lodash';
import React from 'react';
import { useLocation } from 'react-router-dom';
-import { useTrackPageview } from '../../../../../../observability/public';
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
import { useFetcher } from '../../../../hooks/use_fetcher';
import { createAgentConfigurationHref } from '../../../shared/Links/apm/agentConfigurationLinks';
@@ -34,9 +33,6 @@ export function AgentConfigurations() {
{ preservePreviousData: false, showToastOnError: false }
);
- useTrackPageview({ app: 'apm', path: 'agent_configuration' });
- useTrackPageview({ app: 'apm', path: 'agent_configuration', delay: 15000 });
-
const hasConfigurations = !isEmpty(data.configurations);
return (
diff --git a/x-pack/plugins/apm/public/components/app/Settings/schema/confirm_switch_modal.tsx b/x-pack/plugins/apm/public/components/app/Settings/schema/confirm_switch_modal.tsx
index 04817aaf84f3e..5bb93c251777f 100644
--- a/x-pack/plugins/apm/public/components/app/Settings/schema/confirm_switch_modal.tsx
+++ b/x-pack/plugins/apm/public/components/app/Settings/schema/confirm_switch_modal.tsx
@@ -15,6 +15,7 @@ import {
htmlIdGenerator,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
+import { useUiTracker } from '../../../../../../observability/public';
import { ElasticDocsLink } from '../../../shared/Links/ElasticDocsLink';
interface Props {
@@ -27,6 +28,7 @@ export function ConfirmSwitchModal({
onCancel,
unsupportedConfigs,
}: Props) {
+ const trackApmEvent = useUiTracker({ app: 'apm' });
const [isConfirmChecked, setIsConfirmChecked] = useState(false);
const hasUnsupportedConfigs = !!unsupportedConfigs.length;
return (
@@ -48,7 +50,12 @@ export function ConfirmSwitchModal({
}
)}
defaultFocusedButton="confirm"
- onConfirm={onConfirm}
+ onConfirm={() => {
+ trackApmEvent({
+ metric: 'confirm_data_stream_switch',
+ });
+ onConfirm();
+ }}
confirmButtonDisabled={!isConfirmChecked}
>
diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_details/index.tsx
index 344393d42506f..225186cab12c8 100644
--- a/x-pack/plugins/apm/public/components/app/error_group_details/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/error_group_details/index.tsx
@@ -17,7 +17,6 @@ import {
import { i18n } from '@kbn/i18n';
import React from 'react';
import { euiStyled } from '../../../../../../../src/plugins/kibana_react/common';
-import { useTrackPageview } from '../../../../../observability/public';
import { NOT_AVAILABLE_LABEL } from '../../../../common/i18n';
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
import { useErrorGroupDistributionFetcher } from '../../../hooks/use_error_group_distribution_fetcher';
@@ -128,9 +127,6 @@ export function ErrorGroupDetails({
groupId,
});
- useTrackPageview({ app: 'apm', path: 'error_group_details' });
- useTrackPageview({ app: 'apm', path: 'error_group_details', delay: 15000 });
-
if (!errorGroupData || !errorDistributionData) {
return ;
}
diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx
index 4c622758e6c8b..8d8d0cb9c107c 100644
--- a/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx
@@ -14,7 +14,6 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
-import { useTrackPageview } from '../../../../../observability/public';
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
import { useErrorGroupDistributionFetcher } from '../../../hooks/use_error_group_distribution_fetcher';
import { useFetcher } from '../../../hooks/use_fetcher';
@@ -60,12 +59,6 @@ export function ErrorGroupOverview({ serviceName }: ErrorGroupOverviewProps) {
[environment, kuery, serviceName, start, end, sortField, sortDirection]
);
- useTrackPageview({
- app: 'apm',
- path: 'error_group_overview',
- });
- useTrackPageview({ app: 'apm', path: 'error_group_overview', delay: 15000 });
-
if (!errorDistributionData || !errorGroupListData) {
return null;
}
diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx
index cac94885511c1..ef0a5f2df0434 100644
--- a/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx
@@ -9,7 +9,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useEffect } from 'react';
import { toMountPoint } from '../../../../../../../src/plugins/kibana_react/public';
-import { useTrackPageview } from '../../../../../observability/public';
import { useAnomalyDetectionJobsContext } from '../../../context/anomaly_detection_jobs/use_anomaly_detection_jobs_context';
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
@@ -92,13 +91,6 @@ export function ServiceInventory() {
const { core } = useApmPluginContext();
const { servicesData, servicesStatus } = useServicesFetcher();
- // The page is called "service inventory" to avoid confusion with the
- // "service overview", but this is tracked in some dashboards because it's the
- // initial landing page for APM, so it stays as "services_overview" (plural.)
- // for backward compatibility.
- useTrackPageview({ app: 'apm', path: 'services_overview' });
- useTrackPageview({ app: 'apm', path: 'services_overview', delay: 15000 });
-
const {
anomalyDetectionJobsData,
anomalyDetectionJobsStatus,
diff --git a/x-pack/plugins/apm/public/components/app/service_map/index.tsx b/x-pack/plugins/apm/public/components/app/service_map/index.tsx
index 582eafe7553af..22adb10512d7a 100644
--- a/x-pack/plugins/apm/public/components/app/service_map/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_map/index.tsx
@@ -13,7 +13,6 @@ import {
} from '@elastic/eui';
import React, { PropsWithChildren, ReactNode } from 'react';
import { isActivePlatinumLicense } from '../../../../common/license_check';
-import { useTrackPageview } from '../../../../../observability/public';
import {
invalidLicenseMessage,
SERVICE_MAP_TIMEOUT_ERROR,
@@ -106,9 +105,6 @@ export function ServiceMap({
const PADDING_BOTTOM = 24;
const heightWithPadding = height - PADDING_BOTTOM;
- useTrackPageview({ app: 'apm', path: 'service_map' });
- useTrackPageview({ app: 'apm', path: 'service_map', delay: 15000 });
-
if (!license) {
return null;
}
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx
index fce543b05c6c3..374b2d59ea347 100644
--- a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx
@@ -7,7 +7,6 @@
import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui';
import React from 'react';
-import { useTrackPageview } from '../../../../../observability/public';
import { isRumAgentName, isIosAgentName } from '../../../../common/agent_name';
import { AnnotationsContextProvider } from '../../../context/annotations/annotations_context';
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
@@ -35,9 +34,6 @@ interface ServiceOverviewProps {
export function ServiceOverview({ serviceName }: ServiceOverviewProps) {
const { agentName } = useApmServiceContext();
- useTrackPageview({ app: 'apm', path: 'service_overview' });
- useTrackPageview({ app: 'apm', path: 'service_overview', delay: 15000 });
-
// The default EuiFlexGroup breaks at 768, but we want to break at 992, so we
// observe the window width and set the flex directions of rows accordingly
const { isMedium } = useBreakPoints();
diff --git a/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx b/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx
index d280b36a603ba..ccb5fea72432c 100644
--- a/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx
@@ -6,7 +6,6 @@
*/
import React from 'react';
-import { useTrackPageview } from '../../../../../observability/public';
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher';
import { APIReturnType } from '../../../services/rest/createCallApmApi';
@@ -43,9 +42,6 @@ export function TraceOverview() {
[environment, kuery, start, end]
);
- useTrackPageview({ app: 'apm', path: 'traces_overview' });
- useTrackPageview({ app: 'apm', path: 'traces_overview', delay: 15000 });
-
return (
<>
diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx
index 1e13e224a511a..40f50e768e76e 100644
--- a/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx
@@ -9,7 +9,6 @@ import { EuiHorizontalRule, EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui';
import { flatten, isEmpty } from 'lodash';
import React from 'react';
import { useHistory } from 'react-router-dom';
-import { useTrackPageview } from '../../../../../observability/public';
import { ChartPointerEventContextProvider } from '../../../context/chart_pointer_event/chart_pointer_event_context';
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
import { FETCH_STATUS } from '../../../hooks/use_fetcher';
@@ -41,9 +40,6 @@ export function TransactionDetails() {
} = useWaterfallFetcher();
const { transactionName } = urlParams;
- useTrackPageview({ app: 'apm', path: 'transaction_details' });
- useTrackPageview({ app: 'apm', path: 'transaction_details', delay: 15000 });
-
const selectedSample = flatten(
distributionData.buckets.map((bucket) => bucket.samples)
).find(
diff --git a/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx
index 041c12822357c..2435e5fc5a1f6 100644
--- a/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx
@@ -17,7 +17,6 @@ import { FormattedMessage } from '@kbn/i18n/react';
import { Location } from 'history';
import React from 'react';
import { useLocation } from 'react-router-dom';
-import { useTrackPageview } from '../../../../../observability/public';
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
import { IUrlParams } from '../../../context/url_params_context/types';
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
@@ -62,8 +61,6 @@ export function TransactionOverview({ serviceName }: TransactionOverviewProps) {
// redirect to first transaction type
useRedirect(getRedirectLocation({ location, transactionType, urlParams }));
- useTrackPageview({ app: 'apm', path: 'transaction_overview' });
- useTrackPageview({ app: 'apm', path: 'transaction_overview', delay: 15000 });
const {
transactionListData,
transactionListStatus,
diff --git a/x-pack/plugins/apm/public/components/routing/app_root.tsx b/x-pack/plugins/apm/public/components/routing/app_root.tsx
index 8fc59a01eeca0..a924c1f31cbef 100644
--- a/x-pack/plugins/apm/public/components/routing/app_root.tsx
+++ b/x-pack/plugins/apm/public/components/routing/app_root.tsx
@@ -9,7 +9,7 @@ import { ApmRoute } from '@elastic/apm-rum-react';
import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import React from 'react';
-import { Route, Router, Switch } from 'react-router-dom';
+import { Route, RouteComponentProps, Router, Switch } from 'react-router-dom';
import { DefaultTheme, ThemeProvider } from 'styled-components';
import { APP_WRAPPER_CLASS } from '../../../../../../src/core/public';
import {
@@ -17,20 +17,21 @@ import {
RedirectAppLinks,
useUiSetting$,
} from '../../../../../../src/plugins/kibana_react/public';
+import { HeaderMenuPortal } from '../../../../observability/public';
import { ScrollToTopOnPathChange } from '../../components/app/Main/ScrollToTopOnPathChange';
+import { AnomalyDetectionJobsContextProvider } from '../../context/anomaly_detection_jobs/anomaly_detection_jobs_context';
import {
ApmPluginContext,
ApmPluginContextValue,
} from '../../context/apm_plugin/apm_plugin_context';
+import { useApmPluginContext } from '../../context/apm_plugin/use_apm_plugin_context';
import { LicenseProvider } from '../../context/license/license_context';
import { UrlParamsProvider } from '../../context/url_params_context/url_params_context';
import { useApmBreadcrumbs } from '../../hooks/use_apm_breadcrumbs';
import { ApmPluginStartDeps } from '../../plugin';
-import { HeaderMenuPortal } from '../../../../observability/public';
import { ApmHeaderActionMenu } from '../shared/apm_header_action_menu';
-import { useApmPluginContext } from '../../context/apm_plugin/use_apm_plugin_context';
-import { AnomalyDetectionJobsContextProvider } from '../../context/anomaly_detection_jobs/anomaly_detection_jobs_context';
import { apmRouteConfig } from './apm_route_config';
+import { TelemetryWrapper } from './telemetry_wrapper';
export function ApmAppRoot({
apmPluginContextValue,
@@ -62,9 +63,18 @@ export function ApmAppRoot({
- {apmRouteConfig.map((route, i) => (
-
- ))}
+ {apmRouteConfig.map((route, i) => {
+ const { component, render, ...rest } = route;
+ return (
+ {
+ return TelemetryWrapper({ route, props });
+ }}
+ />
+ );
+ })}
diff --git a/x-pack/plugins/apm/public/components/routing/telemetry_wrapper.tsx b/x-pack/plugins/apm/public/components/routing/telemetry_wrapper.tsx
new file mode 100644
index 0000000000000..fc3fc6a338d18
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/routing/telemetry_wrapper.tsx
@@ -0,0 +1,33 @@
+/*
+ * 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 { RouteComponentProps } from 'react-router-dom';
+import { useTrackPageview } from '../../../../observability/public';
+import { APMRouteDefinition } from '../../application/routes';
+import { redirectTo } from './redirect_to';
+
+export function TelemetryWrapper({
+ route,
+ props,
+}: {
+ route: APMRouteDefinition;
+ props: RouteComponentProps;
+}) {
+ const { component, render, path } = route;
+ const pathAsString = path as string;
+
+ useTrackPageview({ app: 'apm', path: pathAsString });
+ useTrackPageview({ app: 'apm', path: pathAsString, delay: 15000 });
+
+ if (component) {
+ return React.createElement(component, props);
+ }
+ if (render) {
+ return <>{render(props)}>;
+ }
+ return <>{redirectTo('/')}>;
+}
diff --git a/x-pack/plugins/apm/server/lib/fleet/sync_agent_configs_to_apm_package_policies.ts b/x-pack/plugins/apm/server/lib/fleet/sync_agent_configs_to_apm_package_policies.ts
index 4294c5b82cd63..1365ddc28ddb2 100644
--- a/x-pack/plugins/apm/server/lib/fleet/sync_agent_configs_to_apm_package_policies.ts
+++ b/x-pack/plugins/apm/server/lib/fleet/sync_agent_configs_to_apm_package_policies.ts
@@ -10,6 +10,7 @@ import {
CoreStart,
SavedObjectsClientContract,
} from 'kibana/server';
+import { TelemetryUsageCounter } from '../../routes/typings';
import { APMPluginStartDependencies } from '../../types';
import { getInternalSavedObjectsClient } from '../helpers/get_internal_saved_objects_client';
import { Setup } from '../helpers/setup_request';
@@ -21,11 +22,19 @@ export async function syncAgentConfigsToApmPackagePolicies({
core,
fleetPluginStart,
setup,
+ telemetryUsageCounter,
}: {
core: { setup: CoreSetup; start: () => Promise };
fleetPluginStart: NonNullable;
setup: Setup;
+ telemetryUsageCounter?: TelemetryUsageCounter;
}) {
+ if (telemetryUsageCounter) {
+ telemetryUsageCounter.incrementCounter({
+ counterName: 'sync_agent_config_to_apm_package_policies',
+ counterType: 'success',
+ });
+ }
const coreStart = await core.start();
const esClient = coreStart.elasticsearch.client.asInternalUser;
const [
diff --git a/x-pack/plugins/apm/server/routes/register_routes/index.ts b/x-pack/plugins/apm/server/routes/register_routes/index.ts
index 8e6070de722be..16e77f59f4d02 100644
--- a/x-pack/plugins/apm/server/routes/register_routes/index.ts
+++ b/x-pack/plugins/apm/server/routes/register_routes/index.ts
@@ -18,9 +18,12 @@ import {
routeValidationObject,
} from '@kbn/server-route-repository';
import { mergeRt, jsonRt } from '@kbn/io-ts-utils';
-import { UsageCollectionSetup } from '../../../../../../src/plugins/usage_collection/server';
import { pickKeys } from '../../../common/utils/pick_keys';
-import { APMRouteHandlerResources, InspectResponse } from '../typings';
+import {
+ APMRouteHandlerResources,
+ InspectResponse,
+ TelemetryUsageCounter,
+} from '../typings';
import type { ApmPluginRequestHandlerContext } from '../typings';
const inspectRt = t.exact(
@@ -56,9 +59,7 @@ export function registerRoutes({
repository: ServerRouteRepository;
config: APMRouteHandlerResources['config'];
ruleDataClient: APMRouteHandlerResources['ruleDataClient'];
- telemetryUsageCounter?: ReturnType<
- UsageCollectionSetup['createUsageCounter']
- >;
+ telemetryUsageCounter?: TelemetryUsageCounter;
}) {
const routes = repository.getRoutes();
@@ -104,6 +105,7 @@ export function registerRoutes({
logger,
core,
plugins,
+ telemetryUsageCounter,
params: merge(
{
query: {
diff --git a/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts b/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts
index 05eec47893793..f50770cb5ded7 100644
--- a/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts
+++ b/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts
@@ -79,7 +79,7 @@ const deleteAgentConfigurationRoute = createApmServerRoute({
}),
handler: async (resources) => {
const setup = await setupRequest(resources);
- const { params, logger, core } = resources;
+ const { params, logger, core, telemetryUsageCounter } = resources;
const { service } = params.body;
@@ -106,6 +106,7 @@ const deleteAgentConfigurationRoute = createApmServerRoute({
core,
fleetPluginStart: await resources.plugins.fleet.start(),
setup,
+ telemetryUsageCounter,
});
logger.info(
`Updated Fleet integration policy for APM to remove the deleted agent configuration.`
@@ -128,7 +129,7 @@ const createOrUpdateAgentConfigurationRoute = createApmServerRoute({
]),
handler: async (resources) => {
const setup = await setupRequest(resources);
- const { params, logger, core } = resources;
+ const { params, logger, core, telemetryUsageCounter } = resources;
const { body, query } = params;
// if the config already exists, it is fetched and updated
@@ -162,6 +163,7 @@ const createOrUpdateAgentConfigurationRoute = createApmServerRoute({
core,
fleetPluginStart: await resources.plugins.fleet.start(),
setup,
+ telemetryUsageCounter,
});
logger.info(
`Saved latest agent settings to Fleet integration policy for APM.`
diff --git a/x-pack/plugins/apm/server/routes/typings.ts b/x-pack/plugins/apm/server/routes/typings.ts
index 56a5950c27367..4279cfd84328c 100644
--- a/x-pack/plugins/apm/server/routes/typings.ts
+++ b/x-pack/plugins/apm/server/routes/typings.ts
@@ -18,6 +18,7 @@ import type { RacApiRequestHandlerContext } from '../../../rule_registry/server'
import { LicensingApiRequestHandlerContext } from '../../../licensing/server';
import { APMConfig } from '..';
import { APMPluginDependencies } from '../types';
+import { UsageCollectionSetup } from '../../../../../src/plugins/usage_collection/server';
export interface ApmPluginRequestHandlerContext extends RequestHandlerContext {
licensing: LicensingApiRequestHandlerContext;
@@ -47,6 +48,10 @@ export interface APMRouteCreateOptions {
};
}
+export type TelemetryUsageCounter = ReturnType<
+ UsageCollectionSetup['createUsageCounter']
+>;
+
export interface APMRouteHandlerResources {
request: KibanaRequest;
context: ApmPluginRequestHandlerContext;
@@ -68,4 +73,5 @@ export interface APMRouteHandlerResources {
};
};
ruleDataClient: RuleDataClient;
+ telemetryUsageCounter?: TelemetryUsageCounter;
}