[Usage Collection] Add execution context to the fetch methods (#125873)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Alejandro Fernández Haro 2022-02-22 11:58:43 +01:00 committed by GitHub
parent 2cabe1a68f
commit 6bf91d77ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 187 additions and 103 deletions

View file

@ -6,13 +6,9 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { CollectorSet } from '../../plugins/usage_collection/server/collector'; import { createUsageCollectionSetupMock } from '../../plugins/usage_collection/server/mocks';
import { loggerMock } from '../../core/server/logging/logger.mock';
const { makeUsageCollector } = new CollectorSet({ const { makeUsageCollector } = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
enum TELEMETRY_LAYER_TYPE { enum TELEMETRY_LAYER_TYPE {
ES_DOCS = 'es_docs', ES_DOCS = 'es_docs',

View file

@ -6,16 +6,10 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { import type { UsageCollectorOptions } from 'src/plugins/usage_collection/server';
CollectorSet, import { createUsageCollectionSetupMock } from '../../plugins/usage_collection/server/mocks';
UsageCollectorOptions,
} from '../../plugins/usage_collection/server/collector';
import { loggerMock } from '../../core/server/logging/logger.mock';
const collectorSet = new CollectorSet({ const collectorSet = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
interface Usage { interface Usage {
locale: string; locale: string;

View file

@ -6,14 +6,10 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { CollectorSet } from '../../../plugins/usage_collection/server/collector';
import { loggerMock } from '../../../core/server/logging/logger.mock';
import type { Usage } from './types'; import type { Usage } from './types';
import { createUsageCollectionSetupMock } from '../../../plugins/usage_collection/server/mocks';
const { makeUsageCollector } = new CollectorSet({ const { makeUsageCollector } = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
export const myCollector = makeUsageCollector<Usage, false>({ export const myCollector = makeUsageCollector<Usage, false>({
type: 'importing_from_export_collector', type: 'importing_from_export_collector',

View file

@ -6,14 +6,10 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { CollectorSet } from '../../plugins/usage_collection/server/collector'; import { createUsageCollectionSetupMock } from '../../plugins/usage_collection/server/mocks';
import { loggerMock } from '../../core/server/logging/logger.mock';
import { externallyDefinedSchema } from './constants'; import { externallyDefinedSchema } from './constants';
const { makeUsageCollector } = new CollectorSet({ const { makeUsageCollector } = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
interface Usage { interface Usage {
locale?: string; locale?: string;

View file

@ -6,14 +6,10 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { CollectorSet } from '../../plugins/usage_collection/server/collector';
import { loggerMock } from '../../core/server/logging/logger.mock';
import { Usage } from './constants'; import { Usage } from './constants';
import { createUsageCollectionSetupMock } from '../../plugins/usage_collection/server/mocks';
const { makeUsageCollector } = new CollectorSet({ const { makeUsageCollector } = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
export const myCollector = makeUsageCollector<Usage>({ export const myCollector = makeUsageCollector<Usage>({
type: 'imported_usage_interface_collector', type: 'imported_usage_interface_collector',

View file

@ -6,13 +6,9 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { CollectorSet } from '../../plugins/usage_collection/server/collector'; import { createUsageCollectionSetupMock } from '../../plugins/usage_collection/server/mocks';
import { loggerMock } from '../../core/server/logging/logger.mock';
const { makeUsageCollector } = new CollectorSet({ const { makeUsageCollector } = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
interface Usage { interface Usage {
[key: string]: { [key: string]: {

View file

@ -6,13 +6,10 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { CollectorSet, Collector } from '../../plugins/usage_collection/server/collector'; import type { Collector } from 'src/plugins/usage_collection/server';
import { loggerMock } from '../../core/server/logging/logger.mock'; import { createUsageCollectionSetupMock } from '../../plugins/usage_collection/server/mocks';
const collectorSet = new CollectorSet({ const collectorSet = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
interface Usage { interface Usage {
locale?: string; locale?: string;

View file

@ -6,13 +6,10 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { CollectorSet, MakeSchemaFrom } from '../../plugins/usage_collection/server/collector'; import type { MakeSchemaFrom } from 'src/plugins/usage_collection/server';
import { loggerMock } from '../../core/server/logging/logger.mock'; import { createUsageCollectionSetupMock } from '../../plugins/usage_collection/server/mocks';
const { makeUsageCollector } = new CollectorSet({ const { makeUsageCollector } = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
interface MyObject { interface MyObject {
total: number; total: number;

View file

@ -6,13 +6,9 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { CollectorSet } from '../../plugins/usage_collection/server/collector'; import { createUsageCollectionSetupMock } from '../../plugins/usage_collection/server/mocks';
import { loggerMock } from '../../core/server/logging/logger.mock';
const { makeStatsCollector } = new CollectorSet({ const { makeStatsCollector } = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
interface Usage { interface Usage {
some_field: string; some_field: string;

View file

@ -6,13 +6,9 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { CollectorSet } from '../../plugins/usage_collection/server/collector'; import { createUsageCollectionSetupMock } from '../../plugins/usage_collection/server/mocks';
import { loggerMock } from '../../core/server/logging/logger.mock';
const { makeUsageCollector } = new CollectorSet({ const { makeUsageCollector } = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
interface Usage { interface Usage {
locale: string; locale: string;

View file

@ -6,13 +6,9 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { CollectorSet } from '../../plugins/usage_collection/server/collector'; import { createUsageCollectionSetupMock } from '../../plugins/usage_collection/server/mocks';
import { loggerMock } from '../../core/server/logging/logger.mock';
const { makeUsageCollector } = new CollectorSet({ const { makeUsageCollector } = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
interface MyObject { interface MyObject {
total: number; total: number;

View file

@ -6,13 +6,9 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { CollectorSet } from '../../plugins/usage_collection/server/collector'; import { createUsageCollectionSetupMock } from '../../plugins/usage_collection/server/mocks';
import { loggerMock } from '../../core/server/logging/logger.mock';
const { makeUsageCollector } = new CollectorSet({ const { makeUsageCollector } = createUsageCollectionSetupMock();
logger: loggerMock.create(),
maximumWaitTimeForAllCollectorsInS: 0,
});
interface MyObject { interface MyObject {
total: number; total: number;

View file

@ -8,7 +8,7 @@
import { noop } from 'lodash'; import { noop } from 'lodash';
import { Collector } from './collector'; import { Collector } from './collector';
import { CollectorSet } from './collector_set'; import { CollectorSet, CollectorSetConfig } from './collector_set';
import { UsageCollector } from './usage_collector'; import { UsageCollector } from './usage_collector';
import { import {
@ -16,29 +16,33 @@ import {
loggingSystemMock, loggingSystemMock,
savedObjectsClientMock, savedObjectsClientMock,
httpServerMock, httpServerMock,
executionContextServiceMock,
} from '../../../../core/server/mocks'; } from '../../../../core/server/mocks';
import type { ExecutionContextSetup, Logger } from 'src/core/server';
describe('CollectorSet', () => { describe('CollectorSet', () => {
const logger = loggingSystemMock.createLogger(); let logger: jest.Mocked<Logger>;
let executionContext: jest.Mocked<ExecutionContextSetup>;
const loggerSpies = { let collectorSetConfig: CollectorSetConfig;
debug: jest.spyOn(logger, 'debug'),
warn: jest.spyOn(logger, 'warn'), beforeEach(() => {
}; logger = loggingSystemMock.createLogger();
executionContext = executionContextServiceMock.createSetupContract();
collectorSetConfig = { logger, executionContext };
});
describe('registers a collector set and runs lifecycle events', () => { describe('registers a collector set and runs lifecycle events', () => {
let fetch: Function; let fetch: Function;
beforeEach(() => { beforeEach(() => {
fetch = noop; fetch = noop;
loggerSpies.debug.mockRestore();
loggerSpies.warn.mockRestore();
}); });
const mockEsClient = elasticsearchServiceMock.createClusterClient().asInternalUser; const mockEsClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
const mockSoClient = savedObjectsClientMock.create(); const mockSoClient = savedObjectsClientMock.create();
const req = void 0; // No need to instantiate any KibanaRequest in these tests const req = void 0; // No need to instantiate any KibanaRequest in these tests
it('should throw an error if non-Collector type of object is registered', () => { it('should throw an error if non-Collector type of object is registered', () => {
const collectors = new CollectorSet({ logger }); const collectors = new CollectorSet(collectorSetConfig);
const registerPojo = () => { const registerPojo = () => {
collectors.registerCollector({ collectors.registerCollector({
type: 'type_collector_test', type: 'type_collector_test',
@ -53,7 +57,7 @@ describe('CollectorSet', () => {
}); });
it('should throw when 2 collectors with the same type are registered', () => { it('should throw when 2 collectors with the same type are registered', () => {
const collectorSet = new CollectorSet({ logger }); const collectorSet = new CollectorSet(collectorSetConfig);
collectorSet.registerCollector( collectorSet.registerCollector(
new Collector(logger, { type: 'test_duplicated', fetch: () => 1, isReady: () => true }) new Collector(logger, { type: 'test_duplicated', fetch: () => 1, isReady: () => true })
); );
@ -73,7 +77,7 @@ describe('CollectorSet', () => {
it('should log debug status of fetching from the collector', async () => { it('should log debug status of fetching from the collector', async () => {
// @ts-expect-error we are just mocking the output of any call // @ts-expect-error we are just mocking the output of any call
mockEsClient.ping.mockResolvedValue({ passTest: 1000 }); mockEsClient.ping.mockResolvedValue({ passTest: 1000 });
const collectors = new CollectorSet({ logger }); const collectors = new CollectorSet(collectorSetConfig);
collectors.registerCollector( collectors.registerCollector(
new Collector(logger, { new Collector(logger, {
type: 'MY_TEST_COLLECTOR', type: 'MY_TEST_COLLECTOR',
@ -85,11 +89,9 @@ describe('CollectorSet', () => {
); );
const result = await collectors.bulkFetch(mockEsClient, mockSoClient, req); const result = await collectors.bulkFetch(mockEsClient, mockSoClient, req);
expect(loggerSpies.debug).toHaveBeenCalledTimes(2); expect(logger.debug).toHaveBeenCalledTimes(2);
expect(loggerSpies.debug).toHaveBeenCalledWith('Getting ready collectors'); expect(logger.debug).toHaveBeenCalledWith('Getting ready collectors');
expect(loggerSpies.debug).toHaveBeenCalledWith( expect(logger.debug).toHaveBeenCalledWith('Fetching data from MY_TEST_COLLECTOR collector');
'Fetching data from MY_TEST_COLLECTOR collector'
);
expect(result).toStrictEqual([ expect(result).toStrictEqual([
{ {
type: 'MY_TEST_COLLECTOR', type: 'MY_TEST_COLLECTOR',
@ -108,7 +110,7 @@ describe('CollectorSet', () => {
}); });
it('should gracefully handle a collector fetch method throwing an error', async () => { it('should gracefully handle a collector fetch method throwing an error', async () => {
const collectors = new CollectorSet({ logger }); const collectors = new CollectorSet(collectorSetConfig);
collectors.registerCollector( collectors.registerCollector(
new Collector(logger, { new Collector(logger, {
type: 'MY_TEST_COLLECTOR', type: 'MY_TEST_COLLECTOR',
@ -138,7 +140,7 @@ describe('CollectorSet', () => {
}); });
it('should not break if isReady is not a function', async () => { it('should not break if isReady is not a function', async () => {
const collectors = new CollectorSet({ logger }); const collectors = new CollectorSet(collectorSetConfig);
collectors.registerCollector( collectors.registerCollector(
new Collector(logger, { new Collector(logger, {
type: 'MY_TEST_COLLECTOR', type: 'MY_TEST_COLLECTOR',
@ -167,7 +169,7 @@ describe('CollectorSet', () => {
}); });
it('should not break if isReady is not provided', async () => { it('should not break if isReady is not provided', async () => {
const collectors = new CollectorSet({ logger }); const collectors = new CollectorSet(collectorSetConfig);
collectors.registerCollector( collectors.registerCollector(
// @ts-expect-error we are intentionally sending it wrong. // @ts-expect-error we are intentionally sending it wrong.
new Collector(logger, { new Collector(logger, {
@ -199,7 +201,7 @@ describe('CollectorSet', () => {
let collectorSet: CollectorSet; let collectorSet: CollectorSet;
beforeEach(() => { beforeEach(() => {
collectorSet = new CollectorSet({ logger }); collectorSet = new CollectorSet(collectorSetConfig);
}); });
it('should snake_case and convert field names to api standards', () => { it('should snake_case and convert field names to api standards', () => {
@ -261,7 +263,12 @@ describe('CollectorSet', () => {
}); });
describe('makeStatsCollector', () => { describe('makeStatsCollector', () => {
const collectorSet = new CollectorSet({ logger }); let collectorSet: CollectorSet;
beforeEach(() => {
collectorSet = new CollectorSet(collectorSetConfig);
});
test('TS should hide kibanaRequest when not opted-in', () => { test('TS should hide kibanaRequest when not opted-in', () => {
collectorSet.makeStatsCollector({ collectorSet.makeStatsCollector({
type: 'MY_TEST_COLLECTOR', type: 'MY_TEST_COLLECTOR',
@ -326,7 +333,12 @@ describe('CollectorSet', () => {
}); });
describe('makeUsageCollector', () => { describe('makeUsageCollector', () => {
const collectorSet = new CollectorSet({ logger }); let collectorSet: CollectorSet;
beforeEach(() => {
collectorSet = new CollectorSet(collectorSetConfig);
});
describe('TS validations', () => { describe('TS validations', () => {
describe('when types are inferred', () => { describe('when types are inferred', () => {
test('TS should hide kibanaRequest when not opted-in', () => { test('TS should hide kibanaRequest when not opted-in', () => {
@ -529,10 +541,14 @@ describe('CollectorSet', () => {
}); });
describe('bulkFetch', () => { describe('bulkFetch', () => {
const collectorSetConfig = { logger, maximumWaitTimeForAllCollectorsInS: 1 }; let collectorSet: CollectorSet;
let collectorSet = new CollectorSet(collectorSetConfig);
afterEach(() => { beforeEach(() => {
collectorSet = new CollectorSet(collectorSetConfig); const collectorSetConfigWithMaxTime: CollectorSetConfig = {
...collectorSetConfig,
maximumWaitTimeForAllCollectorsInS: 1,
};
collectorSet = new CollectorSet(collectorSetConfigWithMaxTime);
}); });
it('skips collectors that are not ready', async () => { it('skips collectors that are not ready', async () => {
@ -698,6 +714,70 @@ describe('CollectorSet', () => {
expect(results).toHaveLength(2); expect(results).toHaveLength(2);
}); });
it('calls fetch with execution context', async () => {
collectorSet.registerCollector(
collectorSet.makeUsageCollector({
type: 'ready_col',
isReady: () => true,
schema: { test: { type: 'long' } },
fetch: () => ({ test: 1000 }),
})
);
const mockEsClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
const mockSoClient = savedObjectsClientMock.create();
await collectorSet.bulkFetch(mockEsClient, mockSoClient, undefined);
expect(executionContext.withContext).toHaveBeenCalledTimes(1);
expect(executionContext.withContext).toHaveBeenCalledWith(
{
type: 'usage_collection',
name: 'collector.fetch',
id: 'ready_col',
description: `Fetch method in the Collector "ready_col"`,
},
expect.any(Function)
);
});
it('calls fetch with execution context for every collector', async () => {
['ready_col_1', 'ready_col_2'].forEach((type) =>
collectorSet.registerCollector(
collectorSet.makeUsageCollector({
type,
isReady: () => true,
schema: { test: { type: 'long' } },
fetch: () => ({ test: 1000 }),
})
)
);
const mockEsClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
const mockSoClient = savedObjectsClientMock.create();
await collectorSet.bulkFetch(mockEsClient, mockSoClient, undefined);
expect(executionContext.withContext).toHaveBeenCalledTimes(2);
expect(executionContext.withContext).toHaveBeenCalledWith(
{
type: 'usage_collection',
name: 'collector.fetch',
id: 'ready_col_1',
description: `Fetch method in the Collector "ready_col_1"`,
},
expect.any(Function)
);
expect(executionContext.withContext).toHaveBeenCalledWith(
{
type: 'usage_collection',
name: 'collector.fetch',
id: 'ready_col_2',
description: `Fetch method in the Collector "ready_col_2"`,
},
expect.any(Function)
);
});
it('adds extra context to collectors with extendFetchContext config', async () => { it('adds extra context to collectors with extendFetchContext config', async () => {
const mockReadyFetch = jest.fn().mockResolvedValue({}); const mockReadyFetch = jest.fn().mockResolvedValue({});
collectorSet.registerCollector( collectorSet.registerCollector(

View file

@ -12,6 +12,8 @@ import type {
ElasticsearchClient, ElasticsearchClient,
SavedObjectsClientContract, SavedObjectsClientContract,
KibanaRequest, KibanaRequest,
KibanaExecutionContext,
ExecutionContextSetup,
} from 'src/core/server'; } from 'src/core/server';
import { Collector } from './collector'; import { Collector } from './collector';
import type { ICollector, CollectorOptions } from './types'; import type { ICollector, CollectorOptions } from './types';
@ -26,8 +28,9 @@ interface CollectorWithStatus {
collector: AnyCollector; collector: AnyCollector;
} }
interface CollectorSetConfig { export interface CollectorSetConfig {
logger: Logger; logger: Logger;
executionContext: ExecutionContextSetup;
maximumWaitTimeForAllCollectorsInS?: number; maximumWaitTimeForAllCollectorsInS?: number;
collectors?: AnyCollector[]; collectors?: AnyCollector[];
} }
@ -42,14 +45,17 @@ interface CollectorStats {
export class CollectorSet { export class CollectorSet {
private readonly logger: Logger; private readonly logger: Logger;
private readonly executionContext: ExecutionContextSetup;
private readonly maximumWaitTimeForAllCollectorsInS: number; private readonly maximumWaitTimeForAllCollectorsInS: number;
private readonly collectors: Map<string, AnyCollector>; private readonly collectors: Map<string, AnyCollector>;
constructor({ constructor({
logger, logger,
executionContext,
maximumWaitTimeForAllCollectorsInS = DEFAULT_MAXIMUM_WAIT_TIME_FOR_ALL_COLLECTORS_IN_S, maximumWaitTimeForAllCollectorsInS = DEFAULT_MAXIMUM_WAIT_TIME_FOR_ALL_COLLECTORS_IN_S,
collectors = [], collectors = [],
}: CollectorSetConfig) { }: CollectorSetConfig) {
this.logger = logger; this.logger = logger;
this.executionContext = executionContext;
this.collectors = new Map(collectors.map((collector) => [collector.type, collector])); this.collectors = new Map(collectors.map((collector) => [collector.type, collector]));
this.maximumWaitTimeForAllCollectorsInS = maximumWaitTimeForAllCollectorsInS; this.maximumWaitTimeForAllCollectorsInS = maximumWaitTimeForAllCollectorsInS;
} }
@ -208,7 +214,15 @@ export class CollectorSet {
soClient, soClient,
...(collector.extendFetchContext.kibanaRequest && { kibanaRequest }), ...(collector.extendFetchContext.kibanaRequest && { kibanaRequest }),
}; };
const result = await collector.fetch(context); const executionContext: KibanaExecutionContext = {
type: 'usage_collection',
name: 'collector.fetch',
id: collector.type,
description: `Fetch method in the Collector "${collector.type}"`,
};
const result = await this.executionContext.withContext(executionContext, () =>
collector.fetch(context)
);
collectorStats.succeeded.names.push(collector.type); collectorStats.succeeded.names.push(collector.type);
return { type: collector.type, result }; return { type: collector.type, result };
} catch (err) { } catch (err) {
@ -297,6 +311,7 @@ export class CollectorSet {
private makeCollectorSetFromArray = (collectors: AnyCollector[]) => { private makeCollectorSetFromArray = (collectors: AnyCollector[]) => {
return new CollectorSet({ return new CollectorSet({
logger: this.logger, logger: this.logger,
executionContext: this.executionContext,
maximumWaitTimeForAllCollectorsInS: this.maximumWaitTimeForAllCollectorsInS, maximumWaitTimeForAllCollectorsInS: this.maximumWaitTimeForAllCollectorsInS,
collectors, collectors,
}); });

View file

@ -8,6 +8,7 @@
import { import {
elasticsearchServiceMock, elasticsearchServiceMock,
executionContextServiceMock,
httpServerMock, httpServerMock,
loggingSystemMock, loggingSystemMock,
savedObjectsClientMock, savedObjectsClientMock,
@ -23,6 +24,7 @@ export { Collector };
export const createUsageCollectionSetupMock = () => { export const createUsageCollectionSetupMock = () => {
const collectorSet = new CollectorSet({ const collectorSet = new CollectorSet({
logger: loggingSystemMock.createLogger(), logger: loggingSystemMock.createLogger(),
executionContext: executionContextServiceMock.createSetupContract(),
maximumWaitTimeForAllCollectorsInS: 1, maximumWaitTimeForAllCollectorsInS: 1,
}); });
const { createUsageCounter, getUsageCounterByType } = const { createUsageCounter, getUsageCounterByType } =

View file

@ -112,6 +112,7 @@ export class UsageCollectionPlugin implements Plugin<UsageCollectionSetup> {
const collectorSet = new CollectorSet({ const collectorSet = new CollectorSet({
logger: this.logger.get('usage-collection', 'collector-set'), logger: this.logger.get('usage-collection', 'collector-set'),
executionContext: core.executionContext,
maximumWaitTimeForAllCollectorsInS: config.maximumWaitTimeForAllCollectorsInS, maximumWaitTimeForAllCollectorsInS: config.maximumWaitTimeForAllCollectorsInS,
}); });

View file

@ -51,6 +51,7 @@ describe('/api/stats', () => {
router, router,
collectorSet: new CollectorSet({ collectorSet: new CollectorSet({
logger: loggingSystemMock.create().asLoggerFactory().get(), logger: loggingSystemMock.create().asLoggerFactory().get(),
executionContext: executionContextServiceMock.createSetupContract(),
}), }),
config: { config: {
allowAnonymous: true, allowAnonymous: true,

View file

@ -108,5 +108,38 @@ export default function ({ getService }: FtrProviderContext) {
retry, retry,
}); });
}); });
it('propagates context for Telemetry collection', async () => {
await supertest
.post('/api/telemetry/v2/clusters/_stats')
.set('kbn-xsrf', 'true')
.send({ unencrypted: false })
.expect(200);
await assertLogContains({
description:
'usage_collection execution context propagates to Elasticsearch via "x-opaque-id" header',
predicate: (record) =>
Boolean(
// exclude part with collector types
record.http?.request?.id?.includes(
`kibana:usage_collection:collector.fetch:application_usage`
)
),
retry,
});
await assertLogContains({
description: 'execution context propagates to Kibana logs',
predicate: (record) =>
isExecutionContextLog(record?.message, {
type: 'usage_collection',
name: 'collector.fetch',
id: 'application_usage',
description: 'Fetch method in the Collector "application_usage"',
}),
retry,
});
});
}); });
} }