Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Search] Add telemetry for data plugin search service #70677

Merged
merged 45 commits into from
Jul 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
d964c84
[search] Refactor the way search strategies are registered/retrieved …
lukasolson Jun 5, 2020
1452ed5
Fix types and tests and update docs
lukasolson Jun 9, 2020
c7d6b61
Fix failing test
lukasolson Jun 9, 2020
955bd88
Fix build of example plugin
lukasolson Jun 10, 2020
93b41fe
Merge branch 'master' into refactorServerGetStrategy
lukasolson Jun 10, 2020
b0be2df
Fix functional test
lukasolson Jun 10, 2020
e09429a
Merge branch 'master' of github.com:elastic/kibana into pr/68452
Jun 16, 2020
4eb9dd1
Merge branch 'master' of github.com:elastic/kibana into pr/68452
Jun 16, 2020
b536e74
Make server strategies sync
Jun 16, 2020
1c79c1f
Merge branch 'master' of github.com:elastic/kibana into search/server…
Jun 16, 2020
97c456e
Move strategy name into options
Jun 16, 2020
239e3a5
docs
Jun 17, 2020
cd21c29
Merge branch 'master' of github.com:elastic/kibana into search/server…
Jun 18, 2020
b918556
Remove FE strategies
Jun 18, 2020
dbb943a
Merge branch 'master' into search/server-side-search-strategy
elasticmachine Jun 25, 2020
823e56a
Merge branch 'master' of github.com:elastic/kibana into search/server…
Jun 28, 2020
ddd0d0e
TypeScript of hell
Jun 28, 2020
aa5958d
Merge branch 'search/server-side-search-strategy' of github.com:lizoz…
Jun 28, 2020
a708610
Fix search interceptor OSS tests
Jun 29, 2020
0b97b0e
typos
Jun 30, 2020
8897f99
test cleanup
Jun 30, 2020
14c4be2
Update search interceptor tests and abort utils
lukasolson Jun 30, 2020
c65cdaf
[Search] Add telemetry for data plugin search service
lukasolson Jul 2, 2020
cee8880
Merge branch 'master' into search/telemetry
lukasolson Jul 7, 2020
67b24b8
Merge branch 'master' into search/telemetry
lukasolson Jul 8, 2020
ed7cec7
Add tracking of average query time
lukasolson Jul 9, 2020
2469afd
Merge branch 'master' into search/telemetry
lukasolson Jul 9, 2020
67fa8a2
Merge branch 'master' into search/telemetry
lukasolson Jul 9, 2020
3396903
Add tests and rename to collectors
lukasolson Jul 10, 2020
1ade6fd
Merge branch 'master' of github.com:elastic/kibana into pr/70677
Jul 13, 2020
6d689d3
Fix TS
Jul 13, 2020
d0d0b59
Fixed interceptor jest tests
Jul 13, 2020
643a261
Add to kibana json
Jul 13, 2020
dab0f4f
docs
Jul 13, 2020
62881e6
Merge branch 'master' into search/telemetry
lukasolson Jul 13, 2020
9d879f5
Merge branch 'search/telemetry' of github.com:lukasolson/kibana into …
lukasolson Jul 13, 2020
e64e807
Properly use observables rather than only during setup
lukasolson Jul 14, 2020
642614a
Update or create
lukasolson Jul 14, 2020
9381b35
Swallow version conflict errors
lukasolson Jul 14, 2020
a734ae2
Merge branch 'master' of github.com:elastic/kibana into pr/70677
Jul 14, 2020
b5c1262
Merge branch 'master' into search/telemetry
lukasolson Jul 14, 2020
d53c86f
Merge branch 'master' into search/telemetry
lukasolson Jul 15, 2020
b874ddc
Merge branch 'master' into search/telemetry
lukasolson Jul 15, 2020
c6cd551
Merge branch 'master' into search/telemetry
lukasolson Jul 15, 2020
5dc7b16
Merge branch 'master' into search/telemetry
lukasolson Jul 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
<b>Signature:</b>

