@multiplayer-app/session-recorder-browser 1.2.25 → 1.2.27
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 +26 -0
- package/dist/browser/index.js +105 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/exporters/index.js +1 -1
- package/dist/exporters/index.js.map +1 -1
- package/dist/index.js +105 -1
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +105 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/otel/index.d.ts +8 -0
- package/dist/otel/index.d.ts.map +1 -1
- package/dist/otel/index.js +66 -0
- package/dist/otel/index.js.map +1 -1
- package/dist/sessionRecorder.d.ts +6 -0
- package/dist/sessionRecorder.d.ts.map +1 -1
- package/dist/sessionRecorder.js +36 -1
- package/dist/sessionRecorder.js.map +1 -1
- package/dist/types/sessionRecorder.d.ts +4 -0
- package/dist/types/sessionRecorder.d.ts.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -259,6 +259,32 @@ SessionRecorder.save()
|
|
|
259
259
|
SessionRecorder.stop('Finished session') // optional: pass reason for stopping the session
|
|
260
260
|
```
|
|
261
261
|
|
|
262
|
+
### Capture exceptions
|
|
263
|
+
|
|
264
|
+
The browser SDK captures uncaught errors and unhandled promise rejections automatically and turns them into error traces that are linked to your session.
|
|
265
|
+
|
|
266
|
+
For each error span we record:
|
|
267
|
+
|
|
268
|
+
- status set to `ERROR`
|
|
269
|
+
- standard exception attributes: `exception.type`, `exception.message`, `exception.stacktrace`
|
|
270
|
+
|
|
271
|
+
Manual reporting (e.g. inside try/catch or library boundaries):
|
|
272
|
+
|
|
273
|
+
```javascript
|
|
274
|
+
import SessionRecorder from '@multiplayer-app/session-recorder-browser'
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
// code that may throw
|
|
278
|
+
} catch (err) {
|
|
279
|
+
SessionRecorder.captureException(err) // Error | unknown | string
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// You can also send arbitrary reasons
|
|
283
|
+
SessionRecorder.captureException('Payment form validation failed')
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
When running in `CONTINUOUS` mode, any captured exception automatically marks the current trace as an error and auto‑saves the rolling window so you can replay the seconds leading up to the failure.
|
|
287
|
+
|
|
262
288
|
Continuous session recordings may also be saved from within any service or component involved in a trace by adding the attributes below to a span:
|
|
263
289
|
|
|
264
290
|
```javascript
|
package/dist/browser/index.js
CHANGED
|
@@ -25243,7 +25243,7 @@ const DEFAULT_MAX_HTTP_CAPTURING_PAYLOAD_SIZE = 100000;
|
|
|
25243
25243
|
const SESSION_RESPONSE = 'multiplayer-debug-session-response';
|
|
25244
25244
|
const CONTINUOUS_DEBUGGING_TIMEOUT = 60000; // 1 minutes
|
|
25245
25245
|
const DEBUG_SESSION_MAX_DURATION_SECONDS = 10 * 60 + 30; // TODO: move to shared config otel core
|
|
25246
|
-
const PACKAGE_VERSION_EXPORT = "1.2.
|
|
25246
|
+
const PACKAGE_VERSION_EXPORT = "1.2.27" || 0;
|
|
25247
25247
|
// Regex patterns for OpenTelemetry ignore URLs
|
|
25248
25248
|
const OTEL_IGNORE_URLS = [
|
|
25249
25249
|
// Traces endpoint
|
|
@@ -26128,6 +26128,9 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
26128
26128
|
/* harmony import */ var _opentelemetry_instrumentation__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @opentelemetry/instrumentation */ "../../node_modules/@opentelemetry/instrumentation/build/esm/autoLoader.js");
|
|
26129
26129
|
/* harmony import */ var _opentelemetry_auto_instrumentations_web__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @opentelemetry/auto-instrumentations-web */ "../../node_modules/@opentelemetry/auto-instrumentations-web/build/esm/index.js");
|
|
26130
26130
|
/* harmony import */ var _multiplayer_app_session_recorder_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @multiplayer-app/session-recorder-common */ "../session-recorder-common/dist/esm/index-browser.js");
|
|
26131
|
+
/* harmony import */ var _opentelemetry_api__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @opentelemetry/api */ "../../node_modules/@opentelemetry/api/build/esm/trace-api.js");
|
|
26132
|
+
/* harmony import */ var _opentelemetry_api__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @opentelemetry/api */ "../../node_modules/@opentelemetry/api/build/esm/context-api.js");
|
|
26133
|
+
/* harmony import */ var _opentelemetry_api__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @opentelemetry/api */ "../../node_modules/@opentelemetry/api/build/esm/trace/status.js");
|
|
26131
26134
|
/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../config */ "./src/config/index.ts");
|
|
26132
26135
|
/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./helpers */ "./src/otel/helpers.ts");
|
|
26133
26136
|
|
|
@@ -26140,10 +26143,13 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
26140
26143
|
|
|
26141
26144
|
|
|
26142
26145
|
|
|
26146
|
+
|
|
26147
|
+
|
|
26143
26148
|
class TracerBrowserSDK {
|
|
26144
26149
|
constructor() {
|
|
26145
26150
|
this.allowedElements = new Set(['A', 'BUTTON']);
|
|
26146
26151
|
this.sessionId = '';
|
|
26152
|
+
this.globalErrorListenersRegistered = false;
|
|
26147
26153
|
}
|
|
26148
26154
|
setSessionId(sessionId, sessionType = _multiplayer_app_session_recorder_common__WEBPACK_IMPORTED_MODULE_1__.SessionType.PLAIN) {
|
|
26149
26155
|
this.sessionId = sessionId;
|
|
@@ -26282,6 +26288,7 @@ class TracerBrowserSDK {
|
|
|
26282
26288
|
}),
|
|
26283
26289
|
],
|
|
26284
26290
|
});
|
|
26291
|
+
this._registerGlobalErrorListeners();
|
|
26285
26292
|
}
|
|
26286
26293
|
start(sessionId, sessionType) {
|
|
26287
26294
|
if (!this.tracerProvider) {
|
|
@@ -26301,6 +26308,46 @@ class TracerBrowserSDK {
|
|
|
26301
26308
|
}
|
|
26302
26309
|
this.exporter.setApiKey(apiKey);
|
|
26303
26310
|
}
|
|
26311
|
+
/**
|
|
26312
|
+
* Capture an exception as an error span/event.
|
|
26313
|
+
* If there is an active span, the exception will be recorded on it.
|
|
26314
|
+
* Otherwise, a short-lived span will be created to hold the exception event.
|
|
26315
|
+
*/
|
|
26316
|
+
captureException(error, errorInfo) {
|
|
26317
|
+
if (!error)
|
|
26318
|
+
return;
|
|
26319
|
+
// Prefer attaching to the active span to keep correlation intact
|
|
26320
|
+
try {
|
|
26321
|
+
const activeSpan = _opentelemetry_api__WEBPACK_IMPORTED_MODULE_10__.trace.getSpan(_opentelemetry_api__WEBPACK_IMPORTED_MODULE_11__.context.active());
|
|
26322
|
+
if (activeSpan) {
|
|
26323
|
+
// Standard OTEL exception event + span status
|
|
26324
|
+
_multiplayer_app_session_recorder_common__WEBPACK_IMPORTED_MODULE_1__.SessionRecorderSdk.captureException(error);
|
|
26325
|
+
activeSpan.addEvent('exception', {
|
|
26326
|
+
'exception.type': error.name || 'Error',
|
|
26327
|
+
'exception.message': error.message,
|
|
26328
|
+
'exception.stacktrace': error.stack || '',
|
|
26329
|
+
...(errorInfo || {}),
|
|
26330
|
+
});
|
|
26331
|
+
return;
|
|
26332
|
+
}
|
|
26333
|
+
}
|
|
26334
|
+
catch (_ignored) { }
|
|
26335
|
+
// Fallback: create a short-lived span to hold the exception details
|
|
26336
|
+
try {
|
|
26337
|
+
const tracer = _opentelemetry_api__WEBPACK_IMPORTED_MODULE_10__.trace.getTracer('exception');
|
|
26338
|
+
const span = tracer.startSpan(error.name || 'Error');
|
|
26339
|
+
span.recordException(error);
|
|
26340
|
+
span.setStatus({ code: _opentelemetry_api__WEBPACK_IMPORTED_MODULE_12__.SpanStatusCode.ERROR, message: error.message });
|
|
26341
|
+
span.addEvent('exception', {
|
|
26342
|
+
'exception.type': error.name || 'Error',
|
|
26343
|
+
'exception.message': error.message,
|
|
26344
|
+
'exception.stacktrace': error.stack || '',
|
|
26345
|
+
...(errorInfo || {}),
|
|
26346
|
+
});
|
|
26347
|
+
span.end();
|
|
26348
|
+
}
|
|
26349
|
+
catch (_ignored) { }
|
|
26350
|
+
}
|
|
26304
26351
|
_getSpanSessionIdProcessor() {
|
|
26305
26352
|
return {
|
|
26306
26353
|
forceFlush: () => Promise.resolve(),
|
|
@@ -26314,6 +26361,28 @@ class TracerBrowserSDK {
|
|
|
26314
26361
|
},
|
|
26315
26362
|
};
|
|
26316
26363
|
}
|
|
26364
|
+
_registerGlobalErrorListeners() {
|
|
26365
|
+
if (this.globalErrorListenersRegistered)
|
|
26366
|
+
return;
|
|
26367
|
+
if (typeof window === 'undefined')
|
|
26368
|
+
return;
|
|
26369
|
+
const errorHandler = (event) => {
|
|
26370
|
+
const err = (event === null || event === void 0 ? void 0 : event.error) instanceof Error
|
|
26371
|
+
? event.error
|
|
26372
|
+
: new Error((event === null || event === void 0 ? void 0 : event.message) || 'Script error');
|
|
26373
|
+
this.captureException(err);
|
|
26374
|
+
};
|
|
26375
|
+
const rejectionHandler = (event) => {
|
|
26376
|
+
const reason = (event && 'reason' in event) ? event.reason : undefined;
|
|
26377
|
+
const err = reason instanceof Error
|
|
26378
|
+
? reason
|
|
26379
|
+
: new Error(typeof reason === 'string' ? reason : 'Unhandled promise rejection');
|
|
26380
|
+
this.captureException(err);
|
|
26381
|
+
};
|
|
26382
|
+
window.addEventListener('error', errorHandler);
|
|
26383
|
+
window.addEventListener('unhandledrejection', rejectionHandler);
|
|
26384
|
+
this.globalErrorListenersRegistered = true;
|
|
26385
|
+
}
|
|
26317
26386
|
}
|
|
26318
26387
|
|
|
26319
26388
|
|
|
@@ -27523,6 +27592,19 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_14__.Obse
|
|
|
27523
27592
|
set recordingButtonClickHandler(handler) {
|
|
27524
27593
|
this._sessionWidget.buttonClickExternalHandler = handler;
|
|
27525
27594
|
}
|
|
27595
|
+
/**
|
|
27596
|
+
* Capture an exception manually and send it as an error trace.
|
|
27597
|
+
*/
|
|
27598
|
+
captureException(error, errorInfo) {
|
|
27599
|
+
try {
|
|
27600
|
+
const normalizedError = this._normalizeError(error);
|
|
27601
|
+
const normalizedErrorInfo = this._normalizeErrorInfo(errorInfo);
|
|
27602
|
+
this._tracer.captureException(normalizedError, normalizedErrorInfo);
|
|
27603
|
+
}
|
|
27604
|
+
catch (e) {
|
|
27605
|
+
this.error = (e === null || e === void 0 ? void 0 : e.message) || 'Failed to capture exception';
|
|
27606
|
+
}
|
|
27607
|
+
}
|
|
27526
27608
|
/**
|
|
27527
27609
|
* @description Check if session should be started/stopped automatically
|
|
27528
27610
|
* @param {ISession} [sessionPayload]
|
|
@@ -27770,6 +27852,28 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_14__.Obse
|
|
|
27770
27852
|
break;
|
|
27771
27853
|
}
|
|
27772
27854
|
}
|
|
27855
|
+
_normalizeError(error) {
|
|
27856
|
+
if (error instanceof Error)
|
|
27857
|
+
return error;
|
|
27858
|
+
if (typeof error === 'string')
|
|
27859
|
+
return new Error(error);
|
|
27860
|
+
try {
|
|
27861
|
+
return new Error(JSON.stringify(error));
|
|
27862
|
+
}
|
|
27863
|
+
catch (_e) {
|
|
27864
|
+
return new Error(String(error));
|
|
27865
|
+
}
|
|
27866
|
+
}
|
|
27867
|
+
_normalizeErrorInfo(errorInfo) {
|
|
27868
|
+
if (!errorInfo)
|
|
27869
|
+
return {};
|
|
27870
|
+
try {
|
|
27871
|
+
return JSON.parse(JSON.stringify(errorInfo));
|
|
27872
|
+
}
|
|
27873
|
+
catch (_e) {
|
|
27874
|
+
return { errorInfo: String(errorInfo) };
|
|
27875
|
+
}
|
|
27876
|
+
}
|
|
27773
27877
|
}
|
|
27774
27878
|
|
|
27775
27879
|
|