@webex/internal-plugin-metrics 3.3.1-next.6 → 3.3.1-next.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/behavioral/behavioral-metrics.js +199 -0
- package/dist/behavioral/behavioral-metrics.js.map +1 -0
- package/dist/behavioral/config.js +11 -0
- package/dist/behavioral/config.js.map +1 -0
- package/dist/call-diagnostic/config.js +1 -1
- package/dist/call-diagnostic/config.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/metrics.js +1 -1
- package/dist/metrics.types.js.map +1 -1
- package/dist/new-metrics.js +31 -6
- package/dist/new-metrics.js.map +1 -1
- package/dist/types/behavioral/behavioral-metrics.d.ts +63 -0
- package/dist/types/behavioral/config.d.ts +1 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/metrics.types.d.ts +28 -7
- package/dist/types/new-metrics.d.ts +14 -6
- package/package.json +11 -11
- package/src/behavioral/behavioral-metrics.ts +179 -0
- package/src/behavioral/config.ts +3 -0
- package/src/call-diagnostic/config.ts +1 -1
- package/src/index.ts +2 -0
- package/src/metrics.types.ts +56 -8
- package/src/new-metrics.ts +34 -8
- package/test/unit/spec/behavioral/behavioral-metrics.ts +164 -0
package/src/metrics.types.ts
CHANGED
|
@@ -20,6 +20,39 @@ export type BrowserLaunchMethodType = NonNullable<
|
|
|
20
20
|
RawEvent['origin']['clientInfo']
|
|
21
21
|
>['browserLaunchMethod'];
|
|
22
22
|
|
|
23
|
+
export type MetricEventProduct = 'webex' | 'wxcc_desktop';
|
|
24
|
+
|
|
25
|
+
export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service';
|
|
26
|
+
|
|
27
|
+
export type MetricEventVerb =
|
|
28
|
+
| 'create'
|
|
29
|
+
| 'get'
|
|
30
|
+
| 'fetch'
|
|
31
|
+
| 'update'
|
|
32
|
+
| 'list'
|
|
33
|
+
| 'delete'
|
|
34
|
+
| 'select'
|
|
35
|
+
| 'view'
|
|
36
|
+
| 'set'
|
|
37
|
+
| 'toggle'
|
|
38
|
+
| 'load'
|
|
39
|
+
| 'reload'
|
|
40
|
+
| 'click'
|
|
41
|
+
| 'hover'
|
|
42
|
+
| 'register'
|
|
43
|
+
| 'unregister'
|
|
44
|
+
| 'enable'
|
|
45
|
+
| 'disable'
|
|
46
|
+
| 'use'
|
|
47
|
+
| 'complete'
|
|
48
|
+
| 'submit'
|
|
49
|
+
| 'apply'
|
|
50
|
+
| 'cancel'
|
|
51
|
+
| 'abort'
|
|
52
|
+
| 'sync'
|
|
53
|
+
| 'login'
|
|
54
|
+
| 'logout';
|
|
55
|
+
|
|
23
56
|
export type SubmitClientEventOptions = {
|
|
24
57
|
meetingId?: string;
|
|
25
58
|
mediaConnections?: any[];
|
|
@@ -66,13 +99,26 @@ export interface ClientEvent {
|
|
|
66
99
|
options?: SubmitClientEventOptions;
|
|
67
100
|
}
|
|
68
101
|
|
|
102
|
+
export interface BehavioralEventContext {
|
|
103
|
+
app: {version: string};
|
|
104
|
+
device: {id: string};
|
|
105
|
+
locale: string;
|
|
106
|
+
os: {
|
|
107
|
+
name: string;
|
|
108
|
+
version: string;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
69
112
|
export interface BehavioralEvent {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
113
|
+
context: BehavioralEventContext;
|
|
114
|
+
metricName: string;
|
|
115
|
+
tags: Record<string, string | number | boolean>;
|
|
116
|
+
timestamp: number;
|
|
117
|
+
type: string[];
|
|
74
118
|
}
|
|
75
119
|
|
|
120
|
+
export type BehavioralEventPayload = BehavioralEvent['tags'];
|
|
121
|
+
|
|
76
122
|
export interface OperationalEvent {
|
|
77
123
|
// TODO: not implemented
|
|
78
124
|
name: never;
|
|
@@ -104,7 +150,7 @@ export type RecursivePartial<T> = {
|
|
|
104
150
|
export type MetricEventNames =
|
|
105
151
|
| InternalEvent['name']
|
|
106
152
|
| ClientEvent['name']
|
|
107
|
-
| BehavioralEvent['
|
|
153
|
+
| BehavioralEvent['metricName']
|
|
108
154
|
| OperationalEvent['name']
|
|
109
155
|
| FeatureEvent['name']
|
|
110
156
|
| MediaQualityEvent['name'];
|
|
@@ -137,9 +183,11 @@ export type SubmitInternalEvent = (args: {
|
|
|
137
183
|
}) => void;
|
|
138
184
|
|
|
139
185
|
export type SubmitBehavioralEvent = (args: {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
186
|
+
product: MetricEventProduct;
|
|
187
|
+
agent: MetricEventAgent;
|
|
188
|
+
target: string;
|
|
189
|
+
verb: MetricEventVerb;
|
|
190
|
+
payload?: BehavioralEventPayload;
|
|
143
191
|
}) => void;
|
|
144
192
|
|
|
145
193
|
export type SubmitClientEvent = (args: {
|
package/src/new-metrics.ts
CHANGED
|
@@ -6,11 +6,15 @@
|
|
|
6
6
|
import {WebexPlugin} from '@webex/webex-core';
|
|
7
7
|
|
|
8
8
|
import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
|
|
9
|
+
import BehavioralMetrics from './behavioral/behavioral-metrics';
|
|
9
10
|
import {
|
|
10
11
|
RecursivePartial,
|
|
12
|
+
MetricEventProduct,
|
|
13
|
+
MetricEventAgent,
|
|
14
|
+
MetricEventVerb,
|
|
11
15
|
ClientEvent,
|
|
12
16
|
FeatureEvent,
|
|
13
|
-
|
|
17
|
+
BehavioralEventPayload,
|
|
14
18
|
OperationalEvent,
|
|
15
19
|
MediaQualityEvent,
|
|
16
20
|
InternalEvent,
|
|
@@ -32,6 +36,7 @@ class Metrics extends WebexPlugin {
|
|
|
32
36
|
callDiagnosticLatencies: CallDiagnosticLatencies;
|
|
33
37
|
// Helper classes to handle the different types of metrics
|
|
34
38
|
callDiagnosticMetrics: CallDiagnosticMetrics;
|
|
39
|
+
behavioralMetrics: BehavioralMetrics;
|
|
35
40
|
|
|
36
41
|
/**
|
|
37
42
|
* Constructor
|
|
@@ -56,6 +61,8 @@ class Metrics extends WebexPlugin {
|
|
|
56
61
|
this.webex.once('ready', () => {
|
|
57
62
|
// @ts-ignore
|
|
58
63
|
this.callDiagnosticMetrics = new CallDiagnosticMetrics({}, {parent: this.webex});
|
|
64
|
+
// @ts-ignore
|
|
65
|
+
this.behavioralMetrics = new BehavioralMetrics({}, {parent: this.webex});
|
|
59
66
|
});
|
|
60
67
|
}
|
|
61
68
|
|
|
@@ -79,21 +86,40 @@ class Metrics extends WebexPlugin {
|
|
|
79
86
|
}
|
|
80
87
|
}
|
|
81
88
|
|
|
89
|
+
/**
|
|
90
|
+
* @returns true once we have the deviceId we need to submit behavioral events to Amplitude
|
|
91
|
+
*/
|
|
92
|
+
isReadyToSubmitBehavioralEvents() {
|
|
93
|
+
return this.behavioralMetrics.isReadyToSubmitBehavioralEvents();
|
|
94
|
+
}
|
|
95
|
+
|
|
82
96
|
/**
|
|
83
97
|
* Behavioral event
|
|
84
98
|
* @param args
|
|
85
99
|
*/
|
|
86
100
|
submitBehavioralEvent({
|
|
87
|
-
|
|
101
|
+
product,
|
|
102
|
+
agent,
|
|
103
|
+
target,
|
|
104
|
+
verb,
|
|
88
105
|
payload,
|
|
89
|
-
options,
|
|
90
106
|
}: {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
107
|
+
product: MetricEventProduct;
|
|
108
|
+
agent: MetricEventAgent;
|
|
109
|
+
target: string;
|
|
110
|
+
verb: MetricEventVerb;
|
|
111
|
+
payload?: BehavioralEventPayload;
|
|
94
112
|
}) {
|
|
95
|
-
this.
|
|
96
|
-
|
|
113
|
+
if (!this.behavioralMetrics) {
|
|
114
|
+
// @ts-ignore
|
|
115
|
+
this.webex.logger.log(
|
|
116
|
+
`NewMetrics: @submitBehavioralEvent. Attempted to submit before webex.ready: ${product}.${agent}.${target}.${verb}`
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
return Promise.resolve();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return this.behavioralMetrics.submitBehavioralEvent({product, agent, target, verb, payload});
|
|
97
123
|
}
|
|
98
124
|
|
|
99
125
|
/**
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import sinon from 'sinon';
|
|
2
|
+
import {assert} from '@webex/test-helper-chai';
|
|
3
|
+
import {BrowserDetection} from '@webex/common';
|
|
4
|
+
import {BehavioralMetrics, config, getOSNameInternal} from '@webex/internal-plugin-metrics';
|
|
5
|
+
import uuid from 'uuid';
|
|
6
|
+
import {merge} from 'lodash';
|
|
7
|
+
|
|
8
|
+
//@ts-ignore
|
|
9
|
+
global.window = {location: {hostname: 'whatever'}, navigator: {language: 'language'}};
|
|
10
|
+
process.env.NODE_ENV = 'test';
|
|
11
|
+
|
|
12
|
+
const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
13
|
+
|
|
14
|
+
describe('internal-plugin-metrics', () => {
|
|
15
|
+
describe('BehavioralMetrics', () => {
|
|
16
|
+
let webex;
|
|
17
|
+
let now;
|
|
18
|
+
let behavioralMetrics: BehavioralMetrics;
|
|
19
|
+
|
|
20
|
+
const tags = {key: 'val'};
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
now = new Date();
|
|
24
|
+
|
|
25
|
+
webex = {
|
|
26
|
+
canAuthorize: true,
|
|
27
|
+
version: 'webex-version',
|
|
28
|
+
internal: {
|
|
29
|
+
services: {
|
|
30
|
+
get: () => 'locus-url',
|
|
31
|
+
},
|
|
32
|
+
metrics: {
|
|
33
|
+
submitClientMetrics: sinon.stub(),
|
|
34
|
+
config: {...config.metrics},
|
|
35
|
+
},
|
|
36
|
+
newMetrics: {},
|
|
37
|
+
device: {
|
|
38
|
+
userId: 'userId',
|
|
39
|
+
url: 'https://wdm-intb.ciscospark.com/wdm/api/v1/devices/deviceId',
|
|
40
|
+
orgId: 'orgId',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
meetings: {
|
|
44
|
+
config: {
|
|
45
|
+
metrics: {
|
|
46
|
+
clientType: 'TEAMS_CLIENT',
|
|
47
|
+
subClientType: 'WEB_APP',
|
|
48
|
+
clientName: 'Cantina',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
geoHintInfo: {
|
|
52
|
+
clientAddress: '1.3.4.5',
|
|
53
|
+
countryCode: 'UK',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
credentials: {
|
|
57
|
+
isUnverifiedGuest: false,
|
|
58
|
+
},
|
|
59
|
+
prepareFetchOptions: sinon.stub().callsFake((opts: any) => ({...opts, foo: 'bar'})),
|
|
60
|
+
request: sinon.stub().resolves({body: {}}),
|
|
61
|
+
logger: {
|
|
62
|
+
log: sinon.stub(),
|
|
63
|
+
error: sinon.stub(),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
sinon.createSandbox();
|
|
68
|
+
sinon.useFakeTimers(now.getTime());
|
|
69
|
+
behavioralMetrics = new BehavioralMetrics({}, {parent: webex});
|
|
70
|
+
sinon.stub(uuid, 'v4').returns('my-fake-id');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
afterEach(() => {
|
|
74
|
+
sinon.restore();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('#getContext', () => {
|
|
78
|
+
it('should build context correctly', () => {
|
|
79
|
+
const res = behavioralMetrics.getContext();
|
|
80
|
+
|
|
81
|
+
assert.deepEqual(res, {
|
|
82
|
+
app: {
|
|
83
|
+
version: 'webex-version',
|
|
84
|
+
},
|
|
85
|
+
device: {
|
|
86
|
+
id: 'deviceId',
|
|
87
|
+
},
|
|
88
|
+
locale: 'language',
|
|
89
|
+
os: {
|
|
90
|
+
name: getOSNameInternal(),
|
|
91
|
+
version: getOSVersion(),
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('#getDefaultTags', () => {
|
|
98
|
+
it('should build tags correctly', () => {
|
|
99
|
+
const res = behavioralMetrics.getDefaultTags();
|
|
100
|
+
|
|
101
|
+
assert.deepEqual(res, {
|
|
102
|
+
browser: getBrowserName(),
|
|
103
|
+
browserHeight: window.innerHeight,
|
|
104
|
+
browserVersion: getBrowserVersion(),
|
|
105
|
+
browserWidth: window.innerWidth,
|
|
106
|
+
domain: window.location.hostname,
|
|
107
|
+
inIframe: false,
|
|
108
|
+
locale: window.navigator.language,
|
|
109
|
+
os: getOSNameInternal(),
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('#isReadyToSubmitBehavioralEvents', () => {
|
|
115
|
+
it('should return true when we have a deviceId, false when deviceId is empty or undefined', async () => {
|
|
116
|
+
assert.equal(true, behavioralMetrics.isReadyToSubmitBehavioralEvents());
|
|
117
|
+
|
|
118
|
+
webex.internal.device.url = "";
|
|
119
|
+
assert.equal(false, behavioralMetrics.isReadyToSubmitBehavioralEvents());
|
|
120
|
+
|
|
121
|
+
delete webex.internal.device.url;
|
|
122
|
+
assert.equal(false, behavioralMetrics.isReadyToSubmitBehavioralEvents());
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe('#createEventObject', () => {
|
|
127
|
+
it('should build event object correctly', async () => {
|
|
128
|
+
const res = behavioralMetrics.createEventObject({
|
|
129
|
+
product: 'webex',
|
|
130
|
+
agent: 'user',
|
|
131
|
+
target: 'target',
|
|
132
|
+
verb: 'create',
|
|
133
|
+
payload: tags,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
assert.deepEqual(res, {
|
|
137
|
+
context: {
|
|
138
|
+
app: {
|
|
139
|
+
version: 'webex-version',
|
|
140
|
+
},
|
|
141
|
+
device: {
|
|
142
|
+
id: 'deviceId',
|
|
143
|
+
},
|
|
144
|
+
locale: 'language',
|
|
145
|
+
os: {
|
|
146
|
+
name: getOSNameInternal(),
|
|
147
|
+
version: getOSVersion(),
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
metricName: 'webex.user.target.create',
|
|
151
|
+
tags: merge(tags, {
|
|
152
|
+
browser: getBrowserName(),
|
|
153
|
+
browserVersion: getBrowserVersion(),
|
|
154
|
+
domain: window.location.hostname,
|
|
155
|
+
locale: window.navigator.language,
|
|
156
|
+
os: getOSNameInternal(),
|
|
157
|
+
}),
|
|
158
|
+
timestamp: res.timestamp,
|
|
159
|
+
type: ['behavioral'],
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|