```typescript
setup(core: CoreSetup, { expressions, uiActions }: DataSetupDependencies): DataPublicPluginSetup;
setup(core: CoreSetup, { expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| core | <code>CoreSetup</code> | |
| { expressions, uiActions } | <code>DataSetupDependencies</code> | |
| { expressions, uiActions, usageCollection } | <code>DataSetupDependencies</code> | |

<b>Returns:</b>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ export interface SearchInterceptorDeps
| [http](./kibana-plugin-plugins-data-public.searchinterceptordeps.http.md) | <code>CoreStart['http']</code> | |
| [toasts](./kibana-plugin-plugins-data-public.searchinterceptordeps.toasts.md) | <code>ToastsStart</code> | |
| [uiSettings](./kibana-plugin-plugins-data-public.searchinterceptordeps.uisettings.md) | <code>CoreStart['uiSettings']</code> | |
| [usageCollector](./kibana-plugin-plugins-data-public.searchinterceptordeps.usagecollector.md) | <code>SearchUsageCollector</code> | |

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [SearchInterceptorDeps](./kibana-plugin-plugins-data-public.searchinterceptordeps.md) &gt; [usageCollector](./kibana-plugin-plugins-data-public.searchinterceptordeps.usagecollector.md)

## SearchInterceptorDeps.usageCollector property

<b>Signature:</b>

```typescript
usageCollector?: SearchUsageCollector;
```
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ export interface ISearchSetup

| Property | Type | Description |
| --- | --- | --- |
| [registerSearchStrategy](./kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md) | <code>(name: string, strategy: ISearchStrategy) =&gt; void</code> | Extension point exposed for other plugins to register their own search strategies. |
| [registerSearchStrategy](./kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md) | <code>TRegisterSearchStrategy</code> | Extension point exposed for other plugins to register their own search strategies. |
| [usage](./kibana-plugin-plugins-data-server.isearchsetup.usage.md) | <code>SearchUsage</code> | Used internally for telemetry |

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) &gt; [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) &gt; [usage](./kibana-plugin-plugins-data-server.isearchsetup.usage.md)

## ISearchSetup.usage property

Used internally for telemetry

<b>Signature:</b>

```typescript
usage: SearchUsage;
```
1 change: 1 addition & 0 deletions src/plugins/data/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"optionalPlugins": ["usageCollection"],
"extraPublicDirs": ["common", "common/utils/abort_utils"],
"requiredBundles": [
"usageCollection",
"kibanaUtils",
"kibanaReact",
"kibanaLegacy",
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/data/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export class DataPublicPlugin implements Plugin<DataPublicPluginSetup, DataPubli

public setup(
core: CoreSetup,
{ expressions, uiActions }: DataSetupDependencies
{ expressions, uiActions, usageCollection }: DataSetupDependencies
): DataPublicPluginSetup {
const startServices = createStartServicesGetter(core.getStartServices);

Expand Down Expand Up @@ -152,6 +152,7 @@ export class DataPublicPlugin implements Plugin<DataPublicPluginSetup, DataPubli
autocomplete: this.autocomplete.setup(core),
search: this.searchService.setup(core, {
expressions,
usageCollection,
getInternalStartServices,
packageInfo: this.packageInfo,
}),
Expand Down
14 changes: 10 additions & 4 deletions src/plugins/data/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ import { KibanaConfigType } from 'src/core/server/kibana_config';
import { Location } from 'history';
import { LocationDescriptorObject } from 'history';
import { MaybePromise } from '@kbn/utility-types';
import { METRIC_TYPE } from '@kbn/analytics';
import { MGetParams } from 'elasticsearch';
import { MGetResponse } from 'elasticsearch';
import { Moment } from 'moment';
Expand Down Expand Up @@ -145,6 +146,7 @@ import { RecursiveReadonly } from '@kbn/utility-types';
import { ReindexParams } from 'elasticsearch';
import { ReindexRethrottleParams } from 'elasticsearch';
import { RenderSearchTemplateParams } from 'elasticsearch';
import { Reporter } from '@kbn/analytics';
import { RequestAdapter } from 'src/plugins/inspector/common';
import { RequestStatistics as RequestStatistics_2 } from 'src/plugins/inspector/common';
import { Required } from '@kbn/utility-types';
Expand Down Expand Up @@ -1450,7 +1452,7 @@ export class Plugin implements Plugin_2<DataPublicPluginSetup, DataPublicPluginS
// Warning: (ae-forgotten-export) The symbol "DataSetupDependencies" needs to be exported by the entry point index.d.ts
//
// (undocumented)
setup(core: CoreSetup, { expressions, uiActions }: DataSetupDependencies): DataPublicPluginSetup;
setup(core: CoreSetup, { expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup;
// Warning: (ae-forgotten-export) The symbol "DataStartDependencies" needs to be exported by the entry point index.d.ts
//
// (undocumented)
Expand Down Expand Up @@ -1778,6 +1780,10 @@ export interface SearchInterceptorDeps {
toasts: ToastsStart;
// (undocumented)
uiSettings: CoreStart['uiSettings'];
// Warning: (ae-forgotten-export) The symbol "SearchUsageCollector" needs to be exported by the entry point index.d.ts
//
// (undocumented)
usageCollector?: SearchUsageCollector;
}

// Warning: (ae-missing-release-tag) "SearchRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
Expand Down Expand Up @@ -2003,9 +2009,9 @@ export const UI_SETTINGS: {
// src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:396:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:41:60 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:53:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:61:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:54:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:55:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:63:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { CoreSetup, CoreStart } from '../../../../../core/public';
import { coreMock } from '../../../../../core/public/mocks';
import { usageCollectionPluginMock, Setup } from '../../../../usage_collection/public/mocks';
import { createUsageCollector } from './create_usage_collector';
import { SEARCH_EVENT_TYPE, SearchUsageCollector } from './types';
import { METRIC_TYPE } from '@kbn/analytics';
import { from } from 'rxjs';

describe('Search Usage Collector', () => {
let mockCoreSetup: MockedKeys<CoreSetup>;
let mockUsageCollectionSetup: Setup;
let usageCollector: SearchUsageCollector;

beforeEach(() => {
mockCoreSetup = coreMock.createSetup();
(mockCoreSetup as any).getStartServices.mockResolvedValue([
{
application: {
currentAppId$: from(['foo/bar']),
},
} as jest.Mocked<CoreStart>,
{} as any,
{} as any,
]);
mockUsageCollectionSetup = usageCollectionPluginMock.createSetupContract();
usageCollector = createUsageCollector(mockCoreSetup, mockUsageCollectionSetup);
});

test('tracks query timeouts', async () => {
await usageCollector.trackQueryTimedOut();
expect(mockUsageCollectionSetup.reportUiStats).toHaveBeenCalled();
expect(mockUsageCollectionSetup.reportUiStats.mock.calls[0][0]).toBe('foo/bar');
expect(mockUsageCollectionSetup.reportUiStats.mock.calls[0][1]).toBe(METRIC_TYPE.LOADED);
expect(mockUsageCollectionSetup.reportUiStats.mock.calls[0][2]).toBe(
SEARCH_EVENT_TYPE.QUERY_TIMED_OUT
);
});

test('tracks query cancellation', async () => {
await usageCollector.trackQueriesCancelled();
expect(mockUsageCollectionSetup.reportUiStats).toHaveBeenCalled();
expect(mockUsageCollectionSetup.reportUiStats.mock.calls[0][1]).toBe(METRIC_TYPE.LOADED);
expect(mockUsageCollectionSetup.reportUiStats.mock.calls[0][2]).toBe(
SEARCH_EVENT_TYPE.QUERIES_CANCELLED
);
});

test('tracks long popups', async () => {
await usageCollector.trackLongQueryPopupShown();
expect(mockUsageCollectionSetup.reportUiStats).toHaveBeenCalled();
expect(mockUsageCollectionSetup.reportUiStats.mock.calls[0][1]).toBe(METRIC_TYPE.LOADED);
expect(mockUsageCollectionSetup.reportUiStats.mock.calls[0][2]).toBe(
SEARCH_EVENT_TYPE.LONG_QUERY_POPUP_SHOWN
);
});

test('tracks long popups dismissed', async () => {
await usageCollector.trackLongQueryDialogDismissed();
expect(mockUsageCollectionSetup.reportUiStats).toHaveBeenCalled();
expect(mockUsageCollectionSetup.reportUiStats.mock.calls[0][1]).toBe(METRIC_TYPE.CLICK);
expect(mockUsageCollectionSetup.reportUiStats.mock.calls[0][2]).toBe(
SEARCH_EVENT_TYPE.LONG_QUERY_DIALOG_DISMISSED
);
});

test('tracks run query beyond timeout', async () => {
await usageCollector.trackLongQueryRunBeyondTimeout();
expect(mockUsageCollectionSetup.reportUiStats).toHaveBeenCalled();
expect(mockUsageCollectionSetup.reportUiStats.mock.calls[0][1]).toBe(METRIC_TYPE.CLICK);
expect(mockUsageCollectionSetup.reportUiStats.mock.calls[0][2]).toBe(
SEARCH_EVENT_TYPE.LONG_QUERY_RUN_BEYOND_TIMEOUT
);
});

test('tracks response errors', async () => {
const duration = 10;
await usageCollector.trackError(duration);
expect(mockCoreSetup.http.post).toBeCalled();
expect(mockCoreSetup.http.post.mock.calls[0][0]).toBe('/api/search/usage');
});

test('tracks response duration', async () => {
const duration = 5;
await usageCollector.trackSuccess(duration);
expect(mockCoreSetup.http.post).toBeCalled();
expect(mockCoreSetup.http.post.mock.calls[0][0]).toBe('/api/search/usage');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { first } from 'rxjs/operators';
import { CoreSetup } from '../../../../../core/public';
import { METRIC_TYPE, UsageCollectionSetup } from '../../../../usage_collection/public';
import { SEARCH_EVENT_TYPE, SearchUsageCollector } from './types';

export const createUsageCollector = (
core: CoreSetup,
usageCollection?: UsageCollectionSetup
): SearchUsageCollector => {
const getCurrentApp = async () => {
const [{ application }] = await core.getStartServices();
return application.currentAppId$.pipe(first()).toPromise();
};

return {
trackQueryTimedOut: async () => {
const currentApp = await getCurrentApp();
return usageCollection?.reportUiStats(
currentApp!,
METRIC_TYPE.LOADED,
SEARCH_EVENT_TYPE.QUERY_TIMED_OUT
);
},
trackQueriesCancelled: async () => {
const currentApp = await getCurrentApp();
return usageCollection?.reportUiStats(
currentApp!,
METRIC_TYPE.LOADED,
SEARCH_EVENT_TYPE.QUERIES_CANCELLED
);
},
trackLongQueryPopupShown: async () => {
const currentApp = await getCurrentApp();
return usageCollection?.reportUiStats(
currentApp!,
METRIC_TYPE.LOADED,
SEARCH_EVENT_TYPE.LONG_QUERY_POPUP_SHOWN
);
},
trackLongQueryDialogDismissed: async () => {
const currentApp = await getCurrentApp();
return usageCollection?.reportUiStats(
currentApp!,
METRIC_TYPE.CLICK,
SEARCH_EVENT_TYPE.LONG_QUERY_DIALOG_DISMISSED
);
},
trackLongQueryRunBeyondTimeout: async () => {
const currentApp = await getCurrentApp();
return usageCollection?.reportUiStats(
currentApp!,
METRIC_TYPE.CLICK,
SEARCH_EVENT_TYPE.LONG_QUERY_RUN_BEYOND_TIMEOUT
);
},
trackError: async (duration: number) => {
return core.http.post('/api/search/usage', {
body: JSON.stringify({
eventType: 'error',
duration,
}),
});
},
trackSuccess: async (duration: number) => {
return core.http.post('/api/search/usage', {
body: JSON.stringify({
eventType: 'success',
duration,
}),
});
},
};
};
21 changes: 21 additions & 0 deletions src/plugins/data/public/search/collectors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export { createUsageCollector } from './create_usage_collector';
export { SEARCH_EVENT_TYPE, SearchUsageCollector } from './types';
36 changes: 36 additions & 0 deletions src/plugins/data/public/search/collectors/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export enum SEARCH_EVENT_TYPE {
QUERY_TIMED_OUT = 'queryTimedOut',
QUERIES_CANCELLED = 'queriesCancelled',
LONG_QUERY_POPUP_SHOWN = 'longQueryPopupShown',
LONG_QUERY_DIALOG_DISMISSED = 'longQueryDialogDismissed',
LONG_QUERY_RUN_BEYOND_TIMEOUT = 'longQueryRunBeyondTimeout',
}

export interface SearchUsageCollector {
trackQueryTimedOut: () => Promise<void>;
trackQueriesCancelled: () => Promise<void>;
trackLongQueryPopupShown: () => Promise<void>;
trackLongQueryDialogDismissed: () => Promise<void>;
trackLongQueryRunBeyondTimeout: () => Promise<void>;
trackError: (duration: number) => Promise<void>;
trackSuccess: (duration: number) => Promise<void>;
}
Loading