@webex/internal-plugin-metrics 3.0.0-beta.196 → 3.0.0-beta.198
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/call-diagnostic/call-diagnostic-metrics-batcher.js +5 -83
- package/dist/call-diagnostic/call-diagnostic-metrics-batcher.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.js +76 -3
- package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js +120 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
- package/dist/call-diagnostic/generated-types-temp/ClientEvent.js.map +1 -1
- package/dist/call-diagnostic/generated-types-temp/Event.js.map +1 -1
- package/dist/metrics.js +1 -1
- package/dist/metrics.types.js.map +1 -1
- package/dist/new-metrics.js +64 -0
- package/dist/new-metrics.js.map +1 -1
- package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +24 -0
- package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +21 -0
- package/dist/types/call-diagnostic/generated-types-temp/ClientEvent.d.ts +135 -135
- package/dist/types/call-diagnostic/generated-types-temp/Event.d.ts +379 -379
- package/dist/types/metrics.types.d.ts +5 -0
- package/dist/types/new-metrics.d.ts +36 -0
- package/package.json +8 -8
- package/src/call-diagnostic/call-diagnostic-metrics-batcher.ts +2 -99
- package/src/call-diagnostic/call-diagnostic-metrics.ts +64 -2
- package/src/call-diagnostic/call-diagnostic-metrics.util.ts +132 -1
- package/src/call-diagnostic/generated-types-temp/ClientEvent.ts +1360 -1322
- package/src/call-diagnostic/generated-types-temp/Event.ts +3142 -3049
- package/src/metrics.types.ts +6 -0
- package/src/new-metrics.ts +52 -0
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +145 -46
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +262 -2
- package/test/unit/spec/new-metrics.ts +84 -22
package/src/metrics.types.ts
CHANGED
|
@@ -129,3 +129,9 @@ export type SubmitMQE = (args: {
|
|
|
129
129
|
payload: SubmitMQEPayload;
|
|
130
130
|
options: any;
|
|
131
131
|
}) => void;
|
|
132
|
+
|
|
133
|
+
export type BuildClientEventFetchRequestOptions = (args: {
|
|
134
|
+
name: ClientEvent['name'];
|
|
135
|
+
payload?: RecursivePartial<ClientEvent['payload']>;
|
|
136
|
+
options: SubmitClientEventOptions;
|
|
137
|
+
}) => Promise<any>;
|
package/src/new-metrics.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
SubmitClientEventOptions,
|
|
18
18
|
} from './metrics.types';
|
|
19
19
|
import CallDiagnosticLatencies from './call-diagnostic/call-diagnostic-metrics-latencies';
|
|
20
|
+
import {setMetricTimings} from './call-diagnostic/call-diagnostic-metrics.util';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Metrics plugin to centralize all types of metrics.
|
|
@@ -166,6 +167,57 @@ class Metrics extends WebexPlugin {
|
|
|
166
167
|
|
|
167
168
|
return this.callDiagnosticMetrics.submitClientEvent({name, payload, options});
|
|
168
169
|
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Returns a promise that will resolve to fetch options for submitting a metric.
|
|
173
|
+
*
|
|
174
|
+
* This is to support quickly submitting metrics when the browser/tab is closing.
|
|
175
|
+
* Calling submitClientEvent will not work because there some async steps that will
|
|
176
|
+
* not complete before the browser is closed. Instead, we pre-gather all the
|
|
177
|
+
* information/options needed for the request(s), and then simply and quickly
|
|
178
|
+
* fire the fetch(es) when beforeUnload is triggered.
|
|
179
|
+
*
|
|
180
|
+
* We must use fetch instead of request because fetch has a keepalive option that
|
|
181
|
+
* allows the request it to outlive the page.
|
|
182
|
+
*
|
|
183
|
+
* Note: the timings values will be wrong, but setMetricTimingsAndFetch() will
|
|
184
|
+
* properly adjust them before submitting.
|
|
185
|
+
*
|
|
186
|
+
* @public
|
|
187
|
+
* @param {Object} arg
|
|
188
|
+
* @param {String} arg.name - event name
|
|
189
|
+
* @param {Object} arg.payload - event payload
|
|
190
|
+
* @param {Object} arg.options - other options
|
|
191
|
+
* @returns {Promise} promise that resolves to options to be used with fetch
|
|
192
|
+
*/
|
|
193
|
+
public async buildClientEventFetchRequestOptions({
|
|
194
|
+
name,
|
|
195
|
+
payload,
|
|
196
|
+
options,
|
|
197
|
+
}: {
|
|
198
|
+
name: ClientEvent['name'];
|
|
199
|
+
payload?: RecursivePartial<ClientEvent['payload']>;
|
|
200
|
+
options: SubmitClientEventOptions;
|
|
201
|
+
}): Promise<any> {
|
|
202
|
+
return this.callDiagnosticMetrics.buildClientEventFetchRequestOptions({
|
|
203
|
+
name,
|
|
204
|
+
payload,
|
|
205
|
+
options,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Submits a metric from pre-built request options via the fetch API. Updates
|
|
211
|
+
* the "$timings" and "originTime" values to Date.now() since the existing times
|
|
212
|
+
* were set when the options were built (not submitted).
|
|
213
|
+
|
|
214
|
+
* @param {any} options - the pre-built request options for submitting a metric
|
|
215
|
+
* @returns {Promise} promise that resolves to the response object
|
|
216
|
+
*/
|
|
217
|
+
public setMetricTimingsAndFetch(options: any): Promise<any> {
|
|
218
|
+
// @ts-ignore
|
|
219
|
+
return this.webex.setTimingsAndFetch(setMetricTimings(options));
|
|
220
|
+
}
|
|
169
221
|
}
|
|
170
222
|
|
|
171
223
|
export default Metrics;
|
|
@@ -2,6 +2,7 @@ import sinon from 'sinon';
|
|
|
2
2
|
import {assert} from '@webex/test-helper-chai';
|
|
3
3
|
|
|
4
4
|
import CallDiagnosticMetrics from '../../../../src/call-diagnostic/call-diagnostic-metrics';
|
|
5
|
+
import CallDiagnosticLatencies from '../../../../src/call-diagnostic/call-diagnostic-metrics-latencies';
|
|
5
6
|
import * as Utils from '../../../../src/call-diagnostic/call-diagnostic-metrics.util';
|
|
6
7
|
import {BrowserDetection} from '@webex/common';
|
|
7
8
|
import {getOSNameInternal} from '@webex/internal-plugin-metrics';
|
|
@@ -10,7 +11,10 @@ import uuid from 'uuid';
|
|
|
10
11
|
//@ts-ignore
|
|
11
12
|
global.window = {location: {hostname: 'whatever'}};
|
|
12
13
|
|
|
13
|
-
const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
14
|
+
const {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
15
|
+
const userAgent = `webex-js-sdk/test-webex-version client=Cantina; (os=${getOSName()}/${
|
|
16
|
+
getOSVersion().split('.')[0]
|
|
17
|
+
})`;
|
|
14
18
|
|
|
15
19
|
describe('internal-plugin-metrics', () => {
|
|
16
20
|
describe('CallDiagnosticMetrics', () => {
|
|
@@ -42,13 +46,14 @@ describe('internal-plugin-metrics', () => {
|
|
|
42
46
|
get: () => 'locus-url',
|
|
43
47
|
},
|
|
44
48
|
metrics: {
|
|
45
|
-
submitClientMetrics: sinon.stub()
|
|
49
|
+
submitClientMetrics: sinon.stub(),
|
|
46
50
|
},
|
|
51
|
+
newMetrics: {},
|
|
47
52
|
device: {
|
|
48
53
|
userId: 'userId',
|
|
49
54
|
url: 'deviceUrl',
|
|
50
55
|
orgId: 'orgId',
|
|
51
|
-
}
|
|
56
|
+
},
|
|
52
57
|
},
|
|
53
58
|
meetings: {
|
|
54
59
|
config: {
|
|
@@ -61,7 +66,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
61
66
|
clientName: 'Cantina',
|
|
62
67
|
},
|
|
63
68
|
meetingCollection: {
|
|
64
|
-
get: () => fakeMeeting
|
|
69
|
+
get: () => fakeMeeting,
|
|
65
70
|
},
|
|
66
71
|
geoHintInfo: {
|
|
67
72
|
clientAddress: '1.3.4.5',
|
|
@@ -69,10 +74,16 @@ describe('internal-plugin-metrics', () => {
|
|
|
69
74
|
},
|
|
70
75
|
},
|
|
71
76
|
credentials: {
|
|
72
|
-
isUnverifiedGuest: false
|
|
73
|
-
}
|
|
77
|
+
isUnverifiedGuest: false,
|
|
78
|
+
},
|
|
79
|
+
prepareFetchOptions: sinon.stub().callsFake((opts: any) => ({...opts, foo: 'bar'})),
|
|
74
80
|
};
|
|
75
81
|
|
|
82
|
+
webex.internal.newMetrics.callDiagnosticLatencies = new CallDiagnosticLatencies(
|
|
83
|
+
{},
|
|
84
|
+
{parent: webex}
|
|
85
|
+
);
|
|
86
|
+
|
|
76
87
|
sinon.createSandbox();
|
|
77
88
|
sinon.useFakeTimers(now.getTime());
|
|
78
89
|
cd = new CallDiagnosticMetrics({}, {parent: webex});
|
|
@@ -83,7 +94,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
83
94
|
sinon.restore();
|
|
84
95
|
});
|
|
85
96
|
|
|
86
|
-
describe(
|
|
97
|
+
describe('#getOrigin', () => {
|
|
87
98
|
it('should build origin correctly', () => {
|
|
88
99
|
sinon.stub(Utils, 'anonymizeIPAddress').returns('1.1.1.1');
|
|
89
100
|
|
|
@@ -107,7 +118,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
107
118
|
environment: 'meeting_evn',
|
|
108
119
|
name: 'endpoint',
|
|
109
120
|
networkType: 'unknown',
|
|
110
|
-
userAgent
|
|
121
|
+
userAgent,
|
|
111
122
|
});
|
|
112
123
|
});
|
|
113
124
|
|
|
@@ -130,12 +141,12 @@ describe('internal-plugin-metrics', () => {
|
|
|
130
141
|
},
|
|
131
142
|
name: 'endpoint',
|
|
132
143
|
networkType: 'unknown',
|
|
133
|
-
userAgent
|
|
144
|
+
userAgent,
|
|
134
145
|
});
|
|
135
146
|
});
|
|
136
|
-
})
|
|
147
|
+
});
|
|
137
148
|
|
|
138
|
-
describe(
|
|
149
|
+
describe('#getIdentifiers', () => {
|
|
139
150
|
it('should build identifiers correctly', () => {
|
|
140
151
|
const res = cd.getIdentifiers({
|
|
141
152
|
mediaConnections: [
|
|
@@ -159,7 +170,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
159
170
|
|
|
160
171
|
it('should build identifiers correctly given correlationId', () => {
|
|
161
172
|
const res = cd.getIdentifiers({
|
|
162
|
-
correlationId: 'correlationId'
|
|
173
|
+
correlationId: 'correlationId',
|
|
163
174
|
});
|
|
164
175
|
|
|
165
176
|
assert.deepEqual(res, {
|
|
@@ -181,7 +192,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
181
192
|
})
|
|
182
193
|
);
|
|
183
194
|
});
|
|
184
|
-
})
|
|
195
|
+
});
|
|
185
196
|
|
|
186
197
|
it('should prepare diagnostic event successfully', () => {
|
|
187
198
|
const options = {meetingId: fakeMeeting.id};
|
|
@@ -308,7 +319,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
308
319
|
sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
|
|
309
320
|
|
|
310
321
|
const options = {
|
|
311
|
-
|
|
322
|
+
correlationId: 'correlationId',
|
|
312
323
|
};
|
|
313
324
|
|
|
314
325
|
cd.submitClientEvent({
|
|
@@ -405,15 +416,17 @@ describe('internal-plugin-metrics', () => {
|
|
|
405
416
|
orgId: 'orgId',
|
|
406
417
|
userId: 'userId',
|
|
407
418
|
},
|
|
408
|
-
errors: [
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
419
|
+
errors: [
|
|
420
|
+
{
|
|
421
|
+
category: 'expected',
|
|
422
|
+
errorDescription: 'StartRecordingFailed',
|
|
423
|
+
fatal: true,
|
|
424
|
+
name: 'other',
|
|
425
|
+
shownToUser: false,
|
|
426
|
+
serviceErrorCode: 2409005,
|
|
427
|
+
errorCode: 4029,
|
|
428
|
+
},
|
|
429
|
+
],
|
|
417
430
|
loginType: 'login-ci',
|
|
418
431
|
name: 'client.alert.displayed',
|
|
419
432
|
userType: 'host',
|
|
@@ -431,7 +444,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
431
444
|
});
|
|
432
445
|
});
|
|
433
446
|
|
|
434
|
-
it('should include
|
|
447
|
+
it('should include errors in payload if provided via payload', () => {
|
|
435
448
|
sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
|
|
436
449
|
const submitToCallDiagnosticsSpy = sinon.spy(cd, 'submitToCallDiagnostics');
|
|
437
450
|
|
|
@@ -443,12 +456,14 @@ describe('internal-plugin-metrics', () => {
|
|
|
443
456
|
cd.submitClientEvent({
|
|
444
457
|
name: 'client.alert.displayed',
|
|
445
458
|
payload: {
|
|
446
|
-
errors: [
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
459
|
+
errors: [
|
|
460
|
+
{
|
|
461
|
+
name: 'locus.response',
|
|
462
|
+
fatal: true,
|
|
463
|
+
category: 'signaling',
|
|
464
|
+
shownToUser: false,
|
|
465
|
+
},
|
|
466
|
+
],
|
|
452
467
|
},
|
|
453
468
|
options,
|
|
454
469
|
});
|
|
@@ -470,12 +485,14 @@ describe('internal-plugin-metrics', () => {
|
|
|
470
485
|
orgId: 'orgId',
|
|
471
486
|
userId: 'userId',
|
|
472
487
|
},
|
|
473
|
-
errors: [
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
488
|
+
errors: [
|
|
489
|
+
{
|
|
490
|
+
name: 'locus.response',
|
|
491
|
+
fatal: true,
|
|
492
|
+
category: 'signaling',
|
|
493
|
+
shownToUser: false,
|
|
494
|
+
},
|
|
495
|
+
],
|
|
479
496
|
loginType: 'login-ci',
|
|
480
497
|
name: 'client.alert.displayed',
|
|
481
498
|
userType: 'host',
|
|
@@ -491,7 +508,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
491
508
|
senderCountryCode: 'UK',
|
|
492
509
|
version: 1,
|
|
493
510
|
});
|
|
494
|
-
})
|
|
511
|
+
});
|
|
495
512
|
|
|
496
513
|
it('should throw if meetingId nor correlationId not provided', () => {
|
|
497
514
|
assert.throws(() =>
|
|
@@ -512,7 +529,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
512
529
|
fields: {meetingId: 'meetingId', name: 'client.alert.displayed'},
|
|
513
530
|
}
|
|
514
531
|
);
|
|
515
|
-
})
|
|
532
|
+
});
|
|
516
533
|
});
|
|
517
534
|
|
|
518
535
|
it('should send request to call diagnostic batcher', () => {
|
|
@@ -528,7 +545,10 @@ describe('internal-plugin-metrics', () => {
|
|
|
528
545
|
it('submits the event correctly', () => {
|
|
529
546
|
const prepareDiagnosticEventSpy = sinon.spy(cd, 'prepareDiagnosticEvent');
|
|
530
547
|
const submitToCallDiagnosticsSpy = sinon.spy(cd, 'submitToCallDiagnostics');
|
|
531
|
-
const getErrorPayloadForClientErrorCodeSpy = sinon.spy(
|
|
548
|
+
const getErrorPayloadForClientErrorCodeSpy = sinon.spy(
|
|
549
|
+
cd,
|
|
550
|
+
'getErrorPayloadForClientErrorCode'
|
|
551
|
+
);
|
|
532
552
|
const getIdentifiersSpy = sinon.spy(cd, 'getIdentifiers');
|
|
533
553
|
sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
|
|
534
554
|
const options = {
|
|
@@ -639,11 +659,14 @@ describe('internal-plugin-metrics', () => {
|
|
|
639
659
|
fields: {meetingId: 'meetingId', name: 'client.mediaquality.event'},
|
|
640
660
|
}
|
|
641
661
|
);
|
|
642
|
-
})
|
|
662
|
+
});
|
|
643
663
|
});
|
|
644
664
|
describe('#getErrorPayloadForClientErrorCode', () => {
|
|
645
665
|
it('it should grab the payload for client error code correctly', () => {
|
|
646
|
-
const res = cd.getErrorPayloadForClientErrorCode({
|
|
666
|
+
const res = cd.getErrorPayloadForClientErrorCode({
|
|
667
|
+
clientErrorCode: 4008,
|
|
668
|
+
serviceErrorCode: 10000,
|
|
669
|
+
});
|
|
647
670
|
assert.deepEqual(res, {
|
|
648
671
|
category: 'signaling',
|
|
649
672
|
errorDescription: 'NewLocusError',
|
|
@@ -656,7 +679,10 @@ describe('internal-plugin-metrics', () => {
|
|
|
656
679
|
});
|
|
657
680
|
|
|
658
681
|
it('it should return undefined if trying to get payload for client error code that doesnt exist', () => {
|
|
659
|
-
const res = cd.getErrorPayloadForClientErrorCode({
|
|
682
|
+
const res = cd.getErrorPayloadForClientErrorCode({
|
|
683
|
+
clientErrorCode: 123456,
|
|
684
|
+
serviceErrorCode: 100000,
|
|
685
|
+
});
|
|
660
686
|
assert.deepEqual(res, undefined);
|
|
661
687
|
});
|
|
662
688
|
});
|
|
@@ -671,7 +697,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
671
697
|
name: 'other',
|
|
672
698
|
shownToUser: false,
|
|
673
699
|
errorCode: 4029,
|
|
674
|
-
serviceErrorCode: 2409005
|
|
700
|
+
serviceErrorCode: 2409005,
|
|
675
701
|
});
|
|
676
702
|
});
|
|
677
703
|
|
|
@@ -688,7 +714,6 @@ describe('internal-plugin-metrics', () => {
|
|
|
688
714
|
});
|
|
689
715
|
});
|
|
690
716
|
|
|
691
|
-
|
|
692
717
|
it('should return default meeting info lookup error payload correctly if not locus error', () => {
|
|
693
718
|
const res = cd.generateClientEventErrorPayload({body: {errorCode: 9400000}});
|
|
694
719
|
assert.deepEqual(res, {
|
|
@@ -716,7 +741,81 @@ describe('internal-plugin-metrics', () => {
|
|
|
716
741
|
it('returns unverified guest', () => {
|
|
717
742
|
webex.credentials.isUnverifiedGuest = true;
|
|
718
743
|
assert.deepEqual(cd.getCurLoginType(), 'unverified-guest');
|
|
719
|
-
})
|
|
720
|
-
})
|
|
744
|
+
});
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
describe('#buildClientEventFetchRequestOptions', () => {
|
|
748
|
+
it('returns expected options', async () => {
|
|
749
|
+
const options = {
|
|
750
|
+
meetingId: fakeMeeting.id,
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
const triggered = new Date();
|
|
754
|
+
const fetchOptions = await cd.buildClientEventFetchRequestOptions({
|
|
755
|
+
name: 'client.exit.app',
|
|
756
|
+
payload: {trigger: 'user-interaction', canProceed: false},
|
|
757
|
+
options,
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
assert.deepEqual(fetchOptions, {
|
|
761
|
+
body: {
|
|
762
|
+
metrics: [
|
|
763
|
+
{
|
|
764
|
+
eventPayload: {
|
|
765
|
+
event: {
|
|
766
|
+
canProceed: false,
|
|
767
|
+
eventData: {
|
|
768
|
+
webClientDomain: 'whatever',
|
|
769
|
+
},
|
|
770
|
+
identifiers: {
|
|
771
|
+
correlationId: 'correlationId',
|
|
772
|
+
deviceId: 'deviceUrl',
|
|
773
|
+
locusId: 'url',
|
|
774
|
+
locusStartTime: 'lastActive',
|
|
775
|
+
locusUrl: 'locus/url',
|
|
776
|
+
orgId: 'orgId',
|
|
777
|
+
userId: 'userId',
|
|
778
|
+
},
|
|
779
|
+
loginType: 'login-ci',
|
|
780
|
+
name: 'client.exit.app',
|
|
781
|
+
trigger: 'user-interaction',
|
|
782
|
+
userType: 'host',
|
|
783
|
+
},
|
|
784
|
+
eventId: 'my-fake-id',
|
|
785
|
+
origin: {
|
|
786
|
+
buildType: 'test',
|
|
787
|
+
clientInfo: {
|
|
788
|
+
clientType: 'TEAMS_CLIENT',
|
|
789
|
+
clientVersion: 'webex-js-sdk/webex-version',
|
|
790
|
+
localNetworkPrefix:
|
|
791
|
+
Utils.anonymizeIPAddress(webex.meetings.geoHintInfo?.clientAddress) ||
|
|
792
|
+
undefined,
|
|
793
|
+
os: getOSNameInternal() || 'unknown',
|
|
794
|
+
osVersion: getOSVersion(),
|
|
795
|
+
subClientType: 'WEB_APP',
|
|
796
|
+
},
|
|
797
|
+
environment: 'meeting_evn',
|
|
798
|
+
name: 'endpoint',
|
|
799
|
+
networkType: 'unknown',
|
|
800
|
+
userAgent,
|
|
801
|
+
},
|
|
802
|
+
originTime: {
|
|
803
|
+
sent: 'not_defined_yet',
|
|
804
|
+
triggered: triggered.toISOString(),
|
|
805
|
+
},
|
|
806
|
+
senderCountryCode: webex.meetings.geoHintInfo?.countryCode,
|
|
807
|
+
version: 1,
|
|
808
|
+
},
|
|
809
|
+
type: ['diagnostic-event'],
|
|
810
|
+
},
|
|
811
|
+
],
|
|
812
|
+
},
|
|
813
|
+
foo: 'bar',
|
|
814
|
+
method: 'POST',
|
|
815
|
+
resource: 'clientmetrics',
|
|
816
|
+
service: 'metrics',
|
|
817
|
+
});
|
|
818
|
+
});
|
|
819
|
+
});
|
|
721
820
|
});
|
|
722
821
|
});
|