mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[Discover] Add EBT events for next resolved contextual profiles (#203124)](https://github.com/elastic/kibana/pull/203124) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Julia Rechkunova","email":"julia.rechkunova@elastic.co"},"sourceCommit":{"committedDate":"2024-12-13T12:31:42Z","message":"[Discover] Add EBT events for next resolved contextual profiles (#203124)\n\n- Closes https://github.com/elastic/kibana/issues/200257\r\n\r\n## Summary\r\n\r\nThis PR adds `discover_profile_resolved` EBT events when a new\r\ncontextual profile is resolved at any level (root, data source, or\r\ndocument level).\r\n\r\nEvents will be triggered from Discover pages and dashboards.\r\n\r\nPlease note that duplicate events will not be sent in the current\r\nimplementation. Only when profile ID is changing.\r\n\r\n<img width=\"1710\" alt=\"Screenshot 2024-12-06 at 17 39 23\"\r\nsrc=\"https://github.com/user-attachments/assets/54eef630-8bcc-4185-917f-d251c003df65\">\r\n\r\n<img width=\"1699\" alt=\"Screenshot 2024-12-06 at 17 38 36\"\r\nsrc=\"https://github.com/user-attachments/assets/541522eb-9cc5-47b6-a51a-81186232b7e5\">\r\n\r\n\r\n## Testing\r\n\r\nAdd logging to `trackContextualProfileResolvedEvent` or do the\r\nfollowing:\r\n\r\nEnable \"Usage collection\" global setting.\r\n\r\nNavigate to Discover and observe `kibana-browser` requests in Network\r\ntab.\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Davis McPhee <davismcphee@hotmail.com>","sha":"f2f2a0a689c717435c61f2f8f8694b28776eed76","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:DataDiscovery","backport:prev-minor","Project:OneDiscover"],"title":"[Discover] Add EBT events for next resolved contextual profiles","number":203124,"url":"https://github.com/elastic/kibana/pull/203124","mergeCommit":{"message":"[Discover] Add EBT events for next resolved contextual profiles (#203124)\n\n- Closes https://github.com/elastic/kibana/issues/200257\r\n\r\n## Summary\r\n\r\nThis PR adds `discover_profile_resolved` EBT events when a new\r\ncontextual profile is resolved at any level (root, data source, or\r\ndocument level).\r\n\r\nEvents will be triggered from Discover pages and dashboards.\r\n\r\nPlease note that duplicate events will not be sent in the current\r\nimplementation. Only when profile ID is changing.\r\n\r\n<img width=\"1710\" alt=\"Screenshot 2024-12-06 at 17 39 23\"\r\nsrc=\"https://github.com/user-attachments/assets/54eef630-8bcc-4185-917f-d251c003df65\">\r\n\r\n<img width=\"1699\" alt=\"Screenshot 2024-12-06 at 17 38 36\"\r\nsrc=\"https://github.com/user-attachments/assets/541522eb-9cc5-47b6-a51a-81186232b7e5\">\r\n\r\n\r\n## Testing\r\n\r\nAdd logging to `trackContextualProfileResolvedEvent` or do the\r\nfollowing:\r\n\r\nEnable \"Usage collection\" global setting.\r\n\r\nNavigate to Discover and observe `kibana-browser` requests in Network\r\ntab.\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Davis McPhee <davismcphee@hotmail.com>","sha":"f2f2a0a689c717435c61f2f8f8694b28776eed76"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/203124","number":203124,"mergeCommit":{"message":"[Discover] Add EBT events for next resolved contextual profiles (#203124)\n\n- Closes https://github.com/elastic/kibana/issues/200257\r\n\r\n## Summary\r\n\r\nThis PR adds `discover_profile_resolved` EBT events when a new\r\ncontextual profile is resolved at any level (root, data source, or\r\ndocument level).\r\n\r\nEvents will be triggered from Discover pages and dashboards.\r\n\r\nPlease note that duplicate events will not be sent in the current\r\nimplementation. Only when profile ID is changing.\r\n\r\n<img width=\"1710\" alt=\"Screenshot 2024-12-06 at 17 39 23\"\r\nsrc=\"https://github.com/user-attachments/assets/54eef630-8bcc-4185-917f-d251c003df65\">\r\n\r\n<img width=\"1699\" alt=\"Screenshot 2024-12-06 at 17 38 36\"\r\nsrc=\"https://github.com/user-attachments/assets/541522eb-9cc5-47b6-a51a-81186232b7e5\">\r\n\r\n\r\n## Testing\r\n\r\nAdd logging to `trackContextualProfileResolvedEvent` or do the\r\nfollowing:\r\n\r\nEnable \"Usage collection\" global setting.\r\n\r\nNavigate to Discover and observe `kibana-browser` requests in Network\r\ntab.\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Davis McPhee <davismcphee@hotmail.com>","sha":"f2f2a0a689c717435c61f2f8f8694b28776eed76"}}]}] BACKPORT--> Co-authored-by: Julia Rechkunova <julia.rechkunova@elastic.co>
This commit is contained in:
parent
6ac20e0373
commit
e92ced1cd0
7 changed files with 446 additions and 25 deletions
|
@ -26,6 +26,7 @@ describe('ProfilesManager', () => {
|
|||
jest.clearAllMocks();
|
||||
mocks = createContextAwarenessMocks();
|
||||
jest.spyOn(mocks.ebtManagerMock, 'updateProfilesContextWith');
|
||||
jest.spyOn(mocks.ebtManagerMock, 'trackContextualProfileResolvedEvent');
|
||||
});
|
||||
|
||||
it('should return default profiles', () => {
|
||||
|
@ -74,6 +75,15 @@ describe('ProfilesManager', () => {
|
|||
'root-profile',
|
||||
'data-source-profile',
|
||||
]);
|
||||
|
||||
expect(mocks.ebtManagerMock.trackContextualProfileResolvedEvent).toHaveBeenNthCalledWith(1, {
|
||||
profileId: 'root-profile',
|
||||
contextLevel: 'rootLevel',
|
||||
});
|
||||
expect(mocks.ebtManagerMock.trackContextualProfileResolvedEvent).toHaveBeenNthCalledWith(2, {
|
||||
profileId: 'data-source-profile',
|
||||
contextLevel: 'dataSourceLevel',
|
||||
});
|
||||
});
|
||||
|
||||
it('should expose profiles as an observable', async () => {
|
||||
|
@ -152,7 +162,7 @@ describe('ProfilesManager', () => {
|
|||
resolveSpy.mockRejectedValue(new Error('Failed to resolve'));
|
||||
await mocks.profilesManagerMock.resolveRootProfile({ solutionNavId: 'newSolutionNavId' });
|
||||
expect(addLog).toHaveBeenCalledWith(
|
||||
'[ProfilesManager] root context resolution failed with params: {\n "solutionNavId": "newSolutionNavId"\n}',
|
||||
'[ProfilesManager] rootLevel context resolution failed with params: {\n "solutionNavId": "newSolutionNavId"\n}',
|
||||
new Error('Failed to resolve')
|
||||
);
|
||||
profiles = mocks.profilesManagerMock.getProfiles();
|
||||
|
@ -177,7 +187,7 @@ describe('ProfilesManager', () => {
|
|||
query: { esql: 'from logs-*' },
|
||||
});
|
||||
expect(addLog).toHaveBeenCalledWith(
|
||||
'[ProfilesManager] data source context resolution failed with params: {\n "esqlQuery": "from logs-*"\n}',
|
||||
'[ProfilesManager] dataSourceLevel context resolution failed with params: {\n "esqlQuery": "from logs-*"\n}',
|
||||
new Error('Failed to resolve')
|
||||
);
|
||||
profiles = mocks.profilesManagerMock.getProfiles();
|
||||
|
@ -199,10 +209,14 @@ describe('ProfilesManager', () => {
|
|||
});
|
||||
profiles = mocks.profilesManagerMock.getProfiles({ record: record2 });
|
||||
expect(addLog).toHaveBeenCalledWith(
|
||||
'[ProfilesManager] document context resolution failed with params: {\n "recordId": "logstash-2014.09.09::388::"\n}',
|
||||
'[ProfilesManager] documentLevel context resolution failed with params: {\n "recordId": "logstash-2014.09.09::388::"\n}',
|
||||
new Error('Failed to resolve')
|
||||
);
|
||||
expect(profiles).toEqual([{}, {}, {}]);
|
||||
expect(mocks.ebtManagerMock.trackContextualProfileResolvedEvent).toHaveBeenCalledWith({
|
||||
profileId: 'document-profile',
|
||||
contextLevel: 'documentLevel',
|
||||
});
|
||||
});
|
||||
|
||||
it('should cancel existing root profile resolution when another is triggered', async () => {
|
||||
|
|
|
@ -51,6 +51,12 @@ export interface GetProfilesOptions {
|
|||
record?: DataTableRecord;
|
||||
}
|
||||
|
||||
export enum ContextualProfileLevel {
|
||||
rootLevel = 'rootLevel',
|
||||
dataSourceLevel = 'dataSourceLevel',
|
||||
documentLevel = 'documentLevel',
|
||||
}
|
||||
|
||||
export class ProfilesManager {
|
||||
private readonly rootContext$: BehaviorSubject<ContextWithProfileId<RootContext>>;
|
||||
private readonly dataSourceContext$: BehaviorSubject<ContextWithProfileId<DataSourceContext>>;
|
||||
|
@ -104,7 +110,7 @@ export class ProfilesManager {
|
|||
try {
|
||||
context = await this.rootProfileService.resolve(params);
|
||||
} catch (e) {
|
||||
logResolutionError(ContextType.Root, serializedParams, e);
|
||||
logResolutionError(ContextualProfileLevel.rootLevel, serializedParams, e);
|
||||
}
|
||||
|
||||
if (abortController.signal.aborted) {
|
||||
|
@ -142,7 +148,7 @@ export class ProfilesManager {
|
|||
rootContext: this.rootContext$.getValue(),
|
||||
});
|
||||
} catch (e) {
|
||||
logResolutionError(ContextType.DataSource, serializedParams, e);
|
||||
logResolutionError(ContextualProfileLevel.dataSourceLevel, serializedParams, e);
|
||||
}
|
||||
|
||||
if (abortController.signal.aborted) {
|
||||
|
@ -179,11 +185,20 @@ export class ProfilesManager {
|
|||
dataSourceContext: this.dataSourceContext$.getValue(),
|
||||
});
|
||||
} catch (e) {
|
||||
logResolutionError(ContextType.Document, { recordId: params.record.id }, e);
|
||||
logResolutionError(
|
||||
ContextualProfileLevel.documentLevel,
|
||||
{ recordId: params.record.id },
|
||||
e
|
||||
);
|
||||
context = this.documentProfileService.defaultContext;
|
||||
}
|
||||
}
|
||||
|
||||
this.ebtManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.documentLevel,
|
||||
profileId: context.profileId,
|
||||
});
|
||||
|
||||
return context;
|
||||
},
|
||||
});
|
||||
|
@ -223,6 +238,15 @@ export class ProfilesManager {
|
|||
private trackActiveProfiles(rootContextProfileId: string, dataSourceContextProfileId: string) {
|
||||
const dscProfiles = [rootContextProfileId, dataSourceContextProfileId];
|
||||
|
||||
this.ebtManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.rootLevel,
|
||||
profileId: rootContextProfileId,
|
||||
});
|
||||
this.ebtManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.dataSourceLevel,
|
||||
profileId: dataSourceContextProfileId,
|
||||
});
|
||||
|
||||
this.ebtManager.updateProfilesContextWith(dscProfiles);
|
||||
}
|
||||
}
|
||||
|
@ -256,19 +280,13 @@ const recordHasContext = (
|
|||
return Boolean(record && 'context' in record);
|
||||
};
|
||||
|
||||
enum ContextType {
|
||||
Root = 'root',
|
||||
DataSource = 'data source',
|
||||
Document = 'document',
|
||||
}
|
||||
|
||||
const logResolutionError = <TParams, TError>(
|
||||
profileType: ContextType,
|
||||
profileLevel: ContextualProfileLevel,
|
||||
params: TParams,
|
||||
error: TError
|
||||
) => {
|
||||
addLog(
|
||||
`[ProfilesManager] ${profileType} context resolution failed with params: ${JSON.stringify(
|
||||
`[ProfilesManager] ${profileLevel} context resolution failed with params: ${JSON.stringify(
|
||||
params,
|
||||
null,
|
||||
2
|
||||
|
|
|
@ -180,7 +180,7 @@ export class DiscoverPlugin
|
|||
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
||||
});
|
||||
|
||||
ebtManager.enableContext();
|
||||
ebtManager.onDiscoverAppMounted();
|
||||
|
||||
const services = buildServices({
|
||||
core: coreStart,
|
||||
|
@ -229,7 +229,7 @@ export class DiscoverPlugin
|
|||
});
|
||||
|
||||
return () => {
|
||||
ebtManager.disableAndResetContext();
|
||||
ebtManager.onDiscoverAppUnmounted();
|
||||
unlistenParentHistory();
|
||||
unmount();
|
||||
appUnMounted();
|
||||
|
|
|
@ -11,6 +11,7 @@ import { BehaviorSubject } from 'rxjs';
|
|||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { DiscoverEBTManager } from './discover_ebt_manager';
|
||||
import { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public';
|
||||
import { ContextualProfileLevel } from '../context_awareness/profiles_manager';
|
||||
|
||||
describe('DiscoverEBTManager', () => {
|
||||
let discoverEBTContextManager: DiscoverEBTManager;
|
||||
|
@ -31,6 +32,7 @@ describe('DiscoverEBTManager', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
discoverEBTContextManager = new DiscoverEBTManager();
|
||||
(coreSetupMock.analytics.reportEvent as jest.Mock).mockClear();
|
||||
});
|
||||
|
||||
describe('register', () => {
|
||||
|
@ -95,7 +97,7 @@ describe('DiscoverEBTManager', () => {
|
|||
shouldInitializeCustomContext: true,
|
||||
shouldInitializeCustomEvents: false,
|
||||
});
|
||||
discoverEBTContextManager.enableContext();
|
||||
discoverEBTContextManager.onDiscoverAppMounted();
|
||||
|
||||
discoverEBTContextManager.updateProfilesContextWith(dscProfiles);
|
||||
expect(discoverEBTContextManager.getProfilesContext()).toBe(dscProfiles);
|
||||
|
@ -112,7 +114,7 @@ describe('DiscoverEBTManager', () => {
|
|||
shouldInitializeCustomContext: true,
|
||||
shouldInitializeCustomEvents: false,
|
||||
});
|
||||
discoverEBTContextManager.enableContext();
|
||||
discoverEBTContextManager.onDiscoverAppMounted();
|
||||
|
||||
discoverEBTContextManager.updateProfilesContextWith(dscProfiles);
|
||||
expect(discoverEBTContextManager.getProfilesContext()).toBe(dscProfiles);
|
||||
|
@ -140,14 +142,14 @@ describe('DiscoverEBTManager', () => {
|
|||
shouldInitializeCustomContext: true,
|
||||
shouldInitializeCustomEvents: false,
|
||||
});
|
||||
discoverEBTContextManager.enableContext();
|
||||
discoverEBTContextManager.onDiscoverAppMounted();
|
||||
discoverEBTContextManager.updateProfilesContextWith(dscProfiles);
|
||||
expect(discoverEBTContextManager.getProfilesContext()).toBe(dscProfiles);
|
||||
discoverEBTContextManager.disableAndResetContext();
|
||||
discoverEBTContextManager.onDiscoverAppUnmounted();
|
||||
expect(discoverEBTContextManager.getProfilesContext()).toEqual([]);
|
||||
discoverEBTContextManager.updateProfilesContextWith(dscProfiles);
|
||||
expect(discoverEBTContextManager.getProfilesContext()).toEqual([]);
|
||||
discoverEBTContextManager.enableContext();
|
||||
discoverEBTContextManager.onDiscoverAppMounted();
|
||||
discoverEBTContextManager.updateProfilesContextWith(dscProfiles);
|
||||
expect(discoverEBTContextManager.getProfilesContext()).toBe(dscProfiles);
|
||||
});
|
||||
|
@ -239,4 +241,117 @@ describe('DiscoverEBTManager', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('trackContextualProfileResolvedEvent', () => {
|
||||
it('should track the event when a next contextual profile is resolved', async () => {
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: false,
|
||||
shouldInitializeCustomEvents: true,
|
||||
});
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.rootLevel,
|
||||
profileId: 'test',
|
||||
});
|
||||
|
||||
expect(coreSetupMock.analytics.reportEvent).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'discover_profile_resolved',
|
||||
{
|
||||
contextLevel: 'rootLevel',
|
||||
profileId: 'test',
|
||||
}
|
||||
);
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.dataSourceLevel,
|
||||
profileId: 'data-source-test',
|
||||
});
|
||||
|
||||
expect(coreSetupMock.analytics.reportEvent).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'discover_profile_resolved',
|
||||
{
|
||||
contextLevel: 'dataSourceLevel',
|
||||
profileId: 'data-source-test',
|
||||
}
|
||||
);
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.documentLevel,
|
||||
profileId: 'document-test',
|
||||
});
|
||||
|
||||
expect(coreSetupMock.analytics.reportEvent).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
'discover_profile_resolved',
|
||||
{
|
||||
contextLevel: 'documentLevel',
|
||||
profileId: 'document-test',
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should not trigger duplicate requests', async () => {
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: false,
|
||||
shouldInitializeCustomEvents: true,
|
||||
});
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.rootLevel,
|
||||
profileId: 'test1',
|
||||
});
|
||||
|
||||
expect(coreSetupMock.analytics.reportEvent).toHaveBeenCalledTimes(1);
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.rootLevel,
|
||||
profileId: 'test1',
|
||||
});
|
||||
|
||||
expect(coreSetupMock.analytics.reportEvent).toHaveBeenCalledTimes(1);
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.rootLevel,
|
||||
profileId: 'test2',
|
||||
});
|
||||
|
||||
expect(coreSetupMock.analytics.reportEvent).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should trigger similar requests after remount', async () => {
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: false,
|
||||
shouldInitializeCustomEvents: true,
|
||||
});
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.rootLevel,
|
||||
profileId: 'test1',
|
||||
});
|
||||
|
||||
expect(coreSetupMock.analytics.reportEvent).toHaveBeenCalledTimes(1);
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.rootLevel,
|
||||
profileId: 'test1',
|
||||
});
|
||||
|
||||
expect(coreSetupMock.analytics.reportEvent).toHaveBeenCalledTimes(1);
|
||||
|
||||
discoverEBTContextManager.onDiscoverAppUnmounted();
|
||||
discoverEBTContextManager.onDiscoverAppMounted();
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
||||
contextLevel: ContextualProfileLevel.rootLevel,
|
||||
profileId: 'test1',
|
||||
});
|
||||
|
||||
expect(coreSetupMock.analytics.reportEvent).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,7 +11,11 @@ import { BehaviorSubject } from 'rxjs';
|
|||
import { isEqual } from 'lodash';
|
||||
import type { CoreSetup } from '@kbn/core-lifecycle-browser';
|
||||
import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public';
|
||||
import { ContextualProfileLevel } from '../context_awareness/profiles_manager';
|
||||
|
||||
/**
|
||||
* Field usage events i.e. when a field is selected in the data table, removed from the data table, or a filter is added
|
||||
*/
|
||||
const FIELD_USAGE_EVENT_TYPE = 'discover_field_usage';
|
||||
const FIELD_USAGE_EVENT_NAME = 'eventName';
|
||||
const FIELD_USAGE_FIELD_NAME = 'fieldName';
|
||||
|
@ -30,6 +34,19 @@ interface FieldUsageEventData {
|
|||
[FIELD_USAGE_FILTER_OPERATION]?: FilterOperation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contextual profile resolved event i.e. when a different contextual profile is resolved at root, data source, or document level
|
||||
* Duplicated events for the same profile level will not be sent.
|
||||
*/
|
||||
const CONTEXTUAL_PROFILE_RESOLVED_EVENT_TYPE = 'discover_profile_resolved';
|
||||
const CONTEXTUAL_PROFILE_LEVEL = 'contextLevel';
|
||||
const CONTEXTUAL_PROFILE_ID = 'profileId';
|
||||
|
||||
interface ContextualProfileResolvedEventData {
|
||||
[CONTEXTUAL_PROFILE_LEVEL]: ContextualProfileLevel;
|
||||
[CONTEXTUAL_PROFILE_ID]: string;
|
||||
}
|
||||
|
||||
export interface DiscoverEBTContextProps {
|
||||
discoverProfiles: string[]; // Discover Context Awareness Profiles
|
||||
}
|
||||
|
@ -39,8 +56,19 @@ export class DiscoverEBTManager {
|
|||
private isCustomContextEnabled: boolean = false;
|
||||
private customContext$: DiscoverEBTContext | undefined;
|
||||
private reportEvent: CoreSetup['analytics']['reportEvent'] | undefined;
|
||||
private lastResolvedContextProfiles: {
|
||||
[ContextualProfileLevel.rootLevel]: string | undefined;
|
||||
[ContextualProfileLevel.dataSourceLevel]: string | undefined;
|
||||
[ContextualProfileLevel.documentLevel]: string | undefined;
|
||||
};
|
||||
|
||||
constructor() {}
|
||||
constructor() {
|
||||
this.lastResolvedContextProfiles = {
|
||||
[ContextualProfileLevel.rootLevel]: undefined,
|
||||
[ContextualProfileLevel.dataSourceLevel]: undefined,
|
||||
[ContextualProfileLevel.documentLevel]: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
// https://docs.elastic.dev/telemetry/collection/event-based-telemetry
|
||||
public initialize({
|
||||
|
@ -104,17 +132,40 @@ export class DiscoverEBTManager {
|
|||
},
|
||||
},
|
||||
});
|
||||
core.analytics.registerEventType({
|
||||
eventType: CONTEXTUAL_PROFILE_RESOLVED_EVENT_TYPE,
|
||||
schema: {
|
||||
[CONTEXTUAL_PROFILE_LEVEL]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description:
|
||||
'The context level at which it was resolved i.e. rootLevel, dataSourceLevel, documentLevel',
|
||||
},
|
||||
},
|
||||
[CONTEXTUAL_PROFILE_ID]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: 'The resolved name of the active profile',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
this.reportEvent = core.analytics.reportEvent;
|
||||
}
|
||||
}
|
||||
|
||||
public enableContext() {
|
||||
public onDiscoverAppMounted() {
|
||||
this.isCustomContextEnabled = true;
|
||||
}
|
||||
|
||||
public disableAndResetContext() {
|
||||
public onDiscoverAppUnmounted() {
|
||||
this.updateProfilesContextWith([]);
|
||||
this.isCustomContextEnabled = false;
|
||||
this.lastResolvedContextProfiles = {
|
||||
[ContextualProfileLevel.rootLevel]: undefined,
|
||||
[ContextualProfileLevel.dataSourceLevel]: undefined,
|
||||
[ContextualProfileLevel.documentLevel]: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
public updateProfilesContextWith(discoverProfiles: DiscoverEBTContextProps['discoverProfiles']) {
|
||||
|
@ -216,4 +267,30 @@ export class DiscoverEBTManager {
|
|||
filterOperation,
|
||||
});
|
||||
}
|
||||
|
||||
public trackContextualProfileResolvedEvent({
|
||||
contextLevel,
|
||||
profileId,
|
||||
}: {
|
||||
contextLevel: ContextualProfileLevel;
|
||||
profileId: string;
|
||||
}) {
|
||||
if (!this.reportEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.lastResolvedContextProfiles[contextLevel] === profileId) {
|
||||
// avoid sending duplicate events to EBT
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastResolvedContextProfiles[contextLevel] = profileId;
|
||||
|
||||
const eventData: ContextualProfileResolvedEventData = {
|
||||
[CONTEXTUAL_PROFILE_LEVEL]: contextLevel,
|
||||
[CONTEXTUAL_PROFILE_ID]: profileId,
|
||||
};
|
||||
|
||||
this.reportEvent(CONTEXTUAL_PROFILE_RESOLVED_EVENT_TYPE, eventData);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,7 +121,99 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
});
|
||||
});
|
||||
|
||||
describe('events', () => {
|
||||
describe('contextual profiles', () => {
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional');
|
||||
await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover');
|
||||
});
|
||||
|
||||
it('should send EBT events when a different data source profile gets resolved', async () => {
|
||||
await common.navigateToApp('discover');
|
||||
await discover.selectTextBaseLang();
|
||||
await discover.waitUntilSearchingHasFinished();
|
||||
await monacoEditor.setCodeEditorValue('from my-example-logs | sort @timestamp desc');
|
||||
await ebtUIHelper.setOptIn(true); // starts the recording of events from this moment
|
||||
await testSubjects.click('querySubmitButton');
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
await discover.waitUntilSearchingHasFinished();
|
||||
|
||||
let events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, {
|
||||
eventTypes: ['discover_profile_resolved'],
|
||||
withTimeoutMs: 500,
|
||||
});
|
||||
|
||||
// root profile stays the same as it's not changing after switching to ES|QL mode
|
||||
|
||||
// but the data source profile should change because of the different data source
|
||||
expect(events[0].properties).to.eql({
|
||||
contextLevel: 'dataSourceLevel',
|
||||
profileId: 'example-data-source-profile',
|
||||
});
|
||||
|
||||
// should not trigger any new events after a simple refresh
|
||||
await testSubjects.click('querySubmitButton');
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
await discover.waitUntilSearchingHasFinished();
|
||||
|
||||
events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, {
|
||||
eventTypes: ['discover_profile_resolved'],
|
||||
withTimeoutMs: 500,
|
||||
});
|
||||
|
||||
expect(events.length).to.be(1);
|
||||
|
||||
// should detect a new data source profile when switching to a different data source
|
||||
await monacoEditor.setCodeEditorValue('from my-example-* | sort @timestamp desc');
|
||||
await testSubjects.click('querySubmitButton');
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
await discover.waitUntilSearchingHasFinished();
|
||||
|
||||
events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, {
|
||||
eventTypes: ['discover_profile_resolved'],
|
||||
withTimeoutMs: 500,
|
||||
});
|
||||
|
||||
expect(events[1].properties).to.eql({
|
||||
contextLevel: 'dataSourceLevel',
|
||||
profileId: 'default-data-source-profile',
|
||||
});
|
||||
|
||||
expect(events.length).to.be(2);
|
||||
});
|
||||
|
||||
it('should send EBT events when a different document profile gets resolved', async () => {
|
||||
await common.navigateToApp('discover');
|
||||
await discover.selectTextBaseLang();
|
||||
await monacoEditor.setCodeEditorValue('from my-example-* | sort @timestamp desc');
|
||||
await testSubjects.click('querySubmitButton');
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
await discover.waitUntilSearchingHasFinished();
|
||||
|
||||
await ebtUIHelper.setOptIn(true); // starts the recording of events from this moment
|
||||
|
||||
// should trigger a new event after opening the doc viewer
|
||||
await dataGrid.clickRowToggle();
|
||||
await discover.isShowingDocViewer();
|
||||
|
||||
const events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, {
|
||||
eventTypes: ['discover_profile_resolved'],
|
||||
withTimeoutMs: 500,
|
||||
});
|
||||
|
||||
expect(events.length).to.be(1);
|
||||
|
||||
expect(events[0].properties).to.eql({
|
||||
contextLevel: 'documentLevel',
|
||||
profileId: 'default-document-profile',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('field usage events', () => {
|
||||
beforeEach(async () => {
|
||||
await common.navigateToApp('discover');
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
|
|
|
@ -123,6 +123,111 @@ export default function ({ getService, getPageObjects }: ObservabilityTelemetryF
|
|||
});
|
||||
});
|
||||
|
||||
describe('contextual profiles', () => {
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional');
|
||||
await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover');
|
||||
});
|
||||
|
||||
it('should send EBT events when a different data source profile gets resolved', async () => {
|
||||
await common.navigateToApp('discover');
|
||||
await discover.selectTextBaseLang();
|
||||
await discover.waitUntilSearchingHasFinished();
|
||||
await monacoEditor.setCodeEditorValue('from my-example-logs | sort @timestamp desc');
|
||||
await ebtUIHelper.setOptIn(true); // starts the recording of events from this moment
|
||||
await testSubjects.click('querySubmitButton');
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
await discover.waitUntilSearchingHasFinished();
|
||||
|
||||
let events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, {
|
||||
eventTypes: ['discover_profile_resolved'],
|
||||
withTimeoutMs: 500,
|
||||
});
|
||||
|
||||
expect(events[0].properties).to.eql({
|
||||
contextLevel: 'rootLevel',
|
||||
profileId: 'observability-root-profile',
|
||||
});
|
||||
|
||||
expect(events[1].properties).to.eql({
|
||||
contextLevel: 'dataSourceLevel',
|
||||
profileId: 'default-data-source-profile',
|
||||
});
|
||||
|
||||
expect(events[2].properties).to.eql({
|
||||
contextLevel: 'dataSourceLevel',
|
||||
profileId: 'observability-logs-data-source-profile',
|
||||
});
|
||||
|
||||
// should not trigger any new events after a simple refresh
|
||||
await testSubjects.click('querySubmitButton');
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
await discover.waitUntilSearchingHasFinished();
|
||||
|
||||
events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, {
|
||||
eventTypes: ['discover_profile_resolved'],
|
||||
withTimeoutMs: 500,
|
||||
});
|
||||
|
||||
expect(events.length).to.be(3);
|
||||
|
||||
// should detect a new data source profile when switching to a different data source
|
||||
await monacoEditor.setCodeEditorValue('from my-example-* | sort @timestamp desc');
|
||||
await testSubjects.click('querySubmitButton');
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
await discover.waitUntilSearchingHasFinished();
|
||||
|
||||
events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, {
|
||||
eventTypes: ['discover_profile_resolved'],
|
||||
withTimeoutMs: 500,
|
||||
});
|
||||
|
||||
expect(events[3].properties).to.eql({
|
||||
contextLevel: 'dataSourceLevel',
|
||||
profileId: 'default-data-source-profile',
|
||||
});
|
||||
|
||||
expect(events.length).to.be(4);
|
||||
});
|
||||
|
||||
it('should send EBT events when a different document profile gets resolved', async () => {
|
||||
await common.navigateToApp('discover');
|
||||
await discover.selectTextBaseLang();
|
||||
await monacoEditor.setCodeEditorValue('from my-example-logs | sort @timestamp desc');
|
||||
await ebtUIHelper.setOptIn(true); // starts the recording of events from this moment
|
||||
await testSubjects.click('querySubmitButton');
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
await discover.waitUntilSearchingHasFinished();
|
||||
|
||||
let events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, {
|
||||
eventTypes: ['discover_profile_resolved'],
|
||||
withTimeoutMs: 500,
|
||||
});
|
||||
|
||||
expect(events.length).to.be(3);
|
||||
|
||||
// should trigger a new event after opening the doc viewer
|
||||
await dataGrid.clickRowToggle();
|
||||
await discover.isShowingDocViewer();
|
||||
|
||||
events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, {
|
||||
eventTypes: ['discover_profile_resolved'],
|
||||
withTimeoutMs: 500,
|
||||
});
|
||||
|
||||
expect(events.length).to.be(4);
|
||||
|
||||
expect(events[events.length - 1].properties).to.eql({
|
||||
contextLevel: 'documentLevel',
|
||||
profileId: 'observability-log-document-profile',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('events', () => {
|
||||
beforeEach(async () => {
|
||||
await common.navigateToApp('discover');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue