diff --git a/x-pack/plugins/monitoring/public/components/apm/instance/index.js b/x-pack/plugins/monitoring/public/components/apm/instance/index.js
new file mode 100644
index 0000000000000..50462a66fc134
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/components/apm/instance/index.js
@@ -0,0 +1,7 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export { ApmServerInstance } from './instance';
diff --git a/x-pack/plugins/monitoring/public/components/apm/instance/instance.js b/x-pack/plugins/monitoring/public/components/apm/instance/instance.js
new file mode 100644
index 0000000000000..c40d19d384a0d
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/components/apm/instance/instance.js
@@ -0,0 +1,59 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { MonitoringTimeseriesContainer } from '../../chart';
+import {
+ EuiFlexItem,
+ EuiPanel,
+ EuiSpacer,
+ EuiPage,
+ EuiPageBody,
+ EuiFlexGroup
+} from '@elastic/eui';
+import { Status } from './status';
+
+export function ApmServerInstance({ summary, metrics, ...props }) {
+ const seriesToShow = [
+ metrics.apm_responses_valid,
+ metrics.apm_responses_errors,
+
+ metrics.apm_output_events_rate_success,
+ metrics.apm_output_events_rate_failure,
+
+ metrics.apm_requests,
+ metrics.apm_transformations,
+
+
+ metrics.apm_cpu,
+ metrics.apm_memory,
+
+ metrics.apm_os_load,
+ ];
+
+ const charts = seriesToShow.map((data, index) => (
+
+
+
+
+
+ ));
+
+ return (
+
+
+
+
+
+ {charts}
+
+
+
+ );
+}
diff --git a/x-pack/plugins/monitoring/public/components/apm/instance/status.js b/x-pack/plugins/monitoring/public/components/apm/instance/status.js
new file mode 100644
index 0000000000000..f68bf6a72d2f8
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/components/apm/instance/status.js
@@ -0,0 +1,64 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React, { Fragment } from 'react';
+import moment from 'moment';
+import { SummaryStatus } from '../../summary_status';
+import { ApmStatusIcon } from '../status_icon';
+import { formatMetric } from '../../../lib/format_number';
+import { formatTimestampToDuration } from '../../../../common';
+
+export function Status({ stats }) {
+ const {
+ name,
+ output,
+ version,
+ uptime,
+ timeOfLastEvent,
+ } = stats;
+
+ const metrics = [
+ {
+ label: 'Name',
+ value: name,
+ dataTestSubj: 'name'
+ },
+ {
+ label: 'Output',
+ value: output,
+ dataTestSubj: 'output'
+ },
+ {
+ label: 'Version',
+ value: version,
+ dataTestSubj: 'version'
+ },
+ {
+ label: 'Uptime',
+ value: formatMetric(uptime, 'time_since'),
+ dataTestSubj: 'uptime'
+ },
+ {
+ label: 'Last Event',
+ value: formatTimestampToDuration(+moment(timeOfLastEvent), 'since') + ' ago',
+ dataTestSubj: 'timeOfLastEvent',
+ }
+ ];
+
+ const IconComponent = ({ status }) => (
+
+ Status:
+
+ );
+
+ return (
+
+ );
+}
diff --git a/x-pack/plugins/monitoring/public/components/apm/instances/index.js b/x-pack/plugins/monitoring/public/components/apm/instances/index.js
new file mode 100644
index 0000000000000..b6d0d6fa853ba
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/components/apm/instances/index.js
@@ -0,0 +1,7 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export { ApmServerInstances } from './instances';
diff --git a/x-pack/plugins/monitoring/public/components/apm/instances/instances.js b/x-pack/plugins/monitoring/public/components/apm/instances/instances.js
new file mode 100644
index 0000000000000..66b67cedbf065
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/components/apm/instances/instances.js
@@ -0,0 +1,107 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import moment from 'moment';
+import { MonitoringTable } from '../../table';
+import {
+ KuiTableRowCell,
+ KuiTableRow
+} from '@kbn/ui-framework/components';
+import { EuiLink } from '@elastic/eui';
+import { Status } from './status';
+import { SORT_ASCENDING, SORT_DESCENDING, TABLE_ACTION_UPDATE_FILTER } from '../../../../common/constants';
+import { formatMetric } from '../../../lib/format_number';
+import { formatTimestampToDuration } from '../../../../common';
+
+
+const filterFields = [ 'name', 'type', 'version', 'output' ];
+const columns = [
+ { title: 'Name', sortKey: 'name', sortOrder: SORT_ASCENDING },
+ { title: 'Output Enabled', sortKey: 'output' },
+ { title: 'Total Events Rate', sortKey: 'total_events_rate', secondarySortOrder: SORT_DESCENDING },
+ { title: 'Bytes Sent Rate', sortKey: 'bytes_sent_rate' },
+ { title: 'Output Errors', sortKey: 'errors' },
+ { title: 'Last Event', sortKey: 'time_of_last_event' },
+ { title: 'Allocated Memory', sortKey: 'memory' },
+ { title: 'Version', sortKey: 'version' },
+];
+const instanceRowFactory = () => {
+ return function KibanaRow(props) {
+ const applyFiltering = filterText => () => {
+ props.dispatchTableAction(TABLE_ACTION_UPDATE_FILTER, filterText);
+ };
+
+ return (
+
+
+
+
+ {props.name}
+
+
+
+
+ {props.output}
+
+
+ {formatMetric(props.total_events_rate, '', '/s')}
+
+
+ {formatMetric(props.bytes_sent_rate, 'byte', '/s')}
+
+
+ {formatMetric(props.errors, '0')}
+
+
+ {formatTimestampToDuration(+moment(props.time_of_last_event), 'since') + ' ago'}
+
+
+ {formatMetric(props.memory, 'byte')}
+
+
+
+ {props.version}
+
+
+
+ );
+ };
+};
+
+export function ApmServerInstances({ apms }) {
+ const {
+ pageIndex,
+ filterText,
+ sortKey,
+ sortOrder,
+ onNewState,
+ } = apms;
+
+ return (
+
+
+
+
+ );
+}
diff --git a/x-pack/plugins/monitoring/public/components/apm/instances/status.js b/x-pack/plugins/monitoring/public/components/apm/instances/status.js
new file mode 100644
index 0000000000000..e51063f02979b
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/components/apm/instances/status.js
@@ -0,0 +1,54 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React, { Fragment } from 'react';
+import moment from 'moment';
+import { SummaryStatus } from '../../summary_status';
+import { ApmStatusIcon } from '../status_icon';
+import { formatMetric } from '../../../lib/format_number';
+import { formatTimestampToDuration } from '../../../../common';
+
+export function Status({ stats }) {
+ const {
+ apms: {
+ total
+ },
+ totalEvents,
+ timeOfLastEvent,
+ } = stats;
+
+ const metrics = [
+ {
+ label: 'Servers',
+ value: total,
+ dataTestSubj: 'total'
+ },
+ {
+ label: 'Total Events',
+ value: formatMetric(totalEvents, '0.[0]a'),
+ dataTestSubj: 'totalEvents'
+ },
+ {
+ label: 'Last Event',
+ value: formatTimestampToDuration(+moment(timeOfLastEvent), 'since') + ' ago',
+ dataTestSubj: 'timeOfLastEvent',
+ }
+ ];
+
+ const IconComponent = ({ status }) => (
+
+ Status:
+
+ );
+
+ return (
+
+ );
+}
diff --git a/x-pack/plugins/monitoring/public/components/apm/overview/index.js b/x-pack/plugins/monitoring/public/components/apm/overview/index.js
new file mode 100644
index 0000000000000..634a5e78127c0
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/components/apm/overview/index.js
@@ -0,0 +1,63 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { MonitoringTimeseriesContainer } from '../../chart';
+import {
+ EuiSpacer,
+ EuiPage,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiPageBody,
+ EuiPanel
+} from '@elastic/eui';
+import { Status } from '../instances/status';
+
+export function ApmOverview({
+ stats,
+ metrics,
+ ...props
+}) {
+ const seriesToShow = [
+ metrics.apm_responses_valid,
+ metrics.apm_responses_errors,
+
+ metrics.apm_output_events_rate_success,
+ metrics.apm_output_events_rate_failure,
+
+ metrics.apm_requests,
+ metrics.apm_transformations,
+
+
+ metrics.apm_cpu,
+ metrics.apm_memory,
+
+ metrics.apm_os_load,
+ ];
+
+ const charts = seriesToShow.map((data, index) => (
+
+
+
+
+
+ ));
+
+ return (
+
+
+
+
+
+ {charts}
+
+
+
+ );
+}
diff --git a/x-pack/plugins/monitoring/public/components/apm/status_icon.js b/x-pack/plugins/monitoring/public/components/apm/status_icon.js
new file mode 100644
index 0000000000000..49fe0faed1ad1
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/components/apm/status_icon.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { StatusIcon } from 'plugins/monitoring/components/status_icon';
+
+export function ApmStatusIcon({ status, availability = true }) {
+ const type = (() => {
+ if (!availability) {
+ return StatusIcon.TYPES.GRAY;
+ }
+
+ const statusKey = status.toUpperCase();
+ return StatusIcon.TYPES[statusKey] || StatusIcon.TYPES.YELLOW;
+ })();
+
+ return (
+
+ );
+}
diff --git a/x-pack/plugins/monitoring/public/components/cluster/overview/apm_panel.js b/x-pack/plugins/monitoring/public/components/cluster/overview/apm_panel.js
new file mode 100644
index 0000000000000..a5726ab46666c
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/components/cluster/overview/apm_panel.js
@@ -0,0 +1,88 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import moment from 'moment';
+import { get } from 'lodash';
+import { formatMetric } from 'plugins/monitoring/lib/format_number';
+import { ClusterItemContainer, BytesPercentageUsage } from './helpers';
+
+import {
+ EuiFlexGrid,
+ EuiFlexItem,
+ EuiLink,
+ EuiTitle,
+ EuiPanel,
+ EuiDescriptionList,
+ EuiDescriptionListTitle,
+ EuiDescriptionListDescription,
+ EuiHorizontalRule,
+} from '@elastic/eui';
+import { formatTimestampToDuration } from '../../../../common';
+
+export function ApmPanel(props) {
+ if (!get(props, 'apms.total', 0) > 0) {
+ return null;
+ }
+
+ const goToApm = () => props.changeUrl('apm');
+ const goToInstances = () => props.changeUrl('apm/instances');
+
+ return (
+
+
+
+
+
+
+
+ Overview
+
+
+
+
+
+ Processed Events
+
+ {formatMetric(props.totalEvents, '0.[0]a')}
+
+ Last Event
+
+ {formatTimestampToDuration(+moment(props.timeOfLastEvent), 'since') + ' ago'}
+
+
+
+
+
+
+
+
+
+ APM Servers: {props.apms.total}
+
+
+
+
+
+ Memory Usage
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/x-pack/plugins/monitoring/public/components/cluster/overview/helpers.js b/x-pack/plugins/monitoring/public/components/cluster/overview/helpers.js
index c0e3a6a6b28e4..88c0e1b91940f 100644
--- a/x-pack/plugins/monitoring/public/components/cluster/overview/helpers.js
+++ b/x-pack/plugins/monitoring/public/components/cluster/overview/helpers.js
@@ -53,6 +53,7 @@ export function ClusterItemContainer(props) {
kibana: 'logoKibana',
logstash: 'logoLogstash',
beats: 'logoBeats',
+ apm: 'apmApp'
};
const icon = iconMap[props.url];
diff --git a/x-pack/plugins/monitoring/public/components/cluster/overview/index.js b/x-pack/plugins/monitoring/public/components/cluster/overview/index.js
index ba166d73e449b..67549912e5315 100644
--- a/x-pack/plugins/monitoring/public/components/cluster/overview/index.js
+++ b/x-pack/plugins/monitoring/public/components/cluster/overview/index.js
@@ -12,6 +12,7 @@ import { AlertsPanel } from './alerts_panel';
import { BeatsPanel } from './beats_panel';
import { EuiPage, EuiPageBody } from '@elastic/eui';
+import { ApmPanel } from './apm_panel';
export function Overview(props) {
return (
@@ -33,6 +34,8 @@ export function Overview(props) {
+
+
);
diff --git a/x-pack/plugins/monitoring/public/directives/main/index.html b/x-pack/plugins/monitoring/public/directives/main/index.html
index 2804898b85283..c48775107dd4c 100644
--- a/x-pack/plugins/monitoring/public/directives/main/index.html
+++ b/x-pack/plugins/monitoring/public/directives/main/index.html
@@ -60,6 +60,12 @@
{{ monitoringMain.instance }}
+
+
+
+
diff --git a/x-pack/plugins/monitoring/public/views/apm/instance/index.js b/x-pack/plugins/monitoring/public/views/apm/instance/index.js
new file mode 100644
index 0000000000000..55f085429977b
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/views/apm/instance/index.js
@@ -0,0 +1,64 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { find, get } from 'lodash';
+import uiRoutes from'ui/routes';
+import { routeInitProvider } from 'plugins/monitoring/lib/route_init';
+import template from './index.html';
+import { MonitoringViewBaseController } from '../../base_controller';
+import { ApmServerInstance } from '../../../components/apm/instance';
+
+uiRoutes.when('/apm/instances/:uuid', {
+ template,
+ resolve: {
+ clusters: function (Private) {
+ const routeInit = Private(routeInitProvider);
+ return routeInit();
+ },
+ },
+
+ controller: class extends MonitoringViewBaseController {
+ constructor($injector, $scope) {
+ const $route = $injector.get('$route');
+ const title = $injector.get('title');
+ const globalState = $injector.get('globalState');
+ $scope.cluster = find($route.current.locals.clusters, {
+ cluster_uuid: globalState.cluster_uuid
+ });
+
+ super({
+ title: `APM - Instance`,
+ api: `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/apm/${$route.current.params.uuid}`,
+ defaultData: {},
+ reactNodeId: 'apmInstanceReact',
+ $scope,
+ $injector
+ });
+
+ $scope.$watch(() => this.data, data => {
+ title($scope.cluster, `APM - ${get(data, 'apmSummary.name')}`);
+ this.renderReact(data);
+ });
+ }
+
+ renderReact(data) {
+ const component = (
+
+ );
+ super.renderReact(component);
+ }
+ }
+});
diff --git a/x-pack/plugins/monitoring/public/views/apm/instances/index.html b/x-pack/plugins/monitoring/public/views/apm/instances/index.html
new file mode 100644
index 0000000000000..fd8029e277d78
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/views/apm/instances/index.html
@@ -0,0 +1,7 @@
+
+
+
diff --git a/x-pack/plugins/monitoring/public/views/apm/instances/index.js b/x-pack/plugins/monitoring/public/views/apm/instances/index.js
new file mode 100644
index 0000000000000..e928289db61eb
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/views/apm/instances/index.js
@@ -0,0 +1,70 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { find } from 'lodash';
+import uiRoutes from'ui/routes';
+import { routeInitProvider } from 'plugins/monitoring/lib/route_init';
+import template from './index.html';
+import { ApmServerInstances } from '../../../components/apm/instances';
+import { MonitoringViewBaseTableController } from '../../base_table_controller';
+
+uiRoutes.when('/apm/instances', {
+ template,
+ resolve: {
+ clusters: function (Private) {
+ const routeInit = Private(routeInitProvider);
+ return routeInit();
+ },
+ },
+ controller: class extends MonitoringViewBaseTableController {
+ constructor($injector, $scope) {
+ const $route = $injector.get('$route');
+ const globalState = $injector.get('globalState');
+ $scope.cluster = find($route.current.locals.clusters, {
+ cluster_uuid: globalState.cluster_uuid
+ });
+
+ super({
+ title: 'APM - Instances',
+ storageKey: 'apm.instances',
+ api: `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/apm/instances`,
+ defaultData: {},
+ reactNodeId: 'apmInstancesReact',
+ $scope,
+ $injector
+ });
+
+ $scope.$watch(() => this.data, data => {
+ this.renderReact(data);
+ });
+ }
+
+ renderReact(data) {
+ const {
+ pageIndex,
+ filterText,
+ sortKey,
+ sortOrder,
+ onNewState,
+ } = this;
+
+ const component = (
+
+ );
+ super.renderReact(component);
+ }
+ }
+});
diff --git a/x-pack/plugins/monitoring/public/views/apm/overview/index.html b/x-pack/plugins/monitoring/public/views/apm/overview/index.html
new file mode 100644
index 0000000000000..0cf804e377476
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/views/apm/overview/index.html
@@ -0,0 +1,7 @@
+
+
+
diff --git a/x-pack/plugins/monitoring/public/views/apm/overview/index.js b/x-pack/plugins/monitoring/public/views/apm/overview/index.js
new file mode 100644
index 0000000000000..f3ab24b4712ce
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/views/apm/overview/index.js
@@ -0,0 +1,54 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { find } from 'lodash';
+import uiRoutes from'ui/routes';
+import { routeInitProvider } from 'plugins/monitoring/lib/route_init';
+import template from './index.html';
+import { MonitoringViewBaseController } from '../../base_controller';
+import { ApmOverview } from '../../../components/apm/overview';
+
+uiRoutes.when('/apm', {
+ template,
+ resolve: {
+ clusters: function (Private) {
+ const routeInit = Private(routeInitProvider);
+ return routeInit();
+ },
+ },
+ controller: class extends MonitoringViewBaseController {
+ constructor($injector, $scope) {
+ const $route = $injector.get('$route');
+ const globalState = $injector.get('globalState');
+ $scope.cluster = find($route.current.locals.clusters, {
+ cluster_uuid: globalState.cluster_uuid
+ });
+
+ super({
+ title: 'APM',
+ api: `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/apm`,
+ defaultData: {},
+ reactNodeId: 'apmOverviewReact',
+ $scope,
+ $injector
+ });
+
+ $scope.$watch(() => this.data, data => {
+ this.renderReact(data);
+ });
+ }
+
+ renderReact(data) {
+ const component = (
+
+ );
+ super.renderReact(component);
+ }
+ }
+});
diff --git a/x-pack/plugins/monitoring/server/lib/apm/_apm_stats.js b/x-pack/plugins/monitoring/server/lib/apm/_apm_stats.js
new file mode 100644
index 0000000000000..493fb3fadfa37
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/lib/apm/_apm_stats.js
@@ -0,0 +1,114 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { get } from 'lodash';
+
+export const getDiffCalculation = (max, min) => {
+ // no need to test max >= 0, but min <= 0 which is normal for a derivative after restart
+ // because we are aggregating/collapsing on ephemeral_ids
+ if (
+ max !== null && min !== null &&
+ max >= 0 && min >= 0 &&
+ max >= min
+ ) {
+ return max - min;
+ }
+
+ return null;
+};
+
+export const apmAggFilterPath = [
+ 'aggregations.total',
+ 'aggregations.min_events_total.value',
+ 'aggregations.max_events_total.value',
+ 'aggregations.min_mem_rss_total.value',
+ 'aggregations.max_mem_rss_total.value',
+ 'aggregations.max_mem_total_total.value',
+];
+
+export const apmUuidsAgg = maxBucketSize => ({
+ total: {
+ cardinality: {
+ field: 'beats_stats.beat.uuid',
+ precision_threshold: 10000
+ }
+ },
+ ephemeral_ids: {
+ terms: {
+ field: 'beats_stats.metrics.beat.info.ephemeral_id',
+ size: maxBucketSize
+ },
+ aggs: {
+ min_events: {
+ min: {
+ field: 'beats_stats.metrics.libbeat.pipeline.events.total'
+ }
+ },
+ max_events: {
+ max: {
+ field: 'beats_stats.metrics.libbeat.pipeline.events.total'
+ }
+ },
+ min_mem_rss: {
+ min: {
+ field: 'beats_stats.metrics.beat.memstats.rss'
+ }
+ },
+ max_mem_rss: {
+ max: {
+ field: 'beats_stats.metrics.beat.memstats.rss'
+ }
+ },
+ max_mem_total: {
+ max: {
+ field: 'beats_stats.metrics.beat.memstats.memory_total'
+ }
+ }
+ },
+ },
+ min_events_total: {
+ sum_bucket: {
+ buckets_path: 'ephemeral_ids>min_events'
+ }
+ },
+ max_events_total: {
+ sum_bucket: {
+ buckets_path: 'ephemeral_ids>max_events'
+ }
+ },
+ min_mem_rss_total: {
+ sum_bucket: {
+ buckets_path: 'ephemeral_ids>min_mem_rss'
+ }
+ },
+ max_mem_rss_total: {
+ sum_bucket: {
+ buckets_path: 'ephemeral_ids>max_mem_rss'
+ }
+ },
+ max_mem_total_total: {
+ sum_bucket: {
+ buckets_path: 'ephemeral_ids>max_mem_total'
+ }
+ }
+});
+
+export const apmAggResponseHandler = response => {
+ const apmTotal = get(response, 'aggregations.total.value', null);
+
+ const eventsTotalMax = get(response, 'aggregations.max_events_total.value', null);
+ const eventsTotalMin = get(response, 'aggregations.min_events_total.value', null);
+ const memRssMax = get(response, 'aggregations.max_mem_rss_total.value', null);
+ const memRssMin = get(response, 'aggregations.min_mem_rss_total.value', null);
+ const memTotal = get(response, 'aggregations.max_mem_total_total.value', null);
+
+ return {
+ apmTotal,
+ totalEvents: getDiffCalculation(eventsTotalMax, eventsTotalMin),
+ memRss: getDiffCalculation(memRssMax, memRssMin),
+ memTotal
+ };
+};
diff --git a/x-pack/plugins/monitoring/server/lib/apm/_get_time_of_last_event.js b/x-pack/plugins/monitoring/server/lib/apm/_get_time_of_last_event.js
new file mode 100644
index 0000000000000..9bc427ef5fda5
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/lib/apm/_get_time_of_last_event.js
@@ -0,0 +1,43 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { get } from 'lodash';
+import { createApmQuery } from './create_apm_query';
+import { ApmClusterMetric } from '../metrics';
+
+export async function getTimeOfLastEvent({ req, callWithRequest, apmIndexPattern, start, end, clusterUuid }) {
+ const params = {
+ index: apmIndexPattern,
+ size: 1,
+ ignoreUnavailable: true,
+ body: {
+ _source: ['timestamp'],
+ sort: [{
+ timestamp: {
+ order: 'desc'
+ }
+ }],
+ query: createApmQuery({
+ start,
+ end,
+ clusterUuid,
+ metric: ApmClusterMetric.getMetricFields(),
+ filters: [
+ {
+ range: {
+ 'beats_stats.metrics.libbeat.output.events.acked': {
+ gt: 0,
+ }
+ }
+ }
+ ],
+ }),
+ }
+ };
+
+ const response = await callWithRequest(req, 'search', params);
+ return get(response, 'hits.hits[0]._source.timestamp');
+}
diff --git a/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.js b/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.js
new file mode 100644
index 0000000000000..7a8b296f02427
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { defaults } from 'lodash';
+import { ApmMetric } from '../metrics';
+import { createQuery } from '../create_query';
+
+/**
+ * {@code createQuery} for all APM instances.
+ *
+ * @param {Object} options The options to pass to {@code createQuery}
+ */
+export function createApmQuery(options = { }) {
+ options = defaults(options, {
+ filters: [],
+ metric: ApmMetric.getMetricFields(),
+ type: 'beats_stats',
+ });
+
+ options.filters.push({
+ bool: {
+ must: {
+ term: {
+ 'beats_stats.beat.type': 'apm-server'
+ }
+ }
+ }
+ });
+
+ return createQuery(options);
+}
diff --git a/x-pack/plugins/monitoring/server/lib/apm/get_apm_info.js b/x-pack/plugins/monitoring/server/lib/apm/get_apm_info.js
new file mode 100644
index 0000000000000..ebe81ef9ef9e3
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/lib/apm/get_apm_info.js
@@ -0,0 +1,111 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { get, capitalize } from 'lodash';
+import { checkParam } from '../error_missing_required';
+import { createQuery } from '../create_query';
+import { getDiffCalculation } from '../beats/_beats_stats';
+import { ApmMetric } from '../metrics';
+import { getTimeOfLastEvent } from './_get_time_of_last_event';
+
+export function handleResponse(response, apmUuid) {
+ const firstStats = get(response, 'hits.hits[0].inner_hits.first_hit.hits.hits[0]._source.beats_stats');
+ const stats = get(response, 'hits.hits[0]._source.beats_stats');
+
+ const eventsTotalFirst = get(firstStats, 'metrics.libbeat.pipeline.events.total', null);
+ const eventsEmittedFirst = get(firstStats, 'metrics.libbeat.pipeline.events.published', null);
+ const eventsDroppedFirst = get(firstStats, 'metrics.libbeat.pipeline.events.dropped', null);
+ const bytesWrittenFirst = get(firstStats, 'metrics.libbeat.output.write.bytes', null);
+
+ const eventsTotalLast = get(stats, 'metrics.libbeat.pipeline.events.total', null);
+ const eventsEmittedLast = get(stats, 'metrics.libbeat.pipeline.events.published', null);
+ const eventsDroppedLast = get(stats, 'metrics.libbeat.pipeline.events.dropped', null);
+ const bytesWrittenLast = get(stats, 'metrics.libbeat.output.write.bytes', null);
+
+ return {
+ uuid: apmUuid,
+ transportAddress: get(stats, 'beat.host', null),
+ version: get(stats, 'beat.version', null),
+ name: get(stats, 'beat.name', null),
+ type: capitalize(get(stats, 'beat.type')) || null,
+ output: capitalize(get(stats, 'metrics.libbeat.output.type')) || null,
+ configReloads: get(stats, 'metrics.libbeat.config.reloads', null),
+ uptime: get(stats, 'metrics.beat.info.uptime.ms', null),
+ eventsTotal: getDiffCalculation(eventsTotalLast, eventsTotalFirst),
+ eventsEmitted: getDiffCalculation(eventsEmittedLast, eventsEmittedFirst),
+ eventsDropped: getDiffCalculation(eventsDroppedLast, eventsDroppedFirst),
+ bytesWritten: getDiffCalculation(bytesWrittenLast, bytesWrittenFirst),
+ };
+}
+
+export async function getApmInfo(req, apmIndexPattern, { clusterUuid, apmUuid, start, end }) {
+ checkParam(apmIndexPattern, 'apmIndexPattern in beats/getBeatSummary');
+
+ const filters = [
+ { term: { 'beats_stats.beat.uuid': apmUuid } },
+ { term: { 'beats_stats.beat.type': 'apm-server' } }
+ ];
+ const params = {
+ index: apmIndexPattern,
+ size: 1,
+ ignoreUnavailable: true,
+ filterPath: [
+ 'hits.hits._source.beats_stats.beat.host',
+ 'hits.hits._source.beats_stats.beat.version',
+ 'hits.hits._source.beats_stats.beat.name',
+ 'hits.hits._source.beats_stats.beat.type',
+ 'hits.hits._source.beats_stats.metrics.libbeat.output.type',
+ 'hits.hits._source.beats_stats.metrics.libbeat.pipeline.events.published',
+ 'hits.hits._source.beats_stats.metrics.libbeat.pipeline.events.total',
+ 'hits.hits._source.beats_stats.metrics.libbeat.pipeline.events.dropped',
+ 'hits.hits._source.beats_stats.metrics.libbeat.output.write.bytes',
+ 'hits.hits._source.beats_stats.metrics.libbeat.config.reloads',
+ 'hits.hits._source.beats_stats.metrics.beat.info.uptime.ms',
+ 'hits.hits.inner_hits.first_hit.hits.hits._source.beats_stats.metrics.libbeat.pipeline.events.published',
+ 'hits.hits.inner_hits.first_hit.hits.hits._source.beats_stats.metrics.libbeat.pipeline.events.total',
+ 'hits.hits.inner_hits.first_hit.hits.hits._source.beats_stats.metrics.libbeat.pipeline.events.dropped',
+ 'hits.hits.inner_hits.first_hit.hits.hits._source.beats_stats.metrics.libbeat.output.write.bytes',
+ ],
+ body: {
+ sort: { timestamp: { order: 'desc' } },
+ query: createQuery({
+ start,
+ end,
+ clusterUuid,
+ metric: ApmMetric.getMetricFields(),
+ filters
+ }),
+ collapse: {
+ field: 'beats_stats.metrics.beat.info.ephemeral_id', // collapse on ephemeral_id to handle restart
+ inner_hits: {
+ name: 'first_hit',
+ size: 1,
+ sort: { 'beats_stats.timestamp': 'asc' }
+ }
+ }
+ }
+ };
+
+ const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring');
+
+ const [response, timeOfLastEvent] = await Promise.all([
+ callWithRequest(req, 'search', params),
+ getTimeOfLastEvent({
+ req,
+ callWithRequest,
+ apmIndexPattern,
+ start,
+ end,
+ clusterUuid
+ })
+ ]);
+
+ const formattedResponse = handleResponse(response, apmUuid);
+ return {
+ ...formattedResponse,
+ timeOfLastEvent,
+ };
+}
diff --git a/x-pack/plugins/monitoring/server/lib/apm/get_apms.js b/x-pack/plugins/monitoring/server/lib/apm/get_apms.js
new file mode 100644
index 0000000000000..24073b899c3cd
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/lib/apm/get_apms.js
@@ -0,0 +1,140 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import moment from 'moment';
+import { capitalize, get } from 'lodash';
+import { checkParam } from '../error_missing_required';
+import { createApmQuery } from './create_apm_query';
+import { calculateRate } from '../calculate_rate';
+import { getDiffCalculation } from './_apm_stats';
+
+export function handleResponse(response, start, end) {
+ const hits = get(response, 'hits.hits', []);
+ const initial = { ids: new Set(), beats: [] };
+ const { beats } = hits.reduceRight((accum, hit) => {
+ const stats = get(hit, '_source.beats_stats');
+ const uuid = get(stats, 'beat.uuid');
+
+ // skip this duplicated beat, newer one was already added
+ if (accum.ids.has(uuid)) {
+ return accum;
+ }
+
+ // add another beat summary
+ accum.ids.add(uuid);
+ const earliestStats = get(hit, 'inner_hits.earliest.hits.hits[0]._source.beats_stats');
+
+ // add the beat
+ const rateOptions = {
+ hitTimestamp: get(stats, 'timestamp'),
+ earliestHitTimestamp: get(earliestStats, 'timestamp'),
+ timeWindowMin: start,
+ timeWindowMax: end
+ };
+
+ const { rate: bytesSentRate } = calculateRate({
+ latestTotal: get(stats, 'metrics.libbeat.output.write.bytes'),
+ earliestTotal: get(earliestStats, 'metrics.libbeat.output.write.bytes'),
+ ...rateOptions
+ });
+
+ const { rate: totalEventsRate } = calculateRate({
+ latestTotal: get(stats, 'metrics.libbeat.pipeline.events.total'),
+ earliestTotal: get(earliestStats, 'metrics.libbeat.pipeline.events.total'),
+ ...rateOptions
+ });
+
+ const errorsWrittenLatest = get(stats, 'metrics.libbeat.output.write.errors');
+ const errorsWrittenEarliest = get(earliestStats, 'metrics.libbeat.output.write.errors');
+ const errorsReadLatest = get(stats, 'metrics.libbeat.output.read.errors');
+ const errorsReadEarliest = get(earliestStats, 'metrics.libbeat.output.read.errors');
+ const errors = getDiffCalculation(
+ errorsWrittenLatest + errorsReadLatest,
+ errorsWrittenEarliest + errorsReadEarliest
+ );
+
+ accum.beats.push({
+ uuid: get(stats, 'beat.uuid'),
+ name: get(stats, 'beat.name'),
+ type: capitalize(get(stats, 'beat.type')),
+ output: capitalize(get(stats, 'metrics.libbeat.output.type')),
+ total_events_rate: totalEventsRate,
+ bytes_sent_rate: bytesSentRate,
+ errors,
+ memory: get(stats, 'metrics.beat.memstats.memory_alloc'),
+ version: get(stats, 'beat.version'),
+ time_of_last_event: get(hit, '_source.timestamp')
+ });
+
+ return accum;
+ }, initial);
+
+ return beats;
+}
+
+export async function getApms(req, apmIndexPattern, clusterUuid) {
+ checkParam(apmIndexPattern, 'apmIndexPattern in getBeats');
+
+ const config = req.server.config();
+ const start = moment.utc(req.payload.timeRange.min).valueOf();
+ const end = moment.utc(req.payload.timeRange.max).valueOf();
+
+ const params = {
+ index: apmIndexPattern,
+ size: config.get('xpack.monitoring.max_bucket_size'), // FIXME
+ ignoreUnavailable: true,
+ filterPath: [ // only filter path can filter for inner_hits
+ 'hits.hits._source.timestamp',
+ 'hits.hits._source.beats_stats.beat.uuid',
+ 'hits.hits._source.beats_stats.beat.name',
+ 'hits.hits._source.beats_stats.beat.host',
+ 'hits.hits._source.beats_stats.beat.type',
+ 'hits.hits._source.beats_stats.beat.version',
+ 'hits.hits._source.beats_stats.metrics.libbeat.output.type',
+ 'hits.hits._source.beats_stats.metrics.libbeat.output.read.errors',
+ 'hits.hits._source.beats_stats.metrics.libbeat.output.write.errors',
+ 'hits.hits._source.beats_stats.metrics.beat.memstats.memory_alloc',
+
+ // latest hits for calculating metrics
+ 'hits.hits._source.beats_stats.timestamp',
+ 'hits.hits._source.beats_stats.metrics.libbeat.output.write.bytes',
+ 'hits.hits._source.beats_stats.metrics.libbeat.pipeline.events.total',
+
+ // earliest hits for calculating metrics
+ 'hits.hits.inner_hits.earliest.hits.hits._source.beats_stats.timestamp',
+ 'hits.hits.inner_hits.earliest.hits.hits._source.beats_stats.metrics.libbeat.output.write.bytes',
+ 'hits.hits.inner_hits.earliest.hits.hits._source.beats_stats.metrics.libbeat.pipeline.events.total',
+
+ // earliest hits for calculating diffs
+ 'hits.hits.inner_hits.earliest.hits.hits._source.beats_stats.metrics.libbeat.output.read.errors',
+ 'hits.hits.inner_hits.earliest.hits.hits._source.beats_stats.metrics.libbeat.output.write.errors'
+ ],
+ body: {
+ query: createApmQuery({
+ start,
+ end,
+ clusterUuid
+ }),
+ collapse: {
+ field: 'beats_stats.metrics.beat.info.ephemeral_id', // collapse on ephemeral_id to handle restarts
+ inner_hits: {
+ name: 'earliest',
+ size: 1,
+ sort: [{ 'beats_stats.timestamp': 'asc' }]
+ }
+ },
+ sort: [
+ { 'beats_stats.beat.uuid': { order: 'asc' } }, // need to keep duplicate uuids grouped
+ { timestamp: { order: 'desc' } } // need oldest timestamp to come first for rate calcs to work
+ ]
+ }
+ };
+
+ const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring');
+ const response = await callWithRequest(req, 'search', params);
+
+ return handleResponse(response, start, end);
+}
diff --git a/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js b/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js
new file mode 100644
index 0000000000000..bf6f6e62248c1
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js
@@ -0,0 +1,80 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { checkParam } from '../error_missing_required';
+import { createApmQuery } from './create_apm_query';
+import { ApmMetric } from '../metrics';
+import { apmAggResponseHandler, apmUuidsAgg, apmAggFilterPath } from './_apm_stats';
+import { getTimeOfLastEvent } from './_get_time_of_last_event';
+
+export function handleResponse(clusterUuid, response) {
+ const { apmTotal, totalEvents, memRss, memTotal } = apmAggResponseHandler(response);
+
+ // combine stats
+ const stats = {
+ totalEvents,
+ memRss,
+ memTotal,
+ apms: {
+ total: apmTotal,
+ }
+ };
+
+ return {
+ clusterUuid,
+ stats,
+ };
+}
+
+export function getApmsForClusters(req, apmIndexPattern, clusters) {
+ checkParam(apmIndexPattern, 'apmIndexPattern in apms/getApmsForClusters');
+
+ const start = req.payload.timeRange.min;
+ const end = req.payload.timeRange.max;
+ const config = req.server.config();
+ const maxBucketSize = config.get('xpack.monitoring.max_bucket_size');
+
+ return Promise.all(clusters.map(async cluster => {
+ const clusterUuid = cluster.cluster_uuid;
+ const params = {
+ index: apmIndexPattern,
+ size: 0,
+ ignoreUnavailable: true,
+ filterPath: apmAggFilterPath,
+ body: {
+ query: createApmQuery({
+ start,
+ end,
+ clusterUuid,
+ metric: ApmMetric.getMetricFields() // override default of BeatMetric.getMetricFields
+ }),
+ aggs: apmUuidsAgg(maxBucketSize)
+ },
+ };
+
+ const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring');
+ const [response, timeOfLastEvent] = await Promise.all([
+ callWithRequest(req, 'search', params),
+ getTimeOfLastEvent({
+ req,
+ callWithRequest,
+ apmIndexPattern,
+ start,
+ end,
+ clusterUuid
+ })
+ ]);
+
+ const formattedResponse = handleResponse(clusterUuid, response);
+ return {
+ ...formattedResponse,
+ stats: {
+ ...formattedResponse.stats,
+ timeOfLastEvent,
+ }
+ };
+ }));
+}
diff --git a/x-pack/plugins/monitoring/server/lib/apm/get_stats.js b/x-pack/plugins/monitoring/server/lib/apm/get_stats.js
new file mode 100644
index 0000000000000..5b693e7aab370
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/lib/apm/get_stats.js
@@ -0,0 +1,70 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import moment from 'moment';
+import { checkParam } from '../error_missing_required';
+import { createApmQuery } from './create_apm_query';
+import {
+ apmAggFilterPath,
+ apmUuidsAgg,
+ apmAggResponseHandler,
+} from './_apm_stats';
+import { getTimeOfLastEvent } from './_get_time_of_last_event';
+
+export function handleResponse(...args) {
+ const { apmTotal, totalEvents, bytesSent } = apmAggResponseHandler(...args);
+
+ return {
+ bytesSent,
+ totalEvents,
+ apms: {
+ total: apmTotal
+ }
+ };
+}
+
+export async function getStats(req, apmIndexPattern, clusterUuid) {
+ checkParam(apmIndexPattern, 'apmIndexPattern in getBeats');
+
+ const config = req.server.config();
+ const start = moment.utc(req.payload.timeRange.min).valueOf();
+ const end = moment.utc(req.payload.timeRange.max).valueOf();
+ const maxBucketSize = config.get('xpack.monitoring.max_bucket_size');
+
+ const params = {
+ index: apmIndexPattern,
+ filterPath: apmAggFilterPath,
+ size: 0,
+ ignoreUnavailable: true,
+ body: {
+ query: createApmQuery({
+ start,
+ end,
+ clusterUuid,
+ }),
+ aggs: apmUuidsAgg(maxBucketSize)
+ }
+ };
+
+ const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring');
+ const [response, timeOfLastEvent] = await Promise.all([
+ callWithRequest(req, 'search', params),
+ getTimeOfLastEvent({
+ req,
+ callWithRequest,
+ apmIndexPattern,
+ start,
+ end,
+ clusterUuid
+ })
+ ]);
+
+ const formattedResponse = handleResponse(response, start, end);
+ return {
+ ...formattedResponse,
+ timeOfLastEvent,
+ };
+}
diff --git a/x-pack/plugins/monitoring/server/lib/apm/index.js b/x-pack/plugins/monitoring/server/lib/apm/index.js
new file mode 100644
index 0000000000000..76009fde0cc3f
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/lib/apm/index.js
@@ -0,0 +1,10 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export { getApmsForClusters } from './get_apms_for_clusters';
+export { getStats } from './get_stats';
+export { getApms } from './get_apms';
+export { getApmInfo } from './get_apm_info';
diff --git a/x-pack/plugins/monitoring/server/lib/cluster/__test__/__snapshots__/get_clusters_summary.test.js.snap b/x-pack/plugins/monitoring/server/lib/cluster/__test__/__snapshots__/get_clusters_summary.test.js.snap
index 7a27dc22e1d41..fcb05ad52ead2 100644
--- a/x-pack/plugins/monitoring/server/lib/cluster/__test__/__snapshots__/get_clusters_summary.test.js.snap
+++ b/x-pack/plugins/monitoring/server/lib/cluster/__test__/__snapshots__/get_clusters_summary.test.js.snap
@@ -8,6 +8,7 @@ Array [
"enabled": true,
},
},
+ "apm": undefined,
"beats": Object {
"beats": Object {
"total": null,
@@ -108,6 +109,7 @@ Array [
"enabled": true,
},
},
+ "apm": undefined,
"beats": Object {
"beats": Object {
"total": null,
@@ -213,6 +215,7 @@ Array [
"enabled": true,
},
},
+ "apm": undefined,
"beats": Object {
"beats": Object {
"total": null,
@@ -313,6 +316,7 @@ Array [
"enabled": true,
},
},
+ "apm": undefined,
"beats": Object {
"beats": Object {
"total": null,
diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js
index 427cd5af19ab1..6e88e55811fd2 100644
--- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js
+++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js
@@ -18,12 +18,20 @@ import { alertsClusterSearch } from '../../cluster_alerts/alerts_cluster_search'
import { checkLicense as checkLicenseForAlerts } from '../../cluster_alerts/check_license';
import { getClustersSummary } from './get_clusters_summary';
import { CLUSTER_ALERTS_SEARCH_SIZE } from '../../../common/constants';
+import { getApmsForClusters } from '../apm/get_apms_for_clusters';
/**
* Get all clusters or the cluster associated with {@code clusterUuid} when it is defined.
*/
export async function getClustersFromRequest(req, indexPatterns, { clusterUuid, start, end } = {}) {
- const { esIndexPattern, kbnIndexPattern, lsIndexPattern, beatsIndexPattern, alertsIndex } = indexPatterns;
+ const {
+ esIndexPattern,
+ kbnIndexPattern,
+ lsIndexPattern,
+ beatsIndexPattern,
+ apmIndexPattern,
+ alertsIndex
+ } = indexPatterns;
// get clusters with stats and cluster state
let clusters = await getClustersStats(req, esIndexPattern, clusterUuid);
@@ -106,6 +114,13 @@ export async function getClustersFromRequest(req, indexPatterns, { clusterUuid,
set(clusters[clusterIndex], 'beats', beats.stats);
});
+ // add apm data
+ const apmsByCluster = await getApmsForClusters(req, apmIndexPattern, clusters);
+ apmsByCluster.forEach(apm => {
+ const clusterIndex = findIndex(clusters, { cluster_uuid: apm.clusterUuid });
+ set(clusters[clusterIndex], 'apm', apm.stats);
+ });
+
const config = req.server.config();
const kibanaUuid = config.get('server.uuid');
return getClustersSummary(clusters, kibanaUuid);
diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_summary.js b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_summary.js
index 3dc19e70c8891..1a6911a3239ea 100644
--- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_summary.js
+++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_summary.js
@@ -20,6 +20,7 @@ export function getClustersSummary(clusters, kibanaUuid) {
kibana,
ml,
beats,
+ apm,
alerts
} = cluster;
@@ -66,6 +67,7 @@ export function getClustersSummary(clusters, kibanaUuid) {
kibana: omit(kibana, 'uuids'),
ml,
beats,
+ apm,
alerts,
isPrimary: kibana.uuids.includes(kibanaUuid),
status: calculateOverallStatus([
diff --git a/x-pack/plugins/monitoring/server/lib/details/get_series.js b/x-pack/plugins/monitoring/server/lib/details/get_series.js
index 5c74ef47b4dc2..7c642656cb585 100644
--- a/x-pack/plugins/monitoring/server/lib/details/get_series.js
+++ b/x-pack/plugins/monitoring/server/lib/details/get_series.js
@@ -111,6 +111,10 @@ function fetchSeries(req, indexPattern, metric, min, max, bucketSize, filters) {
}
};
+ if (metric.debug) {
+ console.log('metric.debug', JSON.stringify(params));
+ }
+
const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring');
return callWithRequest(req, 'search', params);
}
diff --git a/x-pack/plugins/monitoring/server/lib/metrics/__test__/__snapshots__/metrics.test.js.snap b/x-pack/plugins/monitoring/server/lib/metrics/__test__/__snapshots__/metrics.test.js.snap
index 401fc150ba391..26586c824fdec 100644
--- a/x-pack/plugins/monitoring/server/lib/metrics/__test__/__snapshots__/metrics.test.js.snap
+++ b/x-pack/plugins/monitoring/server/lib/metrics/__test__/__snapshots__/metrics.test.js.snap
@@ -2,6 +2,1041 @@
exports[`Metrics should export metric objects that match a snapshot 1`] = `
Object {
+ "apm_cpu_total": ApmCpuUtilizationMetric {
+ "app": "apm",
+ "calculation": [Function],
+ "derivative": true,
+ "description": "Percentage of CPU time spent executing (user+kernel mode) for the APM process",
+ "field": "beats_stats.metrics.beat.cpu.total.value",
+ "format": "0.[00]",
+ "label": "Total",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "CPU Utilization",
+ "units": "%",
+ "uuidField": "beats_stats.beat.uuid",
+ },
+ "apm_mem_alloc": ApmMetric {
+ "app": "apm",
+ "derivative": false,
+ "description": "Allocated memory",
+ "field": "beats_stats.metrics.beat.memstats.memory_alloc",
+ "format": "0,0.0 b",
+ "label": "Allocated Memory",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Memory",
+ "units": "B",
+ "uuidField": "beats_stats.beat.uuid",
+ },
+ "apm_mem_gc_next": ApmMetric {
+ "app": "apm",
+ "derivative": false,
+ "description": "Limit of allocated memory at which garbage collection will occur",
+ "field": "beats_stats.metrics.beat.memstats.gc_next",
+ "format": "0,0.0 b",
+ "label": "GC Next",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Memory",
+ "units": "B",
+ "uuidField": "beats_stats.beat.uuid",
+ },
+ "apm_mem_rss": ApmMetric {
+ "app": "apm",
+ "derivative": false,
+ "description": "Resident set size of memory reserved by the APM service from the OS",
+ "field": "beats_stats.metrics.beat.memstats.rss",
+ "format": "0,0.0 b",
+ "label": "Process Total",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Memory",
+ "units": "B",
+ "uuidField": "beats_stats.beat.uuid",
+ },
+ "apm_output_events_acked": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.libbeat.output.events.acked",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "Events processed by the output (including retries)",
+ "field": "beats_stats.metrics.libbeat.output.events.acked",
+ "format": "0,0.[00]",
+ "label": "Acked",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Output Acked Events Rate",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_output_events_active": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.libbeat.output.events.active",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "Events processed by the output (including retries)",
+ "field": "beats_stats.metrics.libbeat.output.events.active",
+ "format": "0,0.[00]",
+ "label": "Active",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Output Active Events Rate",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_output_events_dropped": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.libbeat.output.events.dropped",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "Events processed by the output (including retries)",
+ "field": "beats_stats.metrics.libbeat.output.events.dropped",
+ "format": "0,0.[00]",
+ "label": "Dropped",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Output Dropped Events Rate",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_output_events_failed": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.libbeat.output.events.failed",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "Events processed by the output (including retries)",
+ "field": "beats_stats.metrics.libbeat.output.events.failed",
+ "format": "0,0.[00]",
+ "label": "Failed",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Output Failed Events Rate",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_output_events_total": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.libbeat.output.events.total",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "Events processed by the output (including retries)",
+ "field": "beats_stats.metrics.libbeat.output.events.total",
+ "format": "0,0.[00]",
+ "label": "Total",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Output Events Rate",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_processor_error_transformations": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.processor.error.transformations",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "Error events processed",
+ "field": "beats_stats.metrics.apm-server.processor.error.transformations",
+ "format": "0,0.[00]",
+ "label": "Error",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Transformations",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_processor_metric_transformations": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.processor.metric.transformations",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "Metric events processed",
+ "field": "beats_stats.metrics.apm-server.processor.metric.transformations",
+ "format": "0,0.[00]",
+ "label": "Metric",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Transformations",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_processor_span_transformations": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.processor.span.transformations",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "Span events processed",
+ "field": "beats_stats.metrics.apm-server.processor.span.transformations",
+ "format": "0,0.[00]",
+ "label": "Span",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Transformations",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_processor_transaction_transformations": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.processor.transaction.transformations",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "Transaction events processed",
+ "field": "beats_stats.metrics.apm-server.processor.transaction.transformations",
+ "format": "0,0.[00]",
+ "label": "Transaction",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Processed Events",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_requests": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.request.count",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests received by server",
+ "field": "beats_stats.metrics.apm-server.server.request.count",
+ "format": "0,0.[00]",
+ "label": "Requested",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Requests",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_count": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.count",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests responded to by server",
+ "field": "beats_stats.metrics.apm-server.server.response.count",
+ "format": "0,0.[00]",
+ "label": "Total",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Response Count",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_errors_closed": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.errors.closed",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests rejected during server shutdown",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.closed",
+ "format": "0,0.[00]",
+ "label": "Closed",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Closed",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_errors_concurrency": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.errors.concurrency",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests rejected due to overall concurrency limit breach",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.concurrency",
+ "format": "0,0.[00]",
+ "label": "Concurrency",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Concurrency",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_errors_decode": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.errors.decode",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests rejected to due decoding errors - invalid json, incorrect data type for entity",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.decode",
+ "format": "0,0.[00]",
+ "label": "Decode",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Decode",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_errors_forbidden": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.errors.forbidden",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "Forbidden HTTP Requests rejected - CORS violation, disabled enpoint",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.forbidden",
+ "format": "0,0.[00]",
+ "label": "Forbidden",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Forbidden",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_errors_method": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.errors.method",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests rejected due to incorrect HTTP method",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.method",
+ "format": "0,0.[00]",
+ "label": "Method",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Method",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_errors_queue": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.errors.queue",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests rejected to due internal queue filling up",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.queue",
+ "format": "0,0.[00]",
+ "label": "Queue",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Queue",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_errors_ratelimit": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.errors.ratelimit",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests rejected to due excessive rate limit",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.ratelimit",
+ "format": "0,0.[00]",
+ "label": "Rate limit",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Rate limit",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_errors_toolarge": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.errors.toolarge",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests rejected due to excessive payload size",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.toolarge",
+ "format": "0,0.[00]",
+ "label": "Too large",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Response Errors",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_errors_unauthorized": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.errors.unauthorized",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests rejected due to invalid secret token",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.unauthorized",
+ "format": "0,0.[00]",
+ "label": "Unauthorized",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Unauthorized",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_errors_validate": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.errors.validate",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests rejected due to payload validation error",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.validate",
+ "format": "0,0.[00]",
+ "label": "Validate",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Validate",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_valid_accepted": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.valid.accepted",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "HTTP Requests successfully reporting new events",
+ "field": "beats_stats.metrics.apm-server.server.response.valid.accepted",
+ "format": "0,0.[00]",
+ "label": "Accepted",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Accepted",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_responses_valid_ok": ApmEventsRateClusterMetric {
+ "aggs": Object {
+ "beats_uuids": Object {
+ "aggs": Object {
+ "event_rate_per_beat": Object {
+ "max": Object {
+ "field": "beats_stats.metrics.apm-server.server.response.valid.ok",
+ },
+ },
+ },
+ "terms": Object {
+ "field": "beats_stats.beat.uuid",
+ "size": 10000,
+ },
+ },
+ "event_rate": Object {
+ "sum_bucket": Object {
+ "buckets_path": "beats_uuids>event_rate_per_beat",
+ "gap_policy": "skip",
+ },
+ },
+ "metric_deriv": Object {
+ "derivative": Object {
+ "buckets_path": "event_rate",
+ "gap_policy": "skip",
+ "unit": "1m",
+ },
+ },
+ },
+ "app": "apm",
+ "derivative": true,
+ "description": "200 OK response count",
+ "field": "beats_stats.metrics.apm-server.server.response.valid.ok",
+ "format": "0,0.[00]",
+ "label": "Ok",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "Ok",
+ "units": "/m",
+ "uuidField": "cluster_uuid",
+ },
+ "apm_system_os_load_1": ApmMetric {
+ "app": "apm",
+ "derivative": false,
+ "description": "Load average over the last 1 minute",
+ "field": "beats_stats.metrics.system.load.1",
+ "format": "0,0.[00]",
+ "label": "1m",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "System Load",
+ "units": "",
+ "uuidField": "beats_stats.beat.uuid",
+ },
+ "apm_system_os_load_15": ApmMetric {
+ "app": "apm",
+ "derivative": false,
+ "description": "Load average over the last 15 minutes",
+ "field": "beats_stats.metrics.system.load.15",
+ "format": "0,0.[00]",
+ "label": "15m",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "System Load",
+ "units": "",
+ "uuidField": "beats_stats.beat.uuid",
+ },
+ "apm_system_os_load_5": ApmMetric {
+ "app": "apm",
+ "derivative": false,
+ "description": "Load average over the last 5 minutes",
+ "field": "beats_stats.metrics.system.load.5",
+ "format": "0,0.[00]",
+ "label": "5m",
+ "metricAgg": "max",
+ "timestampField": "beats_stats.timestamp",
+ "title": "System Load",
+ "units": "",
+ "uuidField": "beats_stats.beat.uuid",
+ },
"beat_bytes_written": BeatsByteRateMetric {
"app": "beats",
"derivative": true,
diff --git a/x-pack/plugins/monitoring/server/lib/metrics/apm/classes.js b/x-pack/plugins/monitoring/server/lib/metrics/apm/classes.js
new file mode 100644
index 0000000000000..2356f1ad03ebc
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/lib/metrics/apm/classes.js
@@ -0,0 +1,118 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { ClusterMetric, Metric } from '../classes';
+import { SMALL_FLOAT, LARGE_FLOAT } from '../../../../common/formatting';
+
+export class ApmClusterMetric extends ClusterMetric {
+ constructor(opts) {
+ super({
+ ...opts,
+ app: 'apm',
+ ...ApmClusterMetric.getMetricFields()
+ });
+ }
+
+ static getMetricFields() {
+ return {
+ uuidField: 'cluster_uuid',
+ timestampField: 'beats_stats.timestamp'
+ };
+ }
+}
+
+export class ApmMetric extends Metric {
+ constructor(opts) {
+ super({
+ ...opts,
+ app: 'apm',
+ ...ApmMetric.getMetricFields()
+ });
+ }
+
+ static getMetricFields() {
+ return {
+ uuidField: 'beats_stats.beat.uuid',
+ timestampField: 'beats_stats.timestamp'
+ };
+ }
+}
+
+export class ApmCpuUtilizationMetric extends ApmMetric {
+ constructor(opts) {
+ super({
+ ...opts,
+ format: SMALL_FLOAT,
+ metricAgg: 'max',
+ units: '%',
+ derivative: true
+ });
+
+ /*
+ * Convert a counter of milliseconds of utilization time into a percentage of the bucket size
+ */
+ this.calculation = (
+ { metric_deriv: metricDeriv } = {},
+ _key,
+ _metric,
+ bucketSizeInSeconds
+ ) => {
+ if (metricDeriv) {
+ const { normalized_value: metricDerivNormalizedValue } = metricDeriv;
+ const bucketSizeInMillis = bucketSizeInSeconds * 1000;
+
+ if (
+ metricDerivNormalizedValue >= 0 &&
+ metricDerivNormalizedValue !== null
+ ) {
+ return metricDerivNormalizedValue / bucketSizeInMillis * 100;
+ }
+ }
+ return null;
+ };
+ }
+}
+
+export class ApmEventsRateClusterMetric extends ApmClusterMetric {
+ constructor(opts) {
+ super({
+ ...opts,
+ derivative: true,
+ format: LARGE_FLOAT,
+ metricAgg: 'max',
+ units: '/m'
+ });
+
+ this.aggs = {
+ beats_uuids: {
+ terms: {
+ field: 'beats_stats.beat.uuid',
+ size: 10000
+ },
+ aggs: {
+ event_rate_per_beat: {
+ max: {
+ field: this.field
+ }
+ }
+ }
+ },
+ event_rate: {
+ sum_bucket: {
+ buckets_path: 'beats_uuids>event_rate_per_beat',
+ gap_policy: 'skip'
+ }
+ },
+ metric_deriv: {
+ derivative: {
+ buckets_path: 'event_rate',
+ gap_policy: 'skip',
+ unit: '1m'
+ }
+ }
+ };
+ }
+}
diff --git a/x-pack/plugins/monitoring/server/lib/metrics/apm/metrics.js b/x-pack/plugins/monitoring/server/lib/metrics/apm/metrics.js
new file mode 100644
index 0000000000000..c8249ccfdddac
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/lib/metrics/apm/metrics.js
@@ -0,0 +1,222 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { LARGE_BYTES, LARGE_FLOAT } from '../../../../common/formatting';
+import {
+ ApmMetric,
+ ApmCpuUtilizationMetric,
+ ApmEventsRateClusterMetric,
+} from './classes';
+
+export const metrics = {
+ apm_cpu_total: new ApmCpuUtilizationMetric({
+ title: 'CPU Utilization',
+ label: 'Total',
+ description:
+ 'Percentage of CPU time spent executing (user+kernel mode) for the APM process',
+ field: 'beats_stats.metrics.beat.cpu.total.value'
+ }),
+ apm_system_os_load_1: new ApmMetric({
+ field: 'beats_stats.metrics.system.load.1',
+ label: '1m',
+ title: 'System Load',
+ description: 'Load average over the last 1 minute',
+ format: LARGE_FLOAT,
+ metricAgg: 'max',
+ units: ''
+ }),
+ apm_system_os_load_5: new ApmMetric({
+ field: 'beats_stats.metrics.system.load.5',
+ label: '5m',
+ title: 'System Load',
+ description: 'Load average over the last 5 minutes',
+ format: LARGE_FLOAT,
+ metricAgg: 'max',
+ units: ''
+ }),
+ apm_system_os_load_15: new ApmMetric({
+ field: 'beats_stats.metrics.system.load.15',
+ label: '15m',
+ title: 'System Load',
+ description: 'Load average over the last 15 minutes',
+ format: LARGE_FLOAT,
+ metricAgg: 'max',
+ units: ''
+ }),
+
+ apm_mem_gc_next: new ApmMetric({
+ field: 'beats_stats.metrics.beat.memstats.gc_next',
+ label: 'GC Next',
+ title: 'Memory',
+ description:
+ 'Limit of allocated memory at which garbage collection will occur',
+ format: LARGE_BYTES,
+ metricAgg: 'max',
+ units: 'B'
+ }),
+ apm_mem_alloc: new ApmMetric({
+ field: 'beats_stats.metrics.beat.memstats.memory_alloc',
+ label: 'Allocated Memory',
+ title: 'Memory',
+ description:
+ 'Allocated memory',
+ format: LARGE_BYTES,
+ metricAgg: 'max',
+ units: 'B'
+ }),
+ apm_mem_rss: new ApmMetric({
+ field: 'beats_stats.metrics.beat.memstats.rss',
+ label: 'Process Total',
+ title: 'Memory',
+ description: 'Resident set size of memory reserved by the APM service from the OS',
+ format: LARGE_BYTES,
+ metricAgg: 'max',
+ units: 'B'
+ }),
+
+ apm_requests: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.request.count',
+ title: 'Requests',
+ label: 'Requested',
+ description: 'HTTP Requests received by server'
+ }),
+
+ apm_responses_count: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.count',
+ title: 'Response Count',
+ label: 'Total',
+ description: 'HTTP Requests responded to by server'
+ }),
+ apm_responses_valid_ok: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.valid.ok',
+ title: 'Ok',
+ label: 'Ok',
+ description: '200 OK response count'
+ }),
+ apm_responses_valid_accepted: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.valid.accepted',
+ title: 'Accepted',
+ label: 'Accepted',
+ description: 'HTTP Requests successfully reporting new events'
+ }),
+ apm_responses_errors_toolarge: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.errors.toolarge',
+ title: 'Response Errors',
+ label: 'Too large',
+ description: 'HTTP Requests rejected due to excessive payload size'
+ }),
+ apm_responses_errors_validate: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.errors.validate',
+ title: 'Validate',
+ label: 'Validate',
+ description: 'HTTP Requests rejected due to payload validation error'
+ }),
+ apm_responses_errors_method: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.errors.method',
+ title: 'Method',
+ label: 'Method',
+ description: 'HTTP Requests rejected due to incorrect HTTP method'
+ }),
+ apm_responses_errors_unauthorized: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.errors.unauthorized',
+ title: 'Unauthorized',
+ label: 'Unauthorized',
+ description: 'HTTP Requests rejected due to invalid secret token'
+ }),
+ apm_responses_errors_ratelimit: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.errors.ratelimit',
+ title: 'Rate limit',
+ label: 'Rate limit',
+ description: 'HTTP Requests rejected to due excessive rate limit'
+ }),
+ apm_responses_errors_queue: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.errors.queue',
+ title: 'Queue',
+ label: 'Queue',
+ description: 'HTTP Requests rejected to due internal queue filling up'
+ }),
+ apm_responses_errors_decode: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.errors.decode',
+ title: 'Decode',
+ label: 'Decode',
+ description: 'HTTP Requests rejected to due decoding errors - invalid json, incorrect data type for entity'
+ }),
+ apm_responses_errors_forbidden: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.errors.forbidden',
+ title: 'Forbidden',
+ label: 'Forbidden',
+ description: 'Forbidden HTTP Requests rejected - CORS violation, disabled enpoint'
+ }),
+ apm_responses_errors_concurrency: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.errors.concurrency',
+ title: 'Concurrency',
+ label: 'Concurrency',
+ description: 'HTTP Requests rejected due to overall concurrency limit breach'
+ }),
+ apm_responses_errors_closed: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.server.response.errors.closed',
+ title: 'Closed',
+ label: 'Closed',
+ description: 'HTTP Requests rejected during server shutdown'
+ }),
+
+ apm_processor_transaction_transformations: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.processor.transaction.transformations',
+ title: 'Processed Events',
+ label: 'Transaction',
+ description: 'Transaction events processed'
+ }),
+ apm_processor_span_transformations: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.processor.span.transformations',
+ title: 'Transformations',
+ label: 'Span',
+ description: 'Span events processed'
+ }),
+ apm_processor_error_transformations: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.processor.error.transformations',
+ title: 'Transformations',
+ label: 'Error',
+ description: 'Error events processed'
+ }),
+ apm_processor_metric_transformations: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.apm-server.processor.metric.transformations',
+ title: 'Transformations',
+ label: 'Metric',
+ description: 'Metric events processed'
+ }),
+
+
+ apm_output_events_total: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.libbeat.output.events.total',
+ title: 'Output Events Rate',
+ label: 'Total',
+ description: 'Events processed by the output (including retries)'
+ }),
+ apm_output_events_failed: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.libbeat.output.events.failed',
+ title: 'Output Failed Events Rate',
+ label: 'Failed',
+ description: 'Events processed by the output (including retries)'
+ }),
+ apm_output_events_dropped: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.libbeat.output.events.dropped',
+ title: 'Output Dropped Events Rate',
+ label: 'Dropped',
+ description: 'Events processed by the output (including retries)'
+ }),
+ apm_output_events_active: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.libbeat.output.events.active',
+ title: 'Output Active Events Rate',
+ label: 'Active',
+ description: 'Events processed by the output (including retries)'
+ }),
+ apm_output_events_acked: new ApmEventsRateClusterMetric({
+ field: 'beats_stats.metrics.libbeat.output.events.acked',
+ title: 'Output Acked Events Rate',
+ label: 'Acked',
+ description: 'Events processed by the output (including retries)'
+ }),
+};
diff --git a/x-pack/plugins/monitoring/server/lib/metrics/index.js b/x-pack/plugins/monitoring/server/lib/metrics/index.js
index 460dbb51a3edc..75bc488de3b7e 100644
--- a/x-pack/plugins/monitoring/server/lib/metrics/index.js
+++ b/x-pack/plugins/monitoring/server/lib/metrics/index.js
@@ -6,6 +6,7 @@
export { ElasticsearchMetric } from './elasticsearch/classes';
export { KibanaClusterMetric, KibanaMetric } from './kibana/classes';
+export { ApmMetric, ApmClusterMetric } from './apm/classes';
export { LogstashClusterMetric, LogstashMetric } from './logstash/classes';
export { BeatsClusterMetric, BeatsMetric } from './beats/classes';
export { metrics } from './metrics';
diff --git a/x-pack/plugins/monitoring/server/lib/metrics/metrics.js b/x-pack/plugins/monitoring/server/lib/metrics/metrics.js
index 89c84d7784e27..fb0376ddfea63 100644
--- a/x-pack/plugins/monitoring/server/lib/metrics/metrics.js
+++ b/x-pack/plugins/monitoring/server/lib/metrics/metrics.js
@@ -8,10 +8,12 @@ import { metrics as elasticsearchMetrics } from './elasticsearch/metrics';
import { metrics as kibanaMetrics } from './kibana/metrics';
import { metrics as logstashMetrics } from './logstash/metrics';
import { metrics as beatsMetrics } from './beats/metrics';
+import { metrics as apmMetrics } from './apm/metrics';
export const metrics = {
...elasticsearchMetrics,
...kibanaMetrics,
...logstashMetrics,
- ...beatsMetrics
+ ...beatsMetrics,
+ ...apmMetrics
};
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js
new file mode 100644
index 0000000000000..f63a989252b0f
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js
@@ -0,0 +1,14 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { get } from 'lodash';
+import { getApmsForClusters } from '../../../../lib/apm/get_apms_for_clusters';
+
+export const getApmClusterStatus = (req, apmIndexPattern, { clusterUuid }) => {
+ const clusters = [{ cluster_uuid: clusterUuid }];
+ return getApmsForClusters(req, apmIndexPattern, clusters)
+ .then(apms => get(apms, '[0].stats'));
+};
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/index.js
new file mode 100644
index 0000000000000..3474da2500c7d
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/index.js
@@ -0,0 +1,9 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export { apmInstanceRoute } from './instance';
+export { apmInstancesRoute } from './instances';
+export { apmOverviewRoute } from './overview';
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js
new file mode 100644
index 0000000000000..ff009a3b7fb76
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js
@@ -0,0 +1,55 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import Joi from 'joi';
+import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import { getMetrics } from '../../../../lib/details/get_metrics';
+import { metricSet } from './metric_set_overview';
+import { handleError } from '../../../../lib/errors';
+import { getApmInfo } from '../../../../lib/apm';
+
+export function apmInstanceRoute(server) {
+ server.route({
+ method: 'POST',
+ path: '/api/monitoring/v1/clusters/{clusterUuid}/apm/{apmUuid}',
+ config: {
+ validate: {
+ params: Joi.object({
+ clusterUuid: Joi.string().required(),
+ apmUuid: Joi.string().required()
+ }),
+ payload: Joi.object({
+ ccs: Joi.string().optional(),
+ timeRange: Joi.object({
+ min: Joi.date().required(),
+ max: Joi.date().required()
+ }).required()
+ })
+ }
+ },
+ async handler(req, reply) {
+ const apmUuid = req.params.apmUuid;
+ const config = server.config();
+ const clusterUuid = req.params.clusterUuid;
+ const ccs = req.payload.ccs;
+ const apmIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
+
+ try {
+ const [ metrics, apmSummary ] = await Promise.all([
+ getMetrics(req, apmIndexPattern, metricSet, [{ term: { 'beats_stats.beat.uuid': apmUuid } }]),
+ getApmInfo(req, apmIndexPattern, { clusterUuid, apmUuid }),
+ ]);
+
+ reply({
+ metrics,
+ apmSummary,
+ });
+ } catch (err) {
+ reply(handleError(err, req));
+ }
+ }
+ });
+}
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js
new file mode 100644
index 0000000000000..241d535721ec3
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js
@@ -0,0 +1,53 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import Joi from 'joi';
+import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import { getStats, getApms } from '../../../../lib/apm';
+import { handleError } from '../../../../lib/errors';
+
+export function apmInstancesRoute(server) {
+ server.route({
+ method: 'POST',
+ path: '/api/monitoring/v1/clusters/{clusterUuid}/apm/instances',
+ config: {
+ validate: {
+ params: Joi.object({
+ clusterUuid: Joi.string().required()
+ }),
+ payload: Joi.object({
+ ccs: Joi.string().optional(),
+ timeRange: Joi.object({
+ min: Joi.date().required(),
+ max: Joi.date().required()
+ }).required()
+ })
+ }
+ },
+ async handler(req, reply) {
+ const config = server.config();
+ const ccs = req.payload.ccs;
+ const clusterUuid = req.params.clusterUuid;
+ const apmIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
+
+ try {
+
+ const [ stats, apms ] = await Promise.all([
+ getStats(req, apmIndexPattern, clusterUuid),
+ getApms(req, apmIndexPattern, clusterUuid),
+ ]);
+
+ reply({
+ stats,
+ apms
+ });
+
+ } catch (err) {
+ reply(handleError(err, req));
+ }
+ }
+ });
+}
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/metric_set_instance.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/metric_set_instance.js
new file mode 100644
index 0000000000000..a3f7784aee52f
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/metric_set_instance.js
@@ -0,0 +1,80 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export const metricSet = [
+ {
+ name: 'apm_cpu',
+ keys: [
+ 'apm_cpu_total'
+ ]
+ },
+ {
+ keys: [
+ 'apm_system_os_load_1',
+ 'apm_system_os_load_5',
+ 'apm_system_os_load_15'
+ ],
+ name: 'apm_os_load'
+ },
+ {
+ keys: ['apm_mem_alloc', 'apm_mem_rss', 'apm_mem_gc_next'],
+ name: 'apm_memory'
+ },
+ {
+ keys: [
+ 'apm_output_events_total',
+ 'apm_output_events_active',
+ 'apm_output_events_acked'
+ ],
+ name: 'apm_output_events_rate_success'
+ },
+ {
+ keys: [
+ 'apm_output_events_failed',
+ 'apm_output_events_dropped',
+ ],
+ name: 'apm_output_events_rate_failure'
+ },
+ {
+ keys: [
+ 'apm_responses_count',
+ 'apm_responses_valid_ok',
+ 'apm_responses_valid_accepted'
+ ],
+ name: 'apm_responses_valid'
+ },
+ {
+ keys: [
+ // 'apm_responses_count',
+ 'apm_responses_errors_toolarge',
+ 'apm_responses_errors_validate',
+ 'apm_responses_errors_method',
+ 'apm_responses_errors_unauthorized',
+ 'apm_responses_errors_ratelimit',
+ 'apm_responses_errors_queue',
+ 'apm_responses_errors_decode',
+ 'apm_responses_errors_forbidden',
+ 'apm_responses_errors_concurrency',
+ 'apm_responses_errors_closed',
+ ],
+ name: 'apm_responses_errors'
+ },
+ {
+ keys: [
+ 'apm_requests'
+ ],
+ name: 'apm_requests'
+ },
+ {
+ keys: [
+ 'apm_processor_transaction_transformations',
+ 'apm_processor_span_transformations',
+ 'apm_processor_error_transformations',
+ 'apm_processor_metric_transformations',
+ ],
+ name: 'apm_transformations'
+ }
+];
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/metric_set_overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/metric_set_overview.js
new file mode 100644
index 0000000000000..a3f7784aee52f
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/metric_set_overview.js
@@ -0,0 +1,80 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export const metricSet = [
+ {
+ name: 'apm_cpu',
+ keys: [
+ 'apm_cpu_total'
+ ]
+ },
+ {
+ keys: [
+ 'apm_system_os_load_1',
+ 'apm_system_os_load_5',
+ 'apm_system_os_load_15'
+ ],
+ name: 'apm_os_load'
+ },
+ {
+ keys: ['apm_mem_alloc', 'apm_mem_rss', 'apm_mem_gc_next'],
+ name: 'apm_memory'
+ },
+ {
+ keys: [
+ 'apm_output_events_total',
+ 'apm_output_events_active',
+ 'apm_output_events_acked'
+ ],
+ name: 'apm_output_events_rate_success'
+ },
+ {
+ keys: [
+ 'apm_output_events_failed',
+ 'apm_output_events_dropped',
+ ],
+ name: 'apm_output_events_rate_failure'
+ },
+ {
+ keys: [
+ 'apm_responses_count',
+ 'apm_responses_valid_ok',
+ 'apm_responses_valid_accepted'
+ ],
+ name: 'apm_responses_valid'
+ },
+ {
+ keys: [
+ // 'apm_responses_count',
+ 'apm_responses_errors_toolarge',
+ 'apm_responses_errors_validate',
+ 'apm_responses_errors_method',
+ 'apm_responses_errors_unauthorized',
+ 'apm_responses_errors_ratelimit',
+ 'apm_responses_errors_queue',
+ 'apm_responses_errors_decode',
+ 'apm_responses_errors_forbidden',
+ 'apm_responses_errors_concurrency',
+ 'apm_responses_errors_closed',
+ ],
+ name: 'apm_responses_errors'
+ },
+ {
+ keys: [
+ 'apm_requests'
+ ],
+ name: 'apm_requests'
+ },
+ {
+ keys: [
+ 'apm_processor_transaction_transformations',
+ 'apm_processor_span_transformations',
+ 'apm_processor_error_transformations',
+ 'apm_processor_metric_transformations',
+ ],
+ name: 'apm_transformations'
+ }
+];
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js
new file mode 100644
index 0000000000000..098c68d9a6de3
--- /dev/null
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js
@@ -0,0 +1,56 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import Joi from 'joi';
+import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import { getMetrics } from '../../../../lib/details/get_metrics';
+import { metricSet } from './metric_set_overview';
+import { handleError } from '../../../../lib/errors';
+import { getApmClusterStatus } from './_get_apm_cluster_status';
+
+export function apmOverviewRoute(server) {
+ server.route({
+ method: 'POST',
+ path: '/api/monitoring/v1/clusters/{clusterUuid}/apm',
+ config: {
+ validate: {
+ params: Joi.object({
+ clusterUuid: Joi.string().required()
+ }),
+ payload: Joi.object({
+ ccs: Joi.string().optional(),
+ timeRange: Joi.object({
+ min: Joi.date().required(),
+ max: Joi.date().required()
+ }).required()
+ })
+ }
+ },
+ async handler(req, reply) {
+ const config = server.config();
+ const ccs = req.payload.ccs;
+ const clusterUuid = req.params.clusterUuid;
+ const apmIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
+
+ try {
+ const [
+ stats,
+ metrics,
+ ] = await Promise.all([
+ getApmClusterStatus(req, apmIndexPattern, { clusterUuid }),
+ getMetrics(req, apmIndexPattern, metricSet),
+ ]);
+
+ reply({
+ stats,
+ metrics
+ });
+ } catch (err) {
+ reply(handleError(err, req));
+ }
+ }
+ });
+}
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/cluster/cluster.js b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/cluster.js
index 1d41341b9895e..329dc16e5bab4 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/cluster/cluster.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/cluster.js
@@ -37,8 +37,9 @@ export function clusterRoute(server) {
const kbnIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.kibana.index_pattern', ccs);
const lsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.logstash.index_pattern', ccs);
const beatsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
+ const apmIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
const alertsIndex = prefixIndexPattern(config, 'xpack.monitoring.cluster_alerts.index', ccs);
- const indexPatterns = { esIndexPattern, kbnIndexPattern, lsIndexPattern, beatsIndexPattern, alertsIndex };
+ const indexPatterns = { esIndexPattern, kbnIndexPattern, lsIndexPattern, beatsIndexPattern, apmIndexPattern, alertsIndex };
const options = {
clusterUuid: req.params.clusterUuid,
start: req.payload.timeRange.min,
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/cluster/clusters.js b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/clusters.js
index ad42ed71643b2..315947f034439 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/cluster/clusters.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/clusters.js
@@ -44,8 +44,9 @@ export function clustersRoute(server) {
const kbnIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.kibana.index_pattern', ccs);
const lsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.logstash.index_pattern', ccs);
const beatsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
+ const apmIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
const alertsIndex = prefixIndexPattern(config, 'xpack.monitoring.cluster_alerts.index', ccs);
- const indexPatterns = { esIndexPattern, kbnIndexPattern, lsIndexPattern, beatsIndexPattern, alertsIndex };
+ const indexPatterns = { esIndexPattern, kbnIndexPattern, lsIndexPattern, beatsIndexPattern, apmIndexPattern, alertsIndex };
clusters = await getClustersFromRequest(req, indexPatterns);
} catch (err) {
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/ui.js b/x-pack/plugins/monitoring/server/routes/api/v1/ui.js
index d8c95874417bb..b62406841955c 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/ui.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/ui.js
@@ -39,6 +39,11 @@ export {
kibanaInstancesRoute,
kibanaOverviewRoute
} from './kibana';
+export {
+ apmInstanceRoute,
+ apmInstancesRoute,
+ apmOverviewRoute
+} from './apm';
export {
logstashClusterPipelinesRoute,
logstashNodePipelinesRoute,
diff --git a/x-pack/test/api_integration/apis/monitoring/apm/fixtures/cluster.json b/x-pack/test/api_integration/apis/monitoring/apm/fixtures/cluster.json
new file mode 100644
index 0000000000000..82443713d9dec
--- /dev/null
+++ b/x-pack/test/api_integration/apis/monitoring/apm/fixtures/cluster.json
@@ -0,0 +1,712 @@
+{
+ "stats": {
+ "totalEvents": 18,
+ "memRss": 3821568,
+ "memTotal": 2404475016,
+ "apms": {
+ "total": 2
+ },
+ "timeOfLastEvent": "2018-08-31T13:59:21.201Z"
+ },
+ "metrics": {
+ "apm_cpu": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.beat.cpu.total.value",
+ "metricAgg": "max",
+ "label": "Total",
+ "title": "CPU Utilization",
+ "description": "Percentage of CPU time spent executing (user+kernel mode) for the APM process",
+ "units": "%",
+ "format": "0.[00]",
+ "hasCalculation": true,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0.0033333333333333335],
+ [1535723940000, 0.008888888888888887]
+ ]
+ }],
+ "apm_os_load": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.system.load.1",
+ "metricAgg": "max",
+ "label": "1m",
+ "title": "System Load",
+ "description": "Load average over the last 1 minute",
+ "units": "",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 1.37],
+ [1535723910000, 1.01],
+ [1535723940000, 0.61]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.system.load.5",
+ "metricAgg": "max",
+ "label": "5m",
+ "title": "System Load",
+ "description": "Load average over the last 5 minutes",
+ "units": "",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 1.72],
+ [1535723910000, 1.6],
+ [1535723940000, 1.45]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.system.load.15",
+ "metricAgg": "max",
+ "label": "15m",
+ "title": "System Load",
+ "description": "Load average over the last 15 minutes",
+ "units": "",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 2.5],
+ [1535723910000, 2.43],
+ [1535723940000, 2.35]
+ ]
+ }],
+ "apm_memory": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.beat.memstats.memory_alloc",
+ "metricAgg": "max",
+ "label": "Allocated Memory",
+ "title": "Memory",
+ "description": "Allocated memory",
+ "units": "B",
+ "format": "0,0.0 b",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 4660952],
+ [1535723910000, 3888048],
+ [1535723940000, 3445920]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.beat.memstats.rss",
+ "metricAgg": "max",
+ "label": "Process Total",
+ "title": "Memory",
+ "description": "Resident set size of memory reserved by the APM service from the OS",
+ "units": "B",
+ "format": "0,0.0 b",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 10866688],
+ [1535723910000, 11456512],
+ [1535723940000, 12095488]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.beat.memstats.gc_next",
+ "metricAgg": "max",
+ "label": "GC Next",
+ "title": "Memory",
+ "description": "Limit of allocated memory at which garbage collection will occur",
+ "units": "B",
+ "format": "0,0.0 b",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 5212816],
+ [1535723910000, 4996912],
+ [1535723940000, 4886176]
+ ]
+ }],
+ "apm_output_events_rate_success": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.libbeat.output.events.total",
+ "metricAgg": "max",
+ "label": "Total",
+ "title": "Output Events Rate",
+ "description": "Events processed by the output (including retries)",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 18],
+ [1535723940000, 12]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.libbeat.output.events.active",
+ "metricAgg": "max",
+ "label": "Active",
+ "title": "Output Active Events Rate",
+ "description": "Events processed by the output (including retries)",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, null],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.libbeat.output.events.acked",
+ "metricAgg": "max",
+ "label": "Acked",
+ "title": "Output Acked Events Rate",
+ "description": "Events processed by the output (including retries)",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 18],
+ [1535723940000, 12]
+ ]
+ }],
+ "apm_output_events_rate_failure": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.libbeat.output.events.failed",
+ "metricAgg": "max",
+ "label": "Failed",
+ "title": "Output Failed Events Rate",
+ "description": "Events processed by the output (including retries)",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.libbeat.output.events.dropped",
+ "metricAgg": "max",
+ "label": "Dropped",
+ "title": "Output Dropped Events Rate",
+ "description": "Events processed by the output (including retries)",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }],
+ "apm_responses_valid": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.count",
+ "metricAgg": "max",
+ "label": "Total",
+ "title": "Response Count",
+ "description": "HTTP Requests responded to by server",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 84],
+ [1535723940000, 84]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.valid.ok",
+ "metricAgg": "max",
+ "label": "Ok",
+ "title": "Ok",
+ "description": "200 OK response count",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 80],
+ [1535723940000, 82]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.valid.accepted",
+ "metricAgg": "max",
+ "label": "Accepted",
+ "title": "Accepted",
+ "description": "HTTP Requests successfully reporting new events",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 4],
+ [1535723940000, 2]
+ ]
+ }],
+ "apm_responses_errors": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.toolarge",
+ "metricAgg": "max",
+ "label": "Too large",
+ "title": "Response Errors",
+ "description": "HTTP Requests rejected due to excessive payload size",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.validate",
+ "metricAgg": "max",
+ "label": "Validate",
+ "title": "Validate",
+ "description": "HTTP Requests rejected due to payload validation error",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.method",
+ "metricAgg": "max",
+ "label": "Method",
+ "title": "Method",
+ "description": "HTTP Requests rejected due to incorrect HTTP method",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.unauthorized",
+ "metricAgg": "max",
+ "label": "Unauthorized",
+ "title": "Unauthorized",
+ "description": "HTTP Requests rejected due to invalid secret token",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.ratelimit",
+ "metricAgg": "max",
+ "label": "Rate limit",
+ "title": "Rate limit",
+ "description": "HTTP Requests rejected to due excessive rate limit",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.queue",
+ "metricAgg": "max",
+ "label": "Queue",
+ "title": "Queue",
+ "description": "HTTP Requests rejected to due internal queue filling up",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.decode",
+ "metricAgg": "max",
+ "label": "Decode",
+ "title": "Decode",
+ "description": "HTTP Requests rejected to due decoding errors - invalid json, incorrect data type for entity",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.forbidden",
+ "metricAgg": "max",
+ "label": "Forbidden",
+ "title": "Forbidden",
+ "description": "Forbidden HTTP Requests rejected - CORS violation, disabled enpoint",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.concurrency",
+ "metricAgg": "max",
+ "label": "Concurrency",
+ "title": "Concurrency",
+ "description": "HTTP Requests rejected due to overall concurrency limit breach",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.closed",
+ "metricAgg": "max",
+ "label": "Closed",
+ "title": "Closed",
+ "description": "HTTP Requests rejected during server shutdown",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }],
+ "apm_requests": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.request.count",
+ "metricAgg": "max",
+ "label": "Requested",
+ "title": "Requests",
+ "description": "HTTP Requests received by server",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 84],
+ [1535723940000, 84]
+ ]
+ }],
+ "apm_transformations": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.processor.transaction.transformations",
+ "metricAgg": "max",
+ "label": "Transaction",
+ "title": "Processed Events",
+ "description": "Transaction events processed",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 6],
+ [1535723940000, 4]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.processor.span.transformations",
+ "metricAgg": "max",
+ "label": "Span",
+ "title": "Transformations",
+ "description": "Span events processed",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.processor.error.transformations",
+ "metricAgg": "max",
+ "label": "Error",
+ "title": "Transformations",
+ "description": "Error events processed",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.processor.metric.transformations",
+ "metricAgg": "max",
+ "label": "Metric",
+ "title": "Transformations",
+ "description": "Metric events processed",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }]
+ }
+}
diff --git a/x-pack/test/api_integration/apis/monitoring/apm/fixtures/instance.json b/x-pack/test/api_integration/apis/monitoring/apm/fixtures/instance.json
new file mode 100644
index 0000000000000..fe4472d43aee5
--- /dev/null
+++ b/x-pack/test/api_integration/apis/monitoring/apm/fixtures/instance.json
@@ -0,0 +1,718 @@
+{
+ "metrics": {
+ "apm_cpu": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.beat.cpu.total.value",
+ "metricAgg": "max",
+ "label": "Total",
+ "title": "CPU Utilization",
+ "description": "Percentage of CPU time spent executing (user+kernel mode) for the APM process",
+ "units": "%",
+ "format": "0.[00]",
+ "hasCalculation": true,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0.004444444444444444],
+ [1535723940000, 0.01]
+ ]
+ }],
+ "apm_os_load": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.system.load.1",
+ "metricAgg": "max",
+ "label": "1m",
+ "title": "System Load",
+ "description": "Load average over the last 1 minute",
+ "units": "",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 1.37],
+ [1535723910000, 1.01],
+ [1535723940000, 0.61]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.system.load.5",
+ "metricAgg": "max",
+ "label": "5m",
+ "title": "System Load",
+ "description": "Load average over the last 5 minutes",
+ "units": "",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 1.72],
+ [1535723910000, 1.6],
+ [1535723940000, 1.45]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.system.load.15",
+ "metricAgg": "max",
+ "label": "15m",
+ "title": "System Load",
+ "description": "Load average over the last 15 minutes",
+ "units": "",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 2.5],
+ [1535723910000, 2.43],
+ [1535723940000, 2.35]
+ ]
+ }],
+ "apm_memory": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.beat.memstats.memory_alloc",
+ "metricAgg": "max",
+ "label": "Allocated Memory",
+ "title": "Memory",
+ "description": "Allocated memory",
+ "units": "B",
+ "format": "0,0.0 b",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 4421336],
+ [1535723910000, 3888048],
+ [1535723940000, 3087640]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.beat.memstats.rss",
+ "metricAgg": "max",
+ "label": "Process Total",
+ "title": "Memory",
+ "description": "Resident set size of memory reserved by the APM service from the OS",
+ "units": "B",
+ "format": "0,0.0 b",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 10260480],
+ [1535723910000, 11456512],
+ [1535723940000, 12095488]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.beat.memstats.gc_next",
+ "metricAgg": "max",
+ "label": "GC Next",
+ "title": "Memory",
+ "description": "Limit of allocated memory at which garbage collection will occur",
+ "units": "B",
+ "format": "0,0.0 b",
+ "hasCalculation": false,
+ "isDerivative": false
+ },
+ "data": [
+ [1535723880000, 4996912],
+ [1535723910000, 4996912],
+ [1535723940000, 4886176]
+ ]
+ }],
+ "apm_output_events_rate_success": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.libbeat.output.events.total",
+ "metricAgg": "max",
+ "label": "Total",
+ "title": "Output Events Rate",
+ "description": "Events processed by the output (including retries)",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 6],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.libbeat.output.events.active",
+ "metricAgg": "max",
+ "label": "Active",
+ "title": "Output Active Events Rate",
+ "description": "Events processed by the output (including retries)",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.libbeat.output.events.acked",
+ "metricAgg": "max",
+ "label": "Acked",
+ "title": "Output Acked Events Rate",
+ "description": "Events processed by the output (including retries)",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 6],
+ [1535723940000, 0]
+ ]
+ }],
+ "apm_output_events_rate_failure": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.libbeat.output.events.failed",
+ "metricAgg": "max",
+ "label": "Failed",
+ "title": "Output Failed Events Rate",
+ "description": "Events processed by the output (including retries)",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.libbeat.output.events.dropped",
+ "metricAgg": "max",
+ "label": "Dropped",
+ "title": "Output Dropped Events Rate",
+ "description": "Events processed by the output (including retries)",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }],
+ "apm_responses_valid": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.count",
+ "metricAgg": "max",
+ "label": "Total",
+ "title": "Response Count",
+ "description": "HTTP Requests responded to by server",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 42],
+ [1535723940000, 42]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.valid.ok",
+ "metricAgg": "max",
+ "label": "Ok",
+ "title": "Ok",
+ "description": "200 OK response count",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 40],
+ [1535723940000, 42]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.valid.accepted",
+ "metricAgg": "max",
+ "label": "Accepted",
+ "title": "Accepted",
+ "description": "HTTP Requests successfully reporting new events",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 2],
+ [1535723940000, 0]
+ ]
+ }],
+ "apm_responses_errors": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.toolarge",
+ "metricAgg": "max",
+ "label": "Too large",
+ "title": "Response Errors",
+ "description": "HTTP Requests rejected due to excessive payload size",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.validate",
+ "metricAgg": "max",
+ "label": "Validate",
+ "title": "Validate",
+ "description": "HTTP Requests rejected due to payload validation error",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.method",
+ "metricAgg": "max",
+ "label": "Method",
+ "title": "Method",
+ "description": "HTTP Requests rejected due to incorrect HTTP method",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.unauthorized",
+ "metricAgg": "max",
+ "label": "Unauthorized",
+ "title": "Unauthorized",
+ "description": "HTTP Requests rejected due to invalid secret token",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.ratelimit",
+ "metricAgg": "max",
+ "label": "Rate limit",
+ "title": "Rate limit",
+ "description": "HTTP Requests rejected to due excessive rate limit",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.queue",
+ "metricAgg": "max",
+ "label": "Queue",
+ "title": "Queue",
+ "description": "HTTP Requests rejected to due internal queue filling up",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.decode",
+ "metricAgg": "max",
+ "label": "Decode",
+ "title": "Decode",
+ "description": "HTTP Requests rejected to due decoding errors - invalid json, incorrect data type for entity",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.forbidden",
+ "metricAgg": "max",
+ "label": "Forbidden",
+ "title": "Forbidden",
+ "description": "Forbidden HTTP Requests rejected - CORS violation, disabled enpoint",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.concurrency",
+ "metricAgg": "max",
+ "label": "Concurrency",
+ "title": "Concurrency",
+ "description": "HTTP Requests rejected due to overall concurrency limit breach",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.response.errors.closed",
+ "metricAgg": "max",
+ "label": "Closed",
+ "title": "Closed",
+ "description": "HTTP Requests rejected during server shutdown",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }],
+ "apm_requests": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.server.request.count",
+ "metricAgg": "max",
+ "label": "Requested",
+ "title": "Requests",
+ "description": "HTTP Requests received by server",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 42],
+ [1535723940000, 42]
+ ]
+ }],
+ "apm_transformations": [{
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.processor.transaction.transformations",
+ "metricAgg": "max",
+ "label": "Transaction",
+ "title": "Processed Events",
+ "description": "Transaction events processed",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 2],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.processor.span.transformations",
+ "metricAgg": "max",
+ "label": "Span",
+ "title": "Transformations",
+ "description": "Span events processed",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.processor.error.transformations",
+ "metricAgg": "max",
+ "label": "Error",
+ "title": "Transformations",
+ "description": "Error events processed",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }, {
+ "bucket_size": "30 seconds",
+ "timeRange": {
+ "min": 1535720389104,
+ "max": 1535723989104
+ },
+ "metric": {
+ "app": "apm",
+ "field": "beats_stats.metrics.apm-server.processor.metric.transformations",
+ "metricAgg": "max",
+ "label": "Metric",
+ "title": "Transformations",
+ "description": "Metric events processed",
+ "units": "/m",
+ "format": "0,0.[00]",
+ "hasCalculation": false,
+ "isDerivative": true
+ },
+ "data": [
+ [1535723880000, null],
+ [1535723910000, 0],
+ [1535723940000, 0]
+ ]
+ }]
+ },
+ "apmSummary": {
+ "uuid": "9b16f434-2092-4983-a401-80a2b61c79d6",
+ "transportAddress": "01323afae1fb",
+ "version": "7.0.0-alpha1",
+ "name": "01323afae1fb",
+ "type": "Apm-server",
+ "output": "Elasticsearch",
+ "configReloads": 0,
+ "uptime": 26450107,
+ "eventsTotal": 6,
+ "eventsEmitted": 6,
+ "eventsDropped": 0,
+ "bytesWritten": 10478,
+ "timeOfLastEvent": "2018-08-31T13:59:21.201Z"
+ }
+}
diff --git a/x-pack/test/api_integration/apis/monitoring/apm/index.js b/x-pack/test/api_integration/apis/monitoring/apm/index.js
new file mode 100644
index 0000000000000..9d7945a878c4a
--- /dev/null
+++ b/x-pack/test/api_integration/apis/monitoring/apm/index.js
@@ -0,0 +1,13 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export default function ({ loadTestFile }) {
+ describe('APM', () => {
+ loadTestFile(require.resolve('./overview'));
+ loadTestFile(require.resolve('./instances'));
+ loadTestFile(require.resolve('./instance'));
+ });
+}
diff --git a/x-pack/test/api_integration/apis/monitoring/apm/instance.js b/x-pack/test/api_integration/apis/monitoring/apm/instance.js
new file mode 100644
index 0000000000000..fa933a06257de
--- /dev/null
+++ b/x-pack/test/api_integration/apis/monitoring/apm/instance.js
@@ -0,0 +1,39 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import expect from 'expect.js';
+import apmInstanceFixture from './fixtures/instance';
+
+export default function ({ getService }) {
+ const supertest = getService('supertest');
+ const esArchiver = getService('esArchiver');
+
+ describe('instance detail', () => {
+ const archive = 'monitoring/apm';
+ const timeRange = {
+ min: '2018-08-31T12:59:49.104Z',
+ max: '2018-08-31T13:59:49.104Z'
+ };
+
+ before('load archive', () => {
+ return esArchiver.load(archive);
+ });
+
+ after('unload archive', () => {
+ return esArchiver.unload(archive);
+ });
+
+ it('should summarize beat with metrics', async () => {
+ const { body } = await supertest
+ .post('/api/monitoring/v1/clusters/GUtE4UwgSR-XUICRDEFKkA/apm/9b16f434-2092-4983-a401-80a2b61c79d6')
+ .set('kbn-xsrf', 'xxx')
+ .send({ timeRange })
+ .expect(200);
+
+ expect(body).to.eql(apmInstanceFixture);
+ });
+ });
+}
diff --git a/x-pack/test/api_integration/apis/monitoring/apm/instances.js b/x-pack/test/api_integration/apis/monitoring/apm/instances.js
new file mode 100644
index 0000000000000..4ad9a666ab5d1
--- /dev/null
+++ b/x-pack/test/api_integration/apis/monitoring/apm/instances.js
@@ -0,0 +1,73 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import expect from 'expect.js';
+
+export default function ({ getService }) {
+ const supertest = getService('supertest');
+ const esArchiver = getService('esArchiver');
+
+ describe('list', () => {
+ const archive = 'monitoring/apm';
+ const timeRange = {
+ min: '2018-08-31T12:59:49.104Z',
+ max: '2018-08-31T13:59:49.104Z'
+ };
+
+ before('load clusters archive', () => {
+ return esArchiver.load(archive);
+ });
+
+ after('unload clusters archive', () => {
+ return esArchiver.unload(archive);
+ });
+
+ it('should load multiple clusters', async () => {
+ const { body } = await supertest
+ .post(
+ '/api/monitoring/v1/clusters/GUtE4UwgSR-XUICRDEFKkA/apm/instances'
+ )
+ .set('kbn-xsrf', 'xxx')
+ .send({ timeRange })
+ .expect(200);
+
+ const expected = {
+ stats: {
+ totalEvents: 18,
+ apms: {
+ total: 2
+ },
+ timeOfLastEvent: '2018-08-31T13:59:21.201Z'
+ },
+ apms: [{
+ uuid: '9b16f434-2092-4983-a401-80a2b61c79d6',
+ name: '01323afae1fb',
+ type: 'Apm-server',
+ output: 'Elasticsearch',
+ total_events_rate: 0.0016666666666666668,
+ bytes_sent_rate: 2.9105555555555553,
+ errors: 0,
+ memory: 3087640,
+ version: '7.0.0-alpha1',
+ time_of_last_event: '2018-08-31T13:59:21.165Z'
+ }, {
+ uuid: '55f1089b-43b1-472a-919a-344667bae595',
+ name: 'd06490170f2b',
+ type: 'Apm-server',
+ output: 'Elasticsearch',
+ total_events_rate: 0.0033333333333333335,
+ bytes_sent_rate: 5.7316666666666665,
+ errors: 0,
+ memory: 3445920,
+ version: '7.0.0-alpha1',
+ time_of_last_event: '2018-08-31T13:59:21.201Z'
+ }]
+ };
+
+ expect(body).to.eql(expected);
+ });
+ });
+}
diff --git a/x-pack/test/api_integration/apis/monitoring/apm/overview.js b/x-pack/test/api_integration/apis/monitoring/apm/overview.js
new file mode 100644
index 0000000000000..30a5ae8198b2f
--- /dev/null
+++ b/x-pack/test/api_integration/apis/monitoring/apm/overview.js
@@ -0,0 +1,39 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import expect from 'expect.js';
+import apmClusterFixture from './fixtures/cluster';
+
+export default function ({ getService }) {
+ const supertest = getService('supertest');
+ const esArchiver = getService('esArchiver');
+
+ describe('overview', () => {
+ const archive = 'monitoring/apm';
+ const timeRange = {
+ min: '2018-08-31T12:59:49.104Z',
+ max: '2018-08-31T13:59:49.104Z'
+ };
+
+ before('load archive', () => {
+ return esArchiver.load(archive);
+ });
+
+ after('unload archive', () => {
+ return esArchiver.unload(archive);
+ });
+
+ it('should summarize apm cluster with metrics', async () => {
+ const { body } = await supertest
+ .post('/api/monitoring/v1/clusters/GUtE4UwgSR-XUICRDEFKkA/apm')
+ .set('kbn-xsrf', 'xxx')
+ .send({ timeRange })
+ .expect(200);
+
+ expect(body).to.eql(apmClusterFixture);
+ });
+ });
+}
diff --git a/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/multicluster.json b/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/multicluster.json
index 259d3e962c594..1d71e1ed49cd8 100644
--- a/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/multicluster.json
+++ b/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/multicluster.json
@@ -85,6 +85,14 @@
"memory_limit": 0,
"count": 0
},
+ "apm": {
+ "totalEvents": null,
+ "memRss": null,
+ "memTotal": null,
+ "apms": {
+ "total": null
+ }
+ },
"beats": {
"totalEvents": null,
"bytesSent": null,
@@ -192,6 +200,14 @@
"memory_limit": 0,
"count": 0
},
+ "apm": {
+ "totalEvents": null,
+ "memRss": null,
+ "memTotal": null,
+ "apms": {
+ "total": null
+ }
+ },
"beats": {
"totalEvents": null,
"bytesSent": null,
@@ -301,6 +317,14 @@
"memory_limit": 1501560832,
"count": 1
},
+ "apm": {
+ "totalEvents": null,
+ "memRss": null,
+ "memTotal": null,
+ "apms": {
+ "total": null
+ }
+ },
"beats": {
"totalEvents": null,
"bytesSent": null,
diff --git a/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/overview.json b/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/overview.json
index faa64e2c4cdb5..7a9db98f94139 100644
--- a/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/overview.json
+++ b/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/overview.json
@@ -87,6 +87,14 @@
"memory_limit": 1501560832,
"count": 1
},
+ "apm": {
+ "totalEvents": null,
+ "memRss": null,
+ "memTotal": null,
+ "apms": {
+ "total": null
+ }
+ },
"beats": {
"totalEvents": null,
"bytesSent": null,
diff --git a/x-pack/test/api_integration/apis/monitoring/index.js b/x-pack/test/api_integration/apis/monitoring/index.js
index fc68941cfaa78..d9941b0d7ac7f 100644
--- a/x-pack/test/api_integration/apis/monitoring/index.js
+++ b/x-pack/test/api_integration/apis/monitoring/index.js
@@ -6,6 +6,7 @@
export default function ({ loadTestFile }) {
describe('Monitoring', () => {
+ loadTestFile(require.resolve('./apm'));
loadTestFile(require.resolve('./beats'));
loadTestFile(require.resolve('./cluster'));
loadTestFile(require.resolve('./elasticsearch'));
diff --git a/x-pack/test/functional/es_archives/monitoring/apm/data.json.gz b/x-pack/test/functional/es_archives/monitoring/apm/data.json.gz
new file mode 100644
index 0000000000000..6cd971597f162
Binary files /dev/null and b/x-pack/test/functional/es_archives/monitoring/apm/data.json.gz differ
diff --git a/x-pack/test/functional/es_archives/monitoring/apm/mappings.json b/x-pack/test/functional/es_archives/monitoring/apm/mappings.json
new file mode 100644
index 0000000000000..1b3d57dcf2971
--- /dev/null
+++ b/x-pack/test/functional/es_archives/monitoring/apm/mappings.json
@@ -0,0 +1,688 @@
+{
+ "type": "index",
+ "value": {
+ "index": ".monitoring-beats-6-2018.08.31",
+ "settings": {
+ "index": {
+ "codec": "best_compression",
+ "number_of_shards": "1",
+ "auto_expand_replicas": "0-1",
+ "format": "6",
+ "number_of_replicas": "0"
+ }
+ },
+ "mappings": {
+ "doc": {
+ "dynamic": "false",
+ "properties": {
+ "beats_state": {
+ "properties": {
+ "beat": {
+ "properties": {
+ "host": {
+ "type": "keyword"
+ },
+ "name": {
+ "type": "keyword"
+ },
+ "type": {
+ "type": "keyword"
+ },
+ "uuid": {
+ "type": "keyword"
+ },
+ "version": {
+ "type": "keyword"
+ }
+ }
+ },
+ "state": {
+ "properties": {
+ "beat": {
+ "properties": {
+ "name": {
+ "type": "keyword"
+ }
+ }
+ },
+ "host": {
+ "properties": {
+ "architecture": {
+ "type": "keyword"
+ },
+ "name": {
+ "type": "keyword"
+ },
+ "os": {
+ "properties": {
+ "build": {
+ "type": "keyword"
+ },
+ "family": {
+ "type": "keyword"
+ },
+ "platform": {
+ "type": "keyword"
+ },
+ "version": {
+ "type": "keyword"
+ }
+ }
+ }
+ }
+ },
+ "input": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "names": {
+ "type": "keyword"
+ }
+ }
+ },
+ "module": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "names": {
+ "type": "keyword"
+ }
+ }
+ },
+ "output": {
+ "properties": {
+ "name": {
+ "type": "keyword"
+ }
+ }
+ },
+ "service": {
+ "properties": {
+ "id": {
+ "type": "keyword"
+ },
+ "name": {
+ "type": "keyword"
+ },
+ "version": {
+ "type": "keyword"
+ }
+ }
+ }
+ }
+ },
+ "timestamp": {
+ "type": "date",
+ "format": "date_time"
+ }
+ }
+ },
+ "beats_stats": {
+ "properties": {
+ "beat": {
+ "properties": {
+ "host": {
+ "type": "keyword"
+ },
+ "name": {
+ "type": "keyword"
+ },
+ "type": {
+ "type": "keyword"
+ },
+ "uuid": {
+ "type": "keyword"
+ },
+ "version": {
+ "type": "keyword"
+ }
+ }
+ },
+ "metrics": {
+ "properties": {
+ "apm-server": {
+ "properties": {
+ "decoder": {
+ "properties": {
+ "deflate": {
+ "properties": {
+ "content-length": {
+ "type": "long"
+ },
+ "count": {
+ "type": "long"
+ }
+ }
+ },
+ "gzip": {
+ "properties": {
+ "content-length": {
+ "type": "long"
+ },
+ "count": {
+ "type": "long"
+ }
+ }
+ },
+ "missing-content-length": {
+ "properties": {
+ "count": {
+ "type": "long"
+ }
+ }
+ },
+ "reader": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "size": {
+ "type": "long"
+ }
+ }
+ },
+ "uncompressed": {
+ "properties": {
+ "content-length": {
+ "type": "long"
+ },
+ "count": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ },
+ "processor": {
+ "properties": {
+ "error": {
+ "properties": {
+ "decoding": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "errors": {
+ "type": "long"
+ }
+ }
+ },
+ "errors": {
+ "type": "long"
+ },
+ "frames": {
+ "type": "long"
+ },
+ "stacktraces": {
+ "type": "long"
+ },
+ "transformations": {
+ "type": "long"
+ },
+ "validation": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "errors": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ },
+ "metric": {
+ "properties": {
+ "decoding": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "errors": {
+ "type": "long"
+ }
+ }
+ },
+ "transformations": {
+ "type": "long"
+ },
+ "validation": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "errors": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ },
+ "sourcemap": {
+ "properties": {
+ "counter": {
+ "type": "long"
+ },
+ "decoding": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "errors": {
+ "type": "long"
+ }
+ }
+ },
+ "validation": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "errors": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ },
+ "transaction": {
+ "properties": {
+ "decoding": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "errors": {
+ "type": "long"
+ }
+ }
+ },
+ "frames": {
+ "type": "long"
+ },
+ "spans": {
+ "type": "long"
+ },
+ "stacktraces": {
+ "type": "long"
+ },
+ "transactions": {
+ "type": "long"
+ },
+ "transformations": {
+ "type": "long"
+ },
+ "validation": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "errors": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "server": {
+ "properties": {
+ "concurrent": {
+ "properties": {
+ "wait": {
+ "properties": {
+ "ms": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ },
+ "request": {
+ "properties": {
+ "count": {
+ "type": "long"
+ }
+ }
+ },
+ "response": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "errors": {
+ "properties": {
+ "closed": {
+ "type": "long"
+ },
+ "concurrency": {
+ "type": "long"
+ },
+ "count": {
+ "type": "long"
+ },
+ "decode": {
+ "type": "long"
+ },
+ "forbidden": {
+ "type": "long"
+ },
+ "method": {
+ "type": "long"
+ },
+ "queue": {
+ "type": "long"
+ },
+ "ratelimit": {
+ "type": "long"
+ },
+ "toolarge": {
+ "type": "long"
+ },
+ "unauthorized": {
+ "type": "long"
+ },
+ "validate": {
+ "type": "long"
+ }
+ }
+ },
+ "valid": {
+ "properties": {
+ "accepted": {
+ "type": "long"
+ },
+ "count": {
+ "type": "long"
+ },
+ "ok": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "beat": {
+ "properties": {
+ "cpu": {
+ "properties": {
+ "system": {
+ "properties": {
+ "ticks": {
+ "type": "long"
+ },
+ "time": {
+ "properties": {
+ "ms": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ },
+ "total": {
+ "properties": {
+ "ticks": {
+ "type": "long"
+ },
+ "time": {
+ "properties": {
+ "ms": {
+ "type": "long"
+ }
+ }
+ },
+ "value": {
+ "type": "long"
+ }
+ }
+ },
+ "user": {
+ "properties": {
+ "ticks": {
+ "type": "long"
+ },
+ "time": {
+ "properties": {
+ "ms": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "info": {
+ "properties": {
+ "ephemeral_id": {
+ "type": "keyword"
+ },
+ "uptime": {
+ "properties": {
+ "ms": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ },
+ "memstats": {
+ "properties": {
+ "gc_next": {
+ "type": "long"
+ },
+ "memory_alloc": {
+ "type": "long"
+ },
+ "memory_total": {
+ "type": "long"
+ },
+ "rss": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ },
+ "libbeat": {
+ "properties": {
+ "config": {
+ "properties": {
+ "module": {
+ "properties": {
+ "running": {
+ "type": "long"
+ },
+ "starts": {
+ "type": "long"
+ },
+ "stops": {
+ "type": "long"
+ }
+ }
+ },
+ "reloads": {
+ "type": "long"
+ }
+ }
+ },
+ "output": {
+ "properties": {
+ "events": {
+ "properties": {
+ "acked": {
+ "type": "long"
+ },
+ "active": {
+ "type": "long"
+ },
+ "batches": {
+ "type": "long"
+ },
+ "dropped": {
+ "type": "long"
+ },
+ "duplicates": {
+ "type": "long"
+ },
+ "failed": {
+ "type": "long"
+ },
+ "total": {
+ "type": "long"
+ }
+ }
+ },
+ "read": {
+ "properties": {
+ "bytes": {
+ "type": "long"
+ },
+ "errors": {
+ "type": "long"
+ }
+ }
+ },
+ "type": {
+ "type": "keyword"
+ },
+ "write": {
+ "properties": {
+ "bytes": {
+ "type": "long"
+ },
+ "errors": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ },
+ "pipeline": {
+ "properties": {
+ "clients": {
+ "type": "long"
+ },
+ "events": {
+ "properties": {
+ "active": {
+ "type": "long"
+ },
+ "dropped": {
+ "type": "long"
+ },
+ "failed": {
+ "type": "long"
+ },
+ "filtered": {
+ "type": "long"
+ },
+ "published": {
+ "type": "long"
+ },
+ "retry": {
+ "type": "long"
+ },
+ "total": {
+ "type": "long"
+ }
+ }
+ },
+ "queue": {
+ "properties": {
+ "acked": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "system": {
+ "properties": {
+ "load": {
+ "properties": {
+ "1": {
+ "type": "double"
+ },
+ "5": {
+ "type": "double"
+ },
+ "15": {
+ "type": "double"
+ },
+ "norm": {
+ "properties": {
+ "1": {
+ "type": "double"
+ },
+ "5": {
+ "type": "double"
+ },
+ "15": {
+ "type": "double"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "tags": {
+ "type": "keyword"
+ },
+ "timestamp": {
+ "type": "date",
+ "format": "date_time"
+ }
+ }
+ },
+ "cluster_uuid": {
+ "type": "keyword"
+ },
+ "interval_ms": {
+ "type": "long"
+ },
+ "source_node": {
+ "properties": {
+ "host": {
+ "type": "keyword"
+ },
+ "ip": {
+ "type": "keyword"
+ },
+ "name": {
+ "type": "keyword"
+ },
+ "transport_address": {
+ "type": "keyword"
+ },
+ "uuid": {
+ "type": "keyword"
+ }
+ }
+ },
+ "timestamp": {
+ "type": "date",
+ "format": "date_time"
+ },
+ "type": {
+ "type": "keyword"
+ }
+ }
+ }
+ },
+ "aliases": {}
+ }
+}
\ No newline at end of file