From b4db26683ac3675c25d1d33d16c73214defea6c9 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 26 Apr 2021 09:27:59 -0400 Subject: [PATCH] [Lens] Embeddable error telemetry (#98042) (#98276) Co-authored-by: Joe Reuter --- x-pack/plugins/lens/kibana.json | 3 +- .../embeddable/embeddable.tsx | 19 ++++++++++- .../embeddable/embeddable_factory.ts | 4 +++ .../embeddable/expression_wrapper.tsx | 33 +++++++++++-------- .../public/editor_frame_service/service.tsx | 3 ++ x-pack/plugins/lens/public/plugin.ts | 4 +++ 6 files changed, 50 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/lens/kibana.json b/x-pack/plugins/lens/kibana.json index a5c19911f60b9..bfcc20cc88b81 100644 --- a/x-pack/plugins/lens/kibana.json +++ b/x-pack/plugins/lens/kibana.json @@ -35,6 +35,7 @@ "savedObjects", "kibanaUtils", "kibanaReact", - "embeddable" + "embeddable", + "usageCollection" ] } diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx index a3316e0083d35..214ce6d11cff2 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx @@ -24,6 +24,8 @@ import { toExpression, Ast } from '@kbn/interpreter/common'; import { DefaultInspectorAdapters, RenderMode } from 'src/plugins/expressions'; import { map, distinctUntilChanged, skip } from 'rxjs/operators'; import isEqual from 'fast-deep-equal'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; +import { METRIC_TYPE } from '../../../../../../src/plugins/usage_collection/public'; import { ExpressionRendererEvent, ReactExpressionRendererType, @@ -51,7 +53,7 @@ import { } from '../../types'; import { IndexPatternsContract } from '../../../../../../src/plugins/data/public'; -import { getEditPath, DOC_TYPE } from '../../../common'; +import { getEditPath, DOC_TYPE, PLUGIN_ID } from '../../../common'; import { IBasePath } from '../../../../../../src/core/public'; import { LensAttributeService } from '../../lens_attribute_service'; import type { ErrorMessage } from '../types'; @@ -95,6 +97,7 @@ export interface LensEmbeddableDeps { getTrigger?: UiActionsStart['getTrigger'] | undefined; getTriggerCompatibleActions?: UiActionsStart['getTriggerCompatibleActions']; capabilities: { canSaveVisualizations: boolean; canSaveDashboards: boolean }; + usageCollection?: UsageCollectionSetup; } export class Embeddable @@ -113,6 +116,14 @@ export class Embeddable private inputReloadSubscriptions: Subscription[]; private isDestroyed?: boolean; + private logError(type: 'runtime' | 'validation') { + this.deps.usageCollection?.reportUiCounter( + PLUGIN_ID, + METRIC_TYPE.COUNT, + type === 'runtime' ? 'embeddable_runtime_error' : 'embeddable_validation_error' + ); + } + private externalSearchContext: { timeRange?: TimeRange; query?: Query; @@ -255,6 +266,9 @@ export class Embeddable const { ast, errors } = await this.deps.documentToExpression(this.savedVis); this.errors = errors; this.expression = ast ? toExpression(ast) : null; + if (errors) { + this.logError('validation'); + } await this.initializeOutput(); this.isInitialized = true; } @@ -326,6 +340,9 @@ export class Embeddable className={input.className} style={input.style} canEdit={this.getIsEditable() && input.viewMode === 'edit'} + onRuntimeError={() => { + this.logError('runtime'); + }} />, domNode ); diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts index 1a4962bd1fe8e..095e18e3fb5eb 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { RecursiveReadonly } from '@kbn/utility-types'; import { Ast } from '@kbn/interpreter/target/common'; import { EmbeddableStateWithType } from 'src/plugins/embeddable/common'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; import { IndexPatternsContract, TimefilterContract, @@ -34,6 +35,7 @@ export interface LensEmbeddableStartServices { expressionRenderer: ReactExpressionRendererType; indexPatternService: IndexPatternsContract; uiActions?: UiActionsStart; + usageCollection?: UsageCollectionSetup; documentToExpression: ( doc: Document ) => Promise<{ ast: Ast | null; errors: ErrorMessage[] | undefined }>; @@ -87,6 +89,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition { attributeService, indexPatternService, capabilities, + usageCollection, } = await this.getStartServices(); const { Embeddable } = await import('../../async_services'); @@ -105,6 +108,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition { canSaveDashboards: Boolean(capabilities.dashboard?.showWriteControls), canSaveVisualizations: Boolean(capabilities.visualize.save), }, + usageCollection, }, input, parent diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx index f4d0c85ecbbce..15d168465ec71 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx @@ -38,6 +38,7 @@ export interface ExpressionWrapperProps { style?: React.CSSProperties; className?: string; canEdit: boolean; + onRuntimeError: () => void; } interface VisualizationErrorProps { @@ -106,6 +107,7 @@ export function ExpressionWrapper({ className, errors, canEdit, + onRuntimeError, }: ExpressionWrapperProps) { return ( @@ -123,20 +125,23 @@ export function ExpressionWrapper({ onData$={onData$} renderMode={renderMode} syncColors={syncColors} - renderError={(errorMessage, error) => ( -
- - - - - - {(getOriginalRequestErrorMessages(error) || [errorMessage]).map((message) => ( - {message} - ))} - - -
- )} + renderError={(errorMessage, error) => { + onRuntimeError(); + return ( +
+ + + + + + {(getOriginalRequestErrorMessages(error) || [errorMessage]).map((message) => ( + {message} + ))} + + +
+ ); + }} onEvent={handleEvent} hasCompatibleActions={hasCompatibleActions} /> diff --git a/x-pack/plugins/lens/public/editor_frame_service/service.tsx b/x-pack/plugins/lens/public/editor_frame_service/service.tsx index 8769aceca3bfd..849baa93652cc 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/service.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/service.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { I18nProvider } from '@kbn/i18n/react'; import { CoreSetup, CoreStart } from 'kibana/public'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; import { ExpressionsSetup, ExpressionsStart } from '../../../../../src/plugins/expressions/public'; import { EmbeddableSetup, EmbeddableStart } from '../../../../../src/plugins/embeddable/public'; import { @@ -35,6 +36,7 @@ export interface EditorFrameSetupPlugins { embeddable?: EmbeddableSetup; expressions: ExpressionsSetup; charts: ChartsPluginSetup; + usageCollection?: UsageCollectionSetup; } export interface EditorFrameStartPlugins { @@ -101,6 +103,7 @@ export class EditorFrameService { documentToExpression: this.documentToExpression, indexPatternService: deps.data.indexPatterns, uiActions: deps.uiActions, + usageCollection: plugins.usageCollection, }; }; diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts index 81937f3f41557..99e7199c2d802 100644 --- a/x-pack/plugins/lens/public/plugin.ts +++ b/x-pack/plugins/lens/public/plugin.ts @@ -6,6 +6,7 @@ */ import { AppMountParameters, CoreSetup, CoreStart } from 'kibana/public'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../../src/plugins/data/public'; import { EmbeddableSetup, EmbeddableStart } from '../../../../src/plugins/embeddable/public'; import { DashboardStart } from '../../../../src/plugins/dashboard/public'; @@ -62,6 +63,7 @@ export interface LensPluginSetupDependencies { visualizations: VisualizationsSetup; charts: ChartsPluginSetup; globalSearch?: GlobalSearchPluginSetup; + usageCollection?: UsageCollectionSetup; } export interface LensPluginStartDependencies { @@ -139,6 +141,7 @@ export class LensPlugin { visualizations, charts, globalSearch, + usageCollection, }: LensPluginSetupDependencies ) { this.attributeService = async () => { @@ -153,6 +156,7 @@ export class LensPlugin { embeddable, charts, expressions, + usageCollection, }, this.attributeService );