From d50a3db2b15858586c9141fb2ec5bc137cab94b7 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Fri, 28 May 2021 21:34:29 +0200 Subject: [PATCH 01/68] [ML] Severity control for Anomaly timeline (#99489) --- .../ml/common/types/ml_url_generator.ts | 4 + .../alerting/ml_anomaly_alert_trigger.tsx | 2 +- .../severity_control/severity_control.tsx | 84 ---------- .../select_interval/select_interval.tsx | 18 ++- .../select_severity/select_severity.tsx | 27 +++- .../components}/severity_control/index.ts | 0 .../severity_control/severity_control.tsx | 106 ++++++++++++ .../components}/severity_control/styles.scss | 0 .../application/explorer/_explorer.scss | 8 - .../explorer/actions/load_explorer_data.ts | 14 +- .../application/explorer/anomaly_timeline.tsx | 152 ++++++++++-------- .../public/application/explorer/explorer.js | 64 +++----- .../explorer_anomalies_container.tsx | 20 +-- .../explorer/explorer_constants.ts | 1 + .../explorer/explorer_dashboard_service.ts | 7 + .../reducers/explorer_reducer/reducer.ts | 13 +- .../reducers/explorer_reducer/state.ts | 1 + .../explorer/swimlane_container.tsx | 13 +- .../application/routing/routes/explorer.tsx | 7 +- .../services/anomaly_timeline_service.ts | 15 +- .../services/ml_api_service/index.ts | 10 +- .../results_service/results_service.d.ts | 9 +- .../results_service/results_service.js | 25 ++- .../_timeseriesexplorer.scss | 4 - .../timeseriesexplorer/timeseriesexplorer.js | 41 +---- .../ml/server/routes/anomaly_detectors.ts | 1 + .../schemas/anomaly_detectors_schema.ts | 1 + .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 29 files changed, 353 insertions(+), 298 deletions(-) delete mode 100644 x-pack/plugins/ml/public/alerting/severity_control/severity_control.tsx rename x-pack/plugins/ml/public/{alerting => application/components}/severity_control/index.ts (100%) create mode 100644 x-pack/plugins/ml/public/application/components/severity_control/severity_control.tsx rename x-pack/plugins/ml/public/{alerting => application/components}/severity_control/styles.scss (100%) diff --git a/x-pack/plugins/ml/common/types/ml_url_generator.ts b/x-pack/plugins/ml/common/types/ml_url_generator.ts index c7c3f3ae9b2804..2b05f231e509ff 100644 --- a/x-pack/plugins/ml/common/types/ml_url_generator.ts +++ b/x-pack/plugins/ml/common/types/ml_url_generator.ts @@ -112,6 +112,10 @@ export interface ExplorerAppState { viewByFieldName?: string; viewByPerPage?: number; viewByFromPage?: number; + /** + * Indicated severity threshold for both swim lanes + */ + severity?: number; }; mlExplorerFilter: { influencersFilterQuery?: InfluencersFilterQuery; diff --git a/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx b/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx index 12fbaece54fac1..719b5c4aa4ad58 100644 --- a/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx +++ b/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx @@ -13,7 +13,7 @@ import { JobSelectorControl } from './job_selector'; import { useMlKibana } from '../application/contexts/kibana'; import { jobsApiProvider } from '../application/services/ml_api_service/jobs'; import { HttpService } from '../application/services/http_service'; -import { SeverityControl } from './severity_control'; +import { SeverityControl } from '../application/components/severity_control'; import { ResultTypeSelector } from './result_type_selector'; import { alertingApiProvider } from '../application/services/ml_api_service/alerting'; import { PreviewAlertCondition } from './preview_alert_condition'; diff --git a/x-pack/plugins/ml/public/alerting/severity_control/severity_control.tsx b/x-pack/plugins/ml/public/alerting/severity_control/severity_control.tsx deleted file mode 100644 index b1cd808643ca2f..00000000000000 --- a/x-pack/plugins/ml/public/alerting/severity_control/severity_control.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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, { FC } from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiFormRow, EuiRange, EuiRangeProps } from '@elastic/eui'; -import { SEVERITY_OPTIONS } from '../../application/components/controls/select_severity/select_severity'; -import { ANOMALY_THRESHOLD } from '../../../common'; -import './styles.scss'; - -export interface SeveritySelectorProps { - value: number | undefined; - onChange: (value: number) => void; -} - -const MAX_ANOMALY_SCORE = 100; - -export const SeverityControl: FC = React.memo(({ value, onChange }) => { - const levels: EuiRangeProps['levels'] = [ - { - min: ANOMALY_THRESHOLD.LOW, - max: ANOMALY_THRESHOLD.MINOR - 1, - color: 'success', - }, - { - min: ANOMALY_THRESHOLD.MINOR, - max: ANOMALY_THRESHOLD.MAJOR - 1, - color: 'primary', - }, - { - min: ANOMALY_THRESHOLD.MAJOR, - max: ANOMALY_THRESHOLD.CRITICAL, - color: 'warning', - }, - { - min: ANOMALY_THRESHOLD.CRITICAL, - max: MAX_ANOMALY_SCORE, - color: 'danger', - }, - ]; - - const toggleButtons = SEVERITY_OPTIONS.map((v) => ({ - value: v.val, - label: v.display, - })); - - return ( - - } - > - { - // @ts-ignore Property 'value' does not exist on type 'EventTarget' | (EventTarget & HTMLInputElement) - onChange(Number(e.target.value)); - }} - showLabels - showValue - aria-label={i18n.translate('xpack.ml.severitySelector.formControlLabel', { - defaultMessage: 'Select severity threshold', - })} - showTicks - ticks={toggleButtons} - levels={levels} - data-test-subj={'mlAnomalyAlertScoreSelection'} - /> - - ); -}); diff --git a/x-pack/plugins/ml/public/application/components/controls/select_interval/select_interval.tsx b/x-pack/plugins/ml/public/application/components/controls/select_interval/select_interval.tsx index 348c400b6d5a9c..f1ef62ddc90d49 100644 --- a/x-pack/plugins/ml/public/application/components/controls/select_interval/select_interval.tsx +++ b/x-pack/plugins/ml/public/application/components/controls/select_interval/select_interval.tsx @@ -6,7 +6,7 @@ */ import React, { FC } from 'react'; -import { EuiSelect } from '@elastic/eui'; +import { EuiIcon, EuiSelect, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { usePageUrlState } from '../../../util/url_state'; @@ -78,8 +78,22 @@ export const SelectIntervalUI: FC = ({ interval, onChange return ( + + + } + compressed + id="selectInterval" options={OPTIONS} - className="ml-select-interval" value={interval.val} onChange={handleOnChange} /> diff --git a/x-pack/plugins/ml/public/application/components/controls/select_severity/select_severity.tsx b/x-pack/plugins/ml/public/application/components/controls/select_severity/select_severity.tsx index e8766ea16c0021..3fe50a8b46d550 100644 --- a/x-pack/plugins/ml/public/application/components/controls/select_severity/select_severity.tsx +++ b/x-pack/plugins/ml/public/application/components/controls/select_severity/select_severity.tsx @@ -8,11 +8,11 @@ /* * React component for rendering a select element with threshold levels. */ -import React, { Fragment, FC } from 'react'; +import React, { Fragment, FC, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiHealth, EuiSpacer, EuiSuperSelect, EuiText } from '@elastic/eui'; +import { EuiHealth, EuiSpacer, EuiSuperSelect, EuiText, EuiSuperSelectProps } from '@elastic/eui'; import { getSeverityColor } from '../../../../../common/util/anomaly_utils'; import { usePageUrlState } from '../../../util/url_state'; @@ -124,23 +124,34 @@ export const SelectSeverity: FC = ({ classNames } = { classNames: '' }) = return ; }; -export const SelectSeverityUI: FC<{ - classNames?: string; - severity: TableSeverity; - onChange: (s: TableSeverity) => void; -}> = ({ classNames = '', severity, onChange }) => { +export const SelectSeverityUI: FC< + Omit, 'onChange' | 'options'> & { + classNames?: string; + severity: TableSeverity; + onChange: (s: TableSeverity) => void; + } +> = ({ classNames = '', severity, onChange, compressed }) => { const handleOnChange = (valueDisplay: string) => { onChange(optionValueToThreshold(optionsMap[valueDisplay])); }; + const options = useMemo(() => { + return getSeverityOptions(); + }, []); + return ( ); }; diff --git a/x-pack/plugins/ml/public/alerting/severity_control/index.ts b/x-pack/plugins/ml/public/application/components/severity_control/index.ts similarity index 100% rename from x-pack/plugins/ml/public/alerting/severity_control/index.ts rename to x-pack/plugins/ml/public/application/components/severity_control/index.ts diff --git a/x-pack/plugins/ml/public/application/components/severity_control/severity_control.tsx b/x-pack/plugins/ml/public/application/components/severity_control/severity_control.tsx new file mode 100644 index 00000000000000..7be72b84302334 --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/severity_control/severity_control.tsx @@ -0,0 +1,106 @@ +/* + * 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, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiFieldNumber, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiRange, + EuiRangeProps, +} from '@elastic/eui'; +import { ANOMALY_THRESHOLD } from '../../../../common'; +import './styles.scss'; + +export interface SeveritySelectorProps { + value: number | undefined; + onChange: (value: number) => void; +} + +const MAX_ANOMALY_SCORE = 100; + +export const SeverityControl: FC = React.memo(({ value, onChange }) => { + const levels: EuiRangeProps['levels'] = [ + { + min: ANOMALY_THRESHOLD.LOW, + max: ANOMALY_THRESHOLD.MINOR - 1, + color: 'success', + }, + { + min: ANOMALY_THRESHOLD.MINOR, + max: ANOMALY_THRESHOLD.MAJOR - 1, + color: 'primary', + }, + { + min: ANOMALY_THRESHOLD.MAJOR, + max: ANOMALY_THRESHOLD.CRITICAL, + color: 'warning', + }, + { + min: ANOMALY_THRESHOLD.CRITICAL, + max: MAX_ANOMALY_SCORE, + color: 'danger', + }, + ]; + + const label = i18n.translate('xpack.ml.severitySelector.formControlLabel', { + defaultMessage: 'Severity', + }); + + const resultValue = value ?? ANOMALY_THRESHOLD.LOW; + + const onChangeCallback = ( + e: React.ChangeEvent | React.MouseEvent + ) => { + // @ts-ignore Property 'value' does not exist on type 'EventTarget' | (EventTarget & HTMLInputElement) + onChange(Number(e.target.value)); + }; + + const ticks = new Array(5).fill(null).map((x, i) => { + const v = i * 25; + return { value: v, label: v }; + }); + + return ( + + + + + + + + + + + ); +}); diff --git a/x-pack/plugins/ml/public/alerting/severity_control/styles.scss b/x-pack/plugins/ml/public/application/components/severity_control/styles.scss similarity index 100% rename from x-pack/plugins/ml/public/alerting/severity_control/styles.scss rename to x-pack/plugins/ml/public/application/components/severity_control/styles.scss diff --git a/x-pack/plugins/ml/public/application/explorer/_explorer.scss b/x-pack/plugins/ml/public/application/explorer/_explorer.scss index c08020325428dd..d9d60ecfae67df 100644 --- a/x-pack/plugins/ml/public/application/explorer/_explorer.scss +++ b/x-pack/plugins/ml/public/application/explorer/_explorer.scss @@ -40,14 +40,6 @@ $borderRadius: $euiBorderRadius / 2; font-size: $euiFontSizeXS; } } - - .ml-anomalies-controls { - padding-top: $euiSizeXS; - - #show_charts_checkbox_control { - padding-top: $euiSizeL; - } - } } .mlSwimLaneContainer { diff --git a/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts b/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts index a5d50f1070f5ba..621ce442047309 100644 --- a/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts +++ b/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts @@ -83,6 +83,7 @@ export interface LoadExplorerDataConfig { viewByFromPage: number; viewByPerPage: number; swimlaneContainerWidth: number; + swimLaneSeverity: number; } export const isLoadExplorerDataConfig = (arg: any): arg is LoadExplorerDataConfig => { @@ -135,6 +136,7 @@ const loadExplorerDataProvider = ( swimlaneContainerWidth, viewByFromPage, viewByPerPage, + swimLaneSeverity, } = config; const combinedJobRecords: Record = selectedJobs.reduce((acc, job) => { @@ -192,7 +194,13 @@ const loadExplorerDataProvider = ( influencersFilterQuery ) : Promise.resolve({}), - overallState: memoizedLoadOverallData(lastRefresh, selectedJobs, swimlaneContainerWidth), + overallState: memoizedLoadOverallData( + lastRefresh, + selectedJobs, + swimlaneContainerWidth, + undefined, + swimLaneSeverity + ), tableData: memoizedLoadAnomaliesTableData( lastRefresh, selectedCells, @@ -278,7 +286,9 @@ const loadExplorerDataProvider = ( viewByPerPage, viewByFromPage, swimlaneContainerWidth, - influencersFilterQuery + influencersFilterQuery, + undefined, + swimLaneSeverity ), }).pipe( map(({ viewBySwimlaneState, filteredTopInfluencers }) => { diff --git a/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx b/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx index 1e8f54d10491d9..8375b0a0b1dfc5 100644 --- a/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx +++ b/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useMemo, useState } from 'react'; +import React, { FC, useCallback, useMemo, useState } from 'react'; import { isEqual } from 'lodash'; import { EuiPanel, @@ -14,7 +14,6 @@ import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, - EuiFormRow, EuiSelect, EuiTitle, EuiSpacer, @@ -35,7 +34,9 @@ import { ExplorerNoInfluencersFound } from './components/explorer_no_influencers import { SwimlaneContainer } from './swimlane_container'; import { AppStateSelectedCells, OverallSwimlaneData, ViewBySwimLaneData } from './explorer_utils'; import { NoOverallData } from './components/no_overall_data'; +import { SeverityControl } from '../components/severity_control'; import { AnomalyTimelineHelpPopover } from './anomaly_timeline_help_popover'; +import { isDefined } from '../../../common/types/guards'; function mapSwimlaneOptionsToEuiOptions(options: string[]) { return options.map((option) => ({ @@ -76,10 +77,8 @@ export const AnomalyTimeline: FC = React.memo( filterActive, filteredFields, maskAll, - overallSwimlaneData, selectedCells, viewByLoadedForTimeFormatted, - viewBySwimlaneData, viewBySwimlaneDataLoading, viewBySwimlaneFieldName, viewBySwimlaneOptions, @@ -89,6 +88,9 @@ export const AnomalyTimeline: FC = React.memo( swimlaneLimit, loading, overallAnnotations, + swimLaneSeverity, + overallSwimlaneData, + viewBySwimlaneData, } = explorerState; const annotations = useMemo(() => overallAnnotations.annotationsData, [overallAnnotations]); @@ -128,7 +130,7 @@ export const AnomalyTimeline: FC = React.memo( return ( <> - +

@@ -139,68 +141,10 @@ export const AnomalyTimeline: FC = React.memo(

- {viewBySwimlaneOptions.length > 0 && ( - <> - - - - - } - display={'columnCompressed'} - > - explorerService.setViewBySwimlaneFieldName(e.target.value)} - /> - - - {selectedCells ? ( - - - - - - ) : null} - -
- {viewByLoadedForTimeFormatted && ( - - )} - {viewByLoadedForTimeFormatted === undefined && ( - - )} - {filterActive === true && viewBySwimlaneFieldName === VIEW_BY_JOB_LABEL && ( - - )} -
-
- - )} + + + + {menuItems.length > 0 && ( @@ -226,10 +170,79 @@ export const AnomalyTimeline: FC = React.memo( )} +
+ + + + + {viewBySwimlaneOptions.length > 0 && ( + <> + + explorerService.setViewBySwimlaneFieldName(e.target.value)} + /> + + + )} + + + { + explorerService.setSwimLaneSeverity(update); + }, [])} + /> + + + + + - +
+ {viewByLoadedForTimeFormatted && ( + + )} + {isDefined(viewByLoadedForTimeFormatted) ? null : ( + + )} + {filterActive === true && viewBySwimlaneFieldName === VIEW_BY_JOB_LABEL && ( + + )} +
+ + {selectedCells ? ( + + + + + + ) : null}
@@ -249,6 +262,7 @@ export const AnomalyTimeline: FC = React.memo( noDataWarning={} showTimeline={false} annotationsData={annotations} + showLegend={false} /> @@ -266,7 +280,7 @@ export const AnomalyTimeline: FC = React.memo( }) } timeBuckets={timeBuckets} - showLegend={true} + showLegend={false} swimlaneData={viewBySwimlaneData as ViewBySwimLaneData} swimlaneType={SWIMLANE_TYPE.VIEW_BY} selection={selectedCells} diff --git a/x-pack/plugins/ml/public/application/explorer/explorer.js b/x-pack/plugins/ml/public/application/explorer/explorer.js index 7cc1d0d86e2ff2..4b241c47a267b0 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer.js @@ -19,9 +19,7 @@ import { EuiCallOut, EuiFlexGroup, EuiFlexItem, - EuiFormRow, EuiHorizontalRule, - EuiIcon, EuiIconTip, EuiPage, EuiPageBody, @@ -29,7 +27,6 @@ import { EuiPageHeaderSection, EuiSpacer, EuiTitle, - EuiToolTip, EuiLoadingContent, EuiPanel, EuiAccordion, @@ -78,6 +75,7 @@ import { ANOMALY_DETECTION_DEFAULT_TIME_RANGE } from '../../../common/constants/ import { withKibana } from '../../../../../../src/plugins/kibana_react/public'; import { ML_APP_URL_GENERATOR } from '../../../common/constants/ml_url_generator'; import { AnomalyContextMenu } from './anomaly_context_menu'; +import { isDefined } from '../../../common/types/guards'; const ExplorerPage = ({ children, @@ -263,6 +261,7 @@ export class ExplorerUI extends React.Component { selectedCells, selectedJobs, tableData, + swimLaneSeverity, } = this.props.explorerState; const { annotationsData, aggregations, error: annotationsError } = annotations; @@ -276,6 +275,8 @@ export class ExplorerUI extends React.Component { (hasResults && overallSwimlaneData.points.some((v) => v.value > 0)) || tableData.anomalies?.length > 0; + const hasActiveFilter = isDefined(swimLaneSeverity); + if (noJobsFound && !loading) { return ( @@ -284,7 +285,7 @@ export class ExplorerUI extends React.Component { ); } - if (hasResultsWithAnomalies === false && !loading) { + if (!hasResultsWithAnomalies && !loading && !hasActiveFilter) { return ( + + {annotationsError !== undefined && ( <> )} - {loading === false && tableData.anomalies?.length && ( + {loading === false && tableData.anomalies?.length ? ( - )} + ) : null} {annotationsData.length > 0 && ( <> @@ -476,47 +479,16 @@ export class ExplorerUI extends React.Component {
- - - - - + + + - - - - {i18n.translate('xpack.ml.explorer.intervalLabel', { - defaultMessage: 'Interval', - })} - - - - } - > - - + + {chartsData.seriesToPlot.length > 0 && selectedCells !== undefined && ( - - - - + + )} @@ -524,7 +496,7 @@ export class ExplorerUI extends React.Component {
- {showCharts && ( + {showCharts ? ( - )} + ) : null}
= ( }) => { return ( <> - - - - - + + + diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts b/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts index 4398a4b2c2be75..d737c4733b9cba 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts @@ -33,6 +33,7 @@ export const EXPLORER_ACTION = { SET_VIEW_BY_SWIMLANE_LOADING: 'setViewBySwimlaneLoading', SET_VIEW_BY_PER_PAGE: 'setViewByPerPage', SET_VIEW_BY_FROM_PAGE: 'setViewByFromPage', + SET_SWIM_LANE_SEVERITY: 'setSwimLaneSeverity', }; export const FILTER_ACTION = { diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts b/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts index 343ba88655e4e0..7721532b34338f 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts @@ -79,6 +79,10 @@ const explorerAppState$: Observable = explorerState$.pipe( appState.mlExplorerSwimlane.viewByPerPage = state.viewByPerPage; } + if (state.swimLaneSeverity !== undefined) { + appState.mlExplorerSwimlane.severity = state.swimLaneSeverity; + } + if (state.filterActive) { appState.mlExplorerFilter.influencersFilterQuery = state.influencersFilterQuery; appState.mlExplorerFilter.filterActive = state.filterActive; @@ -161,6 +165,9 @@ export const explorerService = { setViewByPerPage: (payload: number) => { explorerAction$.next({ type: EXPLORER_ACTION.SET_VIEW_BY_PER_PAGE, payload }); }, + setSwimLaneSeverity: (payload: number) => { + explorerAction$.next({ type: EXPLORER_ACTION.SET_SWIM_LANE_SEVERITY, payload }); + }, }; export type ExplorerService = typeof explorerService; diff --git a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts index 15e0caa29af39f..74867af5f89879 100644 --- a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts +++ b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts @@ -149,6 +149,15 @@ export const explorerReducer = (state: ExplorerState, nextAction: Action): Explo }; break; + case EXPLORER_ACTION.SET_SWIM_LANE_SEVERITY: + nextState = { + ...state, + // reset current page on the page size change + viewByFromPage: 1, + swimLaneSeverity: payload, + }; + break; + default: nextState = state; } @@ -181,7 +190,9 @@ export const explorerReducer = (state: ExplorerState, nextAction: Action): Explo ...nextState, swimlaneBucketInterval, viewByLoadedForTimeFormatted: timeRange - ? formatHumanReadableDateTime(timeRange.earliestMs) + ? `${formatHumanReadableDateTime(timeRange.earliestMs)} - ${formatHumanReadableDateTime( + timeRange.latestMs + )}` : null, viewBySwimlaneFieldName, viewBySwimlaneOptions, diff --git a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts index 2365e4e4689026..8a152ab1cadc31 100644 --- a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts +++ b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts @@ -58,6 +58,7 @@ export interface ExplorerState { viewByFromPage: number; viewBySwimlaneOptions: string[]; swimlaneLimit?: number; + swimLaneSeverity?: number; } function getDefaultIndexPattern() { diff --git a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx index 41bbe5b66a605f..d959328218a187 100644 --- a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx +++ b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx @@ -68,6 +68,10 @@ declare global { const RESIZE_THROTTLE_TIME_MS = 500; const CELL_HEIGHT = 30; const LEGEND_HEIGHT = 34; +/** + * Minimum container height to make sure "No data" message is displayed without overflow. + */ +const MIN_CONTAINER_HEIGHT = 40; const Y_AXIS_HEIGHT = 24; @@ -245,7 +249,10 @@ export const SwimlaneContainer: FC = ({ return isLoading ? containerHeightRef.current : // TODO update when elastic charts X label will be fixed - rowsCount * CELL_HEIGHT + LEGEND_HEIGHT + (true ? Y_AXIS_HEIGHT : 0); + Math.max( + rowsCount * CELL_HEIGHT + (showLegend ? LEGEND_HEIGHT : 0) + (true ? Y_AXIS_HEIGHT : 0), + MIN_CONTAINER_HEIGHT + ); }, [isLoading, rowsCount, showTimeline]); useEffect(() => { @@ -331,7 +338,7 @@ export const SwimlaneContainer: FC = ({ brushArea: { stroke: isDarkTheme ? 'rgb(255, 255, 255)' : 'rgb(105, 112, 125)', }, - maxLegendHeight: LEGEND_HEIGHT, + ...(showLegend ? { maxLegendHeight: LEGEND_HEIGHT } : {}), timeZone: 'UTC', }; }, [ @@ -463,7 +470,7 @@ export const SwimlaneContainer: FC = ({ )} {!isLoading && !showSwimlane && ( {noDataWarning}} /> diff --git a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx index 3e5cf252230a26..a0a81f77b7b087 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx @@ -177,7 +177,7 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim explorerService.setFilterData(filterData); } - const { viewByFieldName, viewByFromPage, viewByPerPage } = + const { viewByFieldName, viewByFromPage, viewByPerPage, severity } = explorerUrlState?.mlExplorerSwimlane ?? {}; if (viewByFieldName !== undefined) { @@ -191,6 +191,10 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim if (viewByFromPage !== undefined) { explorerService.setViewByFromPage(viewByFromPage); } + + if (severity !== undefined) { + explorerService.setSwimLaneSeverity(severity); + } }, []); /** Sync URL state with {@link explorerService} state */ @@ -238,6 +242,7 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim swimlaneContainerWidth: explorerState.swimlaneContainerWidth, viewByPerPage: explorerState.viewByPerPage, viewByFromPage: explorerState.viewByFromPage, + swimLaneSeverity: explorerState.swimLaneSeverity, } : undefined; diff --git a/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts b/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts index 54d9626edf26c0..e11eb4048c374b 100644 --- a/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts +++ b/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts @@ -98,7 +98,8 @@ export class AnomalyTimelineService { public async loadOverallData( selectedJobs: ExplorerJob[], chartWidth?: number, - bucketInterval?: TimeBucketsInterval + bucketInterval?: TimeBucketsInterval, + overallScore?: number ): Promise { const interval = bucketInterval ?? this.getSwimlaneBucketInterval(selectedJobs, chartWidth!); @@ -127,7 +128,8 @@ export class AnomalyTimelineService { 1, overallBucketsBounds.min.valueOf(), overallBucketsBounds.max.valueOf(), - interval.asSeconds() + 's' + interval.asSeconds() + 's', + overallScore ); const overallSwimlaneData = this.processOverallResults( resp.results, @@ -161,7 +163,8 @@ export class AnomalyTimelineService { fromPage: number, swimlaneContainerWidth?: number, influencersFilterQuery?: any, - bucketInterval?: TimeBucketsInterval + bucketInterval?: TimeBucketsInterval, + swimLaneSeverity?: number ): Promise { const timefilterBounds = this.getTimeBounds(); @@ -195,7 +198,8 @@ export class AnomalyTimelineService { searchBounds.max.valueOf(), intervalMs, perPage, - fromPage + fromPage, + swimLaneSeverity ); } else { response = await this.mlResultsService.getInfluencerValueMaxScoreByTime( @@ -208,7 +212,8 @@ export class AnomalyTimelineService { swimlaneLimit, perPage, fromPage, - influencersFilterQuery + influencersFilterQuery, + swimLaneSeverity ); } diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts index bf6b752faa8da6..f8ec4b64883160 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts @@ -323,14 +323,22 @@ export function mlApiServicesProvider(httpService: HttpService) { bucketSpan, start, end, + overallScore, }: { jobId: string; topN: string; bucketSpan: string; start: number; end: number; + overallScore?: number; }) { - const body = JSON.stringify({ topN, bucketSpan, start, end }); + const body = JSON.stringify({ + topN, + bucketSpan, + start, + end, + ...(overallScore ? { overall_score: overallScore } : {}), + }); return httpService.http({ path: `${basePath()}/anomaly_detectors/${jobId}/results/overall_buckets`, method: 'POST', diff --git a/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts b/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts index 6161eeb4e79408..ea07d32bfff1d0 100644 --- a/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts +++ b/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts @@ -22,7 +22,8 @@ export function resultsServiceProvider( latestMs: number, intervalMs: number, perPage?: number, - fromPage?: number + fromPage?: number, + swimLaneSeverity?: number ): Promise; getTopInfluencers( selectedJobIds: string[], @@ -40,7 +41,8 @@ export function resultsServiceProvider( topN: any, earliestMs: any, latestMs: any, - interval?: any + interval?: any, + overallScore?: number ): Promise; getInfluencerValueMaxScoreByTime( jobIds: string[], @@ -52,7 +54,8 @@ export function resultsServiceProvider( maxResults: number, perPage: number, fromPage: number, - influencersFilterQuery: InfluencersFilterQuery + influencersFilterQuery: InfluencersFilterQuery, + swimLaneSeverity?: number ): Promise; getRecordInfluencers(): Promise; getRecordsForDetector(): Promise; diff --git a/x-pack/plugins/ml/public/application/services/results_service/results_service.js b/x-pack/plugins/ml/public/application/services/results_service/results_service.js index 71be7bcd2b7eb7..bb6f6b5969ac4d 100644 --- a/x-pack/plugins/ml/public/application/services/results_service/results_service.js +++ b/x-pack/plugins/ml/public/application/services/results_service/results_service.js @@ -30,7 +30,15 @@ export function resultsServiceProvider(mlApiServices) { // Pass an empty array or ['*'] to search over all job IDs. // Returned response contains a results property, with a key for job // which has results for the specified time range. - getScoresByBucket(jobIds, earliestMs, latestMs, intervalMs, perPage = 10, fromPage = 1) { + getScoresByBucket( + jobIds, + earliestMs, + latestMs, + intervalMs, + perPage = 10, + fromPage = 1, + swimLaneSeverity = 0 + ) { return new Promise((resolve, reject) => { const obj = { success: true, @@ -49,6 +57,13 @@ export function resultsServiceProvider(mlApiServices) { }, }, }, + { + range: { + anomaly_score: { + gt: swimLaneSeverity, + }, + }, + }, ]; if (jobIds && jobIds.length > 0 && !(jobIds.length === 1 && jobIds[0] === '*')) { @@ -463,7 +478,7 @@ export function resultsServiceProvider(mlApiServices) { // Obtains the overall bucket scores for the specified job ID(s). // Pass ['*'] to search over all job IDs. // Returned response contains a results property as an object of max score by time. - getOverallBucketScores(jobIds, topN, earliestMs, latestMs, interval) { + getOverallBucketScores(jobIds, topN, earliestMs, latestMs, interval, overallScore) { return new Promise((resolve, reject) => { const obj = { success: true, results: {} }; @@ -474,6 +489,7 @@ export function resultsServiceProvider(mlApiServices) { bucketSpan: interval, start: earliestMs, end: latestMs, + overallScore, }) .then((resp) => { const dataByTime = get(resp, ['overall_buckets'], []); @@ -507,7 +523,8 @@ export function resultsServiceProvider(mlApiServices) { maxResults = ANOMALY_SWIM_LANE_HARD_LIMIT, perPage = SWIM_LANE_DEFAULT_PAGE_SIZE, fromPage = 1, - influencersFilterQuery + influencersFilterQuery, + swimLaneSeverity ) { return new Promise((resolve, reject) => { const obj = { success: true, results: {} }; @@ -527,7 +544,7 @@ export function resultsServiceProvider(mlApiServices) { { range: { influencer_score: { - gt: 0, + gt: swimLaneSeverity !== undefined ? swimLaneSeverity : 0, }, }, }, diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss b/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss index 33f6c65e03e77f..cfd521c882fb71 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss @@ -19,10 +19,6 @@ float: right; } - .ml-anomalies-controls { - padding-top: $euiSizeXS; - } - .ml-timeseries-chart { svg { font-size: $euiFontSizeXS; diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index c33b780631f166..c2b806abcf2860 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -26,11 +26,9 @@ import { EuiFlexGroup, EuiFlexItem, EuiFormRow, - EuiIcon, EuiSpacer, EuiPanel, EuiTitle, - EuiToolTip, EuiAccordion, EuiBadge, } from '@elastic/eui'; @@ -1273,41 +1271,12 @@ export class TimeSeriesExplorer extends React.Component { /> - - - - - + + + - - - - {i18n.translate('xpack.ml.timeSeriesExplorer.intervalLabel', { - defaultMessage: 'Interval', - })} - - - - } - > - - + + diff --git a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts index 6adf6fa474cad0..5205ea7353ac61 100644 --- a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts +++ b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts @@ -522,6 +522,7 @@ export function jobRoutes({ router, routeGuard }: RouteInitialization) { bucket_span: request.body.bucketSpan, start: request.body.start !== undefined ? String(request.body.start) : undefined, end: request.body.end !== undefined ? String(request.body.end) : undefined, + overall_score: request.body.overall_score ?? 0, }, }); return response.ok({ diff --git a/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts b/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts index 4217002e61ef72..392c0d3514d648 100644 --- a/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts +++ b/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts @@ -186,6 +186,7 @@ export const getOverallBucketsSchema = schema.object({ bucketSpan: schema.string(), start: schema.number(), end: schema.number(), + overall_score: schema.maybe(schema.number()), }); export const getCategoriesSchema = schema.object({ diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index fe77b3823ba442..94cc5ca60e451f 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -15967,7 +15967,6 @@ "xpack.ml.timeSeriesExplorer.forecastsList.viewForecastAriaLabel": "{createdDate} に作成された予測を表示", "xpack.ml.timeSeriesExplorer.highestAnomalyScoreErrorToastTitle": "最高異常値スコアのレコードの取得中にエラーが発生しました", "xpack.ml.timeSeriesExplorer.ignoreTimeRangeInfo": "リストには、ジョブのライフタイム中に作成されたすべての異常値の値が含まれます。", - "xpack.ml.timeSeriesExplorer.intervalLabel": "間隔", "xpack.ml.timeSeriesExplorer.invalidTimeRangeInUrlCallout": "無効なデフォルト時間フィルターのため、このジョブの時間フィルターが全範囲に変更されました。{field}の詳細設定を確認してください。", "xpack.ml.timeSeriesExplorer.loadingLabel": "読み込み中", "xpack.ml.timeSeriesExplorer.metricPlotByOption": "関数", @@ -15990,7 +15989,6 @@ "xpack.ml.timeSeriesExplorer.runControls.runNewForecastTitle": "新規予測の実行", "xpack.ml.timeSeriesExplorer.selectFieldMessage": "{fieldName}を選択してください", "xpack.ml.timeSeriesExplorer.setManualInputHelperText": "一致する値がありません", - "xpack.ml.timeSeriesExplorer.severityThresholdLabel": "深刻度のしきい値", "xpack.ml.timeSeriesExplorer.showForecastLabel": "予測を表示", "xpack.ml.timeSeriesExplorer.showModelBoundsLabel": "モデルバウンドを表示", "xpack.ml.timeSeriesExplorer.singleTimeSeriesAnalysisTitle": "{functionLabel} の単独時系列分析", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 9e7996ec09d927..4f78e9c0e0068d 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -16195,7 +16195,6 @@ "xpack.ml.timeSeriesExplorer.forecastsList.viewForecastAriaLabel": "查看在 {createdDate} 创建的预测", "xpack.ml.timeSeriesExplorer.highestAnomalyScoreErrorToastTitle": "在获取异常分数最高的记录时出错", "xpack.ml.timeSeriesExplorer.ignoreTimeRangeInfo": "该列表包含在作业生命周期内创建的所有异常的值。", - "xpack.ml.timeSeriesExplorer.intervalLabel": "时间间隔", "xpack.ml.timeSeriesExplorer.invalidTimeRangeInUrlCallout": "由于默认时间筛选无效,时间筛选已更改为此作业的完整范围。检查 {field} 的高级设置。", "xpack.ml.timeSeriesExplorer.loadingLabel": "正在加载", "xpack.ml.timeSeriesExplorer.metricPlotByOption": "函数", @@ -16218,7 +16217,6 @@ "xpack.ml.timeSeriesExplorer.runControls.runNewForecastTitle": "运行新的预测", "xpack.ml.timeSeriesExplorer.selectFieldMessage": "选择 {fieldName}", "xpack.ml.timeSeriesExplorer.setManualInputHelperText": "无匹配值", - "xpack.ml.timeSeriesExplorer.severityThresholdLabel": "严重性阈值", "xpack.ml.timeSeriesExplorer.showForecastLabel": "显示预测", "xpack.ml.timeSeriesExplorer.showModelBoundsLabel": "显示模型边界", "xpack.ml.timeSeriesExplorer.singleMetricRequiredMessage": "要查看单个指标,请选择 {missingValuesCount, plural, one {{fieldName1} 的值} other {{fieldName1} 和 {fieldName2} 的值}}。", From 0bcd78b0e999feb95057f5e6eafdb572b9b2fe39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Fri, 28 May 2021 15:43:30 -0400 Subject: [PATCH 02/68] [APM] Move APM tutorial from apm_oss to x-pack/apm (#100780) * Register tutorial on APM plugin * using files from apm * removing tutorial from apm_oss * removing export * fixing i18n Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- src/plugins/apm_oss/public/index.ts | 2 - src/plugins/apm_oss/server/index.ts | 18 - src/plugins/apm_oss/server/plugin.ts | 27 +- src/plugins/apm_oss/server/tutorial/index.ts | 84 -- .../instructions/apm_agent_instructions.ts | 754 -------------- .../apm}/common/index_pattern_constants.ts | 5 +- .../plugins/apm}/public/assets/apm.png | Bin .../VisitorBreakdownMap/useLayerList.ts | 2 +- .../VisitorBreakdownMap/useMapFilters.ts | 2 +- .../Links/DiscoverLinks/DiscoverLink.tsx | 2 +- .../create_static_index_pattern.ts | 6 +- x-pack/plugins/apm/server/plugin.ts | 39 +- .../tutorial/{ => envs}/elastic_cloud.ts | 6 +- .../apm}/server/tutorial/envs/on_prem.ts | 151 ++- x-pack/plugins/apm/server/tutorial/index.ts | 117 +++ .../apm}/server/tutorial/index_pattern.json | 0 .../instructions/apm_agent_instructions.ts | 931 ++++++++++++++++++ .../instructions/apm_server_instructions.ts | 70 +- .../translations/translations/ja-JP.json | 127 --- .../translations/translations/zh-CN.json | 127 --- 20 files changed, 1219 insertions(+), 1251 deletions(-) delete mode 100644 src/plugins/apm_oss/server/tutorial/index.ts delete mode 100644 src/plugins/apm_oss/server/tutorial/instructions/apm_agent_instructions.ts rename {src/plugins/apm_oss => x-pack/plugins/apm}/common/index_pattern_constants.ts (55%) rename {src/plugins/apm_oss => x-pack/plugins/apm}/public/assets/apm.png (100%) rename x-pack/plugins/apm/server/tutorial/{ => envs}/elastic_cloud.ts (94%) rename {src/plugins/apm_oss => x-pack/plugins/apm}/server/tutorial/envs/on_prem.ts (52%) create mode 100644 x-pack/plugins/apm/server/tutorial/index.ts rename {src/plugins/apm_oss => x-pack/plugins/apm}/server/tutorial/index_pattern.json (100%) create mode 100644 x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts rename {src/plugins/apm_oss => x-pack/plugins/apm}/server/tutorial/instructions/apm_server_instructions.ts (66%) diff --git a/src/plugins/apm_oss/public/index.ts b/src/plugins/apm_oss/public/index.ts index d5fcabbe146a96..fea8ac4a8a1e42 100644 --- a/src/plugins/apm_oss/public/index.ts +++ b/src/plugins/apm_oss/public/index.ts @@ -14,5 +14,3 @@ export function plugin() { return new ApmOssPlugin(); } export { ApmOssPluginSetup, ApmOssPluginStart } from './types'; - -export { APM_STATIC_INDEX_PATTERN_ID } from '../common/index_pattern_constants'; diff --git a/src/plugins/apm_oss/server/index.ts b/src/plugins/apm_oss/server/index.ts index a02e28201a1b90..1424cb1c7126fb 100644 --- a/src/plugins/apm_oss/server/index.ts +++ b/src/plugins/apm_oss/server/index.ts @@ -7,7 +7,6 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; -import apmIndexPattern from './tutorial/index_pattern.json'; import { PluginInitializerContext } from '../../../core/server'; import { APMOSSPlugin } from './plugin'; @@ -32,20 +31,3 @@ export function plugin(initializerContext: PluginInitializerContext) { export type APMOSSConfig = TypeOf; export { APMOSSPluginSetup } from './plugin'; - -export { apmIndexPattern }; - -export { APM_STATIC_INDEX_PATTERN_ID } from '../common/index_pattern_constants'; - -export { - createNodeAgentInstructions, - createDjangoAgentInstructions, - createFlaskAgentInstructions, - createRailsAgentInstructions, - createRackAgentInstructions, - createJsAgentInstructions, - createGoAgentInstructions, - createJavaAgentInstructions, - createDotNetAgentInstructions, - createPhpAgentInstructions, -} from './tutorial/instructions/apm_agent_instructions'; diff --git a/src/plugins/apm_oss/server/plugin.ts b/src/plugins/apm_oss/server/plugin.ts index e504d5f0b9a9fa..02a8ac38be2a39 100644 --- a/src/plugins/apm_oss/server/plugin.ts +++ b/src/plugins/apm_oss/server/plugin.ts @@ -6,38 +6,18 @@ * Side Public License, v 1. */ -import { Plugin, CoreSetup, PluginInitializerContext } from 'src/core/server'; import { Observable } from 'rxjs'; +import { Plugin, PluginInitializerContext } from 'src/core/server'; import { APMOSSConfig } from './'; -import { HomeServerPluginSetup, TutorialProvider } from '../../home/server'; -import { tutorialProvider } from './tutorial'; export class APMOSSPlugin implements Plugin { constructor(private readonly initContext: PluginInitializerContext) { this.initContext = initContext; } - public setup(core: CoreSetup, plugins: { home: HomeServerPluginSetup }) { + public setup() { const config$ = this.initContext.config.create(); - const config = this.initContext.config.get(); - - const apmTutorialProvider = tutorialProvider({ - indexPatternTitle: config.indexPattern, - indices: { - errorIndices: config.errorIndices, - metricsIndices: config.metricsIndices, - onboardingIndices: config.onboardingIndices, - sourcemapIndices: config.sourcemapIndices, - transactionIndices: config.transactionIndices, - }, - }); - plugins.home.tutorials.registerTutorial(apmTutorialProvider); - - return { - config, - config$, - getRegisteredTutorialProvider: () => apmTutorialProvider, - }; + return { config, config$ }; } start() {} @@ -47,5 +27,4 @@ export class APMOSSPlugin implements Plugin { export interface APMOSSPluginSetup { config: APMOSSConfig; config$: Observable; - getRegisteredTutorialProvider(): TutorialProvider; } diff --git a/src/plugins/apm_oss/server/tutorial/index.ts b/src/plugins/apm_oss/server/tutorial/index.ts deleted file mode 100644 index ce7fec406e7ac0..00000000000000 --- a/src/plugins/apm_oss/server/tutorial/index.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { i18n } from '@kbn/i18n'; -import { onPremInstructions } from './envs/on_prem'; -import apmIndexPattern from './index_pattern.json'; -import { ArtifactsSchema, TutorialsCategory } from '../../../../../src/plugins/home/server'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../common/index_pattern_constants'; - -const apmIntro = i18n.translate('apmOss.tutorial.introduction', { - defaultMessage: 'Collect in-depth performance metrics and errors from inside your applications.', -}); -const moduleName = 'apm'; - -export const tutorialProvider = ({ - indexPatternTitle, - indices, -}: { - indexPatternTitle: string; - indices: { - errorIndices: string; - transactionIndices: string; - metricsIndices: string; - sourcemapIndices: string; - onboardingIndices: string; - }; -}) => () => { - const savedObjects = [ - { - ...apmIndexPattern, - id: APM_STATIC_INDEX_PATTERN_ID, - attributes: { - ...apmIndexPattern.attributes, - title: indexPatternTitle, - }, - }, - ]; - - const artifacts: ArtifactsSchema = { - dashboards: [ - { - id: '8d3ed660-7828-11e7-8c47-65b845b5cfb3', - linkLabel: i18n.translate('apmOss.tutorial.specProvider.artifacts.dashboards.linkLabel', { - defaultMessage: 'APM dashboard', - }), - isOverview: true, - }, - ], - }; - - return { - id: 'apm', - name: i18n.translate('apmOss.tutorial.specProvider.name', { - defaultMessage: 'APM', - }), - moduleName, - category: TutorialsCategory.OTHER, - shortDescription: apmIntro, - longDescription: i18n.translate('apmOss.tutorial.specProvider.longDescription', { - defaultMessage: - 'Application Performance Monitoring (APM) collects in-depth \ -performance metrics and errors from inside your application. \ -It allows you to monitor the performance of thousands of applications in real time. \ -[Learn more]({learnMoreLink}).', - values: { - learnMoreLink: - '{config.docs.base_url}guide/en/apm/get-started/{config.docs.version}/index.html', - }, - }), - euiIconType: 'apmApp', - artifacts, - onPrem: onPremInstructions(indices), - previewImagePath: '/plugins/apmOss/assets/apm.png', - savedObjects, - savedObjectsInstallMsg: i18n.translate('apmOss.tutorial.specProvider.savedObjectsInstallMsg', { - defaultMessage: 'An APM index pattern is required for some features in the APM UI.', - }), - }; -}; diff --git a/src/plugins/apm_oss/server/tutorial/instructions/apm_agent_instructions.ts b/src/plugins/apm_oss/server/tutorial/instructions/apm_agent_instructions.ts deleted file mode 100644 index ba2b062870cf68..00000000000000 --- a/src/plugins/apm_oss/server/tutorial/instructions/apm_agent_instructions.ts +++ /dev/null @@ -1,754 +0,0 @@ -/* - * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { i18n } from '@kbn/i18n'; - -export const createNodeAgentInstructions = (apmServerUrl = '', secretToken = '') => [ - { - title: i18n.translate('apmOss.tutorial.nodeClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('apmOss.tutorial.nodeClient.install.textPre', { - defaultMessage: 'Install the APM agent for Node.js as a dependency to your application.', - }), - commands: ['npm install elastic-apm-node --save'], - }, - { - title: i18n.translate('apmOss.tutorial.nodeClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate('apmOss.tutorial.nodeClient.configure.textPre', { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the `serviceName`. \ -This agent supports a variety of frameworks but can also be used with your custom stack.', - }), - commands: `// ${i18n.translate( - 'apmOss.tutorial.nodeClient.configure.commands.addThisToTheFileTopComment', - { - defaultMessage: 'Add this to the VERY top of the first file loaded in your app', - } - )} -var apm = require('elastic-apm-node').start({curlyOpen} - - // ${i18n.translate( - 'apmOss.tutorial.nodeClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Override the service name from package.json', - } - )} - // ${i18n.translate('apmOss.tutorial.nodeClient.configure.commands.allowedCharactersComment', { - defaultMessage: 'Allowed characters: a-z, A-Z, 0-9, -, _, and space', - })} - serviceName: '', - - // ${i18n.translate( - 'apmOss.tutorial.nodeClient.configure.commands.useIfApmRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a secret token', - } - )} - secretToken: '${secretToken}', - - // ${i18n.translate( - 'apmOss.tutorial.nodeClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: 'Set the custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } - )} - serverUrl: '${apmServerUrl}', - - // ${i18n.translate( - 'apmOss.tutorial.nodeClient.configure.commands.setCustomServiceEnvironmentComment', - { - defaultMessage: 'Set the service environment', - } - )} - environment: 'production' -{curlyClose})`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.nodeClient.configure.textPost', { - defaultMessage: - 'See [the documentation]({documentationLink}) for advanced usage, including how to use with \ -[Babel/ES Modules]({babelEsModulesLink}).', - values: { - documentationLink: '{config.docs.base_url}guide/en/apm/agent/nodejs/current/index.html', - babelEsModulesLink: - '{config.docs.base_url}guide/en/apm/agent/nodejs/current/advanced-setup.html#es-modules', - }, - }), - }, -]; - -export const createDjangoAgentInstructions = (apmServerUrl = '', secretToken = '') => [ - { - title: i18n.translate('apmOss.tutorial.djangoClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('apmOss.tutorial.djangoClient.install.textPre', { - defaultMessage: 'Install the APM agent for Python as a dependency.', - }), - commands: ['$ pip install elastic-apm'], - }, - { - title: i18n.translate('apmOss.tutorial.djangoClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate('apmOss.tutorial.djangoClient.configure.textPre', { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the `SERVICE_NAME`.', - }), - commands: `# ${i18n.translate( - 'apmOss.tutorial.djangoClient.configure.commands.addAgentComment', - { - defaultMessage: 'Add the agent to the installed apps', - } - )} -INSTALLED_APPS = ( - 'elasticapm.contrib.django', - # ... -) - -ELASTIC_APM = {curlyOpen} - # ${i18n.translate( - 'apmOss.tutorial.djangoClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Set the required service name. Allowed characters:', - } - )} - # ${i18n.translate('apmOss.tutorial.djangoClient.configure.commands.allowedCharactersComment', { - defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', - })} - 'SERVICE_NAME': '', - - # ${i18n.translate( - 'apmOss.tutorial.djangoClient.configure.commands.useIfApmServerRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a secret token', - } - )} - 'SECRET_TOKEN': '${secretToken}', - - # ${i18n.translate( - 'apmOss.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: 'Set the custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } - )} - 'SERVER_URL': '${apmServerUrl}', - - # ${i18n.translate( - 'apmOss.tutorial.djangoClient.configure.commands.setServiceEnvironmentComment', - { - defaultMessage: 'Set the service environment', - } - )} - 'ENVIRONMENT': 'production', -{curlyClose} - -# ${i18n.translate('apmOss.tutorial.djangoClient.configure.commands.addTracingMiddlewareComment', { - defaultMessage: 'To send performance metrics, add our tracing middleware:', - })} -MIDDLEWARE = ( - 'elasticapm.contrib.django.middleware.TracingMiddleware', - #... -)`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.djangoClient.configure.textPost', { - defaultMessage: 'See the [documentation]({documentationLink}) for advanced usage.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/python/current/django-support.html', - }, - }), - }, -]; - -export const createFlaskAgentInstructions = (apmServerUrl = '', secretToken = '') => [ - { - title: i18n.translate('apmOss.tutorial.flaskClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('apmOss.tutorial.flaskClient.install.textPre', { - defaultMessage: 'Install the APM agent for Python as a dependency.', - }), - commands: ['$ pip install elastic-apm[flask]'], - }, - { - title: i18n.translate('apmOss.tutorial.flaskClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate('apmOss.tutorial.flaskClient.configure.textPre', { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the `SERVICE_NAME`.', - }), - commands: `# ${i18n.translate( - 'apmOss.tutorial.flaskClient.configure.commands.initializeUsingEnvironmentVariablesComment', - { - defaultMessage: 'initialize using environment variables', - } - )} -from elasticapm.contrib.flask import ElasticAPM -app = Flask(__name__) -apm = ElasticAPM(app) - -# ${i18n.translate('apmOss.tutorial.flaskClient.configure.commands.configureElasticApmComment', { - defaultMessage: "or configure to use ELASTIC_APM in your application's settings", - })} -from elasticapm.contrib.flask import ElasticAPM -app.config['ELASTIC_APM'] = {curlyOpen} - # ${i18n.translate( - 'apmOss.tutorial.flaskClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Set the required service name. Allowed characters:', - } - )} - # ${i18n.translate('apmOss.tutorial.flaskClient.configure.commands.allowedCharactersComment', { - defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', - })} - 'SERVICE_NAME': '', - - # ${i18n.translate( - 'apmOss.tutorial.flaskClient.configure.commands.useIfApmServerRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a secret token', - } - )} - 'SECRET_TOKEN': '${secretToken}', - - # ${i18n.translate( - 'apmOss.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: 'Set the custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } - )} - 'SERVER_URL': '${apmServerUrl}', - - # ${i18n.translate( - 'apmOss.tutorial.flaskClient.configure.commands.setServiceEnvironmentComment', - { - defaultMessage: 'Set the service environment', - } - )} - 'ENVIRONMENT': 'production', -{curlyClose} - -apm = ElasticAPM(app)`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.flaskClient.configure.textPost', { - defaultMessage: 'See the [documentation]({documentationLink}) for advanced usage.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/python/current/flask-support.html', - }, - }), - }, -]; - -export const createRailsAgentInstructions = (apmServerUrl = '', secretToken = '') => [ - { - title: i18n.translate('apmOss.tutorial.railsClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('apmOss.tutorial.railsClient.install.textPre', { - defaultMessage: 'Add the agent to your Gemfile.', - }), - commands: [`gem 'elastic-apm'`], - }, - { - title: i18n.translate('apmOss.tutorial.railsClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate('apmOss.tutorial.railsClient.configure.textPre', { - defaultMessage: - 'APM is automatically started when your app boots. Configure the agent, by creating the config file {configFile}', - values: { configFile: '`config/elastic_apm.yml`' }, - }), - commands: `# config/elastic_apm.yml: - -# Set the service name - allowed characters: a-z, A-Z, 0-9, -, _ and space -# Defaults to the name of your Rails app -service_name: 'my-service' - -# Use if APM Server requires a secret token -secret_token: '${secretToken}' - -# Set the custom APM Server URL (default: http://localhost:8200) -server_url: '${apmServerUrl || 'http://localhost:8200'}' - -# Set the service environment -environment: 'production'`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.railsClient.configure.textPost', { - defaultMessage: - 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', - values: { - documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html', - }, - }), - }, -]; - -export const createRackAgentInstructions = (apmServerUrl = '', secretToken = '') => [ - { - title: i18n.translate('apmOss.tutorial.rackClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('apmOss.tutorial.rackClient.install.textPre', { - defaultMessage: 'Add the agent to your Gemfile.', - }), - commands: [`gem 'elastic-apm'`], - }, - { - title: i18n.translate('apmOss.tutorial.rackClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate('apmOss.tutorial.rackClient.configure.textPre', { - defaultMessage: - 'For Rack or a compatible framework (e.g. Sinatra), include the middleware in your app and start the agent.', - }), - commands: `# config.ru - require 'sinatra/base' - - class MySinatraApp < Sinatra::Base - use ElasticAPM::Middleware - - # ... - end - - ElasticAPM.start( - app: MySinatraApp, # ${i18n.translate( - 'apmOss.tutorial.rackClient.configure.commands.requiredComment', - { - defaultMessage: 'required', - } - )} - config_file: '' # ${i18n.translate( - 'apmOss.tutorial.rackClient.configure.commands.optionalComment', - { - defaultMessage: 'optional, defaults to config/elastic_apm.yml', - } - )} - ) - - run MySinatraApp - - at_exit {curlyOpen} ElasticAPM.stop {curlyClose}`.split('\n'), - }, - { - title: i18n.translate('apmOss.tutorial.rackClient.createConfig.title', { - defaultMessage: 'Create config file', - }), - textPre: i18n.translate('apmOss.tutorial.rackClient.createConfig.textPre', { - defaultMessage: 'Create a config file {configFile}:', - values: { configFile: '`config/elastic_apm.yml`' }, - }), - commands: `# config/elastic_apm.yml: - -# ${i18n.translate('apmOss.tutorial.rackClient.createConfig.commands.setServiceNameComment', { - defaultMessage: 'Set the service name - allowed characters: a-z, A-Z, 0-9, -, _ and space', - })} -# ${i18n.translate( - 'apmOss.tutorial.rackClient.createConfig.commands.defaultsToTheNameOfRackAppClassComment', - { - defaultMessage: "Defaults to the name of your Rack app's class.", - } - )} -service_name: 'my-service' - -# ${i18n.translate( - 'apmOss.tutorial.rackClient.createConfig.commands.useIfApmServerRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a token', - } - )} -secret_token: '${secretToken}' - -# ${i18n.translate('apmOss.tutorial.rackClient.createConfig.commands.setCustomApmServerComment', { - defaultMessage: 'Set custom APM Server URL (default: {defaultServerUrl})', - values: { defaultServerUrl: 'http://localhost:8200' }, - })} -server_url: '${apmServerUrl || 'http://localhost:8200'}', - -# ${i18n.translate('apmOss.tutorial.rackClient.createConfig.commands.setServiceEnvironment', { - defaultMessage: 'Set the service environment', - })} -environment: 'production'`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.rackClient.createConfig.textPost', { - defaultMessage: - 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', - values: { - documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html', - }, - }), - }, -]; - -export const createJsAgentInstructions = (apmServerUrl = '') => [ - { - title: i18n.translate('apmOss.tutorial.jsClient.enableRealUserMonitoring.title', { - defaultMessage: 'Enable Real User Monitoring support in APM Server', - }), - textPre: i18n.translate('apmOss.tutorial.jsClient.enableRealUserMonitoring.textPre', { - defaultMessage: - 'APM Server disables RUM support by default. See the [documentation]({documentationLink}) \ -for details on how to enable RUM support.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/server/{config.docs.version}/configuration-rum.html', - }, - }), - }, - { - title: i18n.translate('apmOss.tutorial.jsClient.installDependency.title', { - defaultMessage: 'Set up the Agent as a dependency', - }), - textPre: i18n.translate('apmOss.tutorial.jsClient.installDependency.textPre', { - defaultMessage: - 'You can install the Agent as a dependency to your application with \ -`npm install @elastic/apm-rum --save`.\n\n\ -The Agent can then be initialized and configured in your application like this:', - }), - commands: `import {curlyOpen} init as initApm {curlyClose} from '@elastic/apm-rum' -var apm = initApm({curlyOpen} - - // ${i18n.translate( - 'apmOss.tutorial.jsClient.installDependency.commands.setRequiredServiceNameComment', - { - defaultMessage: - 'Set required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)', - } - )} - serviceName: 'your-app-name', - - // ${i18n.translate( - 'apmOss.tutorial.jsClient.installDependency.commands.setCustomApmServerUrlComment', - { - defaultMessage: 'Set custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } - )} - serverUrl: '${apmServerUrl}', - - // ${i18n.translate( - 'apmOss.tutorial.jsClient.installDependency.commands.setServiceVersionComment', - { - defaultMessage: 'Set the service version (required for source map feature)', - } - )} - serviceVersion: '', - - // ${i18n.translate( - 'apmOss.tutorial.jsClient.installDependency.commands.setServiceEnvironmentComment', - { - defaultMessage: 'Set the service environment', - } - )} - environment: 'production' -{curlyClose})`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.jsClient.installDependency.textPost', { - defaultMessage: - 'Framework integrations, like React or Angular, have custom dependencies. \ -See the [integration documentation]({docLink}) for more information.', - values: { - docLink: - '{config.docs.base_url}guide/en/apm/agent/rum-js/current/framework-integrations.html', - }, - }), - }, - { - title: i18n.translate('apmOss.tutorial.jsClient.scriptTags.title', { - defaultMessage: 'Set up the Agent with Script Tags', - }), - textPre: i18n.translate('apmOss.tutorial.jsClient.scriptTags.textPre', { - defaultMessage: - "Alternatively, you can use Script tags to set up and configure the Agent. \ -Add a ` - -`.split('\n'), - }, -]; - -export const createGoAgentInstructions = (apmServerUrl = '', secretToken = '') => [ - { - title: i18n.translate('apmOss.tutorial.goClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('apmOss.tutorial.goClient.install.textPre', { - defaultMessage: 'Install the APM agent packages for Go.', - }), - commands: ['go get go.elastic.co/apm'], - }, - { - title: i18n.translate('apmOss.tutorial.goClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate('apmOss.tutorial.goClient.configure.textPre', { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the executable \ -file name, or the `ELASTIC_APM_SERVICE_NAME` environment variable.', - }), - commands: `# ${i18n.translate( - 'apmOss.tutorial.goClient.configure.commands.initializeUsingEnvironmentVariablesComment', - { - defaultMessage: 'Initialize using environment variables:', - } - )} - -# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.setServiceNameComment', { - defaultMessage: 'Set the service name. Allowed characters: # a-z, A-Z, 0-9, -, _, and space.', - })} -# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.usedExecutableNameComment', { - defaultMessage: - 'If ELASTIC_APM_SERVICE_NAME is not specified, the executable name will be used.', - })} -export ELASTIC_APM_SERVICE_NAME= - -# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.setCustomApmServerUrlComment', { - defaultMessage: 'Set custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - })} -export ELASTIC_APM_SERVER_URL=${apmServerUrl} - -# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.useIfApmRequiresTokenComment', { - defaultMessage: 'Use if APM Server requires a secret token', - })} -export ELASTIC_APM_SECRET_TOKEN=${secretToken} - -# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.setServiceEnvironment', { - defaultMessage: 'Set the service environment', - })} -export ELASTIC_APM_ENVIRONMENT= -`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.goClient.configure.textPost', { - defaultMessage: 'See the [documentation]({documentationLink}) for advanced configuration.', - values: { - documentationLink: '{config.docs.base_url}guide/en/apm/agent/go/current/configuration.html', - }, - }), - }, - { - title: i18n.translate('apmOss.tutorial.goClient.instrument.title', { - defaultMessage: 'Instrument your application', - }), - textPre: i18n.translate('apmOss.tutorial.goClient.instrument.textPre', { - defaultMessage: - 'Instrument your Go application by using one of the provided instrumentation modules or \ -by using the tracer API directly.', - }), - commands: `\ -import ( - "net/http" - - "go.elastic.co/apm/module/apmhttp" -) - -func main() {curlyOpen} - mux := http.NewServeMux() - ... - http.ListenAndServe(":8080", apmhttp.Wrap(mux)) -{curlyClose} -`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.goClient.instrument.textPost', { - defaultMessage: - 'See the [documentation]({documentationLink}) for a detailed \ -guide to instrumenting Go source code.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/go/current/instrumenting-source.html', - }, - }), - }, -]; - -export const createJavaAgentInstructions = (apmServerUrl = '', secretToken = '') => [ - { - title: i18n.translate('apmOss.tutorial.javaClient.download.title', { - defaultMessage: 'Download the APM agent', - }), - textPre: i18n.translate('apmOss.tutorial.javaClient.download.textPre', { - defaultMessage: - 'Download the agent jar from [Maven Central]({mavenCentralLink}). \ -Do **not** add the agent as a dependency to your application.', - values: { - mavenCentralLink: 'http://search.maven.org/#search%7Cga%7C1%7Ca%3Aelastic-apm-agent', - }, - }), - }, - { - title: i18n.translate('apmOss.tutorial.javaClient.startApplication.title', { - defaultMessage: 'Start your application with the javaagent flag', - }), - textPre: i18n.translate('apmOss.tutorial.javaClient.startApplication.textPre', { - defaultMessage: - 'Add the `-javaagent` flag and configure the agent with system properties.\n\n \ -* Set the required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)\n \ -* Set the custom APM Server URL (default: {customApmServerUrl})\n \ -* Set the APM Server secret token\n \ -* Set the service environment\n \ -* Set the base package of your application', - values: { customApmServerUrl: 'http://localhost:8200' }, - }), - commands: `java -javaagent:/path/to/elastic-apm-agent-.jar \\ - -Delastic.apm.service_name=my-application \\ - -Delastic.apm.server_urls=${apmServerUrl || 'http://localhost:8200'} \\ - -Delastic.apm.secret_token=${secretToken} \\ - -Delastic.apm.environment=production \\ - -Delastic.apm.application_packages=org.example \\ - -jar my-application.jar`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.javaClient.startApplication.textPost', { - defaultMessage: - 'See the [documentation]({documentationLink}) for configuration options and advanced \ -usage.', - values: { - documentationLink: '{config.docs.base_url}guide/en/apm/agent/java/current/index.html', - }, - }), - }, -]; - -export const createDotNetAgentInstructions = (apmServerUrl = '', secretToken = '') => [ - { - title: i18n.translate('apmOss.tutorial.dotNetClient.download.title', { - defaultMessage: 'Download the APM agent', - }), - textPre: i18n.translate('apmOss.tutorial.dotNetClient.download.textPre', { - defaultMessage: - 'Add the the agent package(s) from [NuGet]({allNuGetPackagesLink}) to your .NET application. There are multiple \ - NuGet packages available for different use cases. \n\nFor an ASP.NET Core application with Entity Framework \ - Core download the [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}) package. This package will automatically add every \ - agent component to your application. \n\n In case you would like to minimize the dependencies, you can use the \ - [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) package for just \ - ASP.NET Core monitoring or the [Elastic.Apm.EfCore]({efCorePackageLink}) package for just Entity Framework Core monitoring. \n\n \ - In case you only want to use the public Agent API for manual instrumentation use the [Elastic.Apm]({elasticApmPackageLink}) package.', - values: { - allNuGetPackagesLink: 'https://www.nuget.org/packages?q=Elastic.apm', - netCoreAllApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm.NetCoreAll', - aspNetCorePackageLink: 'https://www.nuget.org/packages/Elastic.Apm.AspNetCore', - efCorePackageLink: 'https://www.nuget.org/packages/Elastic.Apm.EntityFrameworkCore', - elasticApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm', - }, - }), - }, - { - title: i18n.translate('apmOss.tutorial.dotNetClient.configureApplication.title', { - defaultMessage: 'Add the agent to the application', - }), - textPre: i18n.translate('apmOss.tutorial.dotNetClient.configureApplication.textPre', { - defaultMessage: - 'In case of ASP.NET Core with the `Elastic.Apm.NetCoreAll` package, call the `UseAllElasticApm` \ - method in the `Configure` method within the `Startup.cs` file.', - }), - commands: `public class Startup -{curlyOpen} - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - {curlyOpen} - app.UseAllElasticApm(Configuration); - //…rest of the method - {curlyClose} - //…rest of the class -{curlyClose}`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.dotNetClient.configureApplication.textPost', { - defaultMessage: - 'Passing an `IConfiguration` instance is optional and by doing so, the agent will read config settings through this \ - `IConfiguration` instance (e.g. from the `appsettings.json` file).', - }), - }, - { - title: i18n.translate('apmOss.tutorial.dotNetClient.configureAgent.title', { - defaultMessage: 'Sample appsettings.json file:', - }), - commands: `{curlyOpen} - "ElasticApm": {curlyOpen} - "SecretToken": "${secretToken}", - "ServerUrls": "${ - apmServerUrl || 'http://localhost:8200' - }", //Set custom APM Server URL (default: http://localhost:8200) - "ServiceName": "MyApp", //allowed characters: a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application - "Environment": "production", // Set the service environment - {curlyClose} -{curlyClose}`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.dotNetClient.configureAgent.textPost', { - defaultMessage: - 'In case you don’t pass an `IConfiguration` instance to the agent (e.g. in case of non ASP.NET Core applications) \ - you can also configure the agent through environment variables. \n \ - See [the documentation]({documentationLink}) for advanced usage.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/dotnet/current/configuration.html', - }, - }), - }, -]; - -export const createPhpAgentInstructions = (apmServerUrl = '', secretToken = '') => [ - { - title: i18n.translate('apmOss.tutorial.phpClient.download.title', { - defaultMessage: 'Download the APM agent', - }), - textPre: i18n.translate('apmOss.tutorial.phpClient.download.textPre', { - defaultMessage: - 'Download the package corresponding to your platform from [GitHub releases]({githubReleasesLink}).', - values: { - githubReleasesLink: 'https://github.com/elastic/apm-agent-php/releases', - }, - }), - }, - { - title: i18n.translate('apmOss.tutorial.phpClient.installPackage.title', { - defaultMessage: 'Install the downloaded package', - }), - textPre: i18n.translate('apmOss.tutorial.phpClient.installPackage.textPre', { - defaultMessage: 'For example on Alpine Linux using APK package:', - }), - commands: ['apk add --allow-untrusted .apk'], - textPost: i18n.translate('apmOss.tutorial.phpClient.installPackage.textPost', { - defaultMessage: - 'See the [documentation]({documentationLink}) for installation commands on other supported platforms and advanced installation.', - values: { - documentationLink: '{config.docs.base_url}guide/en/apm/agent/php/current/setup.html', - }, - }), - }, - { - title: i18n.translate('apmOss.tutorial.phpClient.configureAgent.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate('apmOss.tutorial.phpClient.configureAgent.textPre', { - defaultMessage: - 'APM is automatically started when your app boots. Configure the agent either via `php.ini` file:', - }), - commands: `elastic_apm.server_url=http://localhost:8200 -elastic_apm.service_name="My service" -`.split('\n'), - textPost: i18n.translate('apmOss.tutorial.phpClient.configure.textPost', { - defaultMessage: - 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/php/current/configuration.html', - }, - }), - }, -]; diff --git a/src/plugins/apm_oss/common/index_pattern_constants.ts b/x-pack/plugins/apm/common/index_pattern_constants.ts similarity index 55% rename from src/plugins/apm_oss/common/index_pattern_constants.ts rename to x-pack/plugins/apm/common/index_pattern_constants.ts index c35e20ebd58e27..4b67bba1fef910 100644 --- a/src/plugins/apm_oss/common/index_pattern_constants.ts +++ b/x-pack/plugins/apm/common/index_pattern_constants.ts @@ -1,9 +1,8 @@ /* * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ export const APM_STATIC_INDEX_PATTERN_ID = 'apm_static_index_pattern_id'; diff --git a/src/plugins/apm_oss/public/assets/apm.png b/x-pack/plugins/apm/public/assets/apm.png similarity index 100% rename from src/plugins/apm_oss/public/assets/apm.png rename to x-pack/plugins/apm/public/assets/apm.png diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts index 8954adf2c18c71..c998964b864003 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts @@ -22,7 +22,7 @@ import { SYMBOLIZE_AS_TYPES, } from '../../../../../../maps/common/constants'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../../../../src/plugins/apm_oss/public'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../common/index_pattern_constants'; import { useUrlParams } from '../../../../context/url_params_context/use_url_params'; import { SERVICE_NAME, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useMapFilters.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useMapFilters.ts index 7a40880eb90536..e989577ac15aaa 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useMapFilters.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useMapFilters.ts @@ -17,7 +17,7 @@ import { USER_AGENT_OS, } from '../../../../../common/elasticsearch_fieldnames'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../../../../src/plugins/apm_oss/public'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../common/index_pattern_constants'; const getWildcardFilter = (field: string, value: string): Filter => { return { diff --git a/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx index 4343d504c33739..919d140c54c1eb 100644 --- a/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { useLocation } from 'react-router-dom'; import rison, { RisonValue } from 'rison-node'; import url from 'url'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../../../../src/plugins/apm_oss/public'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../common/index_pattern_constants'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { getTimepickerRisonData } from '../rison_helpers'; diff --git a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts index e627e9ed1d6cf6..607a7e6227a9d6 100644 --- a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts +++ b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts @@ -6,10 +6,8 @@ */ import { SavedObjectsErrorHelpers } from '../../../../../../src/core/server'; -import { - apmIndexPattern, - APM_STATIC_INDEX_PATTERN_ID, -} from '../../../../../../src/plugins/apm_oss/server'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../../common/index_pattern_constants'; +import apmIndexPattern from '../../tutorial/index_pattern.json'; import { hasHistoricalAgentData } from '../services/get_services/has_historical_agent_data'; import { Setup } from '../helpers/setup_request'; import { APMRouteHandlerResources } from '../../routes/typings'; diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index 8d83f762e2023e..824eba9bce0b08 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; import { combineLatest } from 'rxjs'; import { map, take } from 'rxjs/operators'; import { @@ -32,7 +31,6 @@ import { createApmAgentConfigurationIndex } from './lib/settings/agent_configura import { getApmIndices } from './lib/settings/apm_indices/get_apm_indices'; import { createApmCustomLinkIndex } from './lib/settings/custom_link/create_custom_link_index'; import { apmIndices, apmTelemetry } from './saved_objects'; -import { createElasticCloudInstructions } from './tutorial/elastic_cloud'; import { uiSettings } from './ui_settings'; import type { ApmPluginRequestHandlerContext, @@ -51,6 +49,7 @@ import { SERVICE_NAME, TRANSACTION_TYPE, } from '../common/elasticsearch_fieldnames'; +import { tutorialProvider } from './tutorial'; export class APMPlugin implements @@ -103,28 +102,20 @@ export class APMPlugin }); } - const ossTutorialProvider = plugins.apmOss.getRegisteredTutorialProvider(); - plugins.home?.tutorials.unregisterTutorial(ossTutorialProvider); - plugins.home?.tutorials.registerTutorial(() => { - const ossPart = ossTutorialProvider({}); - if (this.currentConfig!['xpack.apm.ui.enabled'] && ossPart.artifacts) { - // @ts-expect-error ossPart.artifacts.application is readonly - ossPart.artifacts.application = { - path: '/app/apm', - label: i18n.translate( - 'xpack.apm.tutorial.specProvider.artifacts.application.label', - { - defaultMessage: 'Launch APM', - } - ), - }; - } - - return { - ...ossPart, - elasticCloud: createElasticCloudInstructions(plugins.cloud), - }; - }); + plugins.home?.tutorials.registerTutorial( + tutorialProvider({ + isEnabled: this.currentConfig['xpack.apm.ui.enabled'], + indexPatternTitle: this.currentConfig['apm_oss.indexPattern'], + cloud: plugins.cloud, + indices: { + errorIndices: this.currentConfig['apm_oss.errorIndices'], + metricsIndices: this.currentConfig['apm_oss.metricsIndices'], + onboardingIndices: this.currentConfig['apm_oss.onboardingIndices'], + sourcemapIndices: this.currentConfig['apm_oss.sourcemapIndices'], + transactionIndices: this.currentConfig['apm_oss.transactionIndices'], + }, + }) + ); plugins.features.registerKibanaFeature(APM_FEATURE); diff --git a/x-pack/plugins/apm/server/tutorial/elastic_cloud.ts b/x-pack/plugins/apm/server/tutorial/envs/elastic_cloud.ts similarity index 94% rename from x-pack/plugins/apm/server/tutorial/elastic_cloud.ts rename to x-pack/plugins/apm/server/tutorial/envs/elastic_cloud.ts index 08e1ff75d43242..c6afd6a592fff2 100644 --- a/x-pack/plugins/apm/server/tutorial/elastic_cloud.ts +++ b/x-pack/plugins/apm/server/tutorial/envs/elastic_cloud.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { INSTRUCTION_VARIANT } from '../../../../../src/plugins/home/server'; +import { INSTRUCTION_VARIANT } from '../../../../../../src/plugins/home/server'; import { createNodeAgentInstructions, @@ -19,8 +19,8 @@ import { createJavaAgentInstructions, createDotNetAgentInstructions, createPhpAgentInstructions, -} from '../../../../../src/plugins/apm_oss/server'; -import { CloudSetup } from '../../../cloud/server'; +} from '../instructions/apm_agent_instructions'; +import { CloudSetup } from '../../../../cloud/server'; export function createElasticCloudInstructions(cloudSetup?: CloudSetup) { const apmServerUrl = cloudSetup?.apm.url; diff --git a/src/plugins/apm_oss/server/tutorial/envs/on_prem.ts b/x-pack/plugins/apm/server/tutorial/envs/on_prem.ts similarity index 52% rename from src/plugins/apm_oss/server/tutorial/envs/on_prem.ts rename to x-pack/plugins/apm/server/tutorial/envs/on_prem.ts index 7d261abb0cc018..a0e96f563381cf 100644 --- a/src/plugins/apm_oss/server/tutorial/envs/on_prem.ts +++ b/x-pack/plugins/apm/server/tutorial/envs/on_prem.ts @@ -1,13 +1,12 @@ /* * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import { i18n } from '@kbn/i18n'; -import { INSTRUCTION_VARIANT } from '../../../../home/server'; +import { INSTRUCTION_VARIANT } from '../../../../../../src/plugins/home/server'; import { createWindowsServerInstructions, createEditConfig, @@ -50,31 +49,46 @@ export function onPremInstructions({ return { instructionSets: [ { - title: i18n.translate('apmOss.tutorial.apmServer.title', { + title: i18n.translate('xpack.apm.tutorial.apmServer.title', { defaultMessage: 'APM Server', }), callOut: { - title: i18n.translate('apmOss.tutorial.apmServer.callOut.title', { + title: i18n.translate('xpack.apm.tutorial.apmServer.callOut.title', { defaultMessage: 'Important: Updating to 7.0 or higher', }), - message: i18n.translate('apmOss.tutorial.apmServer.callOut.message', { - defaultMessage: `Please make sure your APM Server is updated to 7.0 or higher. \ + message: i18n.translate( + 'xpack.apm.tutorial.apmServer.callOut.message', + { + defaultMessage: `Please make sure your APM Server is updated to 7.0 or higher. \ You can also migrate your 6.x data with the migration assistant found in Kibana's management section.`, - }), + } + ), iconType: 'alert', }, instructionVariants: [ { id: INSTRUCTION_VARIANT.OSX, - instructions: [createDownloadServerOsx(), EDIT_CONFIG, START_SERVER_UNIX], + instructions: [ + createDownloadServerOsx(), + EDIT_CONFIG, + START_SERVER_UNIX, + ], }, { id: INSTRUCTION_VARIANT.DEB, - instructions: [createDownloadServerDeb(), EDIT_CONFIG, START_SERVER_UNIX_SYSV], + instructions: [ + createDownloadServerDeb(), + EDIT_CONFIG, + START_SERVER_UNIX_SYSV, + ], }, { id: INSTRUCTION_VARIANT.RPM, - instructions: [createDownloadServerRpm(), EDIT_CONFIG, START_SERVER_UNIX_SYSV], + instructions: [ + createDownloadServerRpm(), + EDIT_CONFIG, + START_SERVER_UNIX_SYSV, + ], }, { id: INSTRUCTION_VARIANT.WINDOWS, @@ -82,23 +96,38 @@ export function onPremInstructions({ }, ], statusCheck: { - title: i18n.translate('apmOss.tutorial.apmServer.statusCheck.title', { - defaultMessage: 'APM Server status', - }), - text: i18n.translate('apmOss.tutorial.apmServer.statusCheck.text', { - defaultMessage: - 'Make sure APM Server is running before you start implementing the APM agents.', - }), - btnLabel: i18n.translate('apmOss.tutorial.apmServer.statusCheck.btnLabel', { - defaultMessage: 'Check APM Server status', - }), - success: i18n.translate('apmOss.tutorial.apmServer.statusCheck.successMessage', { - defaultMessage: 'You have correctly setup APM Server', - }), - error: i18n.translate('apmOss.tutorial.apmServer.statusCheck.errorMessage', { - defaultMessage: - 'No APM Server detected. Please make sure it is running and you have updated to 7.0 or higher.', - }), + title: i18n.translate( + 'xpack.apm.tutorial.apmServer.statusCheck.title', + { + defaultMessage: 'APM Server status', + } + ), + text: i18n.translate( + 'xpack.apm.tutorial.apmServer.statusCheck.text', + { + defaultMessage: + 'Make sure APM Server is running before you start implementing the APM agents.', + } + ), + btnLabel: i18n.translate( + 'xpack.apm.tutorial.apmServer.statusCheck.btnLabel', + { + defaultMessage: 'Check APM Server status', + } + ), + success: i18n.translate( + 'xpack.apm.tutorial.apmServer.statusCheck.successMessage', + { + defaultMessage: 'You have correctly setup APM Server', + } + ), + error: i18n.translate( + 'xpack.apm.tutorial.apmServer.statusCheck.errorMessage', + { + defaultMessage: + 'No APM Server detected. Please make sure it is running and you have updated to 7.0 or higher.', + } + ), esHitsCheck: { index: onboardingIndices, query: { @@ -113,7 +142,7 @@ export function onPremInstructions({ }, }, { - title: i18n.translate('apmOss.tutorial.apmAgents.title', { + title: i18n.translate('xpack.apm.tutorial.apmAgents.title', { defaultMessage: 'APM Agents', }), instructionVariants: [ @@ -159,30 +188,56 @@ export function onPremInstructions({ }, ], statusCheck: { - title: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.title', { - defaultMessage: 'Agent status', - }), - text: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.text', { - defaultMessage: - 'Make sure your application is running and the agents are sending data.', - }), - btnLabel: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.btnLabel', { - defaultMessage: 'Check agent status', - }), - success: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.successMessage', { - defaultMessage: 'Data successfully received from one or more agents', - }), - error: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.errorMessage', { - defaultMessage: 'No data has been received from agents yet', - }), + title: i18n.translate( + 'xpack.apm.tutorial.apmAgents.statusCheck.title', + { + defaultMessage: 'Agent status', + } + ), + text: i18n.translate( + 'xpack.apm.tutorial.apmAgents.statusCheck.text', + { + defaultMessage: + 'Make sure your application is running and the agents are sending data.', + } + ), + btnLabel: i18n.translate( + 'xpack.apm.tutorial.apmAgents.statusCheck.btnLabel', + { + defaultMessage: 'Check agent status', + } + ), + success: i18n.translate( + 'xpack.apm.tutorial.apmAgents.statusCheck.successMessage', + { + defaultMessage: + 'Data successfully received from one or more agents', + } + ), + error: i18n.translate( + 'xpack.apm.tutorial.apmAgents.statusCheck.errorMessage', + { + defaultMessage: 'No data has been received from agents yet', + } + ), esHitsCheck: { - index: [errorIndices, transactionIndices, metricsIndices, sourcemapIndices], + index: [ + errorIndices, + transactionIndices, + metricsIndices, + sourcemapIndices, + ], query: { bool: { filter: [ { terms: { - 'processor.event': ['error', 'transaction', 'metric', 'sourcemap'], + 'processor.event': [ + 'error', + 'transaction', + 'metric', + 'sourcemap', + ], }, }, { range: { 'observer.version_major': { gte: 7 } } }, diff --git a/x-pack/plugins/apm/server/tutorial/index.ts b/x-pack/plugins/apm/server/tutorial/index.ts new file mode 100644 index 00000000000000..d678677a4b7514 --- /dev/null +++ b/x-pack/plugins/apm/server/tutorial/index.ts @@ -0,0 +1,117 @@ +/* + * 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 { onPremInstructions } from './envs/on_prem'; +import { createElasticCloudInstructions } from './envs/elastic_cloud'; +import apmIndexPattern from './index_pattern.json'; +import { CloudSetup } from '../../../cloud/server'; +import { + ArtifactsSchema, + TutorialsCategory, +} from '../../../../../src/plugins/home/server'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../common/index_pattern_constants'; + +const apmIntro = i18n.translate('xpack.apm.tutorial.introduction', { + defaultMessage: + 'Collect in-depth performance metrics and errors from inside your applications.', +}); +const moduleName = 'apm'; + +export const tutorialProvider = ({ + isEnabled, + indexPatternTitle, + indices, + cloud, +}: { + isEnabled: boolean; + indexPatternTitle: string; + cloud?: CloudSetup; + indices: { + errorIndices: string; + transactionIndices: string; + metricsIndices: string; + sourcemapIndices: string; + onboardingIndices: string; + }; +}) => () => { + const savedObjects = [ + { + ...apmIndexPattern, + id: APM_STATIC_INDEX_PATTERN_ID, + attributes: { + ...apmIndexPattern.attributes, + title: indexPatternTitle, + }, + }, + ]; + + const artifacts: ArtifactsSchema = { + dashboards: [ + { + id: '8d3ed660-7828-11e7-8c47-65b845b5cfb3', + linkLabel: i18n.translate( + 'xpack.apm.tutorial.specProvider.artifacts.dashboards.linkLabel', + { + defaultMessage: 'APM dashboard', + } + ), + isOverview: true, + }, + ], + }; + + if (isEnabled) { + // @ts-expect-error artifacts.application is readonly + artifacts.application = { + path: '/app/apm', + label: i18n.translate( + 'xpack.apm.tutorial.specProvider.artifacts.application.label', + { + defaultMessage: 'Launch APM', + } + ), + }; + } + + return { + id: 'apm', + name: i18n.translate('xpack.apm.tutorial.specProvider.name', { + defaultMessage: 'APM', + }), + moduleName, + category: TutorialsCategory.OTHER, + shortDescription: apmIntro, + longDescription: i18n.translate( + 'xpack.apm.tutorial.specProvider.longDescription', + { + defaultMessage: + 'Application Performance Monitoring (APM) collects in-depth \ +performance metrics and errors from inside your application. \ +It allows you to monitor the performance of thousands of applications in real time. \ +[Learn more]({learnMoreLink}).', + values: { + learnMoreLink: + '{config.docs.base_url}guide/en/apm/get-started/{config.docs.version}/index.html', + }, + } + ), + euiIconType: 'apmApp', + artifacts, + onPrem: onPremInstructions(indices), + elasticCloud: createElasticCloudInstructions(cloud), + previewImagePath: '/plugins/apm/assets/apm.png', + savedObjects, + savedObjectsInstallMsg: i18n.translate( + 'xpack.apm.tutorial.specProvider.savedObjectsInstallMsg', + { + defaultMessage: + 'An APM index pattern is required for some features in the APM UI.', + } + ), + }; +}; diff --git a/src/plugins/apm_oss/server/tutorial/index_pattern.json b/x-pack/plugins/apm/server/tutorial/index_pattern.json similarity index 100% rename from src/plugins/apm_oss/server/tutorial/index_pattern.json rename to x-pack/plugins/apm/server/tutorial/index_pattern.json diff --git a/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts b/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts new file mode 100644 index 00000000000000..a25021fac5d006 --- /dev/null +++ b/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts @@ -0,0 +1,931 @@ +/* + * 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'; + +export const createNodeAgentInstructions = ( + apmServerUrl = '', + secretToken = '' +) => [ + { + title: i18n.translate('xpack.apm.tutorial.nodeClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('xpack.apm.tutorial.nodeClient.install.textPre', { + defaultMessage: + 'Install the APM agent for Node.js as a dependency to your application.', + }), + commands: ['npm install elastic-apm-node --save'], + }, + { + title: i18n.translate('xpack.apm.tutorial.nodeClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('xpack.apm.tutorial.nodeClient.configure.textPre', { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the `serviceName`. \ +This agent supports a variety of frameworks but can also be used with your custom stack.', + }), + commands: `// ${i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.commands.addThisToTheFileTopComment', + { + defaultMessage: + 'Add this to the VERY top of the first file loaded in your app', + } + )} +var apm = require('elastic-apm-node').start({curlyOpen} + + // ${i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Override the service name from package.json', + } + )} + // ${i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.commands.allowedCharactersComment', + { + defaultMessage: 'Allowed characters: a-z, A-Z, 0-9, -, _, and space', + } + )} + serviceName: '', + + // ${i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.commands.useIfApmRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a secret token', + } + )} + secretToken: '${secretToken}', + + // ${i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: + 'Set the custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + serverUrl: '${apmServerUrl}', + + // ${i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.commands.setCustomServiceEnvironmentComment', + { + defaultMessage: 'Set the service environment', + } + )} + environment: 'production' +{curlyClose})`.split('\n'), + textPost: i18n.translate( + 'xpack.apm.tutorial.nodeClient.configure.textPost', + { + defaultMessage: + 'See [the documentation]({documentationLink}) for advanced usage, including how to use with \ +[Babel/ES Modules]({babelEsModulesLink}).', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/nodejs/current/index.html', + babelEsModulesLink: + '{config.docs.base_url}guide/en/apm/agent/nodejs/current/advanced-setup.html#es-modules', + }, + } + ), + }, +]; + +export const createDjangoAgentInstructions = ( + apmServerUrl = '', + secretToken = '' +) => [ + { + title: i18n.translate('xpack.apm.tutorial.djangoClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('xpack.apm.tutorial.djangoClient.install.textPre', { + defaultMessage: 'Install the APM agent for Python as a dependency.', + }), + commands: ['$ pip install elastic-apm'], + }, + { + title: i18n.translate('xpack.apm.tutorial.djangoClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.textPre', + { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the `SERVICE_NAME`.', + } + ), + commands: `# ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.addAgentComment', + { + defaultMessage: 'Add the agent to the installed apps', + } + )} +INSTALLED_APPS = ( + 'elasticapm.contrib.django', + # ... +) + +ELASTIC_APM = {curlyOpen} + # ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Set the required service name. Allowed characters:', + } + )} + # ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.allowedCharactersComment', + { + defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', + } + )} + 'SERVICE_NAME': '', + + # ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.useIfApmServerRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a secret token', + } + )} + 'SECRET_TOKEN': '${secretToken}', + + # ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: + 'Set the custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + 'SERVER_URL': '${apmServerUrl}', + + # ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.setServiceEnvironmentComment', + { + defaultMessage: 'Set the service environment', + } + )} + 'ENVIRONMENT': 'production', +{curlyClose} + +# ${i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.commands.addTracingMiddlewareComment', + { + defaultMessage: + 'To send performance metrics, add our tracing middleware:', + } + )} +MIDDLEWARE = ( + 'elasticapm.contrib.django.middleware.TracingMiddleware', + #... +)`.split('\n'), + textPost: i18n.translate( + 'xpack.apm.tutorial.djangoClient.configure.textPost', + { + defaultMessage: + 'See the [documentation]({documentationLink}) for advanced usage.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/python/current/django-support.html', + }, + } + ), + }, +]; + +export const createFlaskAgentInstructions = ( + apmServerUrl = '', + secretToken = '' +) => [ + { + title: i18n.translate('xpack.apm.tutorial.flaskClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('xpack.apm.tutorial.flaskClient.install.textPre', { + defaultMessage: 'Install the APM agent for Python as a dependency.', + }), + commands: ['$ pip install elastic-apm[flask]'], + }, + { + title: i18n.translate('xpack.apm.tutorial.flaskClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.textPre', + { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the `SERVICE_NAME`.', + } + ), + commands: `# ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.initializeUsingEnvironmentVariablesComment', + { + defaultMessage: 'initialize using environment variables', + } + )} +from elasticapm.contrib.flask import ElasticAPM +app = Flask(__name__) +apm = ElasticAPM(app) + +# ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.configureElasticApmComment', + { + defaultMessage: + "or configure to use ELASTIC_APM in your application's settings", + } + )} +from elasticapm.contrib.flask import ElasticAPM +app.config['ELASTIC_APM'] = {curlyOpen} + # ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Set the required service name. Allowed characters:', + } + )} + # ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.allowedCharactersComment', + { + defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', + } + )} + 'SERVICE_NAME': '', + + # ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.useIfApmServerRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a secret token', + } + )} + 'SECRET_TOKEN': '${secretToken}', + + # ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: + 'Set the custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + 'SERVER_URL': '${apmServerUrl}', + + # ${i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.commands.setServiceEnvironmentComment', + { + defaultMessage: 'Set the service environment', + } + )} + 'ENVIRONMENT': 'production', +{curlyClose} + +apm = ElasticAPM(app)`.split('\n'), + textPost: i18n.translate( + 'xpack.apm.tutorial.flaskClient.configure.textPost', + { + defaultMessage: + 'See the [documentation]({documentationLink}) for advanced usage.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/python/current/flask-support.html', + }, + } + ), + }, +]; + +export const createRailsAgentInstructions = ( + apmServerUrl = '', + secretToken = '' +) => [ + { + title: i18n.translate('xpack.apm.tutorial.railsClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('xpack.apm.tutorial.railsClient.install.textPre', { + defaultMessage: 'Add the agent to your Gemfile.', + }), + commands: [`gem 'elastic-apm'`], + }, + { + title: i18n.translate('xpack.apm.tutorial.railsClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate( + 'xpack.apm.tutorial.railsClient.configure.textPre', + { + defaultMessage: + 'APM is automatically started when your app boots. Configure the agent, by creating the config file {configFile}', + values: { configFile: '`config/elastic_apm.yml`' }, + } + ), + commands: `# config/elastic_apm.yml: + +# Set the service name - allowed characters: a-z, A-Z, 0-9, -, _ and space +# Defaults to the name of your Rails app +service_name: 'my-service' + +# Use if APM Server requires a secret token +secret_token: '${secretToken}' + +# Set the custom APM Server URL (default: http://localhost:8200) +server_url: '${apmServerUrl || 'http://localhost:8200'}' + +# Set the service environment +environment: 'production'`.split('\n'), + textPost: i18n.translate( + 'xpack.apm.tutorial.railsClient.configure.textPost', + { + defaultMessage: + 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html', + }, + } + ), + }, +]; + +export const createRackAgentInstructions = ( + apmServerUrl = '', + secretToken = '' +) => [ + { + title: i18n.translate('xpack.apm.tutorial.rackClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('xpack.apm.tutorial.rackClient.install.textPre', { + defaultMessage: 'Add the agent to your Gemfile.', + }), + commands: [`gem 'elastic-apm'`], + }, + { + title: i18n.translate('xpack.apm.tutorial.rackClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('xpack.apm.tutorial.rackClient.configure.textPre', { + defaultMessage: + 'For Rack or a compatible framework (e.g. Sinatra), include the middleware in your app and start the agent.', + }), + commands: `# config.ru + require 'sinatra/base' + + class MySinatraApp < Sinatra::Base + use ElasticAPM::Middleware + + # ... + end + + ElasticAPM.start( + app: MySinatraApp, # ${i18n.translate( + 'xpack.apm.tutorial.rackClient.configure.commands.requiredComment', + { + defaultMessage: 'required', + } + )} + config_file: '' # ${i18n.translate( + 'xpack.apm.tutorial.rackClient.configure.commands.optionalComment', + { + defaultMessage: 'optional, defaults to config/elastic_apm.yml', + } + )} + ) + + run MySinatraApp + + at_exit {curlyOpen} ElasticAPM.stop {curlyClose}`.split('\n'), + }, + { + title: i18n.translate('xpack.apm.tutorial.rackClient.createConfig.title', { + defaultMessage: 'Create config file', + }), + textPre: i18n.translate( + 'xpack.apm.tutorial.rackClient.createConfig.textPre', + { + defaultMessage: 'Create a config file {configFile}:', + values: { configFile: '`config/elastic_apm.yml`' }, + } + ), + commands: `# config/elastic_apm.yml: + +# ${i18n.translate( + 'xpack.apm.tutorial.rackClient.createConfig.commands.setServiceNameComment', + { + defaultMessage: + 'Set the service name - allowed characters: a-z, A-Z, 0-9, -, _ and space', + } + )} +# ${i18n.translate( + 'xpack.apm.tutorial.rackClient.createConfig.commands.defaultsToTheNameOfRackAppClassComment', + { + defaultMessage: "Defaults to the name of your Rack app's class.", + } + )} +service_name: 'my-service' + +# ${i18n.translate( + 'xpack.apm.tutorial.rackClient.createConfig.commands.useIfApmServerRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a token', + } + )} +secret_token: '${secretToken}' + +# ${i18n.translate( + 'xpack.apm.tutorial.rackClient.createConfig.commands.setCustomApmServerComment', + { + defaultMessage: + 'Set custom APM Server URL (default: {defaultServerUrl})', + values: { defaultServerUrl: 'http://localhost:8200' }, + } + )} +server_url: '${apmServerUrl || 'http://localhost:8200'}', + +# ${i18n.translate( + 'xpack.apm.tutorial.rackClient.createConfig.commands.setServiceEnvironment', + { + defaultMessage: 'Set the service environment', + } + )} +environment: 'production'`.split('\n'), + textPost: i18n.translate( + 'xpack.apm.tutorial.rackClient.createConfig.textPost', + { + defaultMessage: + 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html', + }, + } + ), + }, +]; + +export const createJsAgentInstructions = (apmServerUrl = '') => [ + { + title: i18n.translate( + 'xpack.apm.tutorial.jsClient.enableRealUserMonitoring.title', + { + defaultMessage: 'Enable Real User Monitoring support in APM Server', + } + ), + textPre: i18n.translate( + 'xpack.apm.tutorial.jsClient.enableRealUserMonitoring.textPre', + { + defaultMessage: + 'APM Server disables RUM support by default. See the [documentation]({documentationLink}) \ +for details on how to enable RUM support.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/server/{config.docs.version}/configuration-rum.html', + }, + } + ), + }, + { + title: i18n.translate( + 'xpack.apm.tutorial.jsClient.installDependency.title', + { + defaultMessage: 'Set up the Agent as a dependency', + } + ), + textPre: i18n.translate( + 'xpack.apm.tutorial.jsClient.installDependency.textPre', + { + defaultMessage: + 'You can install the Agent as a dependency to your application with \ +`npm install @elastic/apm-rum --save`.\n\n\ +The Agent can then be initialized and configured in your application like this:', + } + ), + commands: `import {curlyOpen} init as initApm {curlyClose} from '@elastic/apm-rum' +var apm = initApm({curlyOpen} + + // ${i18n.translate( + 'xpack.apm.tutorial.jsClient.installDependency.commands.setRequiredServiceNameComment', + { + defaultMessage: + 'Set required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)', + } + )} + serviceName: 'your-app-name', + + // ${i18n.translate( + 'xpack.apm.tutorial.jsClient.installDependency.commands.setCustomApmServerUrlComment', + { + defaultMessage: + 'Set custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + serverUrl: '${apmServerUrl}', + + // ${i18n.translate( + 'xpack.apm.tutorial.jsClient.installDependency.commands.setServiceVersionComment', + { + defaultMessage: + 'Set the service version (required for source map feature)', + } + )} + serviceVersion: '', + + // ${i18n.translate( + 'xpack.apm.tutorial.jsClient.installDependency.commands.setServiceEnvironmentComment', + { + defaultMessage: 'Set the service environment', + } + )} + environment: 'production' +{curlyClose})`.split('\n'), + textPost: i18n.translate( + 'xpack.apm.tutorial.jsClient.installDependency.textPost', + { + defaultMessage: + 'Framework integrations, like React or Angular, have custom dependencies. \ +See the [integration documentation]({docLink}) for more information.', + values: { + docLink: + '{config.docs.base_url}guide/en/apm/agent/rum-js/current/framework-integrations.html', + }, + } + ), + }, + { + title: i18n.translate('xpack.apm.tutorial.jsClient.scriptTags.title', { + defaultMessage: 'Set up the Agent with Script Tags', + }), + textPre: i18n.translate('xpack.apm.tutorial.jsClient.scriptTags.textPre', { + defaultMessage: + "Alternatively, you can use Script tags to set up and configure the Agent. \ +Add a ` + +`.split('\n'), + }, +]; + +export const createGoAgentInstructions = ( + apmServerUrl = '', + secretToken = '' +) => [ + { + title: i18n.translate('xpack.apm.tutorial.goClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('xpack.apm.tutorial.goClient.install.textPre', { + defaultMessage: 'Install the APM agent packages for Go.', + }), + commands: ['go get go.elastic.co/apm'], + }, + { + title: i18n.translate('xpack.apm.tutorial.goClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('xpack.apm.tutorial.goClient.configure.textPre', { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the executable \ +file name, or the `ELASTIC_APM_SERVICE_NAME` environment variable.', + }), + commands: `# ${i18n.translate( + 'xpack.apm.tutorial.goClient.configure.commands.initializeUsingEnvironmentVariablesComment', + { + defaultMessage: 'Initialize using environment variables:', + } + )} + +# ${i18n.translate( + 'xpack.apm.tutorial.goClient.configure.commands.setServiceNameComment', + { + defaultMessage: + 'Set the service name. Allowed characters: # a-z, A-Z, 0-9, -, _, and space.', + } + )} +# ${i18n.translate( + 'xpack.apm.tutorial.goClient.configure.commands.usedExecutableNameComment', + { + defaultMessage: + 'If ELASTIC_APM_SERVICE_NAME is not specified, the executable name will be used.', + } + )} +export ELASTIC_APM_SERVICE_NAME= + +# ${i18n.translate( + 'xpack.apm.tutorial.goClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: + 'Set custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} +export ELASTIC_APM_SERVER_URL=${apmServerUrl} + +# ${i18n.translate( + 'xpack.apm.tutorial.goClient.configure.commands.useIfApmRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a secret token', + } + )} +export ELASTIC_APM_SECRET_TOKEN=${secretToken} + +# ${i18n.translate( + 'xpack.apm.tutorial.goClient.configure.commands.setServiceEnvironment', + { + defaultMessage: 'Set the service environment', + } + )} +export ELASTIC_APM_ENVIRONMENT= +`.split('\n'), + textPost: i18n.translate('xpack.apm.tutorial.goClient.configure.textPost', { + defaultMessage: + 'See the [documentation]({documentationLink}) for advanced configuration.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/go/current/configuration.html', + }, + }), + }, + { + title: i18n.translate('xpack.apm.tutorial.goClient.instrument.title', { + defaultMessage: 'Instrument your application', + }), + textPre: i18n.translate('xpack.apm.tutorial.goClient.instrument.textPre', { + defaultMessage: + 'Instrument your Go application by using one of the provided instrumentation modules or \ +by using the tracer API directly.', + }), + commands: `\ +import ( + "net/http" + + "go.elastic.co/apm/module/apmhttp" +) + +func main() {curlyOpen} + mux := http.NewServeMux() + ... + http.ListenAndServe(":8080", apmhttp.Wrap(mux)) +{curlyClose} +`.split('\n'), + textPost: i18n.translate( + 'xpack.apm.tutorial.goClient.instrument.textPost', + { + defaultMessage: + 'See the [documentation]({documentationLink}) for a detailed \ +guide to instrumenting Go source code.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/go/current/instrumenting-source.html', + }, + } + ), + }, +]; + +export const createJavaAgentInstructions = ( + apmServerUrl = '', + secretToken = '' +) => [ + { + title: i18n.translate('xpack.apm.tutorial.javaClient.download.title', { + defaultMessage: 'Download the APM agent', + }), + textPre: i18n.translate('xpack.apm.tutorial.javaClient.download.textPre', { + defaultMessage: + 'Download the agent jar from [Maven Central]({mavenCentralLink}). \ +Do **not** add the agent as a dependency to your application.', + values: { + mavenCentralLink: + 'http://search.maven.org/#search%7Cga%7C1%7Ca%3Aelastic-apm-agent', + }, + }), + }, + { + title: i18n.translate( + 'xpack.apm.tutorial.javaClient.startApplication.title', + { + defaultMessage: 'Start your application with the javaagent flag', + } + ), + textPre: i18n.translate( + 'xpack.apm.tutorial.javaClient.startApplication.textPre', + { + defaultMessage: + 'Add the `-javaagent` flag and configure the agent with system properties.\n\n \ +* Set the required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)\n \ +* Set the custom APM Server URL (default: {customApmServerUrl})\n \ +* Set the APM Server secret token\n \ +* Set the service environment\n \ +* Set the base package of your application', + values: { customApmServerUrl: 'http://localhost:8200' }, + } + ), + commands: `java -javaagent:/path/to/elastic-apm-agent-.jar \\ + -Delastic.apm.service_name=my-application \\ + -Delastic.apm.server_urls=${apmServerUrl || 'http://localhost:8200'} \\ + -Delastic.apm.secret_token=${secretToken} \\ + -Delastic.apm.environment=production \\ + -Delastic.apm.application_packages=org.example \\ + -jar my-application.jar`.split('\n'), + textPost: i18n.translate( + 'xpack.apm.tutorial.javaClient.startApplication.textPost', + { + defaultMessage: + 'See the [documentation]({documentationLink}) for configuration options and advanced \ +usage.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/java/current/index.html', + }, + } + ), + }, +]; + +export const createDotNetAgentInstructions = ( + apmServerUrl = '', + secretToken = '' +) => [ + { + title: i18n.translate('xpack.apm.tutorial.dotNetClient.download.title', { + defaultMessage: 'Download the APM agent', + }), + textPre: i18n.translate( + 'xpack.apm.tutorial.dotNetClient.download.textPre', + { + defaultMessage: + 'Add the the agent package(s) from [NuGet]({allNuGetPackagesLink}) to your .NET application. There are multiple \ + NuGet packages available for different use cases. \n\nFor an ASP.NET Core application with Entity Framework \ + Core download the [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}) package. This package will automatically add every \ + agent component to your application. \n\n In case you would like to minimize the dependencies, you can use the \ + [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) package for just \ + ASP.NET Core monitoring or the [Elastic.Apm.EfCore]({efCorePackageLink}) package for just Entity Framework Core monitoring. \n\n \ + In case you only want to use the public Agent API for manual instrumentation use the [Elastic.Apm]({elasticApmPackageLink}) package.', + values: { + allNuGetPackagesLink: 'https://www.nuget.org/packages?q=Elastic.apm', + netCoreAllApmPackageLink: + 'https://www.nuget.org/packages/Elastic.Apm.NetCoreAll', + aspNetCorePackageLink: + 'https://www.nuget.org/packages/Elastic.Apm.AspNetCore', + efCorePackageLink: + 'https://www.nuget.org/packages/Elastic.Apm.EntityFrameworkCore', + elasticApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm', + }, + } + ), + }, + { + title: i18n.translate( + 'xpack.apm.tutorial.dotNetClient.configureApplication.title', + { + defaultMessage: 'Add the agent to the application', + } + ), + textPre: i18n.translate( + 'xpack.apm.tutorial.dotNetClient.configureApplication.textPre', + { + defaultMessage: + 'In case of ASP.NET Core with the `Elastic.Apm.NetCoreAll` package, call the `UseAllElasticApm` \ + method in the `Configure` method within the `Startup.cs` file.', + } + ), + commands: `public class Startup +{curlyOpen} + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + {curlyOpen} + app.UseAllElasticApm(Configuration); + //…rest of the method + {curlyClose} + //…rest of the class +{curlyClose}`.split('\n'), + textPost: i18n.translate( + 'xpack.apm.tutorial.dotNetClient.configureApplication.textPost', + { + defaultMessage: + 'Passing an `IConfiguration` instance is optional and by doing so, the agent will read config settings through this \ + `IConfiguration` instance (e.g. from the `appsettings.json` file).', + } + ), + }, + { + title: i18n.translate( + 'xpack.apm.tutorial.dotNetClient.configureAgent.title', + { + defaultMessage: 'Sample appsettings.json file:', + } + ), + commands: `{curlyOpen} + "ElasticApm": {curlyOpen} + "SecretToken": "${secretToken}", + "ServerUrls": "${ + apmServerUrl || 'http://localhost:8200' + }", //Set custom APM Server URL (default: http://localhost:8200) + "ServiceName": "MyApp", //allowed characters: a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application + "Environment": "production", // Set the service environment + {curlyClose} +{curlyClose}`.split('\n'), + textPost: i18n.translate( + 'xpack.apm.tutorial.dotNetClient.configureAgent.textPost', + { + defaultMessage: + 'In case you don’t pass an `IConfiguration` instance to the agent (e.g. in case of non ASP.NET Core applications) \ + you can also configure the agent through environment variables. \n \ + See [the documentation]({documentationLink}) for advanced usage.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/dotnet/current/configuration.html', + }, + } + ), + }, +]; + +export const createPhpAgentInstructions = ( + apmServerUrl = '', + secretToken = '' +) => [ + { + title: i18n.translate('xpack.apm.tutorial.phpClient.download.title', { + defaultMessage: 'Download the APM agent', + }), + textPre: i18n.translate('xpack.apm.tutorial.phpClient.download.textPre', { + defaultMessage: + 'Download the package corresponding to your platform from [GitHub releases]({githubReleasesLink}).', + values: { + githubReleasesLink: 'https://github.com/elastic/apm-agent-php/releases', + }, + }), + }, + { + title: i18n.translate('xpack.apm.tutorial.phpClient.installPackage.title', { + defaultMessage: 'Install the downloaded package', + }), + textPre: i18n.translate( + 'xpack.apm.tutorial.phpClient.installPackage.textPre', + { + defaultMessage: 'For example on Alpine Linux using APK package:', + } + ), + commands: ['apk add --allow-untrusted .apk'], + textPost: i18n.translate( + 'xpack.apm.tutorial.phpClient.installPackage.textPost', + { + defaultMessage: + 'See the [documentation]({documentationLink}) for installation commands on other supported platforms and advanced installation.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/php/current/setup.html', + }, + } + ), + }, + { + title: i18n.translate('xpack.apm.tutorial.phpClient.configureAgent.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate( + 'xpack.apm.tutorial.phpClient.configureAgent.textPre', + { + defaultMessage: + 'APM is automatically started when your app boots. Configure the agent either via `php.ini` file:', + } + ), + commands: `elastic_apm.server_url=http://localhost:8200 +elastic_apm.service_name="My service" +`.split('\n'), + textPost: i18n.translate( + 'xpack.apm.tutorial.phpClient.configure.textPost', + { + defaultMessage: + 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/php/current/configuration.html', + }, + } + ), + }, +]; diff --git a/src/plugins/apm_oss/server/tutorial/instructions/apm_server_instructions.ts b/x-pack/plugins/apm/server/tutorial/instructions/apm_server_instructions.ts similarity index 66% rename from src/plugins/apm_oss/server/tutorial/instructions/apm_server_instructions.ts rename to x-pack/plugins/apm/server/tutorial/instructions/apm_server_instructions.ts index eee93d8dc9fd1a..c2fc7b1774f65f 100644 --- a/src/plugins/apm_oss/server/tutorial/instructions/apm_server_instructions.ts +++ b/x-pack/plugins/apm/server/tutorial/instructions/apm_server_instructions.ts @@ -1,18 +1,17 @@ /* * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import { i18n } from '@kbn/i18n'; export const createEditConfig = () => ({ - title: i18n.translate('apmOss.tutorial.editConfig.title', { + title: i18n.translate('xpack.apm.tutorial.editConfig.title', { defaultMessage: 'Edit the configuration', }), - textPre: i18n.translate('apmOss.tutorial.editConfig.textPre', { + textPre: i18n.translate('xpack.apm.tutorial.editConfig.textPre', { defaultMessage: "If you're using an X-Pack secured version of Elastic Stack, you must specify \ credentials in the `apm-server.yml` config file.", @@ -26,10 +25,10 @@ credentials in the `apm-server.yml` config file.", }); const createStartServer = () => ({ - title: i18n.translate('apmOss.tutorial.startServer.title', { + title: i18n.translate('xpack.apm.tutorial.startServer.title', { defaultMessage: 'Start APM Server', }), - textPre: i18n.translate('apmOss.tutorial.startServer.textPre', { + textPre: i18n.translate('xpack.apm.tutorial.startServer.textPre', { defaultMessage: 'The server processes and stores application performance metrics in Elasticsearch.', }), @@ -56,7 +55,7 @@ export function createStartServerUnix() { } const createDownloadServerTitle = () => - i18n.translate('apmOss.tutorial.downloadServer.title', { + i18n.translate('xpack.apm.tutorial.downloadServer.title', { defaultMessage: 'Download and unpack APM Server', }); @@ -75,8 +74,9 @@ export const createDownloadServerDeb = () => ({ 'curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-{config.kibana.version}-amd64.deb', 'sudo dpkg -i apm-server-{config.kibana.version}-amd64.deb', ], - textPost: i18n.translate('apmOss.tutorial.downloadServerTitle', { - defaultMessage: 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', + textPost: i18n.translate('xpack.apm.tutorial.downloadServerTitle', { + defaultMessage: + 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', values: { downloadPageLink: '{config.docs.base_url}downloads/apm/apm-server', }, @@ -89,8 +89,9 @@ export const createDownloadServerRpm = () => ({ 'curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-{config.kibana.version}-x86_64.rpm', 'sudo rpm -vi apm-server-{config.kibana.version}-x86_64.rpm', ], - textPost: i18n.translate('apmOss.tutorial.downloadServerRpm', { - defaultMessage: 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', + textPost: i18n.translate('xpack.apm.tutorial.downloadServerRpm', { + defaultMessage: + 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', values: { downloadPageLink: '{config.docs.base_url}downloads/apm/apm-server', }, @@ -103,32 +104,41 @@ export function createWindowsServerInstructions() { return [ { title: createDownloadServerTitle(), - textPre: i18n.translate('apmOss.tutorial.windowsServerInstructions.textPre', { - defaultMessage: - '1. Download the APM Server Windows zip file from the \ + textPre: i18n.translate( + 'xpack.apm.tutorial.windowsServerInstructions.textPre', + { + defaultMessage: + '1. Download the APM Server Windows zip file from the \ [Download page]({downloadPageLink}).\n2. Extract the contents of \ the zip file into {zipFileExtractFolder}.\n3. Rename the {apmServerDirectory} \ directory to `APM-Server`.\n4. Open a PowerShell prompt as an Administrator \ (right-click the PowerShell icon and select \ **Run As Administrator**). If you are running Windows XP, you might need to download and install \ PowerShell.\n5. From the PowerShell prompt, run the following commands to install APM Server as a Windows service:', - values: { - downloadPageLink: 'https://www.elastic.co/downloads/apm/apm-server', - zipFileExtractFolder: '`C:\\Program Files`', - apmServerDirectory: '`apm-server-{config.kibana.version}-windows`', - }, - }), - commands: [`cd 'C:\\Program Files\\APM-Server'`, `.\\install-service-apm-server.ps1`], - textPost: i18n.translate('apmOss.tutorial.windowsServerInstructions.textPost', { - defaultMessage: - 'Note: If script execution is disabled on your system, \ + values: { + downloadPageLink: 'https://www.elastic.co/downloads/apm/apm-server', + zipFileExtractFolder: '`C:\\Program Files`', + apmServerDirectory: '`apm-server-{config.kibana.version}-windows`', + }, + } + ), + commands: [ + `cd 'C:\\Program Files\\APM-Server'`, + `.\\install-service-apm-server.ps1`, + ], + textPost: i18n.translate( + 'xpack.apm.tutorial.windowsServerInstructions.textPost', + { + defaultMessage: + 'Note: If script execution is disabled on your system, \ you need to set the execution policy for the current session \ to allow the script to run. For example: {command}.', - values: { - command: - '`PowerShell.exe -ExecutionPolicy UnRestricted -File .\\install-service-apm-server.ps1`', - }, - }), + values: { + command: + '`PowerShell.exe -ExecutionPolicy UnRestricted -File .\\install-service-apm-server.ps1`', + }, + } + ), }, createEditConfig(), { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 94cc5ca60e451f..7bf231f67a2b03 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -125,133 +125,6 @@ "advancedSettings.searchBar.unableToParseQueryErrorMessage": "クエリをパースできません", "advancedSettings.searchBarAriaLabel": "高度な設定を検索", "advancedSettings.voiceAnnouncement.ariaLabel": "詳細設定結果情報", - "apmOss.tutorial.apmAgents.statusCheck.btnLabel": "エージェントステータスを確認", - "apmOss.tutorial.apmAgents.statusCheck.errorMessage": "エージェントからまだデータを受け取っていません", - "apmOss.tutorial.apmAgents.statusCheck.successMessage": "1 つまたは複数のエージェントからデータを受け取りました", - "apmOss.tutorial.apmAgents.statusCheck.text": "アプリケーションが実行されていてエージェントがデータを送信していることを確認してください。", - "apmOss.tutorial.apmAgents.statusCheck.title": "エージェントステータス", - "apmOss.tutorial.apmAgents.title": "APM エージェント", - "apmOss.tutorial.apmServer.callOut.message": "ご使用の APM Server を 7.0 以上に更新してあることを確認してください。 Kibana の管理セクションにある移行アシスタントで 6.x データを移行することもできます。", - "apmOss.tutorial.apmServer.callOut.title": "重要:7.0 以上に更新中", - "apmOss.tutorial.apmServer.statusCheck.btnLabel": "APM Server ステータスを確認", - "apmOss.tutorial.apmServer.statusCheck.errorMessage": "APM Server が検出されました。7.0 以上に更新され、動作中であることを確認してください。", - "apmOss.tutorial.apmServer.statusCheck.successMessage": "APM Server が正しくセットアップされました", - "apmOss.tutorial.apmServer.statusCheck.text": "APM エージェントの導入を開始する前に、APM Server が動作していることを確認してください。", - "apmOss.tutorial.apmServer.statusCheck.title": "APM Server ステータス", - "apmOss.tutorial.apmServer.title": "APM Server", - "apmOss.tutorial.djangoClient.configure.commands.addAgentComment": "インストールされたアプリにエージェントを追加します", - "apmOss.tutorial.djangoClient.configure.commands.addTracingMiddlewareComment": "パフォーマンスメトリックを送信するには、追跡ミドルウェアを追加します。", - "apmOss.tutorial.djangoClient.configure.commands.allowedCharactersComment": "a-z、A-Z、0-9、-、_、スペース", - "apmOss.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト:{defaultApmServerUrl}) を設定します", - "apmOss.tutorial.djangoClient.configure.commands.setRequiredServiceNameComment": "任意のサービス名を設定します。使用できる文字:", - "apmOss.tutorial.djangoClient.configure.commands.setServiceEnvironmentComment": "サービス環境を設定します", - "apmOss.tutorial.djangoClient.configure.commands.useIfApmServerRequiresTokenComment": "APM Server でシークレットトークンが必要な場合に使います", - "apmOss.tutorial.djangoClient.configure.textPost": "高度な用途に関しては [ドキュメンテーション] ({documentationLink}) をご覧ください。", - "apmOss.tutorial.djangoClient.configure.textPre": "エージェントとは、アプリケーションプロセス内で実行されるライブラリです。APM サービスは「SERVICE_NAME」に基づいてプログラムで作成されます。", - "apmOss.tutorial.djangoClient.configure.title": "エージェントの構成", - "apmOss.tutorial.djangoClient.install.textPre": "Python 用の APM エージェントを依存関係としてインストールします。", - "apmOss.tutorial.djangoClient.install.title": "APM エージェントのインストール", - "apmOss.tutorial.dotNetClient.configureAgent.textPost": "エージェントに「IConfiguration」インスタンスが渡されていない場合、 (例:非 ASP.NET Core アプリケーションの場合) 、エージェントを環境変数で構成することもできます。\n 高度な用途に関しては [ドキュメンテーション] ({documentationLink}) をご覧ください。", - "apmOss.tutorial.dotNetClient.configureAgent.title": "appsettings.json ファイルの例:", - "apmOss.tutorial.dotNetClient.configureApplication.textPost": "「IConfiguration」インスタンスを渡すのは任意であり、これにより、エージェントはこの「IConfiguration」インスタンス (例:「appsettings.json」ファイル) から構成を読み込みます。", - "apmOss.tutorial.dotNetClient.configureApplication.textPre": "「Elastic.Apm.NetCoreAll」パッケージの ASP.NET Core の場合、「Startup.cs」ファイル内の「Configure」メソドの「UseElasticApm」メソドを呼び出します。", - "apmOss.tutorial.dotNetClient.configureApplication.title": "エージェントをアプリケーションに追加", - "apmOss.tutorial.dotNetClient.download.textPre": "[NuGet] ({allNuGetPackagesLink}) から .NET アプリケーションにエージェントパッケージを追加してください。用途の異なる複数の NuGet パッケージがあります。\n\nEntity Framework Core の ASP.NET Core アプリケーションの場合は、[Elastic.Apm.NetCoreAll] ({netCoreAllApmPackageLink}) パッケージをダウンロードしてください。このパッケージは、自動的にすべてのエージェントコンポーネントをアプリケーションに追加します。\n\n 依存性を最低限に抑えたい場合、ASP.NET Coreの監視のみに[Elastic.Apm.AspNetCore] ({aspNetCorePackageLink}) パッケージ、またはEntity Framework Coreの監視のみに[Elastic.Apm.EfCore] ({efCorePackageLink}) パッケージを使用することができます。\n\n 手動インストルメンテーションのみにパブリック Agent API を使用する場合は、[Elastic.Apm] ({elasticApmPackageLink}) パッケージを使用してください。", - "apmOss.tutorial.dotNetClient.download.title": "APM エージェントのダウンロード", - "apmOss.tutorial.downloadServer.title": "APM Server をダウンロードして展開します", - "apmOss.tutorial.downloadServerRpm": "32 ビットパッケージをお探しですか?[ダウンロードページ] ({downloadPageLink}) をご覧ください。", - "apmOss.tutorial.downloadServerTitle": "32 ビットパッケージをお探しですか?[ダウンロードページ] ({downloadPageLink}) をご覧ください。", - "apmOss.tutorial.editConfig.textPre": "Elastic Stack の X-Pack セキュアバージョンをご使用の場合、「apm-server.yml」構成ファイルで認証情報を指定する必要があります。", - "apmOss.tutorial.editConfig.title": "構成を編集する", - "apmOss.tutorial.flaskClient.configure.commands.allowedCharactersComment": "a-z、A-Z、0-9、-、_、スペース", - "apmOss.tutorial.flaskClient.configure.commands.configureElasticApmComment": "またはアプリケーションの設定で ELASTIC_APM を使用するよう構成します。", - "apmOss.tutorial.flaskClient.configure.commands.initializeUsingEnvironmentVariablesComment": "環境変数を使用して初期化します", - "apmOss.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト:{defaultApmServerUrl}) を設定します", - "apmOss.tutorial.flaskClient.configure.commands.setRequiredServiceNameComment": "任意のサービス名を設定します。使用できる文字:", - "apmOss.tutorial.flaskClient.configure.commands.setServiceEnvironmentComment": "サービス環境を設定します", - "apmOss.tutorial.flaskClient.configure.commands.useIfApmServerRequiresTokenComment": "APM Server でシークレットトークンが必要な場合に使います", - "apmOss.tutorial.flaskClient.configure.textPost": "高度な用途に関しては [ドキュメンテーション] ({documentationLink}) をご覧ください。", - "apmOss.tutorial.flaskClient.configure.textPre": "エージェントとは、アプリケーションプロセス内で実行されるライブラリです。APM サービスは「SERVICE_NAME」に基づいてプログラムで作成されます。", - "apmOss.tutorial.flaskClient.configure.title": "エージェントの構成", - "apmOss.tutorial.flaskClient.install.textPre": "Python 用の APM エージェントを依存関係としてインストールします。", - "apmOss.tutorial.flaskClient.install.title": "APM エージェントのインストール", - "apmOss.tutorial.goClient.configure.commands.initializeUsingEnvironmentVariablesComment": "環境変数を使用して初期化します:", - "apmOss.tutorial.goClient.configure.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト:{defaultApmServerUrl}) を設定します", - "apmOss.tutorial.goClient.configure.commands.setServiceEnvironment": "サービス環境を設定します", - "apmOss.tutorial.goClient.configure.commands.setServiceNameComment": "サービス名を設定します。使用できる文字は # a-z、A-Z、0-9、-、_、スペースです。", - "apmOss.tutorial.goClient.configure.commands.usedExecutableNameComment": "ELASTIC_APM_SERVICE_NAME が指定されていない場合、実行ファイルの名前が使用されます。", - "apmOss.tutorial.goClient.configure.commands.useIfApmRequiresTokenComment": "APM Server でシークレットトークンが必要な場合に使います", - "apmOss.tutorial.goClient.configure.textPost": "高度な構成に関しては [ドキュメンテーション] ({documentationLink}) をご覧ください。", - "apmOss.tutorial.goClient.configure.textPre": "エージェントとは、アプリケーションプロセス内で実行されるライブラリです。APM サービスは実行ファイル名または「ELASTIC_APM_SERVICE_NAME」環境変数に基づいてプログラムで作成されます。", - "apmOss.tutorial.goClient.configure.title": "エージェントの構成", - "apmOss.tutorial.goClient.install.textPre": "Go の APM エージェントパッケージをインストールします。", - "apmOss.tutorial.goClient.install.title": "APM エージェントのインストール", - "apmOss.tutorial.goClient.instrument.textPost": "Go のソースコードのインストルメンテーションの詳細ガイドは、[ドキュメンテーション] ({documentationLink}) をご覧ください。", - "apmOss.tutorial.goClient.instrument.textPre": "提供されたインストルメンテーションモジュールの 1 つ、またはトレーサー API を直接使用して、Go アプリケーションにインストルメンテーションを設定します。", - "apmOss.tutorial.goClient.instrument.title": "アプリケーションのインストルメンテーション", - "apmOss.tutorial.introduction": "アプリケーション内から詳細なパフォーマンスメトリックやエラーを収集します。", - "apmOss.tutorial.javaClient.download.textPre": "[Maven Central] ({mavenCentralLink}) からエージェントをダウンロードします。アプリケーションにエージェントを依存関係として「追加しない」でください。", - "apmOss.tutorial.javaClient.download.title": "APM エージェントのダウンロード", - "apmOss.tutorial.javaClient.startApplication.textPost": "構成オプションと高度な用途に関しては、[ドキュメンテーション] ({documentationLink}) をご覧ください。", - "apmOss.tutorial.javaClient.startApplication.textPre": "「-javaagent」フラグを追加し、システムプロパティを使用してエージェントを構成します。\n\n * 任意のサービス名を設定します (使用可能な文字は a-z、A-Z、0-9、-、_、スペースです) \n * カスタム APM Server URL (デフォルト:{customApmServerUrl}) を設定します\n * APM Server シークレットトークンを設定します\n * サービス環境を設定します\n * アプリケーションのベースパッケージを設定します", - "apmOss.tutorial.javaClient.startApplication.title": "javaagent フラグでアプリケーションを起動", - "apmOss.tutorial.jsClient.enableRealUserMonitoring.textPre": "デフォルトでは、APM Server を実行すると RUM サポートは無効になります。RUM サポートを有効にする手順については、[ドキュメンテーション] ({documentationLink}) をご覧ください。", - "apmOss.tutorial.jsClient.enableRealUserMonitoring.title": "APM Server のリアルユーザー監視サポートを有効にする", - "apmOss.tutorial.jsClient.installDependency.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト:{defaultApmServerUrl}) を設定します", - "apmOss.tutorial.jsClient.installDependency.commands.setRequiredServiceNameComment": "任意のサービス名を設定します (使用可能な文字は a-z、A-Z、0-9、-、_、スペースです) ", - "apmOss.tutorial.jsClient.installDependency.commands.setServiceEnvironmentComment": "サービス環境を設定します", - "apmOss.tutorial.jsClient.installDependency.commands.setServiceVersionComment": "サービスバージョンを設定します (ソースマップ機能に必要) ", - "apmOss.tutorial.jsClient.installDependency.textPost": "React や Angular などのフレームワーク統合には、カスタム依存関係があります。詳細は [統合ドキュメント] ({docLink}) をご覧ください。", - "apmOss.tutorial.jsClient.installDependency.textPre": "「npm install @elastic/apm-rum --save」でエージェントをアプリケーションへの依存関係としてインストールできます。\n\nその後で以下のようにアプリケーションでエージェントを初期化して構成できます。", - "apmOss.tutorial.jsClient.installDependency.title": "エージェントを依存関係としてセットアップ", - "apmOss.tutorial.jsClient.scriptTags.textPre": "または、スクリプトタグを使用してエージェントのセットアップと構成ができます。` を追加