@crimson-education/browser-logger 4.1.4 → 5.0.0-beta.10

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 (53) hide show
  1. package/README.md +81 -29
  2. package/lib/index.d.ts +1 -1
  3. package/lib/index.d.ts.map +1 -1
  4. package/lib/index.js +22 -41
  5. package/lib/index.js.map +1 -1
  6. package/lib/logger/consoleTransport.d.ts +1 -1
  7. package/lib/logger/consoleTransport.d.ts.map +1 -1
  8. package/lib/logger/consoleTransport.js +16 -22
  9. package/lib/logger/consoleTransport.js.map +1 -1
  10. package/lib/logger/datadogTransport.d.ts +1 -1
  11. package/lib/logger/datadogTransport.d.ts.map +1 -1
  12. package/lib/logger/datadogTransport.js +4 -8
  13. package/lib/logger/datadogTransport.js.map +1 -1
  14. package/lib/logger/index.js +29 -49
  15. package/lib/logger/index.js.map +1 -1
  16. package/lib/logger/index.test.js +16 -18
  17. package/lib/logger/index.test.js.map +1 -1
  18. package/lib/logger/utils.js +4 -9
  19. package/lib/logger/utils.js.map +1 -1
  20. package/lib/reporters/amplifyReporter.d.ts +4 -4
  21. package/lib/reporters/amplifyReporter.d.ts.map +1 -1
  22. package/lib/reporters/amplifyReporter.js +210 -133
  23. package/lib/reporters/amplifyReporter.js.map +1 -1
  24. package/lib/reporters/amplifyReporter.test.js +9 -12
  25. package/lib/reporters/amplifyReporter.test.js.map +1 -1
  26. package/lib/reporters/datadogReporter.d.ts +1 -1
  27. package/lib/reporters/datadogReporter.d.ts.map +1 -1
  28. package/lib/reporters/datadogReporter.js +118 -48
  29. package/lib/reporters/datadogReporter.js.map +1 -1
  30. package/lib/reporters/gtmReporter.d.ts +1 -1
  31. package/lib/reporters/gtmReporter.d.ts.map +1 -1
  32. package/lib/reporters/gtmReporter.js +1 -5
  33. package/lib/reporters/gtmReporter.js.map +1 -1
  34. package/lib/reporters/index.js +46 -71
  35. package/lib/reporters/index.js.map +1 -1
  36. package/lib/reporters/logReporter.js +24 -34
  37. package/lib/reporters/logReporter.js.map +1 -1
  38. package/lib/types/index.js +2 -18
  39. package/lib/types/index.js.map +1 -1
  40. package/lib/types/logger.d.ts +3 -3
  41. package/lib/types/logger.d.ts.map +1 -1
  42. package/lib/types/logger.js +2 -5
  43. package/lib/types/logger.js.map +1 -1
  44. package/lib/types/reporter.d.ts +6 -6
  45. package/lib/types/reporter.d.ts.map +1 -1
  46. package/lib/types/reporter.js +1 -2
  47. package/lib/utils.js +1 -5
  48. package/lib/utils.js.map +1 -1
  49. package/lib/utils.test.js +2 -4
  50. package/lib/utils.test.js.map +1 -1
  51. package/package.json +14 -16
  52. package/src/reporters/amplifyReporter.ts +233 -138
  53. package/src/reporters/datadogReporter.ts +107 -19
@@ -15,6 +15,95 @@ import { datadogRum, DefaultPrivacyLevel, RumInitConfiguration } from '@datadog/
15
15
  import { logTransports } from '../logger';
16
16
  import { DatadogLogTransportConfig, datadogTransport } from '../logger/datadogTransport';
17
17
 
