diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index c38bfb2cc86f0..68c63f1da52dd 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -28,7 +28,7 @@ import { DropIllustration } from '@kbn/chart-icons'; import { useDragDropContext, DragDropIdentifier, Droppable } from '@kbn/dom-drag-drop'; import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; import { ChartSizeSpec, isChartSizeEvent } from '@kbn/chart-expressions-common'; -import { estypes } from '@elastic/elasticsearch'; +import { getSuccessfulRequestTimings } from '../../../report_performance_metric_util'; import { trackUiCounterEvents } from '../../../lens_ui_telemetry'; import { getSearchWarningMessages } from '../../../utils'; import { @@ -205,8 +205,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ eventName: 'lensVisualizationRenderTime', duration: currentTime - visualizationRenderStartTime.current, key1: 'time_to_data', - value1: - dataReceivedTime.current - visualizationRenderStartTime.current - esTookTime.current, + value1: dataReceivedTime.current - visualizationRenderStartTime.current, key2: 'time_to_render', value2: currentTime - dataReceivedTime.current, key3: 'es_took', @@ -268,13 +267,9 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ searchService: plugins.data.search, } ); - esTookTime.current = adapters.requests.getRequests().reduce((maxTime, { response }) => { - const took = - (response?.json as { rawResponse: estypes.SearchResponse | undefined } | undefined) - ?.rawResponse?.took ?? 0; - return Math.max(maxTime, took); - }, 0); + const timings = getSuccessfulRequestTimings(adapters); + esTookTime.current = timings ? timings.esTookTotal : 0; } if (requestWarnings.length) { diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index 6c758abb81cff..51bcbb4fed635 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -12,6 +12,7 @@ import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { render, unmountComponentAtNode } from 'react-dom'; import { ENABLE_ESQL } from '@kbn/esql-utils'; +import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; import { DataViewBase, EsQueryConfig, @@ -86,6 +87,7 @@ import { DataViewSpec } from '@kbn/data-views-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; import { useEuiFontSize, useEuiTheme, EuiEmptyPrompt } from '@elastic/eui'; import { canTrackContentfulRender } from '@kbn/presentation-containers'; +import { getSuccessfulRequestTimings } from '../report_performance_metric_util'; import { getExecutionContextEvents, trackUiCounterEvents } from '../lens_ui_telemetry'; import { Document } from '../persistence'; import { ExpressionWrapper, ExpressionWrapperProps } from './expression_wrapper'; @@ -1076,6 +1078,18 @@ export class Embeddable ...this.getOutput(), rendered: true, }); + + const inspectorAdapters = this.getInspectorAdapters(); + const timings = getSuccessfulRequestTimings(inspectorAdapters); + if (timings) { + const esRequestMetrics = { + eventName: 'lens_chart_es_request_totals', + duration: timings.requestTimeTotal, + key1: 'es_took_total', + value1: timings.esTookTotal, + }; + reportPerformanceMetricEvent(this.deps.coreStart.analytics, esRequestMetrics); + } }; getExecutionContext() { diff --git a/x-pack/plugins/lens/public/report_performance_metric_util.ts b/x-pack/plugins/lens/public/report_performance_metric_util.ts new file mode 100644 index 0000000000000..64465e8d20a18 --- /dev/null +++ b/x-pack/plugins/lens/public/report_performance_metric_util.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RequestStatus } from '@kbn/inspector-plugin/common'; +import type { Adapters } from '@kbn/inspector-plugin/public'; +import { estypes } from '@elastic/elasticsearch'; + +export interface ILensRequestPerformance { + requestTimeTotal: number; + esTookTotal: number; +} + +export function getSuccessfulRequestTimings( + inspectorAdapters: Adapters +): ILensRequestPerformance | null { + const requests = inspectorAdapters.requests?.getRequests() || []; + + let esTookTotal = 0; + let requestTimeTotal = 0; + for (let i = 0; i < requests.length; i++) { + const request = requests[i]; + if (request.status !== RequestStatus.OK) { + return null; + } + esTookTotal += + (request.response?.json as { rawResponse: estypes.SearchResponse | undefined } | undefined) + ?.rawResponse?.took ?? 0; + requestTimeTotal += request.time || 0; + } + + return { requestTimeTotal, esTookTotal }; +}