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] Fix telemetry collection to not send extra requests #73382

Merged
merged 9 commits into from
Aug 3, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,4 @@ describe('Search Usage Collector', () => {
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
Expand Up @@ -72,21 +72,5 @@ export const createUsageCollector = (
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,
}),
});
},
};
};
2 changes: 0 additions & 2 deletions src/plugins/data/public/search/collectors/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,4 @@ export interface SearchUsageCollector {
trackLongQueryPopupShown: () => Promise<void>;
trackLongQueryDialogDismissed: () => Promise<void>;
trackLongQueryRunBeyondTimeout: () => Promise<void>;
trackError: (duration: number) => Promise<void>;
trackSuccess: (duration: number) => Promise<void>;
}
7 changes: 0 additions & 7 deletions src/plugins/data/public/search/search_interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,6 @@ export class SearchInterceptor {
this.pendingCount$.next(++this.pendingCount);

return this.runSearch(request, combinedSignal).pipe(
tap({
next: (e) => {
if (this.deps.usageCollector) {
this.deps.usageCollector.trackSuccess(e.rawResponse.took);
}
},
}),
finalize(() => {
this.pendingCount$.next(--this.pendingCount);
cleanup();
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/data/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ export {
ISearchStart,
getDefaultSearchParams,
getTotalLoaded,
usageProvider,
SearchUsage,
} from './search';

// Search namespace
Expand Down
20 changes: 20 additions & 0 deletions src/plugins/data/server/search/collectors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* 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 { usageProvider, SearchUsage } from './usage';
50 changes: 0 additions & 50 deletions src/plugins/data/server/search/collectors/routes.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/plugins/data/server/search/collectors/usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface SearchUsage {
trackSuccess(duration: number): Promise<void>;
}

export function usageProvider(core: CoreSetup<object, DataPluginStart>): SearchUsage {
export function usageProvider(core: CoreSetup<DataPluginStart>): SearchUsage {
const getTracker = (eventType: keyof Usage) => {
return async (duration: number) => {
const repository = await core
Expand Down
29 changes: 20 additions & 9 deletions src/plugins/data/server/search/es_search/es_search_strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ import { first } from 'rxjs/operators';
import { SharedGlobalConfig, Logger } from 'kibana/server';
import { SearchResponse } from 'elasticsearch';
import { Observable } from 'rxjs';
import { SearchUsage } from '../collectors/usage';
import { ISearchStrategy, getDefaultSearchParams, getTotalLoaded } from '..';

export const esSearchStrategyProvider = (
config$: Observable<SharedGlobalConfig>,
logger: Logger
logger: Logger,
usage?: SearchUsage
): ISearchStrategy => {
return {
search: async (context, request, options) => {
Expand All @@ -43,15 +45,24 @@ export const esSearchStrategyProvider = (
...request.params,
};

const rawResponse = (await context.core.elasticsearch.legacy.client.callAsCurrentUser(
'search',
params,
options
)) as SearchResponse<any>;
const startTime = new Date().getTime();

// The above query will either complete or timeout and throw an error.
// There is no progress indication on this api.
return { rawResponse, ...getTotalLoaded(rawResponse._shards) };
try {
const rawResponse = (await context.core.elasticsearch.legacy.client.callAsCurrentUser(
'search',
params,
options
)) as SearchResponse<any>;

if (usage) usage.trackSuccess(new Date().getTime() - startTime);

// The above query will either complete or timeout and throw an error.
// There is no progress indication on this api.
return { rawResponse, ...getTotalLoaded(rawResponse._shards) };
} catch (e) {
if (usage) usage.trackError(new Date().getTime() - startTime);
throw e;
}
},
};
};
2 changes: 2 additions & 0 deletions src/plugins/data/server/search/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@
export { ISearchStrategy, ISearchOptions, ISearchSetup, ISearchStart } from './types';

export { getDefaultSearchParams, getTotalLoaded } from './es_search';

export { usageProvider, SearchUsage } from './collectors';
12 changes: 7 additions & 5 deletions src/plugins/data/server/search/search_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import { UsageCollectionSetup } from '../../../usage_collection/server';
import { registerUsageCollector } from './collectors/register';
import { usageProvider } from './collectors/usage';
import { searchTelemetry } from '../saved_objects';
import { registerSearchUsageRoute } from './collectors/routes';
import { IEsSearchRequest } from '../../common';

interface StrategyMap {
Expand All @@ -51,20 +50,23 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
core: CoreSetup<object, DataPluginStart>,
{ usageCollection }: { usageCollection?: UsageCollectionSetup }
): ISearchSetup {
const usage = usageCollection ? usageProvider(core) : undefined;

this.registerSearchStrategy(
ES_SEARCH_STRATEGY,
esSearchStrategyProvider(this.initializerContext.config.legacy.globalConfig$, this.logger)
esSearchStrategyProvider(
this.initializerContext.config.legacy.globalConfig$,
this.logger,
usage
)
);

core.savedObjects.registerType(searchTelemetry);
if (usageCollection) {
registerUsageCollector(usageCollection, this.initializerContext);
}

const usage = usageProvider(core);

registerSearchRoute(core);
registerSearchUsageRoute(core, usage);

return { registerSearchStrategy: this.registerSearchStrategy, usage };
}
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/data_enhanced/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"requiredPlugins": [
"data"
],
"optionalPlugins": ["kibanaReact", "kibanaUtils"],
"optionalPlugins": ["kibanaReact", "kibanaUtils", "usageCollection"],
"server": true,
"ui": true,
"requiredBundles": ["kibanaReact", "kibanaUtils"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,6 @@ export class EnhancedSearchInterceptor extends SearchInterceptor {

// If the response indicates it is complete, stop polling and complete the observable
if (!response.is_running) {
if (this.deps.usageCollector && response.rawResponse) {
this.deps.usageCollector.trackSuccess(response.rawResponse.took);
}
return EMPTY;
}

Expand Down
15 changes: 12 additions & 3 deletions x-pack/plugins/data_enhanced/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ import {
Logger,
} from '../../../../src/core/server';
import { ES_SEARCH_STRATEGY } from '../../../../src/plugins/data/common';
import { PluginSetup as DataPluginSetup } from '../../../../src/plugins/data/server';
import {
PluginSetup as DataPluginSetup,
PluginStart as DataPluginStart,
usageProvider,
} from '../../../../src/plugins/data/server';
import { enhancedEsSearchStrategyProvider } from './search';
import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/server';

interface SetupDependencies {
data: DataPluginSetup;
usageCollection?: UsageCollectionSetup;
}

export class EnhancedDataServerPlugin implements Plugin<void, void, SetupDependencies> {
Expand All @@ -26,12 +32,15 @@ export class EnhancedDataServerPlugin implements Plugin<void, void, SetupDepende
this.logger = initializerContext.logger.get('data_enhanced');
}

public setup(core: CoreSetup, deps: SetupDependencies) {
public setup(core: CoreSetup<DataPluginStart>, deps: SetupDependencies) {
const usage = deps.usageCollection ? usageProvider(core) : undefined;

deps.data.search.registerSearchStrategy(
ES_SEARCH_STRATEGY,
enhancedEsSearchStrategyProvider(
this.initializerContext.config.legacy.globalConfig$,
this.logger
this.logger,
usage
)
);
}
Expand Down
21 changes: 17 additions & 4 deletions x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
getDefaultSearchParams,
getTotalLoaded,
ISearchStrategy,
SearchUsage,
} from '../../../../../src/plugins/data/server';
import { IEnhancedEsSearchRequest } from '../../common';
import { shimHitsTotal } from './shim_hits_total';
Expand All @@ -32,7 +33,8 @@ export interface AsyncSearchResponse<T> {

export const enhancedEsSearchStrategyProvider = (
config$: Observable<SharedGlobalConfig>,
logger: Logger
logger: Logger,
usage?: SearchUsage
): ISearchStrategy => {
const search = async (
context: RequestHandlerContext,
Expand All @@ -44,10 +46,21 @@ export const enhancedEsSearchStrategyProvider = (
const caller = context.core.elasticsearch.legacy.client.callAsCurrentUser;
const defaultParams = getDefaultSearchParams(config);
const params = { ...defaultParams, ...request.params };
const startTime = new Date().getTime();

return request.indexType === 'rollup'
? rollupSearch(caller, { ...request, params }, options)
: asyncSearch(caller, { ...request, params }, options);
try {
const response =
request.indexType === 'rollup'
? await rollupSearch(caller, { ...request, params }, options)
: await asyncSearch(caller, { ...request, params }, options);

if (usage) usage.trackSuccess(new Date().getTime() - startTime);

return response;
} catch (e) {
if (usage) usage.trackError(new Date().getTime() - startTime);
throw e;
}
};

const cancel = async (context: RequestHandlerContext, id: string) => {
Expand Down