@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.
- package/README.md +81 -29
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +22 -41
- package/lib/index.js.map +1 -1
- package/lib/logger/consoleTransport.d.ts +1 -1
- package/lib/logger/consoleTransport.d.ts.map +1 -1
- package/lib/logger/consoleTransport.js +16 -22
- package/lib/logger/consoleTransport.js.map +1 -1
- package/lib/logger/datadogTransport.d.ts +1 -1
- package/lib/logger/datadogTransport.d.ts.map +1 -1
- package/lib/logger/datadogTransport.js +4 -8
- package/lib/logger/datadogTransport.js.map +1 -1
- package/lib/logger/index.js +29 -49
- package/lib/logger/index.js.map +1 -1
- package/lib/logger/index.test.js +16 -18
- package/lib/logger/index.test.js.map +1 -1
- package/lib/logger/utils.js +4 -9
- package/lib/logger/utils.js.map +1 -1
- package/lib/reporters/amplifyReporter.d.ts +4 -4
- package/lib/reporters/amplifyReporter.d.ts.map +1 -1
- package/lib/reporters/amplifyReporter.js +210 -133
- package/lib/reporters/amplifyReporter.js.map +1 -1
- package/lib/reporters/amplifyReporter.test.js +9 -12
- package/lib/reporters/amplifyReporter.test.js.map +1 -1
- package/lib/reporters/datadogReporter.d.ts +1 -1
- package/lib/reporters/datadogReporter.d.ts.map +1 -1
- package/lib/reporters/datadogReporter.js +118 -48
- package/lib/reporters/datadogReporter.js.map +1 -1
- package/lib/reporters/gtmReporter.d.ts +1 -1
- package/lib/reporters/gtmReporter.d.ts.map +1 -1
- package/lib/reporters/gtmReporter.js +1 -5
- package/lib/reporters/gtmReporter.js.map +1 -1
- package/lib/reporters/index.js +46 -71
- package/lib/reporters/index.js.map +1 -1
- package/lib/reporters/logReporter.js +24 -34
- package/lib/reporters/logReporter.js.map +1 -1
- package/lib/types/index.js +2 -18
- package/lib/types/index.js.map +1 -1
- package/lib/types/logger.d.ts +3 -3
- package/lib/types/logger.d.ts.map +1 -1
- package/lib/types/logger.js +2 -5
- package/lib/types/logger.js.map +1 -1
- package/lib/types/reporter.d.ts +6 -6
- package/lib/types/reporter.d.ts.map +1 -1
- package/lib/types/reporter.js +1 -2
- package/lib/utils.js +1 -5
- package/lib/utils.js.map +1 -1
- package/lib/utils.test.js +2 -4
- package/lib/utils.test.js.map +1 -1
- package/package.json +14 -16
- package/src/reporters/amplifyReporter.ts +233 -138
- 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
|
-
|
|
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
|
-
|
|
240
|
+
// Note: sampleRate is not available in newer Datadog versions
|
|
153
241
|
beforeSend: config.beforeLogsSend,
|
|
154
242
|
|
|
155
243
|
useSecureSessionCookie: config.useSecureSessionCookie ?? !isLocalhost,
|
|
156
|
-
|
|
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
|
-
|
|
180
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
309
|
+
datadogLogs.setGlobalContextProperty(key, value);
|
|
222
310
|
} else {
|
|
223
|
-
datadogRum.
|
|
311
|
+
datadogRum.removeGlobalContextProperty(key);
|
|
224
312
|
|
|
225
313
|
// But this is valuable for logs ingested outside of the browser logger.
|
|
226
|
-
datadogLogs.
|
|
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.
|
|
327
|
+
datadogRum.setUser({});
|
|
240
328
|
}
|
|
241
329
|
},
|
|
242
330
|
setRouteName: function (routeName: string): void {
|