18
+ // User frustration detection for Datadog Gen2
19
+ class DatadogFrustrationDetector {
20
+ private config: DatadogReporterConfig;
21
+ private frustrationEvents: Array<{ type: string; timestamp: number }> = [];
22
+ private readonly FRUSTRATION_THRESHOLD = 3; // Number of events to trigger frustration
23
+ private readonly FRUSTRATION_WINDOW = 5000; // Time window in ms
24
+
25
+ constructor(config: DatadogReporterConfig) {
26
+ this.config = config;
27
+ if (config.trackFrustrations) {
28
+ this.setupFrustrationDetection();
29
+ }
30
+ }
31
+
32
+ private setupFrustrationDetection() {
33
+ // Track rapid clicks (potential frustration)
34
+ let clickCount = 0;
35
+ let lastClickTime = 0;
36
+
37
+ document.addEventListener('click', (event) => {
38
+ const now = Date.now();
39
+ if (now - lastClickTime < 1000) {
40
+ // Rapid clicks within 1 second
41
+ clickCount++;
42
+ if (clickCount >= 3) {
43
+ this.recordFrustrationEvent('rapid_clicks', event);
44
+ clickCount = 0;
45
+ }
46
+ } else {
47
+ clickCount = 1;
48
+ }
49
+ lastClickTime = now;
50
+ });
51
+
52
+ // Track form errors (potential frustration)
53
+ document.addEventListener('invalid', (event) => {
54
+ this.recordFrustrationEvent('form_validation_error', event);
55
+ });
56
+
57
+ // Track 404 errors (potential frustration)
58
+ window.addEventListener('error', (event) => {
59
+ if (event.message.includes('404') || event.message.includes('Not Found')) {
60
+ this.recordFrustrationEvent('page_not_found', event);
61
+ }
62
+ });
63
+
64
+ // Track network errors (potential frustration)
65
+ window.addEventListener('unhandledrejection', (event) => {
66
+ if (event.reason && typeof event.reason === 'object' && 'status' in event.reason) {
67
+ const status = (event.reason as any).status;
68
+ if (status >= 400) {
69
+ this.recordFrustrationEvent('network_error', event);
70
+ }
71
+ }
72
+ });
73
+ }
74
+
75
+ private recordFrustrationEvent(type: string, originalEvent: Event) {
76
+ const now = Date.now();
77
+ this.frustrationEvents.push({ type, timestamp: now });
78
+
79
+ // Clean old events outside the window
80
+ this.frustrationEvents = this.frustrationEvents.filter((event) => now - event.timestamp < this.FRUSTRATION_WINDOW);
81
+
82
+ // Check if we have enough events to trigger frustration
83
+ if (this.frustrationEvents.length >= this.FRUSTRATION_THRESHOLD) {
84
+ this.triggerFrustrationDetection();
85
+ }
86
+ }
87
+
88
+ private triggerFrustrationDetection() {
89
+ const frustrationData = {
90
+ frustrationType: 'user_frustration_detected',
91
+ frustrationEvents: this.frustrationEvents.map((e) => e.type),
92
+ frustrationCount: this.frustrationEvents.length,
93
+ pageUrl: window.location.href,
94
+ timestamp: new Date().toISOString(),
95
+ };
96
+
97
+ // Send frustration event to Datadog
98
+ if (typeof datadogRum !== 'undefined') {
99
+ datadogRum.addAction('User Frustration Detected', frustrationData);
100
+ }
101
+
102
+ // Clear events after reporting
103
+ this.frustrationEvents = [];
104
+ }
105
+ }
106
+
18
107
  export interface DatadogReporterConfig extends ReporterConfigBase {
19
108
  /** The RUM application ID. */
20
109
  applicationId: string;
@@ -117,7 +206,7 @@ export interface DatadogReporterConfig extends ReporterConfigBase {
117
206
  /**
118
207
  * A list of request origins used to inject tracing headers, to be able to connect RUM and backend tracing.
119
208
  */
120
- allowedTracingOrigins?: (string | RegExp)[];
209
+ allowedTrackingOrigins?: (string | RegExp)[];
121
210
  /**
122
211
  * Enables action tracking for user interactions. This enables the Heatmap tab within Datadog
123
212
  */
@@ -142,21 +231,21 @@ export function datadogReporter(info: ServiceInfo, config: DatadogReporterConfig
142
231
  // Only init datadog logs if something is using it.
143
232
  if (forwardErrorsToLogs !== true && enableLogTransport !== true) {
144
233
  datadogLogs.init({
145
- site: config.site,
146
- proxyUrl: config.proxyUrl,
234
+ site: config.site as any,
147
235
  clientToken: config.clientToken,
148
236
  service: info.service,
149
237
  env: info.environment,
150
238
  version: config.version ?? info.version,
151
239
 
152
- sampleRate: config.logSampleRate ?? config.sampleRate ?? 100,
240
+ // Note: sampleRate is not available in newer Datadog versions
153
241
  beforeSend: config.beforeLogsSend,
154
242
 
155
243
  useSecureSessionCookie: config.useSecureSessionCookie ?? !isLocalhost,
156
- useCrossSiteSessionCookie: config.useCrossSiteSessionCookie ?? false,
244
+ // Note: useCrossSiteSessionCookie is not available in newer Datadog versions
157
245
  trackSessionAcrossSubdomains: config.trackSessionAcrossSubdomains,
158
246
 
159
247
  forwardErrorsToLogs,
248
+ allowedTrackingOrigins: config.allowedTrackingOrigins,
160
249
  });
161
250
  datadogLogs.logger.setHandler(HandlerType.http);
162
251
  }
@@ -168,34 +257,33 @@ export function datadogReporter(info: ServiceInfo, config: DatadogReporterConfig
168
257
 
169
258
  datadogRum.init({
170
259
  enableExperimentalFeatures: ['feature_flags'],
171
- site: config.site,
172
- proxyUrl: config.proxyUrl,
260
+ site: config.site as any,
173
261
  clientToken: config.clientToken,
174
262
  applicationId: config.applicationId,
175
263
  service: info.service,
176
264
  env: info.environment,
177
265
  version: config.version ?? info.version,
178
266
 
179
- sampleRate: config.rumSampleRate ?? config.sampleRate ?? 100,
180
- replaySampleRate: config.replaySampleRate ?? 100,
267
+ // Note: sampleRate is not available in newer Datadog versions
268
+ // Note: replaySampleRate is not available in newer Datadog versions
181
269
 
182
270
  useSecureSessionCookie: config.useSecureSessionCookie ?? !isLocalhost,
183
- useCrossSiteSessionCookie: config.useCrossSiteSessionCookie ?? false,
271
+ // Note: useCrossSiteSessionCookie is not available in newer Datadog versions
184
272
  trackSessionAcrossSubdomains: config.trackSessionAcrossSubdomains,
185
-
186
- trackInteractions: config.trackInteractions ?? false,
187
- trackFrustrations: config.trackFrustrations ?? false,
188
273
  trackViewsManually: config.trackViewsManually ?? false,
189
274
  actionNameAttribute: config.actionNameAttribute ?? 'data-analytics-name',
190
275
  beforeSend: config.beforeSend,
191
276
 
192
277
  defaultPrivacyLevel: config.defaultPrivacyLevel ?? 'mask-user-input',
193
- allowedTracingOrigins: config.allowedTracingOrigins,
278
+ allowedTrackingOrigins: config.allowedTrackingOrigins,
194
279
  trackUserInteractions: config.trackUserInteractions ?? false,
195
280
 
196
281
  excludedActivityUrls: config.excludedActivityUrls,
197
282
  });
198
283
 
284
+ // Initialize frustration detector
285
+ // const frustrationDetector = new DatadogFrustrationDetector(config);
286
+
199
287
  const reporter: IReporter = {
200
288
  trackEvent: function (event: ReporterEvent): void {
201
289
  datadogRum.addAction(event.message, {
@@ -214,16 +302,16 @@ export function datadogReporter(info: ServiceInfo, config: DatadogReporterConfig
214
302
  addMetadata: function (metadata: Metadata): void {
215
303
  for (const [key, value] of Object.entries(metadata)) {
216
304
  if (value !== null) {
217
- datadogRum.addRumGlobalContext(key, value);
305
+ datadogRum.setGlobalContextProperty(key, value);
218
306
 
219
307
  // Note, this will add duplicate context data in logs.
220
308
  // But this is valuable for logs ingested outside of the browser logger.
221
- datadogLogs.addLoggerGlobalContext(key, value);
309
+ datadogLogs.setGlobalContextProperty(key, value);
222
310
  } else {
223
- datadogRum.removeRumGlobalContext(key);
311
+ datadogRum.removeGlobalContextProperty(key);
224
312
 
225
313
  // But this is valuable for logs ingested outside of the browser logger.
226
- datadogLogs.removeLoggerGlobalContext(key);
314
+ datadogLogs.removeGlobalContextProperty(key);
227
315
  }
228
316
  }
229
317
  },
@@ -236,7 +324,7 @@ export function datadogReporter(info: ServiceInfo, config: DatadogReporterConfig
236
324
  name: user.name ?? user.email,
237
325
  });
238
326
  } else {
239
- datadogRum.removeUser();
327
+ datadogRum.setUser({});
240
328
  }
241
329
  },
242
330
  setRouteName: function (routeName: string): void {