Skip to content

Commit

Permalink
Fixes search usage telemetry (#1427)
Browse files Browse the repository at this point in the history
* fix search usage telemetry

Signed-off-by: Tao liu <liutaoaz@amazon.com>

* add unit tests and fixes comments

Signed-off-by: Tao liu <liutaoaz@amazon.com>

* add newline at the end of usage.test.ts

Signed-off-by: Tao liu <liutaoaz@amazon.com>

* add docker var change

Signed-off-by: Tao liu <liutaoaz@amazon.com>

* update check configuration

Signed-off-by: Tao liu <liutaoaz@amazon.com>
  • Loading branch information
Flyingliuhub authored Apr 7, 2022
1 parent 4478b90 commit f0ea74e
Showing 6 changed files with 92 additions and 33 deletions.
6 changes: 5 additions & 1 deletion config/opensearch_dashboards.yml
Original file line number Diff line number Diff line change
@@ -164,4 +164,8 @@

# Set the value of this setting to true to capture region blocked warnings and errors
# for your map rendering services.
# map.showRegionBlockedWarning: false
# map.showRegionBlockedWarning: false

# Set the value of this setting to false to suppress search usage telemetry
# for reducing the load of OpenSearch cluster.
# data.search.usageTelemetry.enabled: false
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ opensearch_dashboards_vars=(
csp.rules
csp.strict
csp.warnLegacyBrowsers
data.search.usageTelemetry.enabled
opensearch.customHeaders
opensearch.hosts
opensearch.logQueries
3 changes: 3 additions & 0 deletions src/plugins/data/config.ts
Original file line number Diff line number Diff line change
@@ -48,6 +48,9 @@ export const configSchema = schema.object({
enabled: schema.boolean({ defaultValue: false }),
}),
}),
usageTelemetry: schema.object({
enabled: schema.boolean({ defaultValue: false }),
}),
}),
});

40 changes: 40 additions & 0 deletions src/plugins/data/server/search/collectors/usage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Any modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

import { coreMock } from '../../../../../core/server/mocks';
import { CoreSetup } from '../../../../../core/server';
import { first } from 'rxjs/operators';
import { usageProvider } from '..';
import { ConfigSchema } from '../../../config';

describe('Search usage telemetry', () => {
let mockCoreSetup: MockedKeys<CoreSetup>;
const initializerContext = coreMock.createPluginInitializerContext({
search: { usageTelemetry: { enabled: false } },
});

it('trackSuccess should not throw with disabled usageTelemetry', async () => {
const configObject = await initializerContext.config
.create<ConfigSchema>()
.pipe(first())
.toPromise();
expect(configObject.search.usageTelemetry.enabled).toBe(false);

const searchUsage = usageProvider(mockCoreSetup, initializerContext);
expect(searchUsage.trackSuccess(1)).resolves.not.toThrow();
});

it('trackError should not throw with disabled usageTelemetry', () => {
const searchUsage = usageProvider(mockCoreSetup, initializerContext);
expect(searchUsage.trackError.name).toBe('trackError');
expect(searchUsage.trackError()).resolves.not.toThrow();
});
});
73 changes: 42 additions & 31 deletions src/plugins/data/server/search/collectors/usage.ts
Original file line number Diff line number Diff line change
@@ -28,8 +28,10 @@
* under the License.
*/

import { CoreSetup } from 'opensearch-dashboards/server';
import { CoreSetup, PluginInitializerContext } from 'opensearch-dashboards/server';
import { first } from 'rxjs/operators';
import { Usage } from './register';
import { ConfigSchema } from '../../../config';

const SAVED_OBJECT_ID = 'search-telemetry';

@@ -38,44 +40,53 @@ export interface SearchUsage {
trackSuccess(duration: number): Promise<void>;
}

export function usageProvider(core: CoreSetup): SearchUsage {
export function usageProvider(
core: CoreSetup,
initializerContext: PluginInitializerContext<ConfigSchema>
): SearchUsage {
const getTracker = (eventType: keyof Usage) => {
return async (duration?: number) => {
const repository = await core
.getStartServices()
.then(([coreStart]) => coreStart.savedObjects.createInternalRepository());
const config = await initializerContext.config
.create<ConfigSchema>()
.pipe(first())
.toPromise();
if (config?.search?.usageTelemetry?.enabled) {
const repository = await core
.getStartServices()
.then(([coreStart]) => coreStart.savedObjects.createInternalRepository());

let attributes: Usage;
let doesSavedObjectExist: boolean = true;
let attributes: Usage;
let doesSavedObjectExist: boolean = true;

try {
const response = await repository.get<Usage>(SAVED_OBJECT_ID, SAVED_OBJECT_ID);
attributes = response.attributes;
} catch (e) {
doesSavedObjectExist = false;
attributes = {
successCount: 0,
errorCount: 0,
averageDuration: 0,
};
}
try {
const response = await repository.get<Usage>(SAVED_OBJECT_ID, SAVED_OBJECT_ID);
attributes = response.attributes;
} catch (e) {
doesSavedObjectExist = false;
attributes = {
successCount: 0,
errorCount: 0,
averageDuration: 0,
};
}

attributes[eventType]++;
attributes[eventType]++;

// Only track the average duration for successful requests
if (eventType === 'successCount') {
attributes.averageDuration =
((duration ?? 0) + (attributes.averageDuration ?? 0)) / (attributes.successCount ?? 1);
}
// Only track the average duration for successful requests
if (eventType === 'successCount') {
attributes.averageDuration =
((duration ?? 0) + (attributes.averageDuration ?? 0)) / (attributes.successCount ?? 1);
}

try {
if (doesSavedObjectExist) {
await repository.update(SAVED_OBJECT_ID, SAVED_OBJECT_ID, attributes);
} else {
await repository.create(SAVED_OBJECT_ID, attributes, { id: SAVED_OBJECT_ID });
try {
if (doesSavedObjectExist) {
await repository.update(SAVED_OBJECT_ID, SAVED_OBJECT_ID, attributes);
} else {
await repository.create(SAVED_OBJECT_ID, attributes, { id: SAVED_OBJECT_ID });
}
} catch (e) {
// Version conflict error, swallow
}
} catch (e) {
// Version conflict error, swallow
}
};
};
2 changes: 1 addition & 1 deletion src/plugins/data/server/search/search_service.ts
Original file line number Diff line number Diff line change
@@ -107,7 +107,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
core: CoreSetup<{}, DataPluginStart>,
{ registerFunction, usageCollection }: SearchServiceSetupDependencies
): ISearchSetup {
const usage = usageCollection ? usageProvider(core) : undefined;
const usage = usageCollection ? usageProvider(core, this.initializerContext) : undefined;

const router = core.http.createRouter();
const routeDependencies = {

0 comments on commit f0ea74e

Please sign in to comment.