@webex/internal-plugin-metrics 3.3.1 → 3.4.0-next.2

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.
Files changed (49) hide show
  1. package/dist/behavioral-metrics.js +63 -0
  2. package/dist/behavioral-metrics.js.map +1 -0
  3. package/dist/business-metrics.js +62 -0
  4. package/dist/business-metrics.js.map +1 -0
  5. package/dist/call-diagnostic/call-diagnostic-metrics.js +3 -0
  6. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  7. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +14 -11
  8. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  9. package/dist/call-diagnostic/config.js +19 -13
  10. package/dist/call-diagnostic/config.js.map +1 -1
  11. package/dist/generic-metrics.js +184 -0
  12. package/dist/generic-metrics.js.map +1 -0
  13. package/dist/index.js +21 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/metrics.js +1 -1
  16. package/dist/metrics.types.js.map +1 -1
  17. package/dist/new-metrics.js +116 -23
  18. package/dist/new-metrics.js.map +1 -1
  19. package/dist/operational-metrics.js +56 -0
  20. package/dist/operational-metrics.js.map +1 -0
  21. package/dist/types/behavioral-metrics.d.ts +25 -0
  22. package/dist/types/business-metrics.d.ts +19 -0
  23. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +2 -2
  24. package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +3 -2
  25. package/dist/types/call-diagnostic/config.d.ts +2 -0
  26. package/dist/types/generic-metrics.d.ts +63 -0
  27. package/dist/types/index.d.ts +4 -1
  28. package/dist/types/metrics.types.d.ts +47 -15
  29. package/dist/types/new-metrics.d.ts +39 -11
  30. package/dist/types/operational-metrics.d.ts +19 -0
  31. package/package.json +11 -11
  32. package/src/behavioral-metrics.ts +40 -0
  33. package/src/business-metrics.ts +30 -0
  34. package/src/call-diagnostic/call-diagnostic-metrics.ts +3 -0
  35. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +16 -17
  36. package/src/call-diagnostic/config.ts +9 -2
  37. package/src/generic-metrics.ts +146 -0
  38. package/src/index.ts +6 -0
  39. package/src/metrics.types.ts +82 -18
  40. package/src/new-metrics.ts +95 -18
  41. package/src/operational-metrics.ts +24 -0
  42. package/test/unit/spec/behavioral/behavioral-metrics.ts +205 -0
  43. package/test/unit/spec/business/business-metrics.ts +120 -0
  44. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +48 -52
  45. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1 -1
  46. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +9 -0
  47. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +41 -22
  48. package/test/unit/spec/operational/operational-metrics.ts +115 -0
  49. package/test/unit/spec/prelogin-metrics-batcher.ts +1 -1
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ var _Reflect$construct = require("@babel/runtime-corejs2/core-js/reflect/construct");
4
+ var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
5
+ var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
6
+ _Object$defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ exports.default = void 0;
10
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
11
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
12
+ var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inherits"));
13
+ var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/possibleConstructorReturn"));
14
+ var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/getPrototypeOf"));
15
+ var _genericMetrics = _interopRequireDefault(require("./generic-metrics"));
16
+ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = _Reflect$construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
17
+ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !_Reflect$construct) return false; if (_Reflect$construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
18
+ /**
19
+ * @description Util class to handle Operational Metrics
20
+ * @export
21
+ * @class OperationalMetrics
22
+ */
23
+ var OperationalMetrics = exports.default = /*#__PURE__*/function (_GenericMetrics) {
24
+ (0, _inherits2.default)(OperationalMetrics, _GenericMetrics);
25
+ var _super = _createSuper(OperationalMetrics);
26
+ function OperationalMetrics() {
27
+ (0, _classCallCheck2.default)(this, OperationalMetrics);
28
+ return _super.apply(this, arguments);
29
+ }
30
+ (0, _createClass2.default)(OperationalMetrics, [{
31
+ key: "submitOperationalEvent",
32
+ value:
33
+ /**
34
+ * Submit an operational metric to our metrics endpoint.
35
+ * @param {string} name of the metric
36
+ * @param {EventPayload} user payload of the metric
37
+ * @returns {Promise<any>}
38
+ */
39
+ function submitOperationalEvent(_ref) {
40
+ var name = _ref.name,
41
+ payload = _ref.payload;
42
+ var event = this.createTaggedEventObject({
43
+ type: ['operational'],
44
+ name: name,
45
+ payload: payload
46
+ });
47
+ this.submitEvent({
48
+ kind: 'operational-events -> ',
49
+ name: name,
50
+ event: event
51
+ });
52
+ }
53
+ }]);
54
+ return OperationalMetrics;
55
+ }(_genericMetrics.default);
56
+ //# sourceMappingURL=operational-metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_genericMetrics","_interopRequireDefault","require","_createSuper","Derived","hasNativeReflectConstruct","_isNativeReflectConstruct","_createSuperInternal","Super","_getPrototypeOf2","default","result","NewTarget","constructor","_Reflect$construct","arguments","apply","_possibleConstructorReturn2","Reflect","sham","Proxy","Boolean","prototype","valueOf","call","e","OperationalMetrics","exports","_GenericMetrics","_inherits2","_super","_classCallCheck2","_createClass2","key","value","submitOperationalEvent","_ref","name","payload","event","createTaggedEventObject","type","submitEvent","kind","GenericMetrics"],"sources":["operational-metrics.ts"],"sourcesContent":["import GenericMetrics from './generic-metrics';\nimport {EventPayload} from './metrics.types';\n\n/**\n * @description Util class to handle Operational Metrics\n * @export\n * @class OperationalMetrics\n */\nexport default class OperationalMetrics extends GenericMetrics {\n /**\n * Submit an operational metric to our metrics endpoint.\n * @param {string} name of the metric\n * @param {EventPayload} user payload of the metric\n * @returns {Promise<any>}\n */\n public submitOperationalEvent({name, payload}: {name: string; payload: EventPayload}) {\n const event = this.createTaggedEventObject({\n type: ['operational'],\n name,\n payload,\n });\n this.submitEvent({kind: 'operational-events -> ', name, event});\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA,IAAAA,eAAA,GAAAC,sBAAA,CAAAC,OAAA;AAA+C,SAAAC,aAAAC,OAAA,QAAAC,yBAAA,GAAAC,yBAAA,oBAAAC,qBAAA,QAAAC,KAAA,OAAAC,gBAAA,CAAAC,OAAA,EAAAN,OAAA,GAAAO,MAAA,MAAAN,yBAAA,QAAAO,SAAA,OAAAH,gBAAA,CAAAC,OAAA,QAAAG,WAAA,EAAAF,MAAA,GAAAG,kBAAA,CAAAN,KAAA,EAAAO,SAAA,EAAAH,SAAA,YAAAD,MAAA,GAAAH,KAAA,CAAAQ,KAAA,OAAAD,SAAA,gBAAAE,2BAAA,CAAAP,OAAA,QAAAC,MAAA;AAAA,SAAAL,0BAAA,eAAAY,OAAA,qBAAAJ,kBAAA,oBAAAA,kBAAA,CAAAK,IAAA,2BAAAC,KAAA,oCAAAC,OAAA,CAAAC,SAAA,CAAAC,OAAA,CAAAC,IAAA,CAAAV,kBAAA,CAAAO,OAAA,8CAAAI,CAAA;AAG/C;AACA;AACA;AACA;AACA;AAJA,IAKqBC,kBAAkB,GAAAC,OAAA,CAAAjB,OAAA,0BAAAkB,eAAA;EAAA,IAAAC,UAAA,CAAAnB,OAAA,EAAAgB,kBAAA,EAAAE,eAAA;EAAA,IAAAE,MAAA,GAAA3B,YAAA,CAAAuB,kBAAA;EAAA,SAAAA,mBAAA;IAAA,IAAAK,gBAAA,CAAArB,OAAA,QAAAgB,kBAAA;IAAA,OAAAI,MAAA,CAAAd,KAAA,OAAAD,SAAA;EAAA;EAAA,IAAAiB,aAAA,CAAAtB,OAAA,EAAAgB,kBAAA;IAAAO,GAAA;IAAAC,KAAA;IACrC;AACF;AACA;AACA;AACA;AACA;IACE,SAAAC,uBAAAC,IAAA,EAAsF;MAAA,IAAvDC,IAAI,GAAAD,IAAA,CAAJC,IAAI;QAAEC,OAAO,GAAAF,IAAA,CAAPE,OAAO;MAC1C,IAAMC,KAAK,GAAG,IAAI,CAACC,uBAAuB,CAAC;QACzCC,IAAI,EAAE,CAAC,aAAa,CAAC;QACrBJ,IAAI,EAAJA,IAAI;QACJC,OAAO,EAAPA;MACF,CAAC,CAAC;MACF,IAAI,CAACI,WAAW,CAAC;QAACC,IAAI,EAAE,wBAAwB;QAAEN,IAAI,EAAJA,IAAI;QAAEE,KAAK,EAALA;MAAK,CAAC,CAAC;IACjE;EAAC;EAAA,OAAAb,kBAAA;AAAA,EAd6CkB,uBAAc"}
@@ -0,0 +1,25 @@
1
+ import { MetricEventProduct, MetricEventAgent, MetricEventVerb, EventPayload } from './metrics.types';
2
+ import GenericMetrics from './generic-metrics';
3
+ /**
4
+ * @description Util class to handle Behavioral Metrics
5
+ * @export
6
+ * @class BehavioralMetrics
7
+ */
8
+ export default class BehavioralMetrics extends GenericMetrics {
9
+ /**
10
+ * Submit a behavioral metric to our metrics endpoint.
11
+ * @param {MetricEventProduct} product the product from which the metric is being submitted, e.g. 'webex' web client, 'wxcc_desktop'
12
+ * @param {MetricEventAgent} agent the source of the action for this metric
13
+ * @param {string} target the 'thing' that this metric includes information about
14
+ * @param {MetricEventVerb} verb the action that this metric includes information about
15
+ * @param {EventPayload} payload information specific to this event. This should be flat, i.e. it should not include nested objects.
16
+ * @returns {Promise<any>}
17
+ */
18
+ submitBehavioralEvent({ product, agent, target, verb, payload, }: {
19
+ product: MetricEventProduct;
20
+ agent: MetricEventAgent;
21
+ target: string;
22
+ verb: MetricEventVerb;
23
+ payload?: EventPayload;
24
+ }): void;
25
+ }
@@ -0,0 +1,19 @@
1
+ import GenericMetrics from './generic-metrics';
2
+ import { EventPayload } from './metrics.types';
3
+ /**
4
+ * @description Util class to handle Buisness Metrics
5
+ * @export
6
+ * @class BusinessMetrics
7
+ */
8
+ export default class BusinessMetrics extends GenericMetrics {
9
+ /**
10
+ * Submit a buisness metric to our metrics endpoint.
11
+ * @param {string} name of the metric
12
+ * @param {EventPayload} user payload of the metric
13
+ * @returns {Promise<any>}
14
+ */
15
+ submitBusinessEvent({ name, payload }: {
16
+ name: string;
17
+ payload: EventPayload;
18
+ }): void;
19
+ }
@@ -77,7 +77,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
77
77
  environment?: string;
78
78
  newEnvironment?: string;
79
79
  clientInfo?: {
80
- os?: "other" | "chrome" | "windows" | "mac" | "ios" | "android" | "linux" | "android-x64" | "android-arm64" | "uwp-arm64";
80
+ os?: "windows" | "mac" | "ios" | "android" | "chrome" | "linux" | "other" | "android-x64" | "android-arm64" | "uwp-arm64";
81
81
  osVersion?: string;
82
82
  localIP?: string;
83
83
  gatewayIP?: string;
@@ -336,7 +336,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
336
336
  */
337
337
  generateClientEventErrorPayload(rawError: any): {
338
338
  fatal: boolean;
339
- category: "signaling" | "media" | "network" | "other" | "expected";
339
+ category: "other" | "signaling" | "media" | "network" | "expected";
340
340
  errorDescription?: string;
341
341
  errorCode?: number;
342
342
  errorCodeStr?: string;
@@ -96,8 +96,9 @@ export declare const extractVersionMetadata: (version: string) => {
96
96
  * Generates client error codes for specific ice failures
97
97
  * that happen when trying to add media in a meeting.
98
98
  */
99
- export declare const generateClientErrorCodeForIceFailure: ({ signalingState, iceConnectionState, turnServerUsed, }: {
99
+ export declare const generateClientErrorCodeForIceFailure: ({ signalingState, iceConnected, turnServerUsed, unreachable, }: {
100
100
  signalingState: RTCPeerConnection['signalingState'];
101
- iceConnectionState: RTCPeerConnection['iceConnectionState'];
101
+ iceConnected: boolean;
102
102
  turnServerUsed: boolean;
103
+ unreachable: boolean;
103
104
  }) => number;
@@ -10,6 +10,7 @@ export declare const MISSING_ROAP_ANSWER_CLIENT_CODE = 2007;
10
10
  export declare const DTLS_HANDSHAKE_FAILED_CLIENT_CODE = 2008;
11
11
  export declare const ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE = 2010;
12
12
  export declare const ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE = 2009;
13
+ export declare const ICE_AND_REACHABILITY_FAILED_CLIENT_CODE = 2011;
13
14
  export declare const WBX_APP_API_URL = "wbxappapi";
14
15
  export declare const WEBEX_SUB_SERVICE_TYPES: Record<string, ClientSubServiceType>;
15
16
  export declare const BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP: {
@@ -92,6 +93,7 @@ export declare const ERROR_DESCRIPTIONS: {
92
93
  DTLS_HANDSHAKE_FAILED: string;
93
94
  ICE_FAILED_WITHOUT_TURN_TLS: string;
94
95
  ICE_FAILED_WITH_TURN_TLS: string;
96
+ ICE_AND_REACHABILITY_FAILED: string;
95
97
  SDP_OFFER_CREATION_ERROR: string;
96
98
  SDP_OFFER_CREATION_ERROR_MISSING_CODEC: string;
97
99
  };
@@ -0,0 +1,63 @@
1
+ import { StatelessWebexPlugin } from '@webex/webex-core';
2
+ import { DeviceContext, TaggedEvent, EventPayload, MetricType } from './metrics.types';
3
+ /**
4
+ * @description top-level abstract class to handle Metrics and common routines.
5
+ * @export
6
+ * @class GenericMetrics
7
+ */
8
+ export default abstract class GenericMetrics extends StatelessWebexPlugin {
9
+ private clientMetricsBatcher;
10
+ private logger;
11
+ private device;
12
+ private version;
13
+ private deviceId;
14
+ /**
15
+ * Constructor
16
+ * @param {any[]} args
17
+ */
18
+ constructor(...args: any[]);
19
+ /**
20
+ * Submit a buisness metric to our metrics endpoint.
21
+ * @param {string} kind of metric for logging
22
+ * @param {string} name of the metric
23
+ * @param {object} event
24
+ * @returns {Promise<any>}
25
+ */
26
+ protected submitEvent({ kind, name, event }: {
27
+ kind: string;
28
+ name: string;
29
+ event: object;
30
+ }): any;
31
+ /**
32
+ * Returns the deviceId from our registration with WDM.
33
+ * @returns {string} deviceId or empty string
34
+ */
35
+ protected getDeviceId(): string;
36
+ /**
37
+ * Returns the context object to be submitted with all metrics.
38
+ * @returns {DeviceContext}
39
+ */
40
+ protected getContext(): DeviceContext;
41
+ /**
42
+ * Returns the browser details to be included with all metrics.
43
+ * @returns {object}
44
+ */
45
+ protected getBrowserDetails(): object;
46
+ /**
47
+ * Returns true once we have the deviceId we need to submit behavioral/operational/buisness events
48
+ * @returns {boolean}
49
+ */
50
+ isReadyToSubmitEvents(): boolean;
51
+ /**
52
+ * Creates the object to send to our metrics endpoint for a tagged event (i.e. behavoral or operational)
53
+ * @param {[MetricType]} list of event type (i.e. ['behavioral'], ['operational', 'behavioral'])
54
+ * @param {string} metric name
55
+ * @param {EventPayload} user payload
56
+ * @returns {EventPayload}
57
+ */
58
+ protected createTaggedEventObject({ type, name, payload, }: {
59
+ type: [MetricType];
60
+ name: string;
61
+ payload: EventPayload;
62
+ }): TaggedEvent;
63
+ }
@@ -9,6 +9,9 @@ import * as CALL_DIAGNOSTIC_CONFIG from './call-diagnostic/config';
9
9
  import * as CallDiagnosticUtils from './call-diagnostic/call-diagnostic-metrics.util';
10
10
  import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
11
11
  import CallDiagnosticLatencies from './call-diagnostic/call-diagnostic-metrics-latencies';
12
+ import BehavioralMetrics from './behavioral-metrics';
13
+ import OperationalMetrics from './operational-metrics';
14
+ import BusinessMetrics from './business-metrics';
12
15
  export { default, getOSNameInternal } from './metrics';
13
- export { config, CALL_DIAGNOSTIC_CONFIG, NewMetrics, Utils, CallDiagnosticUtils, CallDiagnosticLatencies, CallDiagnosticMetrics, };
16
+ export { config, CALL_DIAGNOSTIC_CONFIG, NewMetrics, Utils, CallDiagnosticUtils, CallDiagnosticLatencies, CallDiagnosticMetrics, BehavioralMetrics, OperationalMetrics, BusinessMetrics, };
14
17
  export type { ClientEvent, ClientEventLeaveReason, SubmitBehavioralEvent, SubmitClientEvent, SubmitInternalEvent, SubmitMQE, SubmitOperationalEvent, PreComputedLatencies, };
@@ -7,6 +7,9 @@ export type EnvironmentType = NonNullable<RawEvent['origin']['environment']>;
7
7
  export type NewEnvironmentType = NonNullable<RawEvent['origin']['newEnvironment']>;
8
8
  export type ClientLaunchMethodType = NonNullable<RawEvent['origin']['clientInfo']>['clientLaunchMethod'];
9
9
  export type BrowserLaunchMethodType = NonNullable<RawEvent['origin']['clientInfo']>['browserLaunchMethod'];
10
+ export type MetricEventProduct = 'webex' | 'wxcc_desktop';
11
+ export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service';
12
+ export type MetricEventVerb = 'create' | 'get' | 'fetch' | 'update' | 'list' | 'delete' | 'select' | 'view' | 'set' | 'toggle' | 'load' | 'reload' | 'click' | 'hover' | 'register' | 'unregister' | 'enable' | 'disable' | 'use' | 'complete' | 'submit' | 'apply' | 'cancel' | 'abort' | 'sync' | 'login' | 'logout' | 'answer' | 'activate' | 'deactivate';
10
13
  export type SubmitClientEventOptions = {
11
14
  meetingId?: string;
12
15
  mediaConnections?: any[];
@@ -37,16 +40,43 @@ export interface ClientEvent {
37
40
  payload?: RawClientEvent;
38
41
  options?: SubmitClientEventOptions;
39
42
  }
40
- export interface BehavioralEvent {
41
- name: 'host.meeting.participant.admitted' | 'sdk.media-flow.started';
42
- payload?: never;
43
- options?: never;
43
+ export interface DeviceContext {
44
+ app: {
45
+ version: string;
46
+ };
47
+ device: {
48
+ id: string;
49
+ };
50
+ locale: string;
51
+ os: {
52
+ name: string;
53
+ version: string;
54
+ };
44
55
  }
45
- export interface OperationalEvent {
46
- name: never;
47
- payload?: never;
48
- options?: never;
56
+ export type MetricType = 'behavioral' | 'operational' | 'business';
57
+ type InternalEventPayload = string | number | boolean;
58
+ export type EventPayload = Record<string, InternalEventPayload>;
59
+ export type BehavioralEventPayload = EventPayload;
60
+ export interface BusinessEventPayload {
61
+ metricName: string;
62
+ timestamp: number;
63
+ context: DeviceContext;
64
+ browserDetails: EventPayload;
65
+ value: EventPayload;
49
66
  }
67
+ export interface BusinessEvent {
68
+ type: string[];
69
+ eventPayload: BusinessEventPayload;
70
+ }
71
+ export interface TaggedEvent {
72
+ context: DeviceContext;
73
+ metricName: string;
74
+ tags: EventPayload;
75
+ timestamp: number;
76
+ type: [MetricType];
77
+ }
78
+ export type BehavioralEvent = TaggedEvent;
79
+ export type OperationalEvent = TaggedEvent;
50
80
  export interface FeatureEvent {
51
81
  name: never;
52
82
  payload?: never;
@@ -60,7 +90,7 @@ export interface MediaQualityEvent {
60
90
  export type RecursivePartial<T> = {
61
91
  [P in keyof T]?: T[P] extends (infer U)[] ? RecursivePartial<U>[] : T[P] extends object ? RecursivePartial<T[P]> : T[P];
62
92
  };
63
- export type MetricEventNames = InternalEvent['name'] | ClientEvent['name'] | BehavioralEvent['name'] | OperationalEvent['name'] | FeatureEvent['name'] | MediaQualityEvent['name'];
93
+ export type MetricEventNames = InternalEvent['name'] | ClientEvent['name'] | BehavioralEvent['metricName'] | OperationalEvent['metricName'] | BusinessEvent['eventPayload']['metricName'] | FeatureEvent['name'] | MediaQualityEvent['name'];
64
94
  export type ClientInfo = NonNullable<RawEvent['origin']['clientInfo']>;
65
95
  export type ClientType = NonNullable<RawEvent['origin']['clientInfo']>['clientType'];
66
96
  export type SubClientType = NonNullable<RawEvent['origin']['clientInfo']>['subClientType'];
@@ -80,9 +110,11 @@ export type SubmitInternalEvent = (args: {
80
110
  options?: any;
81
111
  }) => void;
82
112
  export type SubmitBehavioralEvent = (args: {
83
- name: BehavioralEvent['name'];
84
- payload?: RecursivePartial<BehavioralEvent['payload']>;
85
- options?: any;
113
+ product: MetricEventProduct;
114
+ agent: MetricEventAgent;
115
+ target: string;
116
+ verb: MetricEventVerb;
117
+ payload?: EventPayload;
86
118
  }) => void;
87
119
  export type SubmitClientEvent = (args: {
88
120
  name: ClientEvent['name'];
@@ -90,9 +122,8 @@ export type SubmitClientEvent = (args: {
90
122
  options?: SubmitClientEventOptions;
91
123
  }) => Promise<any>;
92
124
  export type SubmitOperationalEvent = (args: {
93
- name: OperationalEvent['name'];
94
- payload?: RecursivePartial<OperationalEvent['payload']>;
95
- options?: any;
125
+ name: OperationalEvent['metricName'];
126
+ payload: EventPayload;
96
127
  }) => void;
97
128
  export type SubmitMQE = (args: {
98
129
  name: MediaQualityEvent['name'];
@@ -105,3 +136,4 @@ export type BuildClientEventFetchRequestOptions = (args: {
105
136
  options?: SubmitClientEventOptions;
106
137
  }) => Promise<any>;
107
138
  export type PreComputedLatencies = 'internal.client.pageJMT' | 'internal.download.time' | 'internal.get.cluster.time' | 'internal.click.to.interstitial' | 'internal.refresh.captcha.time' | 'internal.exchange.ci.token.time' | 'internal.get.u2c.time' | 'internal.call.init.join.req' | 'internal.other.app.api.time' | 'internal.api.fetch.intelligence.models';
139
+ export {};
@@ -1,6 +1,9 @@
1
1
  import { WebexPlugin } from '@webex/webex-core';
2
2
  import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
3
- import { RecursivePartial, ClientEvent, FeatureEvent, BehavioralEvent, OperationalEvent, MediaQualityEvent, InternalEvent, SubmitClientEventOptions } from './metrics.types';
3
+ import BehavioralMetrics from './behavioral-metrics';
4
+ import OperationalMetrics from './operational-metrics';
5
+ import BusinessMetrics from './business-metrics';
6
+ import { RecursivePartial, MetricEventProduct, MetricEventAgent, MetricEventVerb, ClientEvent, FeatureEvent, EventPayload, MediaQualityEvent, InternalEvent, SubmitClientEventOptions } from './metrics.types';
4
7
  import CallDiagnosticLatencies from './call-diagnostic/call-diagnostic-metrics-latencies';
5
8
  /**
6
9
  * Metrics plugin to centralize all types of metrics.
@@ -10,6 +13,10 @@ declare class Metrics extends WebexPlugin {
10
13
  static instance: Metrics;
11
14
  callDiagnosticLatencies: CallDiagnosticLatencies;
12
15
  callDiagnosticMetrics: CallDiagnosticMetrics;
16
+ behavioralMetrics: BehavioralMetrics;
17
+ operationalMetrics: OperationalMetrics;
18
+ businessMetrics: BusinessMetrics;
19
+ isReady: boolean;
13
20
  /**
14
21
  * Constructor
15
22
  * @param args
@@ -31,24 +38,45 @@ declare class Metrics extends WebexPlugin {
31
38
  payload?: RecursivePartial<InternalEvent['payload']>;
32
39
  options?: any;
33
40
  }): void;
41
+ /**
42
+ * @returns true once we have the deviceId we need to submit behavioral events to Amplitude
43
+ */
44
+ isReadyToSubmitBehavioralEvents(): boolean;
45
+ /**
46
+ * @returns true once we have the deviceId we need to submit operational events
47
+ */
48
+ isReadyToSubmitOperationalEvents(): boolean;
49
+ /**
50
+ * @returns true once we have the deviceId we need to submit buisness events
51
+ */
52
+ isReadyToSubmitBusinessEvents(): boolean;
34
53
  /**
35
54
  * Behavioral event
36
55
  * @param args
37
56
  */
38
- submitBehavioralEvent({ name, payload, options, }: {
39
- name: BehavioralEvent['name'];
40
- payload?: RecursivePartial<BehavioralEvent['payload']>;
41
- options?: any;
42
- }): void;
57
+ submitBehavioralEvent({ product, agent, target, verb, payload, }: {
58
+ product: MetricEventProduct;
59
+ agent: MetricEventAgent;
60
+ target: string;
61
+ verb: MetricEventVerb;
62
+ payload?: EventPayload;
63
+ }): void | Promise<void>;
43
64
  /**
44
65
  * Operational event
45
66
  * @param args
46
67
  */
47
- submitOperationalEvent({ name, payload, options, }: {
48
- name: OperationalEvent['name'];
49
- payload?: RecursivePartial<OperationalEvent['payload']>;
50
- options?: any;
51
- }): void;
68
+ submitOperationalEvent({ name, payload }: {
69
+ name: string;
70
+ payload?: EventPayload;
71
+ }): void | Promise<void>;
72
+ /**
73
+ * Buisness event
74
+ * @param args
75
+ */
76
+ submitBusinessEvent({ name, payload }: {
77
+ name: string;
78
+ payload: EventPayload;
79
+ }): void | Promise<void>;
52
80
  /**
53
81
  * Call Analyzer: Media Quality Event
54
82
  * @param args
@@ -0,0 +1,19 @@
1
+ import GenericMetrics from './generic-metrics';
2
+ import { EventPayload } from './metrics.types';
3
+ /**
4
+ * @description Util class to handle Operational Metrics
5
+ * @export
6
+ * @class OperationalMetrics
7
+ */
8
+ export default class OperationalMetrics extends GenericMetrics {
9
+ /**
10
+ * Submit an operational metric to our metrics endpoint.
11
+ * @param {string} name of the metric
12
+ * @param {EventPayload} user payload of the metric
13
+ * @returns {Promise<any>}
14
+ */
15
+ submitOperationalEvent({ name, payload }: {
16
+ name: string;
17
+ payload: EventPayload;
18
+ }): void;
19
+ }
package/package.json CHANGED
@@ -26,22 +26,22 @@
26
26
  "@webex/eslint-config-legacy": "0.0.0",
27
27
  "@webex/jest-config-legacy": "0.0.0",
28
28
  "@webex/legacy-tools": "0.0.0",
29
- "@webex/test-helper-chai": "3.3.1",
30
- "@webex/test-helper-mocha": "3.3.1",
31
- "@webex/test-helper-mock-webex": "3.3.1",
32
- "@webex/test-helper-test-users": "3.3.1",
29
+ "@webex/test-helper-chai": "3.4.0-next.2",
30
+ "@webex/test-helper-mocha": "3.4.0-next.2",
31
+ "@webex/test-helper-mock-webex": "3.4.0-next.2",
32
+ "@webex/test-helper-test-users": "3.4.0-next.2",
33
33
  "eslint": "^8.24.0",
34
34
  "prettier": "^2.7.1",
35
35
  "sinon": "^9.2.4"
36
36
  },
37
37
  "dependencies": {
38
- "@webex/common": "3.3.1",
39
- "@webex/common-timers": "3.3.1",
38
+ "@webex/common": "3.4.0-next.2",
39
+ "@webex/common-timers": "3.4.0-next.2",
40
40
  "@webex/event-dictionary-ts": "^1.0.1406",
41
- "@webex/internal-plugin-metrics": "3.3.1",
42
- "@webex/test-helper-chai": "3.3.1",
43
- "@webex/test-helper-mock-webex": "3.3.1",
44
- "@webex/webex-core": "3.3.1",
41
+ "@webex/internal-plugin-metrics": "3.4.0-next.2",
42
+ "@webex/test-helper-chai": "3.4.0-next.2",
43
+ "@webex/test-helper-mock-webex": "3.4.0-next.2",
44
+ "@webex/webex-core": "3.4.0-next.2",
45
45
  "ip-anonymize": "^0.1.0",
46
46
  "lodash": "^4.17.21",
47
47
  "uuid": "^3.3.2"
@@ -54,5 +54,5 @@
54
54
  "test:style": "eslint ./src/**/*.*",
55
55
  "test:unit": "webex-legacy-tools test --unit --runner mocha"
56
56
  },
57
- "version": "3.3.1"
57
+ "version": "3.4.0-next.2"
58
58
  }
@@ -0,0 +1,40 @@
1
+ import {MetricEventProduct, MetricEventAgent, MetricEventVerb, EventPayload} from './metrics.types';
2
+ import GenericMetrics from './generic-metrics';
3
+
4
+ /**
5
+ * @description Util class to handle Behavioral Metrics
6
+ * @export
7
+ * @class BehavioralMetrics
8
+ */
9
+ export default class BehavioralMetrics extends GenericMetrics {
10
+ /**
11
+ * Submit a behavioral metric to our metrics endpoint.
12
+ * @param {MetricEventProduct} product the product from which the metric is being submitted, e.g. 'webex' web client, 'wxcc_desktop'
13
+ * @param {MetricEventAgent} agent the source of the action for this metric
14
+ * @param {string} target the 'thing' that this metric includes information about
15
+ * @param {MetricEventVerb} verb the action that this metric includes information about
16
+ * @param {EventPayload} payload information specific to this event. This should be flat, i.e. it should not include nested objects.
17
+ * @returns {Promise<any>}
18
+ */
19
+ public submitBehavioralEvent({
20
+ product,
21
+ agent,
22
+ target,
23
+ verb,
24
+ payload,
25
+ }: {
26
+ product: MetricEventProduct;
27
+ agent: MetricEventAgent;
28
+ target: string;
29
+ verb: MetricEventVerb;
30
+ payload?: EventPayload;
31
+ }) {
32
+ const name = `${product}.${agent}.${target}.${verb}`;
33
+ const event = this.createTaggedEventObject({
34
+ type: ['behavioral'],
35
+ name,
36
+ payload,
37
+ });
38
+ this.submitEvent({kind: 'behavioral-events -> ', name, event});
39
+ }
40
+ }
@@ -0,0 +1,30 @@
1
+ import GenericMetrics from './generic-metrics';
2
+ import {EventPayload} from './metrics.types';
3
+
4
+ /**
5
+ * @description Util class to handle Buisness Metrics
6
+ * @export
7
+ * @class BusinessMetrics
8
+ */
9
+ export default class BusinessMetrics extends GenericMetrics {
10
+ /**
11
+ * Submit a buisness metric to our metrics endpoint.
12
+ * @param {string} name of the metric
13
+ * @param {EventPayload} user payload of the metric
14
+ * @returns {Promise<any>}
15
+ */
16
+ public submitBusinessEvent({name, payload}: {name: string; payload: EventPayload}) {
17
+ const event = {
18
+ type: ['business'],
19
+ eventPayload: {
20
+ metricName: name,
21
+ timestamp: Date.now(),
22
+ context: this.getContext(),
23
+ browserDetails: this.getBrowserDetails(),
24
+ value: payload,
25
+ },
26
+ };
27
+
28
+ this.submitEvent({kind: 'buisness-events -> ', name, event});
29
+ }
30
+ }
@@ -455,6 +455,9 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
455
455
  },
456
456
  intervals: payload.intervals,
457
457
  callingServiceType: 'LOCUS',
458
+ meetingJoinInfo: {
459
+ clientSignallingProtocol: 'WebRTC',
460
+ },
458
461
  sourceMetadata: {
459
462
  applicationSoftwareType: CLIENT_NAME,
460
463
  // @ts-ignore
@@ -21,6 +21,7 @@ import {
21
21
  MISSING_ROAP_ANSWER_CLIENT_CODE,
22
22
  WBX_APP_API_URL,
23
23
  ERROR_DESCRIPTIONS,
24
+ ICE_AND_REACHABILITY_FAILED_CLIENT_CODE,
24
25
  } from './config';
25
26
 
26
27
  const {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
@@ -225,7 +226,7 @@ export const getBuildType = (
225
226
  */
226
227
  export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
227
228
  const origin: Partial<Event['origin']> = {
228
- buildType: exports.getBuildType(
229
+ buildType: getBuildType(
229
230
  item.eventPayload?.event?.eventData?.webClientDomain,
230
231
  item.eventPayload?.event?.eventData?.markAsTestEvent
231
232
  ),
@@ -284,6 +285,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
284
285
 
285
286
  case 'client.media.rx.start':
286
287
  joinTimes.localSDPGenRemoteSDPRecv = cdl.getLocalSDPGenRemoteSDPRecv();
288
+ audioSetupDelay.joinRespRxStart = cdl.getAudioJoinRespRxStart();
289
+ videoSetupDelay.joinRespRxStart = cdl.getVideoJoinRespRxStart();
287
290
  break;
288
291
 
289
292
  case 'client.media-engine.ready':
@@ -293,10 +296,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
293
296
  joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
294
297
  break;
295
298
 
296
- case 'client.mediaquality.event':
297
- audioSetupDelay.joinRespRxStart = cdl.getAudioJoinRespRxStart();
299
+ case 'client.media.tx.start':
298
300
  audioSetupDelay.joinRespTxStart = cdl.getAudioJoinRespTxStart();
299
- videoSetupDelay.joinRespRxStart = cdl.getVideoJoinRespRxStart();
300
301
  videoSetupDelay.joinRespTxStart = cdl.getVideoJoinRespTxStart();
301
302
  }
302
303
 
@@ -314,7 +315,6 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
314
315
 
315
316
  item.eventPayload.origin = Object.assign(origin, item.eventPayload.origin);
316
317
 
317
- // @ts-ignore
318
318
  webex.logger.log(
319
319
  `CallDiagnosticLatencies,prepareDiagnosticMetricItem: ${JSON.stringify({
320
320
  latencies: Object.fromEntries(cdl.latencyTimestamps),
@@ -370,12 +370,14 @@ export const extractVersionMetadata = (version: string) => {
370
370
  */
371
371
  export const generateClientErrorCodeForIceFailure = ({
372
372
  signalingState,
373
- iceConnectionState,
373
+ iceConnected,
374
374
  turnServerUsed,
375
+ unreachable,
375
376
  }: {
376
377
  signalingState: RTCPeerConnection['signalingState'];
377
- iceConnectionState: RTCPeerConnection['iceConnectionState'];
378
+ iceConnected: boolean;
378
379
  turnServerUsed: boolean;
380
+ unreachable: boolean;
379
381
  }) => {
380
382
  let errorCode = ICE_FAILURE_CLIENT_CODE; // default;
381
383
 
@@ -383,20 +385,17 @@ export const generateClientErrorCodeForIceFailure = ({
383
385
  errorCode = MISSING_ROAP_ANSWER_CLIENT_CODE;
384
386
  }
385
387
 
386
- if (
387
- signalingState === 'stable' &&
388
- (iceConnectionState === 'connected' || iceConnectionState === 'disconnected')
389
- ) {
388
+ if (signalingState === 'stable' && iceConnected) {
390
389
  errorCode = DTLS_HANDSHAKE_FAILED_CLIENT_CODE;
391
390
  }
392
391
 
393
- if (
394
- signalingState !== 'have-local-offer' &&
395
- iceConnectionState !== 'connected' &&
396
- iceConnectionState !== 'disconnected'
397
- ) {
392
+ if (signalingState !== 'have-local-offer' && !iceConnected) {
398
393
  if (turnServerUsed) {
399
- errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE;
394
+ if (unreachable) {
395
+ errorCode = ICE_AND_REACHABILITY_FAILED_CLIENT_CODE;
396
+ } else {
397
+ errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE;
398
+ }
400
399
  } else {
401
400
  errorCode = ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE;
402
401
  }