@@ -19,6 +19,7 @@ import {
19
19
getJSONTrimmed ,
20
20
generateUUID ,
21
21
handleError ,
22
+ leaveBreadcrumb ,
22
23
getDefaultPageProperties ,
23
24
getUserProvidedConfigUrl ,
24
25
findAllEnabledDestinations ,
@@ -28,12 +29,15 @@ import {
28
29
getReferrer ,
29
30
getReferringDomain ,
30
31
commonNames ,
32
+ get ,
31
33
} from "./utils/utils" ;
32
34
import {
33
35
CONFIG_URL ,
34
36
MAX_WAIT_FOR_INTEGRATION_LOAD ,
35
37
INTEGRATION_LOAD_CHECK_INTERVAL ,
36
38
POLYFILL_URL ,
39
+ DEFAULT_ERROR_REPORT_PROVIDER ,
40
+ ERROR_REPORT_PROVIDERS ,
37
41
} from "./utils/constants" ;
38
42
import { integrations } from "./integrations" ;
39
43
import RudderElementBuilder from "./utils/RudderElementBuilder" ;
@@ -44,6 +48,7 @@ import { addDomEventHandlers } from "./utils/autotrack.js";
44
48
import ScriptLoader from "./integrations/ScriptLoader" ;
45
49
import parseLinker from "./utils/linker" ;
46
50
import CookieConsentFactory from "./cookieConsent/CookieConsentFactory" ;
51
+ import * as BugsnagLib from "./metrics/error-report/Bugsnag" ;
47
52
48
53
const queryDefaults = {
49
54
trait : "ajs_trait_" ,
@@ -167,6 +172,31 @@ class Analytics {
167
172
if ( typeof response === "string" ) {
168
173
response = JSON . parse ( response ) ;
169
174
}
175
+
176
+ // Fetch Error reporting enable option from sourceConfig
177
+ const isErrorReportEnabled = get (
178
+ response . source . config ,
179
+ "statsCollection.errorReports.enabled"
180
+ ) ;
181
+
182
+ // Load Bugsnag only if it is enabled in the source config
183
+ if ( isErrorReportEnabled === true ) {
184
+ // Fetch the name of the Error reporter from sourceConfig
185
+ const provider = get (
186
+ response . source . config ,
187
+ "statsCollection.errorReports.provider"
188
+ ) || DEFAULT_ERROR_REPORT_PROVIDER ;
189
+ if ( ! ERROR_REPORT_PROVIDERS . includes ( provider ) ) {
190
+ logger . error ( "Invalid error reporting provider value" ) ;
191
+ }
192
+
193
+ if ( provider === "bugsnag" ) {
194
+ // Load Bugsnag client SDK
195
+ BugsnagLib . load ( ) ;
196
+ BugsnagLib . init ( response . source . id ) ;
197
+ }
198
+ }
199
+
170
200
if (
171
201
response . source . useAutoTracking &&
172
202
! this . autoTrackHandlersRegistered
@@ -194,15 +224,15 @@ class Analytics {
194
224
this . clientIntegrations
195
225
) ;
196
226
197
- var cookieConsent ;
227
+ let cookieConsent ;
198
228
// Call the cookie consent factory to initialize and return the type of cookie
199
229
// consent being set. For now we only support OneTrust.
200
230
try {
201
231
cookieConsent = CookieConsentFactory . initialize (
202
232
this . cookieConsentOptions
203
233
) ;
204
234
} catch ( e ) {
205
- logger . error ( e ) ;
235
+ handleError ( e ) ;
206
236
}
207
237
208
238
// If cookie consent object is return we filter according to consents given by user
@@ -214,7 +244,7 @@ class Analytics {
214
244
( cookieConsent && cookieConsent . isEnabled ( intg . config ) ) )
215
245
) ;
216
246
} ) ;
217
-
247
+ leaveBreadcrumb ( "Starting device-mode initialization" ) ;
218
248
this . init ( this . clientIntegrations ) ;
219
249
} catch ( error ) {
220
250
handleError ( error ) ;
@@ -254,21 +284,17 @@ class Analytics {
254
284
let intgInstance ;
255
285
intgArray . forEach ( ( intg ) => {
256
286
try {
257
- logger . debug (
258
- "[Analytics] init :: trying to initialize integration name:: " ,
259
- intg . name
260
- ) ;
287
+ const msg = `[Analytics] init :: trying to initialize integration name:: ${ intg . name } ` ;
288
+ logger . debug ( msg ) ;
289
+ leaveBreadcrumb ( msg ) ;
261
290
const intgClass = integrations [ intg . name ] ;
262
291
const destConfig = intg . config ;
263
292
intgInstance = new intgClass ( destConfig , self ) ;
264
293
intgInstance . init ( ) ;
265
294
logger . debug ( "initializing destination: " , intg ) ;
266
295
this . isInitialized ( intgInstance ) . then ( this . replayEvents ) ;
267
296
} catch ( e ) {
268
- logger . error (
269
- "[Analytics] initialize integration (integration.init()) failed :: " ,
270
- intg . name
271
- ) ;
297
+ handleError ( e ) ;
272
298
this . failedToBeLoadedIntegration . push ( intgInstance ) ;
273
299
}
274
300
} ) ;
@@ -289,6 +315,7 @@ class Analytics {
289
315
" failed loaded count: " ,
290
316
object . failedToBeLoadedIntegration . length
291
317
) ;
318
+ leaveBreadcrumb ( `Started replaying buffered events` ) ;
292
319
// eslint-disable-next-line no-param-reassign
293
320
object . clientIntegrationObjects = [ ] ;
294
321
// eslint-disable-next-line no-param-reassign
@@ -412,6 +439,7 @@ class Analytics {
412
439
* @memberof Analytics
413
440
*/
414
441
page ( category , name , properties , options , callback ) {
442
+ leaveBreadcrumb ( `Page event` ) ;
415
443
if ( ! this . loaded ) return ;
416
444
if ( typeof options === "function" ) ( callback = options ) , ( options = null ) ;
417
445
if ( typeof properties === "function" )
@@ -444,6 +472,7 @@ class Analytics {
444
472
* @memberof Analytics
445
473
*/
446
474
track ( event , properties , options , callback ) {
475
+ leaveBreadcrumb ( `Track event` ) ;
447
476
if ( ! this . loaded ) return ;
448
477
if ( typeof options === "function" ) ( callback = options ) , ( options = null ) ;
449
478
if ( typeof properties === "function" )
@@ -462,6 +491,7 @@ class Analytics {
462
491
* @memberof Analytics
463
492
*/
464
493
identify ( userId , traits , options , callback ) {
494
+ leaveBreadcrumb ( `Identify event` ) ;
465
495
if ( ! this . loaded ) return ;
466
496
if ( typeof options === "function" ) ( callback = options ) , ( options = null ) ;
467
497
if ( typeof traits === "function" )
@@ -480,6 +510,7 @@ class Analytics {
480
510
* @param {* } callback
481
511
*/
482
512
alias ( to , from , options , callback ) {
513
+ leaveBreadcrumb ( `Alias event` ) ;
483
514
if ( ! this . loaded ) return ;
484
515
if ( typeof options === "function" ) ( callback = options ) , ( options = null ) ;
485
516
if ( typeof from === "function" )
@@ -507,6 +538,7 @@ class Analytics {
507
538
* @param {* } callback
508
539
*/
509
540
group ( groupId , traits , options , callback ) {
541
+ leaveBreadcrumb ( `Group event` ) ;
510
542
if ( ! this . loaded ) return ;
511
543
if ( ! arguments . length ) return ;
512
544
@@ -705,27 +737,27 @@ class Analytics {
705
737
// Blacklist is choosen for filtering events
706
738
case "blacklistedEvents" :
707
739
if ( Array . isArray ( blacklistedEvents ) ) {
708
- return blacklistedEvents . find (
709
- ( eventObj ) =>
710
- eventObj . eventName . trim ( ) . toUpperCase ( ) === formattedEventName
711
- ) === undefined
712
- ? false
713
- : true ;
714
- } else {
715
- return false ;
740
+ return (
741
+ blacklistedEvents . find (
742
+ ( eventObj ) =>
743
+ eventObj . eventName . trim ( ) . toUpperCase ( ) === formattedEventName
744
+ ) !== undefined
745
+ ) ;
716
746
}
747
+ return false ;
748
+
717
749
// Whitelist is choosen for filtering events
718
750
case "whitelistedEvents" :
719
751
if ( Array . isArray ( whitelistedEvents ) ) {
720
- return whitelistedEvents . find (
721
- ( eventObj ) =>
722
- eventObj . eventName . trim ( ) . toUpperCase ( ) === formattedEventName
723
- ) === undefined
724
- ? true
725
- : false ;
726
- } else {
727
- return true ;
752
+ return (
753
+ whitelistedEvents . find (
754
+ ( eventObj ) =>
755
+ eventObj . eventName . trim ( ) . toUpperCase ( ) === formattedEventName
756
+ ) === undefined
757
+ ) ;
728
758
}
759
+ return true ;
760
+
729
761
default :
730
762
return false ;
731
763
}
@@ -747,7 +779,7 @@ class Analytics {
747
779
748
780
// assign page properties to context
749
781
// rudderElement.message.context.page = getDefaultPageProperties();
750
-
782
+ leaveBreadcrumb ( "Started sending data to destinations" ) ;
751
783
rudderElement . message . context . traits = {
752
784
...this . userTraits ,
753
785
} ;
@@ -792,11 +824,12 @@ class Analytics {
792
824
) ;
793
825
794
826
// try to first send to all integrations, if list populated from BE
795
- try {
796
- succesfulLoadedIntersectClientSuppliedIntegrations . forEach ( ( obj ) => {
827
+
828
+ succesfulLoadedIntersectClientSuppliedIntegrations . forEach ( ( obj ) => {
829
+ try {
797
830
if ( ! obj . isFailed || ! obj . isFailed ( ) ) {
798
831
if ( obj [ type ] ) {
799
- let sendEvent = ! this . IsEventBlackListed (
832
+ const sendEvent = ! this . IsEventBlackListed (
800
833
rudderElement . message . event ,
801
834
obj . name
802
835
) ;
@@ -808,10 +841,11 @@ class Analytics {
808
841
}
809
842
}
810
843
}
811
- } ) ;
812
- } catch ( err ) {
813
- handleError ( { message : `[sendToNative]:${ err } ` } ) ;
814
- }
844
+ } catch ( err ) {
845
+ err . message = `[sendToNative]:: [Destination: ${ obj . name } ]:: "${ err . message } "` ;
846
+ handleError ( err ) ;
847
+ }
848
+ } ) ;
815
849
816
850
// config plane native enabled destinations, still not completely loaded
817
851
// in the page, add the events to a queue and process later
@@ -927,6 +961,8 @@ class Analytics {
927
961
* @memberof Analytics
928
962
*/
929
963
reset ( flag ) {
964
+ leaveBreadcrumb ( `reset API :: flag: ${ flag } ` ) ;
965
+
930
966
if ( ! this . loaded ) return ;
931
967
if ( flag ) {
932
968
this . anonymousId = "" ;
@@ -1012,11 +1048,9 @@ class Analytics {
1012
1048
this . cookieConsentOptions = cloneDeep ( options . cookieConsentManager ) ;
1013
1049
let configUrl = CONFIG_URL ;
1014
1050
if ( ! this . isValidWriteKey ( writeKey ) || ! this . isValidServerUrl ( serverUrl ) ) {
1015
- handleError ( {
1016
- message :
1017
- "[Analytics] load:: Unable to load due to wrong writeKey or serverUrl" ,
1018
- } ) ;
1019
- throw Error ( "failed to initialize" ) ;
1051
+ throw Error (
1052
+ "Unable to load the SDK due to invalid writeKey or serverUrl"
1053
+ ) ;
1020
1054
}
1021
1055
1022
1056
let storageOptions = { } ;
@@ -1104,7 +1138,7 @@ class Analytics {
1104
1138
}
1105
1139
if ( options && options . getSourceConfig ) {
1106
1140
if ( typeof options . getSourceConfig !== "function" ) {
1107
- handleError ( 'option "getSourceConfig" must be a function' ) ;
1141
+ handleError ( new Error ( 'option "getSourceConfig" must be a function' ) ) ;
1108
1142
} else {
1109
1143
const res = options . getSourceConfig ( ) ;
1110
1144
0 commit comments