From 7cb73ebbf195c38310163bd1009e5e11ea8902c5 Mon Sep 17 00:00:00 2001 From: Rudolf Meijering Date: Wed, 25 Nov 2020 13:41:32 +0100 Subject: [PATCH] SavedObjectsRepository.incrementCounter supports array of fields --- ...savedobjectsrepository.incrementcounter.md | 30 ++++- ...ugin-core-server.savedobjectsrepository.md | 2 +- .../lib/integration_tests/repository.test.ts | 105 ++++++++++++++++++ .../service/lib/repository.test.js | 58 +++++----- .../saved_objects/service/lib/repository.ts | 65 +++++++++-- src/core/server/server.api.md | 2 +- .../data/server/kql_telemetry/route.ts | 2 +- .../services/sample_data/usage/usage.ts | 4 +- .../server/report/store_report.test.ts | 2 +- .../server/report/store_report.ts | 2 +- .../validation_telemetry_service.ts | 2 +- .../server/collectors/lib/telemetry.ts | 2 +- .../lib/telemetry/es_ui_open_apis.test.ts | 6 +- .../lib/telemetry/es_ui_reindex_apis.test.ts | 8 +- .../lib/telemetry/es_ui_reindex_apis.ts | 8 +- 15 files changed, 237 insertions(+), 61 deletions(-) create mode 100644 src/core/server/saved_objects/service/lib/integration_tests/repository.test.ts diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.incrementcounter.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.incrementcounter.md index f3a2ee38cbdbd..cbbe1f58ffda5 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.incrementcounter.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.incrementcounter.md @@ -4,12 +4,12 @@ ## SavedObjectsRepository.incrementCounter() method -Increases a counter field by one. Creates the document if one doesn't exist for the given id. +Increments all the specified counter fields by one. Creates the document if one doesn't exist for the given id. Signature: ```typescript -incrementCounter(type: string, id: string, counterFieldName: string, options?: SavedObjectsIncrementCounterOptions): Promise; +incrementCounter(type: string, id: string, counterFieldNames: string[], options?: SavedObjectsIncrementCounterOptions): Promise; ``` ## Parameters @@ -18,7 +18,7 @@ incrementCounter(type: string, id: string, counterFieldName: string, options?: S | --- | --- | --- | | type | string | | | id | string | | -| counterFieldName | string | | +| counterFieldNames | string[] | | | options | SavedObjectsIncrementCounterOptions | | Returns: @@ -27,3 +27,27 @@ incrementCounter(type: string, id: string, counterFieldName: string, options?: S {promise} +## Remarks + +When using incrementCounter for collecting usage data, you need to ensure that usage collection happens on a best-effort basis and doesn't negatively affect your plugin or users (see the example): - Swallow any exceptions thrown from the incrementCounter method and log a message in development. - Don't block your application on the incrementCounter method (e.g. don't use `await`) + +## Example + +Collecting usage data + +```ts +const repository = coreStart.savedObjects.createInternalRepository(); + +// NOTE: Usage collection happens on a best-effort basis, so we don't +// `await` the promise returned by `incrementCounter` and we swallow any +// exceptions in production. +repository + .incrementCounter('test_counter_type', 'counter_2', [ + 'stats.api.count', + 'stats.api.count2', + 'stats.total', + ]) + .catch((e) => (coreContext.env.cliArgs.dev ? logger.error(e) : e)); + +``` + diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.md index 6a56f0bee718b..e0a6b8af5658a 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsrepository.md @@ -26,7 +26,7 @@ export declare class SavedObjectsRepository | [deleteFromNamespaces(type, id, namespaces, options)](./kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md) | | Removes one or more namespaces from a given multi-namespace saved object. If no namespaces remain, the saved object is deleted entirely. This method and \[addToNamespaces\][SavedObjectsRepository.addToNamespaces()](./kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md) are the only ways to change which Spaces a multi-namespace saved object is shared to. | | [find(options)](./kibana-plugin-core-server.savedobjectsrepository.find.md) | | | | [get(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.get.md) | | Gets a single object | -| [incrementCounter(type, id, counterFieldName, options)](./kibana-plugin-core-server.savedobjectsrepository.incrementcounter.md) | | Increases a counter field by one. Creates the document if one doesn't exist for the given id. | +| [incrementCounter(type, id, counterFieldNames, options)](./kibana-plugin-core-server.savedobjectsrepository.incrementcounter.md) | | Increments all the specified counter fields by one. Creates the document if one doesn't exist for the given id. | | [removeReferencesTo(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.removereferencesto.md) | | Updates all objects containing a reference to the given {type, id} tuple to remove the said reference. | | [update(type, id, attributes, options)](./kibana-plugin-core-server.savedobjectsrepository.update.md) | | Updates an object | diff --git a/src/core/server/saved_objects/service/lib/integration_tests/repository.test.ts b/src/core/server/saved_objects/service/lib/integration_tests/repository.test.ts new file mode 100644 index 0000000000000..67e69b32c8543 --- /dev/null +++ b/src/core/server/saved_objects/service/lib/integration_tests/repository.test.ts @@ -0,0 +1,105 @@ +/* + * 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 { InternalCoreStart } from 'src/core/server/internal_types'; +import * as kbnTestServer from '../../../../../test_helpers/kbn_server'; +import { Root } from '../../../../root'; + +const { startES } = kbnTestServer.createTestServers({ + adjustTimeout: (t: number) => jest.setTimeout(t), +}); +let esServer: kbnTestServer.TestElasticsearchUtils; + +describe('SavedObjectsRepository', () => { + let root: Root; + let start: InternalCoreStart; + + beforeAll(async () => { + esServer = await startES(); + root = kbnTestServer.createRootWithCorePlugins({ + server: { + basePath: '/hello', + }, + }); + + const setup = await root.setup(); + setup.savedObjects.registerType({ + hidden: false, + mappings: { + dynamic: false, + properties: {}, + }, + name: 'test_counter_type', + namespaceType: 'single', + }); + start = await root.start(); + }); + + afterAll(async () => { + await esServer.stop(); + await root.shutdown(); + }); + + describe('#incrementCounter', () => { + it('initializes a new document if none exists', async () => { + const now = new Date().getTime(); + const repository = start.savedObjects.createInternalRepository(); + await repository.incrementCounter('test_counter_type', 'counter_1', [ + 'stats.api.count', + 'stats.api.count2', + 'stats.total', + ]); + const result = await repository.get('test_counter_type', 'counter_1'); + expect(result.attributes).toMatchInlineSnapshot(` + Object { + "stats.api.count": 1, + "stats.api.count2": 1, + "stats.total": 1, + } + `); + expect(Date.parse(result.updated_at!)).toBeGreaterThanOrEqual(now); + }); + it('increments the specified counters of an existing document', async () => { + const repository = start.savedObjects.createInternalRepository(); + // Create document + await repository.incrementCounter('test_counter_type', 'counter_2', [ + 'stats.api.count', + 'stats.api.count2', + 'stats.total', + ]); + + const now = new Date().getTime(); + // Increment counters + await repository.incrementCounter('test_counter_type', 'counter_2', [ + 'stats.api.count', + 'stats.api.count2', + 'stats.total', + ]); + const result = await repository.get('test_counter_type', 'counter_2'); + expect(result.attributes).toMatchInlineSnapshot(` + Object { + "stats.api.count": 2, + "stats.api.count2": 2, + "stats.total": 2, + } + `); + expect(Date.parse(result.updated_at!)).toBeGreaterThanOrEqual(now); + }); + }); +}); diff --git a/src/core/server/saved_objects/service/lib/repository.test.js b/src/core/server/saved_objects/service/lib/repository.test.js index 6f885f17fd82b..8443d1dd07184 100644 --- a/src/core/server/saved_objects/service/lib/repository.test.js +++ b/src/core/server/saved_objects/service/lib/repository.test.js @@ -3272,11 +3272,11 @@ describe('SavedObjectsRepository', () => { describe('#incrementCounter', () => { const type = 'config'; const id = 'one'; - const field = 'buildNum'; + const counterFields = ['buildNum', 'apiCallsCount']; const namespace = 'foo-namespace'; const originId = 'some-origin-id'; - const incrementCounterSuccess = async (type, id, field, options) => { + const incrementCounterSuccess = async (type, id, fields, options) => { const isMultiNamespace = registry.isMultiNamespace(type); if (isMultiNamespace) { const response = getMockGetResponse({ type, id }, options?.namespace); @@ -3295,7 +3295,10 @@ describe('SavedObjectsRepository', () => { type, ...mockTimestampFields, [type]: { - [field]: 8468, + ...fields.reduce((acc, field) => { + acc[field] = 8468; + return acc; + }, {}), defaultIndex: 'logstash-*', }, }, @@ -3303,25 +3306,25 @@ describe('SavedObjectsRepository', () => { }) ); - const result = await savedObjectsRepository.incrementCounter(type, id, field, options); + const result = await savedObjectsRepository.incrementCounter(type, id, fields, options); expect(client.get).toHaveBeenCalledTimes(isMultiNamespace ? 1 : 0); return result; }; describe('client calls', () => { it(`should use the ES update action if type is not multi-namespace`, async () => { - await incrementCounterSuccess(type, id, field, { namespace }); + await incrementCounterSuccess(type, id, counterFields, { namespace }); expect(client.update).toHaveBeenCalledTimes(1); }); it(`should use the ES get action then update action if type is multi-namespace, ID is defined, and overwrite=true`, async () => { - await incrementCounterSuccess(MULTI_NAMESPACE_TYPE, id, field, { namespace }); + await incrementCounterSuccess(MULTI_NAMESPACE_TYPE, id, counterFields, { namespace }); expect(client.get).toHaveBeenCalledTimes(1); expect(client.update).toHaveBeenCalledTimes(1); }); it(`defaults to a refresh setting of wait_for`, async () => { - await incrementCounterSuccess(type, id, field, { namespace }); + await incrementCounterSuccess(type, id, counterFields, { namespace }); expect(client.update).toHaveBeenCalledWith( expect.objectContaining({ refresh: 'wait_for', @@ -3331,7 +3334,7 @@ describe('SavedObjectsRepository', () => { }); it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => { - await incrementCounterSuccess(type, id, field, { namespace }); + await incrementCounterSuccess(type, id, counterFields, { namespace }); expect(client.update).toHaveBeenCalledWith( expect.objectContaining({ id: `${namespace}:${type}:${id}`, @@ -3341,7 +3344,7 @@ describe('SavedObjectsRepository', () => { }); it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => { - await incrementCounterSuccess(type, id, field); + await incrementCounterSuccess(type, id, counterFields); expect(client.update).toHaveBeenCalledWith( expect.objectContaining({ id: `${type}:${id}`, @@ -3351,7 +3354,7 @@ describe('SavedObjectsRepository', () => { }); it(`normalizes options.namespace from 'default' to undefined`, async () => { - await incrementCounterSuccess(type, id, field, { namespace: 'default' }); + await incrementCounterSuccess(type, id, counterFields, { namespace: 'default' }); expect(client.update).toHaveBeenCalledWith( expect.objectContaining({ id: `${type}:${id}`, @@ -3361,7 +3364,7 @@ describe('SavedObjectsRepository', () => { }); it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => { - await incrementCounterSuccess(NAMESPACE_AGNOSTIC_TYPE, id, field, { namespace }); + await incrementCounterSuccess(NAMESPACE_AGNOSTIC_TYPE, id, counterFields, { namespace }); expect(client.update).toHaveBeenCalledWith( expect.objectContaining({ id: `${NAMESPACE_AGNOSTIC_TYPE}:${id}`, @@ -3370,7 +3373,7 @@ describe('SavedObjectsRepository', () => { ); client.update.mockClear(); - await incrementCounterSuccess(MULTI_NAMESPACE_TYPE, id, field, { namespace }); + await incrementCounterSuccess(MULTI_NAMESPACE_TYPE, id, counterFields, { namespace }); expect(client.update).toHaveBeenCalledWith( expect.objectContaining({ id: `${MULTI_NAMESPACE_TYPE}:${id}`, @@ -3389,7 +3392,7 @@ describe('SavedObjectsRepository', () => { it(`throws when options.namespace is '*'`, async () => { await expect( - savedObjectsRepository.incrementCounter(type, id, field, { + savedObjectsRepository.incrementCounter(type, id, counterFields, { namespace: ALL_NAMESPACES_STRING, }) ).rejects.toThrowError(createBadRequestError('"options.namespace" cannot be "*"')); @@ -3398,7 +3401,7 @@ describe('SavedObjectsRepository', () => { it(`throws when type is not a string`, async () => { const test = async (type) => { await expect( - savedObjectsRepository.incrementCounter(type, id, field) + savedObjectsRepository.incrementCounter(type, id, counterFields) ).rejects.toThrowError(`"type" argument must be a string`); expect(client.update).not.toHaveBeenCalled(); }; @@ -3413,23 +3416,24 @@ describe('SavedObjectsRepository', () => { const test = async (field) => { await expect( savedObjectsRepository.incrementCounter(type, id, field) - ).rejects.toThrowError(`"counterFieldName" argument must be a string`); + ).rejects.toThrowError(`"counterFieldNames" argument must be an array of strings`); expect(client.update).not.toHaveBeenCalled(); }; - await test(null); - await test(42); - await test(false); - await test({}); + await test([null]); + await test([42]); + await test([false]); + await test([{}]); + await test([{}, false, 42, null, 'string']); }); it(`throws when type is invalid`, async () => { - await expectUnsupportedTypeError('unknownType', id, field); + await expectUnsupportedTypeError('unknownType', id, counterFields); expect(client.update).not.toHaveBeenCalled(); }); it(`throws when type is hidden`, async () => { - await expectUnsupportedTypeError(HIDDEN_TYPE, id, field); + await expectUnsupportedTypeError(HIDDEN_TYPE, id, counterFields); expect(client.update).not.toHaveBeenCalled(); }); @@ -3439,7 +3443,9 @@ describe('SavedObjectsRepository', () => { elasticsearchClientMock.createSuccessTransportRequestPromise(response) ); await expect( - savedObjectsRepository.incrementCounter(MULTI_NAMESPACE_TYPE, id, field, { namespace }) + savedObjectsRepository.incrementCounter(MULTI_NAMESPACE_TYPE, id, counterFields, { + namespace, + }) ).rejects.toThrowError(createConflictError(MULTI_NAMESPACE_TYPE, id)); expect(client.get).toHaveBeenCalledTimes(1); }); @@ -3452,8 +3458,8 @@ describe('SavedObjectsRepository', () => { it(`migrates a document and serializes the migrated doc`, async () => { const migrationVersion = mockMigrationVersion; - await incrementCounterSuccess(type, id, field, { migrationVersion }); - const attributes = { buildNum: 1 }; // this is added by the incrementCounter function + await incrementCounterSuccess(type, id, counterFields, { migrationVersion }); + const attributes = { buildNum: 1, apiCallsCount: 1 }; // this is added by the incrementCounter function const doc = { type, id, attributes, migrationVersion, ...mockTimestampFields }; expectMigrationArgs(doc); @@ -3476,6 +3482,7 @@ describe('SavedObjectsRepository', () => { ...mockTimestampFields, config: { buildNum: 8468, + apiCallsCount: 100, defaultIndex: 'logstash-*', }, originId, @@ -3487,7 +3494,7 @@ describe('SavedObjectsRepository', () => { const response = await savedObjectsRepository.incrementCounter( 'config', '6.0.0-alpha1', - 'buildNum', + ['buildNum', 'apiCallsCount'], { namespace: 'foo-namespace', } @@ -3500,6 +3507,7 @@ describe('SavedObjectsRepository', () => { version: mockVersion, attributes: { buildNum: 8468, + apiCallsCount: 100, defaultIndex: 'logstash-*', }, originId, diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index d362c02de4915..57513fa40648e 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -1515,11 +1515,44 @@ export class SavedObjectsRepository { } /** - * Increases a counter field by one. Creates the document if one doesn't exist for the given id. + * Increments all the specified counter fields by one. Creates the document + * if one doesn't exist for the given id. + * + * @remarks + * When using incrementCounter for collecting usage data, you need to ensure + * that usage collection happens on a best-effort basis and doesn't + * negatively affect your plugin or users (see the example): + * - Swallow any exceptions thrown from the incrementCounter method and log + * a message in development. + * - Don't block your application on the incrementCounter method (e.g. + * don't use `await`) + * + * When supplying a field name like `stats.api.counter` the field name will + * be used as-is to create a document like: + * `{attributes: {'stats.api.counter': 1}}` + * It will not create a nested structure like: + * `{attributes: {stats: {api: {counter: 1}}}}` + * + * @example + * Collecting usage data + * ```ts + * const repository = coreStart.savedObjects.createInternalRepository(); + * + * // NOTE: Usage collection happens on a best-effort basis, so we don't + * // `await` the promise returned by `incrementCounter` and we swallow any + * // exceptions in production. + * repository + * .incrementCounter('test_counter_type', 'counter_2', [ + * 'stats.api.count', + * 'stats.api.count2', + * 'stats.total', + * ]) + * .catch((e) => (coreContext.env.cliArgs.dev ? logger.error(e) : e)); + * ``` * * @param {string} type * @param {string} id - * @param {string} counterFieldName + * @param {string} counterFieldNames * @param {object} [options={}] * @property {object} [options.migrationVersion=undefined] * @returns {promise} @@ -1527,14 +1560,17 @@ export class SavedObjectsRepository { async incrementCounter( type: string, id: string, - counterFieldName: string, + counterFieldNames: string[], options: SavedObjectsIncrementCounterOptions = {} ): Promise { if (typeof type !== 'string') { throw new Error('"type" argument must be a string'); } - if (typeof counterFieldName !== 'string') { - throw new Error('"counterFieldName" argument must be a string'); + const isArrayOfStrings = + Array.isArray(counterFieldNames) && + !counterFieldNames.some((field) => typeof field !== 'string'); + if (!isArrayOfStrings) { + throw new Error('"counterFieldNames" argument must be an array of strings'); } if (!this._allowedTypes.includes(type)) { throw SavedObjectsErrorHelpers.createUnsupportedTypeError(type); @@ -1558,7 +1594,10 @@ export class SavedObjectsRepository { type, ...(savedObjectNamespace && { namespace: savedObjectNamespace }), ...(savedObjectNamespaces && { namespaces: savedObjectNamespaces }), - attributes: { [counterFieldName]: 1 }, + attributes: counterFieldNames.reduce((acc, counterFieldName) => { + acc[counterFieldName] = 1; + return acc; + }, {} as Record), migrationVersion, updated_at: time, }); @@ -1573,11 +1612,13 @@ export class SavedObjectsRepository { body: { script: { source: ` - if (ctx._source[params.type][params.counterFieldName] == null) { - ctx._source[params.type][params.counterFieldName] = params.count; - } - else { - ctx._source[params.type][params.counterFieldName] += params.count; + for (counterFieldName in params.counterFieldNames) { + if (ctx._source[params.type][counterFieldName] == null) { + ctx._source[params.type][counterFieldName] = params.count; + } + else { + ctx._source[params.type][counterFieldName] += params.count; + } } ctx._source.updated_at = params.time; `, @@ -1586,7 +1627,7 @@ export class SavedObjectsRepository { count: 1, time, type, - counterFieldName, + counterFieldNames, }, }, upsert: raw._source, diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index a03e5ec9acd27..ce04c1b5412d1 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -2444,7 +2444,7 @@ export class SavedObjectsRepository { // (undocumented) find(options: SavedObjectsFindOptions): Promise>; get(type: string, id: string, options?: SavedObjectsBaseOptions): Promise>; - incrementCounter(type: string, id: string, counterFieldName: string, options?: SavedObjectsIncrementCounterOptions): Promise; + incrementCounter(type: string, id: string, counterFieldNames: string[], options?: SavedObjectsIncrementCounterOptions): Promise; removeReferencesTo(type: string, id: string, options?: SavedObjectsRemoveReferencesToOptions): Promise; update(type: string, id: string, attributes: Partial, options?: SavedObjectsUpdateOptions): Promise>; } diff --git a/src/plugins/data/server/kql_telemetry/route.ts b/src/plugins/data/server/kql_telemetry/route.ts index efcb3d038bcc6..c93500f360ad0 100644 --- a/src/plugins/data/server/kql_telemetry/route.ts +++ b/src/plugins/data/server/kql_telemetry/route.ts @@ -45,7 +45,7 @@ export function registerKqlTelemetryRoute( const counterName = optIn ? 'optInCount' : 'optOutCount'; try { - await internalRepository.incrementCounter('kql-telemetry', 'kql-telemetry', counterName); + await internalRepository.incrementCounter('kql-telemetry', 'kql-telemetry', [counterName]); } catch (error) { logger.warn(`Unable to increment counter: ${error}`); return response.customError({ diff --git a/src/plugins/home/server/services/sample_data/usage/usage.ts b/src/plugins/home/server/services/sample_data/usage/usage.ts index ba67906febf1a..6a243b47dee55 100644 --- a/src/plugins/home/server/services/sample_data/usage/usage.ts +++ b/src/plugins/home/server/services/sample_data/usage/usage.ts @@ -43,7 +43,7 @@ export function usage( addInstall: async (dataSet: string) => { try { const internalRepository = await internalRepositoryPromise; - await internalRepository.incrementCounter(SAVED_OBJECT_ID, dataSet, `installCount`); + await internalRepository.incrementCounter(SAVED_OBJECT_ID, dataSet, [`installCount`]); } catch (err) { handleIncrementError(err); } @@ -51,7 +51,7 @@ export function usage( addUninstall: async (dataSet: string) => { try { const internalRepository = await internalRepositoryPromise; - await internalRepository.incrementCounter(SAVED_OBJECT_ID, dataSet, `unInstallCount`); + await internalRepository.incrementCounter(SAVED_OBJECT_ID, dataSet, [`unInstallCount`]); } catch (err) { handleIncrementError(err); } diff --git a/src/plugins/usage_collection/server/report/store_report.test.ts b/src/plugins/usage_collection/server/report/store_report.test.ts index d8327eb834e12..939c37764ab0e 100644 --- a/src/plugins/usage_collection/server/report/store_report.test.ts +++ b/src/plugins/usage_collection/server/report/store_report.test.ts @@ -69,7 +69,7 @@ describe('store_report', () => { expect(savedObjectClient.incrementCounter).toHaveBeenCalledWith( 'ui-metric', 'test-app-name:test-event-name', - 'count' + ['count'] ); expect(savedObjectClient.bulkCreate).toHaveBeenCalledWith([ { diff --git a/src/plugins/usage_collection/server/report/store_report.ts b/src/plugins/usage_collection/server/report/store_report.ts index d9aac23fd1ff0..a54d3d226d736 100644 --- a/src/plugins/usage_collection/server/report/store_report.ts +++ b/src/plugins/usage_collection/server/report/store_report.ts @@ -50,7 +50,7 @@ export async function storeReport( const savedObjectId = `${appName}:${eventName}`; return { saved_objects: [ - await internalRepository.incrementCounter('ui-metric', savedObjectId, 'count'), + await internalRepository.incrementCounter('ui-metric', savedObjectId, ['count']), ], }; }), diff --git a/src/plugins/vis_type_timeseries/server/validation_telemetry/validation_telemetry_service.ts b/src/plugins/vis_type_timeseries/server/validation_telemetry/validation_telemetry_service.ts index 0969174c7143c..46f46eaa3026f 100644 --- a/src/plugins/vis_type_timeseries/server/validation_telemetry/validation_telemetry_service.ts +++ b/src/plugins/vis_type_timeseries/server/validation_telemetry/validation_telemetry_service.ts @@ -83,7 +83,7 @@ export class ValidationTelemetryService implements Plugin { expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, - `ui_open.overview` + [`ui_open.overview`] ); expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, - `ui_open.cluster` + [`ui_open.cluster`] ); expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, - `ui_open.indices` + [`ui_open.indices`] ); }); }); diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.test.ts index 31e4e3f07b5de..c157d8860de12 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.test.ts @@ -28,22 +28,22 @@ describe('Upgrade Assistant Telemetry SavedObject UIReindex', () => { expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, - `ui_reindex.close` + [`ui_reindex.close`] ); expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, - `ui_reindex.open` + [`ui_reindex.open`] ); expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, - `ui_reindex.start` + [`ui_reindex.start`] ); expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, - `ui_reindex.stop` + [`ui_reindex.stop`] ); }); }); diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.ts index 0aaaf63196d67..4c57b586a46cd 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.ts @@ -23,11 +23,9 @@ async function incrementUIReindexOptionCounter({ }: IncrementUIReindexOptionDependencies) { const internalRepository = savedObjects.createInternalRepository(); - await internalRepository.incrementCounter( - UPGRADE_ASSISTANT_TYPE, - UPGRADE_ASSISTANT_DOC_ID, - `ui_reindex.${uiReindexOptionCounter}` - ); + await internalRepository.incrementCounter(UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, [ + `ui_reindex.${uiReindexOptionCounter}`, + ]); } type UpsertUIReindexOptionDepencies = UIReindex & { savedObjects: SavedObjectsServiceStart };