Skip to content

Commit

Permalink
[8.15] [Search] Notebooks Telemetry (#188007) (#188055)
Browse files Browse the repository at this point in the history
# Backport

This will backport the following commits from `main` to `8.15`:
- [[Search] Notebooks Telemetry
(#188007)](#188007)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Rodney
Norris","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-07-11T07:40:41Z","message":"[Search]
Notebooks Telemetry (#188007)\n\n## Summary\r\n\r\nAdded telemetry
tracking with usageCollection for opening notebooks\r\nview, viewing a
specific notebook and errors fetching notebooks.\r\n\r\n###
Checklist\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)","sha":"b11e9eeb6d8fd7579d95b2515ab0eb2d64523504","branchLabelMapping":{"^v8.16.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Search","v8.15.0","v8.16.0"],"title":"[Search]
Notebooks
Telemetry","number":188007,"url":"https://github.com/elastic/kibana/pull/188007","mergeCommit":{"message":"[Search]
Notebooks Telemetry (#188007)\n\n## Summary\r\n\r\nAdded telemetry
tracking with usageCollection for opening notebooks\r\nview, viewing a
specific notebook and errors fetching notebooks.\r\n\r\n###
Checklist\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)","sha":"b11e9eeb6d8fd7579d95b2515ab0eb2d64523504"}},"sourceBranch":"main","suggestedTargetBranches":["8.15"],"targetPullRequestStates":[{"branch":"8.15","label":"v8.15.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/188007","number":188007,"mergeCommit":{"message":"[Search]
Notebooks Telemetry (#188007)\n\n## Summary\r\n\r\nAdded telemetry
tracking with usageCollection for opening notebooks\r\nview, viewing a
specific notebook and errors fetching notebooks.\r\n\r\n###
Checklist\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)","sha":"b11e9eeb6d8fd7579d95b2515ab0eb2d64523504"}}]}]
BACKPORT-->

Co-authored-by: Rodney Norris <[email protected]>
  • Loading branch information
kibanamachine and TattdCodeMonkey authored Jul 11, 2024
1 parent dd6a8ff commit 216aa79
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 42 deletions.
4 changes: 3 additions & 1 deletion x-pack/plugins/search_notebooks/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
"requiredPlugins": [
"console"
],
"optionalPlugins": [],
"optionalPlugins": [
"usageCollection"
],
"requiredBundles": [
"kibanaReact"
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,40 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { CoreStart } from '@kbn/core/public';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { KibanaThemeProvider } from '@kbn/react-kibana-context-theme';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

import { SearchNotebooks } from './search_notebooks';
import { NotebookListValue } from '../types';
import { AppMetricsTracker, NotebookListValue } from '../types';

export interface SearchNotebooksViewProps {
core: CoreStart;
queryClient: QueryClient;
usageTracker: AppMetricsTracker;
getNotebookList: () => NotebookListValue;
}

export const SearchNotebooksView = ({
core,
queryClient,
usageTracker,
getNotebookList,
}: SearchNotebooksViewProps) => (
<KibanaThemeProvider theme={core.theme}>
<KibanaContextProvider services={{ ...core, notebooks: { getNotebookList } }}>
<QueryClientProvider client={queryClient}>
<SearchNotebooks />
</QueryClientProvider>
</KibanaContextProvider>
</KibanaThemeProvider>
);
}: SearchNotebooksViewProps) => {
React.useEffect(() => {
usageTracker.count('opened_notebooks_view');
}, [usageTracker]);

return (
<KibanaThemeProvider theme={core.theme}>
<KibanaContextProvider services={{ ...core, notebooks: { getNotebookList }, usageTracker }}>
<QueryClientProvider client={queryClient}>
<SearchNotebooks />
</QueryClientProvider>
</KibanaContextProvider>
</KibanaThemeProvider>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,31 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { EuiPanel, EuiEmptyPrompt, EuiCodeBlock } from '@elastic/eui';
import React, { useEffect } from 'react';
import { EuiPanel } from '@elastic/eui';
import { NotebookRenderer } from '@kbn/ipynb';
import { FormattedMessage } from '@kbn/i18n-react';

import { useNotebook } from '../hooks/use_notebook';
import { useUsageTracker } from '../hooks/use_usage_tracker';
import { LoadingPanel } from './loading_panel';
import { SearchNotebookError } from './search_notebook_error';

export interface SearchNotebookProps {
notebookId: string;
}
export const SearchNotebook = ({ notebookId }: SearchNotebookProps) => {
const usageTracker = useUsageTracker();
const { data, isLoading, error } = useNotebook(notebookId);
useEffect(() => {
usageTracker.count(['view-notebook', `nb-${notebookId}`]);
}, [usageTracker, notebookId]);

if (isLoading) {
return <LoadingPanel />;
}
if (!data || error) {
return (
<EuiEmptyPrompt
iconType="warning"
iconColor="danger"
title={
<h2>
<FormattedMessage
id="xpack.searchNotebooks.notebook.fetchError.title"
defaultMessage="Error loading notebook"
/>
</h2>
}
titleSize="l"
body={
<>
<p>
<FormattedMessage
id="xpack.searchNotebooks.notebook.fetchError.body"
defaultMessage="We can't fetch the notebook from Kibana due to the following error:"
/>
</p>
<EuiCodeBlock css={{ textAlign: 'left' }}>{JSON.stringify(error)}</EuiCodeBlock>
</>
}
/>
<SearchNotebookError notebookId={notebookId} usageTracker={usageTracker} error={error} />
);
}
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { EuiEmptyPrompt, EuiCodeBlock } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import type { AppMetricsTracker } from '../types';
import { getErrorMessage } from '../utils/get_error_message';

export interface SearchNotebookErrorProps {
error: unknown;
notebookId: string;
usageTracker: AppMetricsTracker;
}

export const SearchNotebookError = ({
error,
notebookId,
usageTracker,
}: SearchNotebookErrorProps) => {
React.useEffect(() => {
usageTracker.count(['notebookViewError', `error-${notebookId}`]);
}, [usageTracker, notebookId]);

return (
<EuiEmptyPrompt
iconType="warning"
iconColor="danger"
title={
<h2>
<FormattedMessage
id="xpack.searchNotebooks.notebook.fetchError.title"
defaultMessage="Error loading notebook"
/>
</h2>
}
titleSize="l"
body={
<>
<p>
<FormattedMessage
id="xpack.searchNotebooks.notebook.fetchError.body"
defaultMessage="We can't fetch the notebook from Kibana due to the following error:"
/>
</p>
{error !== undefined && typeof error === 'object' ? (
<EuiCodeBlock css={{ textAlign: 'left' }}>{JSON.stringify(error)}</EuiCodeBlock>
) : (
<p>
{getErrorMessage(
error,
i18n.translate('xpack.searchNotebooks.notebook.fetchError.unknownError', {
defaultMessage: 'Unknown error fetching notebook',
})
)}
</p>
)}
</>
}
/>
);
};
4 changes: 3 additions & 1 deletion x-pack/plugins/search_notebooks/public/console_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
import { dynamic } from '@kbn/shared-ux-utility';
import { QueryClient } from '@tanstack/react-query';

import { NotebookListValue } from './types';
import { NotebookListValue, AppMetricsTracker } from './types';

const SearchNotebooksButton = dynamic(async () => ({
default: (await import('./components/notebooks_button')).SearchNotebooksButton,
Expand All @@ -26,6 +26,7 @@ const SearchNotebooksView = dynamic(async () => ({
export const notebooksConsoleView = (
core: CoreStart,
queryClient: QueryClient,
usageTracker: AppMetricsTracker,
clearNotebookList: () => void,
getNotebookListValue: () => NotebookListValue
): EmbeddedConsoleView => {
Expand All @@ -37,6 +38,7 @@ export const notebooksConsoleView = (
<SearchNotebooksView
core={core}
queryClient={queryClient}
usageTracker={usageTracker}
getNotebookList={getNotebookListValue}
/>
),
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/search_notebooks/public/hooks/use_kibana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import type { ConsolePluginStart } from '@kbn/console-plugin/public';
import type { CoreStart } from '@kbn/core/public';
import { useKibana as useKibanaBase } from '@kbn/kibana-react-plugin/public';

import { NotebookListValue } from '../types';
import { NotebookListValue, AppMetricsTracker } from '../types';

export interface SearchNotebooksContext {
console: ConsolePluginStart;
notebooks: {
getNotebookList: () => NotebookListValue;
};
usageTracker: AppMetricsTracker;
}

type ServerlessSearchKibanaContext = CoreStart & SearchNotebooksContext;
Expand Down
15 changes: 15 additions & 0 deletions x-pack/plugins/search_notebooks/public/hooks/use_usage_tracker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* 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 { useKibanaServices } from './use_kibana';
import { AppMetricsTracker } from '../types';

export const useUsageTracker = (): AppMetricsTracker => {
const { usageTracker } = useKibanaServices();

return usageTracker;
};
5 changes: 5 additions & 0 deletions x-pack/plugins/search_notebooks/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@ import {
SearchNotebooksPluginStart,
SearchNotebooksPluginStartDependencies,
NotebookListValue,
AppMetricsTracker,
} from './types';
import { getErrorCode, getErrorMessage, isKibanaServerError } from './utils/get_error_message';
import { createUsageTracker } from './utils/usage_tracker';

export class SearchNotebooksPlugin
implements Plugin<SearchNotebooksPluginSetup, SearchNotebooksPluginStart>
{
private notebooksList: NotebookListValue = null;
private queryClient: QueryClient | undefined;
private usageTracker: AppMetricsTracker | undefined;

public setup(core: CoreSetup): SearchNotebooksPluginSetup {
this.queryClient = new QueryClient({
Expand Down Expand Up @@ -56,11 +59,13 @@ export class SearchNotebooksPlugin
core: CoreStart,
deps: SearchNotebooksPluginStartDependencies
): SearchNotebooksPluginStart {
this.usageTracker = createUsageTracker(deps.usageCollection);
if (deps.console?.registerEmbeddedConsoleAlternateView) {
deps.console.registerEmbeddedConsoleAlternateView(
notebooksConsoleView(
core,
this.queryClient!,
this.usageTracker,
this.clearNotebookList.bind(this),
this.getNotebookList.bind(this)
)
Expand Down
8 changes: 8 additions & 0 deletions x-pack/plugins/search_notebooks/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import type { ConsolePluginStart } from '@kbn/console-plugin/public';
import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public';

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface SearchNotebooksPluginSetup {}
Expand All @@ -16,6 +17,13 @@ export interface SearchNotebooksPluginStart {

export interface SearchNotebooksPluginStartDependencies {
console: ConsolePluginStart;
usageCollection?: UsageCollectionStart;
}

export type NotebookListValue = string | null;

export interface AppMetricsTracker {
click: (eventName: string | string[]) => void;
count: (eventName: string | string[]) => void;
load: (eventName: string | string[]) => void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import { KibanaServerError } from '@kbn/kibana-utils-plugin/common';

export function getErrorMessage(error: unknown): string {
export function getErrorMessage(error: unknown, defaultMessage?: string): string {
if (typeof error === 'string') {
return error;
}
Expand All @@ -19,7 +19,7 @@ export function getErrorMessage(error: unknown): string {
return (error as { name: string }).name;
}

return '';
return defaultMessage ?? '';
}

export function getErrorCode(error: unknown): number | undefined {
Expand Down
33 changes: 33 additions & 0 deletions x-pack/plugins/search_notebooks/public/utils/usage_tracker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics';
import type {
UsageCollectionSetup,
UsageCollectionStart,
} from '@kbn/usage-collection-plugin/public';
import { AppMetricsTracker } from '../types';

const APP_TRACKER_NAME = 'searchNotebooks';

export function createUsageTracker(
usageCollection?: UsageCollectionSetup | UsageCollectionStart
): AppMetricsTracker {
const track = (type: UiCounterMetricType, name: string | string[]) =>
usageCollection?.reportUiCounter(APP_TRACKER_NAME, type, name);
return {
click: (eventName: string | string[]) => {
track(METRIC_TYPE.CLICK, eventName);
},
count: (eventName: string | string[]) => {
track(METRIC_TYPE.COUNT, eventName);
},
load: (eventName: string | string[]) => {
track(METRIC_TYPE.LOADED, eventName);
},
};
}
2 changes: 2 additions & 0 deletions x-pack/plugins/search_notebooks/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"target/**/*"
],
"kbn_references": [
"@kbn/analytics",
"@kbn/config-schema",
"@kbn/core",
"@kbn/i18n",
Expand All @@ -26,5 +27,6 @@
"@kbn/shared-ux-utility",
"@kbn/kibana-utils-plugin",
"@kbn/ipynb",
"@kbn/usage-collection-plugin",
]
}

0 comments on commit 216aa79

Please sign in to comment.