@grafana/faro-react-native 1.2.1 → 1.3.1
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/android/build.gradle +118 -36
- package/android/consumer-proguard-rules.pro +2 -0
- package/android/src/main/java/com/grafana/faro/reactnative/ANRTracker.kt +61 -9
- package/android/src/main/java/com/grafana/faro/reactnative/AnrThreadDumpParser.kt +70 -0
- package/android/src/main/java/com/grafana/faro/reactnative/ApplicationExitTraceReader.kt +142 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroAnrCache.kt +163 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroAnrReporter.kt +163 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashReporter.kt +243 -50
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashTraceCache.kt +75 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroNativeCrashTrace.kt +39 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroReactNativeModule.kt +99 -8
- package/android/src/main/java/com/grafana/faro/reactnative/FaroReactNativePackage.kt +1 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroUncaughtExceptionHandler.kt +62 -0
- package/android/src/main/java/com/grafana/faro/reactnative/TombstoneBacktraceFormatter.kt +117 -0
- package/android/src/main/java/com/grafana/faro/reactnative/TombstoneModels.kt +35 -0
- package/android/src/main/java/com/grafana/faro/reactnative/TombstoneWireParser.kt +235 -0
- package/android/src/main/proto/tombstone.proto +62 -0
- package/android/src/test/java/com/grafana/faro/reactnative/AnrStackFiltersTest.kt +28 -0
- package/android/src/test/java/com/grafana/faro/reactnative/AnrThreadDumpParserTest.kt +38 -0
- package/android/src/test/java/com/grafana/faro/reactnative/FaroAnrCacheTest.kt +81 -0
- package/android/src/test/java/com/grafana/faro/reactnative/TombstoneWireParserTest.kt +51 -0
- package/dist/cjs/config/getRNInstrumentations.js +3 -1
- package/dist/cjs/config/getRNInstrumentations.js.map +1 -1
- package/dist/cjs/config/makeRNConfig.js +48 -9
- package/dist/cjs/config/makeRNConfig.js.map +1 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/generated/faroRNPackageMeta.js +1 -1
- package/dist/cjs/generated/faroRNPackageMeta.js.map +1 -1
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/initialize.js +14 -8
- package/dist/cjs/initialize.js.map +1 -1
- package/dist/cjs/instrumentations/anr/anrStack.js +19 -0
- package/dist/cjs/instrumentations/anr/anrStack.js.map +1 -0
- package/dist/cjs/instrumentations/anr/instrumentation.js +374 -72
- package/dist/cjs/instrumentations/anr/instrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/anr/types.js.map +1 -1
- package/dist/cjs/instrumentations/console/index.js +5 -1
- package/dist/cjs/instrumentations/console/index.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/{instrumentation.js → BaseCrashReportingInstrumentation.js} +110 -103
- package/dist/cjs/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js +41 -0
- package/dist/cjs/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +87 -0
- package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/crashErrorMessage.js +123 -0
- package/dist/cjs/instrumentations/crashReporting/android/crashErrorMessage.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/index.js +12 -0
- package/dist/cjs/instrumentations/crashReporting/android/index.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/nativeTombstoneTrace.js +11 -0
- package/dist/cjs/instrumentations/crashReporting/android/nativeTombstoneTrace.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/parseAndroidCrashTrace.js +181 -0
- package/dist/cjs/instrumentations/crashReporting/android/parseAndroidCrashTrace.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/index.js +35 -2
- package/dist/cjs/instrumentations/crashReporting/index.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +78 -0
- package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/ios/crashErrorMessage.js +103 -0
- package/dist/cjs/instrumentations/crashReporting/ios/crashErrorMessage.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/ios/index.js +11 -0
- package/dist/cjs/instrumentations/crashReporting/ios/index.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/ios/parseIosCrashTrace.js +48 -0
- package/dist/cjs/instrumentations/crashReporting/ios/parseIosCrashTrace.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/types.js.map +1 -1
- package/dist/cjs/instrumentations/errors/index.js +2 -1
- package/dist/cjs/instrumentations/errors/index.js.map +1 -1
- package/dist/cjs/instrumentations/session/installationId.js +91 -0
- package/dist/cjs/instrumentations/session/installationId.js.map +1 -0
- package/dist/cjs/instrumentations/session/sessionAttributes.js +152 -89
- package/dist/cjs/instrumentations/session/sessionAttributes.js.map +1 -1
- package/dist/cjs/metas/appBuildIdentity.js +95 -0
- package/dist/cjs/metas/appBuildIdentity.js.map +1 -0
- package/dist/cjs/testUtils/mockDeviceInfo.js +5 -0
- package/dist/cjs/testUtils/mockDeviceInfo.js.map +1 -1
- package/dist/cjs/testUtils/setupTests.js +7 -0
- package/dist/cjs/testUtils/setupTests.js.map +1 -1
- package/dist/esm/config/getRNInstrumentations.js +3 -1
- package/dist/esm/config/getRNInstrumentations.js.map +1 -1
- package/dist/esm/config/makeRNConfig.js +49 -10
- package/dist/esm/config/makeRNConfig.js.map +1 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/generated/faroRNPackageMeta.js +1 -1
- package/dist/esm/generated/faroRNPackageMeta.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/initialize.js +11 -5
- package/dist/esm/initialize.js.map +1 -1
- package/dist/esm/instrumentations/anr/anrStack.js +16 -0
- package/dist/esm/instrumentations/anr/anrStack.js.map +1 -0
- package/dist/esm/instrumentations/anr/instrumentation.js +260 -67
- package/dist/esm/instrumentations/anr/instrumentation.js.map +1 -1
- package/dist/esm/instrumentations/anr/types.js.map +1 -1
- package/dist/esm/instrumentations/console/index.js +5 -1
- package/dist/esm/instrumentations/console/index.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/{instrumentation.js → BaseCrashReportingInstrumentation.js} +76 -94
- package/dist/esm/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js +18 -0
- package/dist/esm/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +56 -0
- package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/crashErrorMessage.js +116 -0
- package/dist/esm/instrumentations/crashReporting/android/crashErrorMessage.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/index.js +4 -0
- package/dist/esm/instrumentations/crashReporting/android/index.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/nativeTombstoneTrace.js +8 -0
- package/dist/esm/instrumentations/crashReporting/android/nativeTombstoneTrace.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/parseAndroidCrashTrace.js +174 -0
- package/dist/esm/instrumentations/crashReporting/android/parseAndroidCrashTrace.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/index.js +35 -1
- package/dist/esm/instrumentations/crashReporting/index.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +56 -0
- package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/ios/crashErrorMessage.js +98 -0
- package/dist/esm/instrumentations/crashReporting/ios/crashErrorMessage.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/ios/index.js +4 -0
- package/dist/esm/instrumentations/crashReporting/ios/index.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/ios/parseIosCrashTrace.js +44 -0
- package/dist/esm/instrumentations/crashReporting/ios/parseIosCrashTrace.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/types.js.map +1 -1
- package/dist/esm/instrumentations/errors/index.js +2 -1
- package/dist/esm/instrumentations/errors/index.js.map +1 -1
- package/dist/esm/instrumentations/session/installationId.js +48 -0
- package/dist/esm/instrumentations/session/installationId.js.map +1 -0
- package/dist/esm/instrumentations/session/sessionAttributes.js +83 -38
- package/dist/esm/instrumentations/session/sessionAttributes.js.map +1 -1
- package/dist/esm/metas/appBuildIdentity.js +56 -0
- package/dist/esm/metas/appBuildIdentity.js.map +1 -0
- package/dist/esm/testUtils/mockDeviceInfo.js +5 -0
- package/dist/esm/testUtils/mockDeviceInfo.js.map +1 -1
- package/dist/esm/testUtils/setupTests.js +7 -0
- package/dist/esm/testUtils/setupTests.js.map +1 -1
- package/dist/types/config/makeRNConfig.d.ts +4 -3
- package/dist/types/config/types.d.ts +2 -1
- package/dist/types/generated/faroRNPackageMeta.d.ts +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/initialize.d.ts +4 -2
- package/dist/types/instrumentations/anr/anrStack.d.ts +7 -0
- package/dist/types/instrumentations/anr/instrumentation.d.ts +23 -28
- package/dist/types/instrumentations/anr/types.d.ts +5 -1
- package/dist/types/instrumentations/appState/index.d.ts +1 -1
- package/dist/types/instrumentations/console/index.d.ts +1 -1
- package/dist/types/instrumentations/crashReporting/BaseCrashReportingInstrumentation.d.ts +56 -0
- package/dist/types/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.d.ts +12 -0
- package/dist/types/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.d.ts +26 -0
- package/dist/types/instrumentations/crashReporting/android/crashErrorMessage.d.ts +23 -0
- package/dist/types/instrumentations/crashReporting/android/index.d.ts +4 -0
- package/dist/types/instrumentations/crashReporting/android/nativeTombstoneTrace.d.ts +2 -0
- package/dist/types/instrumentations/crashReporting/android/parseAndroidCrashTrace.d.ts +45 -0
- package/dist/types/instrumentations/crashReporting/index.d.ts +25 -2
- package/dist/types/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.d.ts +28 -0
- package/dist/types/instrumentations/crashReporting/ios/crashErrorMessage.d.ts +14 -0
- package/dist/types/instrumentations/crashReporting/ios/index.d.ts +4 -0
- package/dist/types/instrumentations/crashReporting/ios/parseIosCrashTrace.d.ts +38 -0
- package/dist/types/instrumentations/crashReporting/types.d.ts +18 -51
- package/dist/types/instrumentations/frameMonitoring/instrumentation.d.ts +1 -1
- package/dist/types/instrumentations/http/index.d.ts +1 -1
- package/dist/types/instrumentations/performance/index.d.ts +1 -1
- package/dist/types/instrumentations/session/index.d.ts +1 -1
- package/dist/types/instrumentations/session/installationId.d.ts +1 -0
- package/dist/types/instrumentations/session/sessionAttributes.d.ts +13 -4
- package/dist/types/instrumentations/startup/index.d.ts +1 -1
- package/dist/types/instrumentations/userActions/index.d.ts +1 -1
- package/dist/types/instrumentations/view/index.d.ts +1 -1
- package/dist/types/instrumentations/xhr/index.d.ts +1 -1
- package/dist/types/metas/appBuildIdentity.d.ts +16 -0
- package/dist/types/testUtils/mockFaroReactNativeTracing.d.ts +1 -1
- package/dist/types/transports/console/transport.d.ts +1 -1
- package/dist/types/transports/fetch/transport.d.ts +1 -1
- package/dist/types/transports/offline/transport.d.ts +1 -1
- package/package.json +4 -4
- package/src/config/getRNInstrumentations.ts +5 -1
- package/src/config/makeRNConfig.test.ts +59 -3
- package/src/config/makeRNConfig.ts +48 -9
- package/src/config/types.ts +2 -1
- package/src/generated/faroRNPackageMeta.ts +1 -1
- package/src/index.ts +2 -1
- package/src/initialize.test.ts +71 -15
- package/src/initialize.ts +11 -5
- package/src/instrumentations/anr/anrStack.test.ts +27 -0
- package/src/instrumentations/anr/anrStack.ts +19 -0
- package/src/instrumentations/anr/instrumentation.test.ts +45 -0
- package/src/instrumentations/anr/instrumentation.ts +301 -67
- package/src/instrumentations/anr/types.ts +7 -1
- package/src/instrumentations/console/index.ts +5 -1
- package/src/instrumentations/console/instrumentation.test.ts +5 -0
- package/src/instrumentations/crashReporting/{instrumentation.ts → BaseCrashReportingInstrumentation.ts} +119 -93
- package/src/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.ts +23 -0
- package/src/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.ts +62 -0
- package/src/instrumentations/crashReporting/android/crashErrorMessage.test.ts +182 -0
- package/src/instrumentations/crashReporting/android/crashErrorMessage.ts +135 -0
- package/src/instrumentations/crashReporting/android/index.ts +4 -0
- package/src/instrumentations/crashReporting/android/nativeTombstoneTrace.test.ts +19 -0
- package/src/instrumentations/crashReporting/android/nativeTombstoneTrace.ts +8 -0
- package/src/instrumentations/crashReporting/android/parseAndroidCrashTrace.test.ts +232 -0
- package/src/instrumentations/crashReporting/android/parseAndroidCrashTrace.ts +235 -0
- package/src/instrumentations/crashReporting/index.ts +43 -2
- package/src/instrumentations/crashReporting/instrumentation.test.ts +42 -0
- package/src/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.ts +62 -0
- package/src/instrumentations/crashReporting/ios/crashErrorMessage.test.ts +170 -0
- package/src/instrumentations/crashReporting/ios/crashErrorMessage.ts +111 -0
- package/src/instrumentations/crashReporting/ios/index.ts +4 -0
- package/src/instrumentations/crashReporting/ios/parseIosCrashTrace.test.ts +86 -0
- package/src/instrumentations/crashReporting/ios/parseIosCrashTrace.ts +83 -0
- package/src/instrumentations/crashReporting/types.ts +19 -58
- package/src/instrumentations/errors/index.ts +2 -1
- package/src/instrumentations/errors/instrumentation.test.ts +8 -2
- package/src/instrumentations/errors/stackTraceParser.test.ts +1 -1
- package/src/instrumentations/session/installationId.ts +43 -0
- package/src/instrumentations/session/sessionAttributes.test.ts +260 -30
- package/src/instrumentations/session/sessionAttributes.ts +112 -22
- package/src/metas/appBuildIdentity.test.ts +48 -0
- package/src/metas/appBuildIdentity.ts +50 -0
- package/src/testUtils/mockDeviceInfo.ts +5 -0
- package/src/testUtils/setupTests.ts +7 -0
- package/dist/cjs/instrumentations/crashReporting/instrumentation.js.map +0 -1
- package/dist/esm/instrumentations/crashReporting/instrumentation.js.map +0 -1
- package/dist/types/instrumentations/crashReporting/instrumentation.d.ts +0 -58
|
@@ -8,42 +8,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { NativeModules } from 'react-native';
|
|
11
|
-
import { BaseInstrumentation
|
|
12
|
-
import {
|
|
11
|
+
import { BaseInstrumentation } from '@grafana/faro-core';
|
|
12
|
+
import { looksLikeNativeTombstoneTrace } from './android/nativeTombstoneTrace';
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* Abstract base class for platform-specific crash reporting implementations.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* - **Android**: Uses ApplicationExitInfo API (Android 11+ / API 30+)
|
|
20
|
-
* Captures: CRASH, CRASH_NATIVE, ANR, LOW_MEMORY, EXCESSIVE_RESOURCE_USAGE
|
|
21
|
-
* - **iOS**: Uses PLCrashReporter (requires adding dependency to podspec)
|
|
22
|
-
* Captures: Signal crashes (SIGSEGV, SIGABRT, etc.) and Mach exceptions
|
|
23
|
-
*
|
|
24
|
-
* **Note**: This instrumentation only retrieves crash data from previous sessions.
|
|
25
|
-
* The crash itself terminates the app, so the report is sent on next app launch.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```typescript
|
|
29
|
-
* import { initializeFaro, CrashReportingInstrumentation } from '@grafana/faro-react-native';
|
|
30
|
-
*
|
|
31
|
-
* initializeFaro({
|
|
32
|
-
* url: 'https://collector.example.com',
|
|
33
|
-
* instrumentations: [
|
|
34
|
-
* new CrashReportingInstrumentation(),
|
|
35
|
-
* ],
|
|
36
|
-
* });
|
|
37
|
-
* ```
|
|
16
|
+
* Defines the common contract that both Android and iOS implementations must follow.
|
|
17
|
+
* Handles the shared logic for retrieving crash reports from native modules and
|
|
18
|
+
* processing them, while delegating platform-specific parsing and validation to subclasses.
|
|
38
19
|
*/
|
|
39
|
-
export class
|
|
20
|
+
export class BaseCrashReportingInstrumentation extends BaseInstrumentation {
|
|
40
21
|
constructor(options = {}) {
|
|
41
22
|
var _a;
|
|
42
23
|
super();
|
|
43
|
-
this.name = '@grafana/faro-react-native:instrumentation-crash';
|
|
44
|
-
this.version = VERSION;
|
|
45
24
|
this.options = {
|
|
46
25
|
enabled: (_a = options.enabled) !== null && _a !== void 0 ? _a : true,
|
|
26
|
+
releaseBundleFilename: options.releaseBundleFilename,
|
|
47
27
|
};
|
|
48
28
|
}
|
|
49
29
|
initialize() {
|
|
@@ -58,44 +38,28 @@ export class CrashReportingInstrumentation extends BaseInstrumentation {
|
|
|
58
38
|
return;
|
|
59
39
|
}
|
|
60
40
|
this.logDebug('Initializing crash reporting instrumentation');
|
|
61
|
-
// Wait for session attributes
|
|
62
|
-
// This ensures crash reports include full session metadata
|
|
41
|
+
// Wait for session attributes before sending crash reports
|
|
63
42
|
yield this.waitForSessionAttributes();
|
|
64
|
-
// Get crash reports from previous session
|
|
43
|
+
// Get and process crash reports from previous session
|
|
65
44
|
yield this.processCrashReports(nativeModule);
|
|
66
45
|
});
|
|
67
46
|
}
|
|
68
|
-
/**
|
|
69
|
-
* Wait for session attributes to be populated.
|
|
70
|
-
*
|
|
71
|
-
* Crash reports are sent in a new session, so we need to wait for
|
|
72
|
-
* SessionInstrumentation to finish collecting device info, OS version, etc.
|
|
73
|
-
* before sending the crash report. Otherwise, the crash report will be missing
|
|
74
|
-
* session metadata.
|
|
75
|
-
*
|
|
76
|
-
* This checks for multiple device-specific attributes that are collected
|
|
77
|
-
* asynchronously (device_id, device_os_detail, device_model_name) to ensure
|
|
78
|
-
* the async getSessionAttributes() call has completed.
|
|
79
|
-
*
|
|
80
|
-
* @param maxWaitMs Maximum time to wait in milliseconds (default 10000ms)
|
|
81
|
-
*/
|
|
82
47
|
waitForSessionAttributes() {
|
|
83
48
|
return __awaiter(this, arguments, void 0, function* (maxWaitMs = 10000) {
|
|
84
49
|
var _a, _b, _c, _d, _e, _f;
|
|
85
50
|
const startTime = Date.now();
|
|
86
|
-
const pollInterval = 200;
|
|
51
|
+
const pollInterval = 200;
|
|
87
52
|
let checkCount = 0;
|
|
88
53
|
while (Date.now() - startTime < maxWaitMs) {
|
|
89
54
|
checkCount++;
|
|
90
55
|
try {
|
|
91
|
-
// Check if session attributes are populated
|
|
92
56
|
const sessionAttrs = (_c = (_b = (_a = this.metas) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.session) === null || _c === void 0 ? void 0 : _c.attributes;
|
|
93
57
|
if (sessionAttrs) {
|
|
94
58
|
const attrCount = Object.keys(sessionAttrs).length;
|
|
95
59
|
const attrKeys = JSON.stringify(Object.keys(sessionAttrs));
|
|
96
60
|
// Look for multiple device-specific attributes that indicate full async collection is done.
|
|
97
61
|
// getSessionAttributes() collects these asynchronously:
|
|
98
|
-
// - device_id (
|
|
62
|
+
// - device_id (SDK installation id, kept as a flat attr during migration)
|
|
99
63
|
// - device_os_detail (async getDeviceOsDetail)
|
|
100
64
|
// - device_model_name (DeviceInfo.getDeviceNameSync)
|
|
101
65
|
// All three should be present when collection is complete.
|
|
@@ -116,13 +80,10 @@ export class CrashReportingInstrumentation extends BaseInstrumentation {
|
|
|
116
80
|
}
|
|
117
81
|
}
|
|
118
82
|
catch (error) {
|
|
119
|
-
// Continue waiting if we can't access metas yet
|
|
120
83
|
this.logDebug(`Check #${checkCount}: Error accessing metas: ${error}`);
|
|
121
84
|
}
|
|
122
|
-
// Wait before next check
|
|
123
85
|
yield new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
124
86
|
}
|
|
125
|
-
// Timeout reached - log warning but continue
|
|
126
87
|
const finalAttrs = (_f = (_e = (_d = this.metas) === null || _d === void 0 ? void 0 : _d.value) === null || _e === void 0 ? void 0 : _e.session) === null || _f === void 0 ? void 0 : _f.attributes;
|
|
127
88
|
const finalAttrCount = finalAttrs ? Object.keys(finalAttrs).length : 0;
|
|
128
89
|
const finalAttrKeys = finalAttrs ? JSON.stringify(Object.keys(finalAttrs)) : 'none';
|
|
@@ -150,21 +111,33 @@ export class CrashReportingInstrumentation extends BaseInstrumentation {
|
|
|
150
111
|
return;
|
|
151
112
|
}
|
|
152
113
|
this.logDebug(`Processing ${crashReports.length} crash report(s) from previous session`);
|
|
114
|
+
const reportedTimestamps = new Set();
|
|
153
115
|
for (const crashJson of crashReports) {
|
|
154
116
|
try {
|
|
155
117
|
this.logDebug(`Parsing crash report JSON: ${crashJson.substring(0, 200)}...`);
|
|
156
118
|
const crash = JSON.parse(crashJson);
|
|
119
|
+
if (crash.timestamp && reportedTimestamps.has(crash.timestamp)) {
|
|
120
|
+
this.logDebug(`Skipping duplicate crash report at ${crash.timestamp}`);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (this.shouldSkipCrashReport(crash)) {
|
|
124
|
+
this.logDebug(`Skipping crash report at ${crash.timestamp} (platform-specific skip logic)`);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (crash.timestamp) {
|
|
128
|
+
reportedTimestamps.add(crash.timestamp);
|
|
129
|
+
}
|
|
157
130
|
this.sendCrashReport(crash);
|
|
158
131
|
}
|
|
159
132
|
catch (parseError) {
|
|
160
|
-
// If parsing fails, still try to report something
|
|
161
133
|
this.logError('Failed to parse crash report JSON', parseError);
|
|
162
134
|
this.api.pushError(new Error('Application crash (parse error)'), {
|
|
163
135
|
context: {
|
|
164
|
-
mechanism:
|
|
136
|
+
mechanism: 'crash',
|
|
165
137
|
parseError: String(parseError),
|
|
166
|
-
raw: crashJson.substring(0, 500),
|
|
138
|
+
raw: crashJson.substring(0, 500),
|
|
167
139
|
},
|
|
140
|
+
fatal: true,
|
|
168
141
|
type: 'crash',
|
|
169
142
|
});
|
|
170
143
|
}
|
|
@@ -176,11 +149,15 @@ export class CrashReportingInstrumentation extends BaseInstrumentation {
|
|
|
176
149
|
});
|
|
177
150
|
}
|
|
178
151
|
sendCrashReport(crash) {
|
|
179
|
-
|
|
152
|
+
// Platform-specific parsing
|
|
153
|
+
const parsedTrace = crash.trace ? this.parseCrashTrace(crash.trace) : null;
|
|
154
|
+
const errorMessage = this.resolveCrashErrorMessage(crash, parsedTrace).trim() || 'Application crash';
|
|
155
|
+
// Use a message-only Error so pushError does not capture the JS reporter stack
|
|
180
156
|
const error = new Error(errorMessage);
|
|
181
|
-
|
|
157
|
+
error.stack = undefined;
|
|
158
|
+
// Build context from crash data
|
|
182
159
|
const context = {
|
|
183
|
-
mechanism:
|
|
160
|
+
mechanism: 'crash',
|
|
184
161
|
};
|
|
185
162
|
if (crash.trace) {
|
|
186
163
|
context['trace'] = crash.trace;
|
|
@@ -203,46 +180,51 @@ export class CrashReportingInstrumentation extends BaseInstrumentation {
|
|
|
203
180
|
if (crash.importance !== undefined) {
|
|
204
181
|
context['importance'] = String(crash.importance);
|
|
205
182
|
}
|
|
206
|
-
//
|
|
183
|
+
// Platform-specific context
|
|
184
|
+
this.buildPlatformContext(parsedTrace, context);
|
|
185
|
+
// Platform-specific stack frames
|
|
186
|
+
const stackFrames = this.getStackFrames(parsedTrace);
|
|
187
|
+
// Warnings for missing/unparseable traces
|
|
188
|
+
if (!stackFrames.length && crash.trace) {
|
|
189
|
+
this.logWarn(this.getParseFailureWarning());
|
|
190
|
+
}
|
|
191
|
+
else if (!crash.trace) {
|
|
192
|
+
this.logWarn(this.getTraceUnavailableWarning());
|
|
193
|
+
}
|
|
194
|
+
else if (looksLikeNativeTombstoneTrace(crash.trace)) {
|
|
195
|
+
const framePreview = crash.trace
|
|
196
|
+
.split('\n')
|
|
197
|
+
.map((line) => line.trim())
|
|
198
|
+
.find((line) => /#\d+\s+pc\s+/i.test(line));
|
|
199
|
+
this.logInfo(`[Faro crash native] Sending tombstone trace (${crash.trace.split('\n').length} lines) preview=${framePreview !== null && framePreview !== void 0 ? framePreview : 'n/a'}`);
|
|
200
|
+
}
|
|
207
201
|
this.api.pushError(error, {
|
|
208
|
-
|
|
202
|
+
stackFrames,
|
|
209
203
|
context,
|
|
204
|
+
type: 'crash',
|
|
205
|
+
fatal: true,
|
|
210
206
|
});
|
|
211
|
-
this.logDebug(`
|
|
207
|
+
this.logDebug(`Sent crash report: ${errorMessage}`);
|
|
212
208
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
case 'LOW_MEMORY':
|
|
233
|
-
description = 'Application terminated due to low memory';
|
|
234
|
-
break;
|
|
235
|
-
case 'EXCESSIVE_RESOURCE_USAGE':
|
|
236
|
-
description = 'Application terminated due to excessive resource usage';
|
|
237
|
-
break;
|
|
238
|
-
case 'INITIALIZATION_FAILURE':
|
|
239
|
-
description = 'Application failed to initialize';
|
|
240
|
-
break;
|
|
241
|
-
default:
|
|
242
|
-
description = crash.description || 'Application crash';
|
|
243
|
-
break;
|
|
244
|
-
}
|
|
245
|
-
return `${reason}: ${description}, status: ${status}`;
|
|
209
|
+
// Logging helpers
|
|
210
|
+
logDebug(message, ...args) {
|
|
211
|
+
var _a, _b;
|
|
212
|
+
(_b = (_a = this.internalLogger) === null || _a === void 0 ? void 0 : _a.debug) === null || _b === void 0 ? void 0 : _b.call(_a, message, ...args);
|
|
213
|
+
}
|
|
214
|
+
logInfo(message, ...args) {
|
|
215
|
+
var _a, _b;
|
|
216
|
+
(_b = (_a = this.internalLogger) === null || _a === void 0 ? void 0 : _a.info) === null || _b === void 0 ? void 0 : _b.call(_a, message, ...args);
|
|
217
|
+
}
|
|
218
|
+
logWarn(message, ...args) {
|
|
219
|
+
var _a, _b;
|
|
220
|
+
(_b = (_a = this.internalLogger) === null || _a === void 0 ? void 0 : _a.warn) === null || _b === void 0 ? void 0 : _b.call(_a, message, ...args);
|
|
221
|
+
}
|
|
222
|
+
logError(message, ...args) {
|
|
223
|
+
var _a, _b;
|
|
224
|
+
(_b = (_a = this.internalLogger) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b.call(_a, message, ...args);
|
|
225
|
+
}
|
|
226
|
+
unpatch() {
|
|
227
|
+
// No patching to undo
|
|
246
228
|
}
|
|
247
229
|
}
|
|
248
|
-
//# sourceMappingURL=
|
|
230
|
+
//# sourceMappingURL=BaseCrashReportingInstrumentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseCrashReportingInstrumentation.js","sourceRoot":"","sources":["../../../../src/instrumentations/crashReporting/BaseCrashReportingInstrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["import { NativeModules } from 'react-native';\n\nimport { BaseInstrumentation } from '@grafana/faro-core';\n\nimport { looksLikeNativeTombstoneTrace } from './android/nativeTombstoneTrace';\nimport type { CrashReport, CrashReportingOptions } from './types';\n\n/**\n * Abstract base class for platform-specific crash reporting implementations.\n *\n * Defines the common contract that both Android and iOS implementations must follow.\n * Handles the shared logic for retrieving crash reports from native modules and\n * processing them, while delegating platform-specific parsing and validation to subclasses.\n */\nexport abstract class BaseCrashReportingInstrumentation extends BaseInstrumentation {\n abstract override readonly name: string;\n abstract override readonly version: string;\n\n protected readonly options: { enabled: boolean; releaseBundleFilename?: string };\n\n constructor(options: CrashReportingOptions = {}) {\n super();\n this.options = {\n enabled: options.enabled ?? true,\n releaseBundleFilename: options.releaseBundleFilename,\n };\n }\n\n async initialize(): Promise<void> {\n if (!this.options.enabled) {\n this.logDebug('Crash reporting is disabled');\n return;\n }\n\n const nativeModule = this.getNativeModule();\n if (!nativeModule) {\n this.logWarn('Native module not available for crash reporting');\n return;\n }\n\n this.logDebug('Initializing crash reporting instrumentation');\n\n // Wait for session attributes before sending crash reports\n await this.waitForSessionAttributes();\n\n // Get and process crash reports from previous session\n await this.processCrashReports(nativeModule);\n }\n\n /**\n * Platform-specific: Parse a crash trace string into structured stack frames.\n */\n protected abstract parseCrashTrace(trace: string): any | null;\n\n /**\n * Platform-specific: Resolve human-readable error message from crash data.\n */\n protected abstract resolveCrashErrorMessage(crash: CrashReport, parsedTrace: any | null): string;\n\n /**\n * Platform-specific: Determine if a crash report should be skipped.\n */\n protected abstract shouldSkipCrashReport(crash: CrashReport): boolean;\n\n /**\n * Platform-specific: Extract stack frames from parsed trace.\n */\n protected abstract getStackFrames(parsedTrace: any | null): any[];\n\n /**\n * Platform-specific: Build platform-specific context from parsed trace.\n */\n protected abstract buildPlatformContext(parsedTrace: any | null, context: Record<string, string>): void;\n\n /**\n * Platform-specific: Get warning message when trace parsing fails.\n */\n protected abstract getParseFailureWarning(): string;\n\n /**\n * Platform-specific: Get warning message when trace is unavailable.\n */\n protected abstract getTraceUnavailableWarning(): string;\n\n private async waitForSessionAttributes(maxWaitMs = 10000): Promise<void> {\n const startTime = Date.now();\n const pollInterval = 200;\n let checkCount = 0;\n\n while (Date.now() - startTime < maxWaitMs) {\n checkCount++;\n try {\n const sessionAttrs = this.metas?.value?.session?.attributes;\n\n if (sessionAttrs) {\n const attrCount = Object.keys(sessionAttrs).length;\n const attrKeys = JSON.stringify(Object.keys(sessionAttrs));\n\n // Look for multiple device-specific attributes that indicate full async collection is done.\n // getSessionAttributes() collects these asynchronously:\n // - device_id (SDK installation id, kept as a flat attr during migration)\n // - device_os_detail (async getDeviceOsDetail)\n // - device_model_name (DeviceInfo.getDeviceNameSync)\n // All three should be present when collection is complete.\n const hasDeviceId = 'device_id' in sessionAttrs && sessionAttrs['device_id'] !== 'unknown';\n const hasDeviceOsDetail =\n 'device_os_detail' in sessionAttrs && sessionAttrs['device_os_detail'] !== 'unknown';\n const hasDeviceModelName = 'device_model_name' in sessionAttrs;\n\n if (hasDeviceId && hasDeviceOsDetail && hasDeviceModelName) {\n const elapsed = Date.now() - startTime;\n this.logDebug(`Session attributes ready after ${elapsed}ms (${checkCount} checks, ${attrCount} attrs)`);\n return;\n } else {\n this.logDebug(\n `Check #${checkCount}: Found ${attrCount} session attributes: ${attrKeys} but still missing required attrs - device_id:${hasDeviceId}, device_os_detail:${hasDeviceOsDetail}, device_model_name:${hasDeviceModelName}`\n );\n }\n } else {\n this.logDebug(`Check #${checkCount}: No session attributes available yet`);\n }\n } catch (error) {\n this.logDebug(`Check #${checkCount}: Error accessing metas: ${error}`);\n }\n\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n const finalAttrs = this.metas?.value?.session?.attributes;\n const finalAttrCount = finalAttrs ? Object.keys(finalAttrs).length : 0;\n const finalAttrKeys = finalAttrs ? JSON.stringify(Object.keys(finalAttrs)) : 'none';\n this.logWarn(\n `Session attributes not ready after ${maxWaitMs}ms timeout (${checkCount} checks, ${finalAttrCount} attrs: ${finalAttrKeys}). Sending crash report anyway.`\n );\n }\n\n private getNativeModule(): typeof NativeModules.FaroReactNativeModule | null {\n const { FaroReactNativeModule } = NativeModules;\n\n if (!FaroReactNativeModule) {\n return null;\n }\n\n return FaroReactNativeModule;\n }\n\n private async processCrashReports(nativeModule: typeof NativeModules.FaroReactNativeModule): Promise<void> {\n try {\n if (typeof nativeModule.getCrashReport !== 'function') {\n this.logDebug('getCrashReport method not available');\n return;\n }\n\n this.logDebug('Attempting to retrieve crash reports from native module');\n const crashReports = (await nativeModule.getCrashReport()) as string[] | null;\n\n if (!crashReports || crashReports.length === 0) {\n this.logDebug('No crash reports from previous session');\n return;\n }\n\n this.logDebug(`Processing ${crashReports.length} crash report(s) from previous session`);\n\n const reportedTimestamps = new Set<number>();\n\n for (const crashJson of crashReports) {\n try {\n this.logDebug(`Parsing crash report JSON: ${crashJson.substring(0, 200)}...`);\n const crash = JSON.parse(crashJson) as CrashReport;\n\n if (crash.timestamp && reportedTimestamps.has(crash.timestamp)) {\n this.logDebug(`Skipping duplicate crash report at ${crash.timestamp}`);\n continue;\n }\n\n if (this.shouldSkipCrashReport(crash)) {\n this.logDebug(`Skipping crash report at ${crash.timestamp} (platform-specific skip logic)`);\n continue;\n }\n\n if (crash.timestamp) {\n reportedTimestamps.add(crash.timestamp);\n }\n\n this.sendCrashReport(crash);\n } catch (parseError) {\n this.logError('Failed to parse crash report JSON', parseError);\n this.api.pushError(new Error('Application crash (parse error)'), {\n context: {\n mechanism: 'crash',\n parseError: String(parseError),\n raw: crashJson.substring(0, 500),\n },\n fatal: true,\n type: 'crash',\n });\n }\n }\n } catch (error) {\n this.logError('Failed to process crash reports', error);\n }\n }\n\n private sendCrashReport(crash: CrashReport): void {\n // Platform-specific parsing\n const parsedTrace = crash.trace ? this.parseCrashTrace(crash.trace) : null;\n const errorMessage = this.resolveCrashErrorMessage(crash, parsedTrace).trim() || 'Application crash';\n\n // Use a message-only Error so pushError does not capture the JS reporter stack\n const error = new Error(errorMessage);\n error.stack = undefined;\n\n // Build context from crash data\n const context: Record<string, string> = {\n mechanism: 'crash',\n };\n\n if (crash.trace) {\n context['trace'] = crash.trace;\n }\n if (crash.signal) {\n context['signal'] = crash.signal;\n }\n if (crash.timestamp) {\n context['timestamp'] = String(crash.timestamp);\n }\n if (crash.description) {\n context['description'] = crash.description;\n }\n if (crash.processName) {\n context['processName'] = crash.processName;\n }\n if (crash.pid) {\n context['pid'] = String(crash.pid);\n }\n if (crash.importance !== undefined) {\n context['importance'] = String(crash.importance);\n }\n\n // Platform-specific context\n this.buildPlatformContext(parsedTrace, context);\n\n // Platform-specific stack frames\n const stackFrames = this.getStackFrames(parsedTrace);\n\n // Warnings for missing/unparseable traces\n if (!stackFrames.length && crash.trace) {\n this.logWarn(this.getParseFailureWarning());\n } else if (!crash.trace) {\n this.logWarn(this.getTraceUnavailableWarning());\n } else if (looksLikeNativeTombstoneTrace(crash.trace)) {\n const framePreview = crash.trace\n .split('\\n')\n .map((line) => line.trim())\n .find((line) => /#\\d+\\s+pc\\s+/i.test(line));\n this.logInfo(\n `[Faro crash native] Sending tombstone trace (${crash.trace.split('\\n').length} lines) preview=${framePreview ?? 'n/a'}`\n );\n }\n\n this.api.pushError(error, {\n stackFrames,\n context,\n type: 'crash',\n fatal: true,\n });\n\n this.logDebug(`Sent crash report: ${errorMessage}`);\n }\n\n // Logging helpers\n override logDebug(message: string, ...args: any[]): void {\n this.internalLogger?.debug?.(message, ...args);\n }\n\n override logInfo(message: string, ...args: any[]): void {\n this.internalLogger?.info?.(message, ...args);\n }\n\n override logWarn(message: string, ...args: any[]): void {\n this.internalLogger?.warn?.(message, ...args);\n }\n\n override logError(message: string, ...args: any[]): void {\n this.internalLogger?.error?.(message, ...args);\n }\n\n unpatch(): void {\n // No patching to undo\n }\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BaseInstrumentation, VERSION } from '@grafana/faro-core';
|
|
2
|
+
/**
|
|
3
|
+
* Crash reporting stub for platforms other than Android and iOS (e.g. web, macOS, Windows).
|
|
4
|
+
*/
|
|
5
|
+
export class NoOpCrashReportingInstrumentation extends BaseInstrumentation {
|
|
6
|
+
constructor(_options = {}) {
|
|
7
|
+
super();
|
|
8
|
+
this.name = '@grafana/faro-react-native:instrumentation-crash-noop';
|
|
9
|
+
this.version = VERSION;
|
|
10
|
+
}
|
|
11
|
+
initialize() {
|
|
12
|
+
this.logDebug('Crash reporting is not supported on this platform');
|
|
13
|
+
}
|
|
14
|
+
unpatch() {
|
|
15
|
+
// No patching to undo
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=NoOpCrashReportingInstrumentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoOpCrashReportingInstrumentation.js","sourceRoot":"","sources":["../../../../src/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAIlE;;GAEG;AACH,MAAM,OAAO,iCAAkC,SAAQ,mBAAmB;IAIxE,YAAY,WAAkC,EAAE;QAC9C,KAAK,EAAE,CAAC;QAJD,SAAI,GAAG,uDAAuD,CAAC;QAC/D,YAAO,GAAG,OAAO,CAAC;IAI3B,CAAC;IAED,UAAU;QACR,IAAI,CAAC,QAAQ,CAAC,mDAAmD,CAAC,CAAC;IACrE,CAAC;IAED,OAAO;QACL,sBAAsB;IACxB,CAAC;CACF","sourcesContent":["import { BaseInstrumentation, VERSION } from '@grafana/faro-core';\n\nimport type { CrashReportingOptions } from './types';\n\n/**\n * Crash reporting stub for platforms other than Android and iOS (e.g. web, macOS, Windows).\n */\nexport class NoOpCrashReportingInstrumentation extends BaseInstrumentation {\n readonly name = '@grafana/faro-react-native:instrumentation-crash-noop';\n readonly version = VERSION;\n\n constructor(_options: CrashReportingOptions = {}) {\n super();\n }\n\n initialize(): void {\n this.logDebug('Crash reporting is not supported on this platform');\n }\n\n unpatch(): void {\n // No patching to undo\n }\n}\n"]}
|
package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { VERSION } from '@grafana/faro-core';
|
|
2
|
+
import { BaseCrashReportingInstrumentation } from '../BaseCrashReportingInstrumentation';
|
|
3
|
+
import { resolveCrashErrorMessage, shouldSkipCrashReport } from './crashErrorMessage';
|
|
4
|
+
import { parseAndroidCrashTrace } from './parseAndroidCrashTrace';
|
|
5
|
+
/**
|
|
6
|
+
* Android Crash Reporting Instrumentation.
|
|
7
|
+
*
|
|
8
|
+
* Uses ApplicationExitInfo API (Android 11+ / API 30+) to retrieve crash reports
|
|
9
|
+
* from previous sessions. Captures:
|
|
10
|
+
* - CRASH: Java/Kotlin exception crashes
|
|
11
|
+
* - CRASH_NATIVE: Native (NDK) crashes
|
|
12
|
+
* - LOW_MEMORY: App killed due to low memory
|
|
13
|
+
* - EXCESSIVE_RESOURCE_USAGE: App killed due to excessive resource usage
|
|
14
|
+
*
|
|
15
|
+
* ANRs are reported separately by ANRInstrumentation, not via ApplicationExitInfo replay.
|
|
16
|
+
*/
|
|
17
|
+
export class AndroidCrashReportingInstrumentation extends BaseCrashReportingInstrumentation {
|
|
18
|
+
constructor() {
|
|
19
|
+
super(...arguments);
|
|
20
|
+
this.name = '@grafana/faro-react-native:instrumentation-crash-android';
|
|
21
|
+
this.version = VERSION;
|
|
22
|
+
}
|
|
23
|
+
parseCrashTrace(trace) {
|
|
24
|
+
return parseAndroidCrashTrace(trace, {
|
|
25
|
+
releaseBundleFilename: this.options.releaseBundleFilename,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
resolveCrashErrorMessage(crash, parsedTrace) {
|
|
29
|
+
return resolveCrashErrorMessage(crash, parsedTrace);
|
|
30
|
+
}
|
|
31
|
+
shouldSkipCrashReport(crash) {
|
|
32
|
+
return shouldSkipCrashReport(crash);
|
|
33
|
+
}
|
|
34
|
+
getStackFrames(parsedTrace) {
|
|
35
|
+
var _a, _b, _c;
|
|
36
|
+
if (!parsedTrace) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
// Android has JS frames, Java/Kotlin frames (R8 retrace), and NDK tombstone rows (.so retrace).
|
|
40
|
+
return [...((_a = parsedTrace.jsFrames) !== null && _a !== void 0 ? _a : []), ...((_b = parsedTrace.frames) !== null && _b !== void 0 ? _b : []), ...((_c = parsedTrace.nativeFrames) !== null && _c !== void 0 ? _c : [])];
|
|
41
|
+
}
|
|
42
|
+
buildPlatformContext(parsedTrace, context) {
|
|
43
|
+
// Store the native Java/Kotlin exception class separately for drill-down
|
|
44
|
+
// Plugin overview metrics key off exception_type = 'crash', so keep that stable
|
|
45
|
+
if (parsedTrace === null || parsedTrace === void 0 ? void 0 : parsedTrace.exceptionType) {
|
|
46
|
+
context['nativeExceptionType'] = parsedTrace.exceptionType;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
getParseFailureWarning() {
|
|
50
|
+
return 'Native crash trace present but no frames parsed; check Android trace format or UncaughtExceptionHandler cache';
|
|
51
|
+
}
|
|
52
|
+
getTraceUnavailableWarning() {
|
|
53
|
+
return 'Native crash trace unavailable (ApplicationExitInfo traceInputStream was null at crash time)';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=AndroidCrashReportingInstrumentation.js.map
|
package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AndroidCrashReportingInstrumentation.js","sourceRoot":"","sources":["../../../../../src/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,OAAO,EAAE,iCAAiC,EAAE,MAAM,sCAAsC,CAAC;AAGzF,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,sBAAsB,EAAgC,MAAM,0BAA0B,CAAC;AAEhG;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,oCAAqC,SAAQ,iCAAiC;IAA3F;;QACW,SAAI,GAAG,0DAA0D,CAAC;QAClE,YAAO,GAAG,OAAO,CAAC;IAuC7B,CAAC;IArCW,eAAe,CAAC,KAAa;QACrC,OAAO,sBAAsB,CAAC,KAAK,EAAE;YACnC,qBAAqB,EAAE,IAAI,CAAC,OAAO,CAAC,qBAAqB;SAC1D,CAAC,CAAC;IACL,CAAC;IAES,wBAAwB,CAAC,KAAkB,EAAE,WAA2C;QAChG,OAAO,wBAAwB,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IACtD,CAAC;IAES,qBAAqB,CAAC,KAAkB;QAChD,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IAES,cAAc,CAAC,WAA2C;;QAClE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,gGAAgG;QAChG,OAAO,CAAC,GAAG,CAAC,MAAA,WAAW,CAAC,QAAQ,mCAAI,EAAE,CAAC,EAAE,GAAG,CAAC,MAAA,WAAW,CAAC,MAAM,mCAAI,EAAE,CAAC,EAAE,GAAG,CAAC,MAAA,WAAW,CAAC,YAAY,mCAAI,EAAE,CAAC,CAAC,CAAC;IAC/G,CAAC;IAES,oBAAoB,CAAC,WAA2C,EAAE,OAA+B;QACzG,yEAAyE;QACzE,gFAAgF;QAChF,IAAI,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,aAAa,EAAE,CAAC;YAC/B,OAAO,CAAC,qBAAqB,CAAC,GAAG,WAAW,CAAC,aAAa,CAAC;QAC7D,CAAC;IACH,CAAC;IAES,sBAAsB;QAC9B,OAAO,+GAA+G,CAAC;IACzH,CAAC;IAES,0BAA0B;QAClC,OAAO,8FAA8F,CAAC;IACxG,CAAC;CACF","sourcesContent":["import { VERSION } from '@grafana/faro-core';\n\nimport { BaseCrashReportingInstrumentation } from '../BaseCrashReportingInstrumentation';\nimport type { CrashReport } from '../types';\n\nimport { resolveCrashErrorMessage, shouldSkipCrashReport } from './crashErrorMessage';\nimport { parseAndroidCrashTrace, type ParsedAndroidCrashTrace } from './parseAndroidCrashTrace';\n\n/**\n * Android Crash Reporting Instrumentation.\n *\n * Uses ApplicationExitInfo API (Android 11+ / API 30+) to retrieve crash reports\n * from previous sessions. Captures:\n * - CRASH: Java/Kotlin exception crashes\n * - CRASH_NATIVE: Native (NDK) crashes\n * - LOW_MEMORY: App killed due to low memory\n * - EXCESSIVE_RESOURCE_USAGE: App killed due to excessive resource usage\n *\n * ANRs are reported separately by ANRInstrumentation, not via ApplicationExitInfo replay.\n */\nexport class AndroidCrashReportingInstrumentation extends BaseCrashReportingInstrumentation {\n readonly name = '@grafana/faro-react-native:instrumentation-crash-android';\n readonly version = VERSION;\n\n protected parseCrashTrace(trace: string): ParsedAndroidCrashTrace | null {\n return parseAndroidCrashTrace(trace, {\n releaseBundleFilename: this.options.releaseBundleFilename,\n });\n }\n\n protected resolveCrashErrorMessage(crash: CrashReport, parsedTrace: ParsedAndroidCrashTrace | null): string {\n return resolveCrashErrorMessage(crash, parsedTrace);\n }\n\n protected shouldSkipCrashReport(crash: CrashReport): boolean {\n return shouldSkipCrashReport(crash);\n }\n\n protected getStackFrames(parsedTrace: ParsedAndroidCrashTrace | null): any[] {\n if (!parsedTrace) {\n return [];\n }\n // Android has JS frames, Java/Kotlin frames (R8 retrace), and NDK tombstone rows (.so retrace).\n return [...(parsedTrace.jsFrames ?? []), ...(parsedTrace.frames ?? []), ...(parsedTrace.nativeFrames ?? [])];\n }\n\n protected buildPlatformContext(parsedTrace: ParsedAndroidCrashTrace | null, context: Record<string, string>): void {\n // Store the native Java/Kotlin exception class separately for drill-down\n // Plugin overview metrics key off exception_type = 'crash', so keep that stable\n if (parsedTrace?.exceptionType) {\n context['nativeExceptionType'] = parsedTrace.exceptionType;\n }\n }\n\n protected getParseFailureWarning(): string {\n return 'Native crash trace present but no frames parsed; check Android trace format or UncaughtExceptionHandler cache';\n }\n\n protected getTraceUnavailableWarning(): string {\n return 'Native crash trace unavailable (ApplicationExitInfo traceInputStream was null at crash time)';\n }\n}\n"]}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { isPlausibleJavaExceptionIdentifier } from './parseAndroidCrashTrace';
|
|
2
|
+
/**
|
|
3
|
+
* Human-readable exception value for ApplicationExitInfo crash reports.
|
|
4
|
+
* Priority: parsed trace message → exception class → description → generic fallback.
|
|
5
|
+
*/
|
|
6
|
+
export function resolveCrashErrorMessage(crash, parsedTrace) {
|
|
7
|
+
var _a, _b, _c;
|
|
8
|
+
const fromTrace = (_a = parsedTrace === null || parsedTrace === void 0 ? void 0 : parsedTrace.exceptionMessage) === null || _a === void 0 ? void 0 : _a.trim();
|
|
9
|
+
if (fromTrace) {
|
|
10
|
+
return fromTrace;
|
|
11
|
+
}
|
|
12
|
+
const fromType = (_b = parsedTrace === null || parsedTrace === void 0 ? void 0 : parsedTrace.exceptionType) === null || _b === void 0 ? void 0 : _b.trim();
|
|
13
|
+
if (fromType && isPlausibleJavaExceptionIdentifier(fromType)) {
|
|
14
|
+
return fromType;
|
|
15
|
+
}
|
|
16
|
+
const fromDescriptionType = exceptionTypeFromDescription(crash.description);
|
|
17
|
+
if (fromDescriptionType) {
|
|
18
|
+
return fromDescriptionType;
|
|
19
|
+
}
|
|
20
|
+
const fromDescription = (_c = crash.description) === null || _c === void 0 ? void 0 : _c.trim();
|
|
21
|
+
if (fromDescription && !isGenericCrashDescription(fromDescription)) {
|
|
22
|
+
return fromDescription;
|
|
23
|
+
}
|
|
24
|
+
const fallback = buildFallbackCrashMessage(crash);
|
|
25
|
+
return fallback.trim() || crash.reason || 'Application crash';
|
|
26
|
+
}
|
|
27
|
+
const ANR_TIMEOUT_DESCRIPTION_PATTERN = /input dispatching timed out|not responding|application not responding/i;
|
|
28
|
+
/**
|
|
29
|
+
* Android ANR watchdog descriptions from ApplicationExitInfo (any app).
|
|
30
|
+
*/
|
|
31
|
+
export function isAnrTimeoutDescription(description) {
|
|
32
|
+
const trimmed = description === null || description === void 0 ? void 0 : description.trim();
|
|
33
|
+
if (!trimmed) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return ANR_TIMEOUT_DESCRIPTION_PATTERN.test(trimmed);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Skip duplicate ApplicationExitInfo rows that have no stack and no useful title,
|
|
40
|
+
* and ANR incidents mis-tagged as previous-session crashes.
|
|
41
|
+
*/
|
|
42
|
+
export function shouldSkipCrashReport(crash) {
|
|
43
|
+
if (isAnrTimeoutDescription(crash.description)) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return shouldSkipLowSignalCrashReport(crash);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Skip duplicate ApplicationExitInfo rows that have no stack and no useful title.
|
|
50
|
+
* These surface in the plugin as a second generic `crash` row for a single button press.
|
|
51
|
+
*/
|
|
52
|
+
export function shouldSkipLowSignalCrashReport(crash) {
|
|
53
|
+
var _a, _b;
|
|
54
|
+
if ((_a = crash.trace) === null || _a === void 0 ? void 0 : _a.trim()) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const description = (_b = crash.description) === null || _b === void 0 ? void 0 : _b.trim();
|
|
58
|
+
if (description && !isGenericCrashDescription(description)) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
/** Extract `java.lang.NullPointerException` from ApplicationExitInfo description text. */
|
|
64
|
+
function exceptionTypeFromDescription(description) {
|
|
65
|
+
var _a;
|
|
66
|
+
const trimmed = description === null || description === void 0 ? void 0 : description.trim();
|
|
67
|
+
if (!trimmed || isGenericCrashDescription(trimmed)) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
const match = trimmed.match(/^([\w.$]+)(?::(.*))?$/);
|
|
71
|
+
const candidate = (_a = match === null || match === void 0 ? void 0 : match[1]) === null || _a === void 0 ? void 0 : _a.trim();
|
|
72
|
+
if (!candidate || !isPlausibleJavaExceptionIdentifier(candidate)) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
return candidate;
|
|
76
|
+
}
|
|
77
|
+
function isGenericCrashDescription(description) {
|
|
78
|
+
const normalized = description.trim().toLowerCase();
|
|
79
|
+
return (normalized === 'crash' ||
|
|
80
|
+
normalized === 'native crash' ||
|
|
81
|
+
normalized === 'application crash' ||
|
|
82
|
+
normalized === 'application crash (java/kotlin)' ||
|
|
83
|
+
normalized === 'application crash (native)');
|
|
84
|
+
}
|
|
85
|
+
/** Generic fallback when the trace carries no parseable message or type. */
|
|
86
|
+
export function buildFallbackCrashMessage(crash) {
|
|
87
|
+
var _a;
|
|
88
|
+
const reason = crash.reason || 'UNKNOWN';
|
|
89
|
+
const status = (_a = crash.status) !== null && _a !== void 0 ? _a : 0;
|
|
90
|
+
let description;
|
|
91
|
+
switch (crash.reason) {
|
|
92
|
+
case 'ANR':
|
|
93
|
+
description = 'Application Not Responding';
|
|
94
|
+
break;
|
|
95
|
+
case 'CRASH':
|
|
96
|
+
description = 'Application crash (Java/Kotlin)';
|
|
97
|
+
break;
|
|
98
|
+
case 'CRASH_NATIVE':
|
|
99
|
+
description = 'Application crash (Native)';
|
|
100
|
+
break;
|
|
101
|
+
case 'LOW_MEMORY':
|
|
102
|
+
description = 'Application terminated due to low memory';
|
|
103
|
+
break;
|
|
104
|
+
case 'EXCESSIVE_RESOURCE_USAGE':
|
|
105
|
+
description = 'Application terminated due to excessive resource usage';
|
|
106
|
+
break;
|
|
107
|
+
case 'INITIALIZATION_FAILURE':
|
|
108
|
+
description = 'Application failed to initialize';
|
|
109
|
+
break;
|
|
110
|
+
default:
|
|
111
|
+
description = crash.description || 'Application crash';
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
return `${reason}: ${description}, status: ${status}`;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=crashErrorMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crashErrorMessage.js","sourceRoot":"","sources":["../../../../../src/instrumentations/crashReporting/android/crashErrorMessage.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CrashReport } from '../types';\n\nimport { isPlausibleJavaExceptionIdentifier } from './parseAndroidCrashTrace';\nimport type { ParsedAndroidCrashTrace } from './parseAndroidCrashTrace';\n\n/**\n * Human-readable exception value for ApplicationExitInfo crash reports.\n * Priority: parsed trace message → exception class → description → generic fallback.\n */\nexport function resolveCrashErrorMessage(crash: CrashReport, parsedTrace: ParsedAndroidCrashTrace | null): string {\n const fromTrace = parsedTrace?.exceptionMessage?.trim();\n if (fromTrace) {\n return fromTrace;\n }\n\n const fromType = parsedTrace?.exceptionType?.trim();\n if (fromType && isPlausibleJavaExceptionIdentifier(fromType)) {\n return fromType;\n }\n\n const fromDescriptionType = exceptionTypeFromDescription(crash.description);\n if (fromDescriptionType) {\n return fromDescriptionType;\n }\n\n const fromDescription = crash.description?.trim();\n if (fromDescription && !isGenericCrashDescription(fromDescription)) {\n return fromDescription;\n }\n\n const fallback = buildFallbackCrashMessage(crash);\n return fallback.trim() || crash.reason || 'Application crash';\n}\n\nconst ANR_TIMEOUT_DESCRIPTION_PATTERN = /input dispatching timed out|not responding|application not responding/i;\n\n/**\n * Android ANR watchdog descriptions from ApplicationExitInfo (any app).\n */\nexport function isAnrTimeoutDescription(description: string | undefined): boolean {\n const trimmed = description?.trim();\n if (!trimmed) {\n return false;\n }\n return ANR_TIMEOUT_DESCRIPTION_PATTERN.test(trimmed);\n}\n\n/**\n * Skip duplicate ApplicationExitInfo rows that have no stack and no useful title,\n * and ANR incidents mis-tagged as previous-session crashes.\n */\nexport function shouldSkipCrashReport(crash: CrashReport): boolean {\n if (isAnrTimeoutDescription(crash.description)) {\n return true;\n }\n\n return shouldSkipLowSignalCrashReport(crash);\n}\n\n/**\n * Skip duplicate ApplicationExitInfo rows that have no stack and no useful title.\n * These surface in the plugin as a second generic `crash` row for a single button press.\n */\nexport function shouldSkipLowSignalCrashReport(crash: CrashReport): boolean {\n if (crash.trace?.trim()) {\n return false;\n }\n\n const description = crash.description?.trim();\n if (description && !isGenericCrashDescription(description)) {\n return false;\n }\n\n return true;\n}\n\n/** Extract `java.lang.NullPointerException` from ApplicationExitInfo description text. */\nfunction exceptionTypeFromDescription(description: string | undefined): string | undefined {\n const trimmed = description?.trim();\n if (!trimmed || isGenericCrashDescription(trimmed)) {\n return undefined;\n }\n\n const match = trimmed.match(/^([\\w.$]+)(?::(.*))?$/);\n const candidate = match?.[1]?.trim();\n if (!candidate || !isPlausibleJavaExceptionIdentifier(candidate)) {\n return undefined;\n }\n\n return candidate;\n}\n\nfunction isGenericCrashDescription(description: string): boolean {\n const normalized = description.trim().toLowerCase();\n return (\n normalized === 'crash' ||\n normalized === 'native crash' ||\n normalized === 'application crash' ||\n normalized === 'application crash (java/kotlin)' ||\n normalized === 'application crash (native)'\n );\n}\n\n/** Generic fallback when the trace carries no parseable message or type. */\nexport function buildFallbackCrashMessage(crash: CrashReport): string {\n const reason = crash.reason || 'UNKNOWN';\n const status = crash.status ?? 0;\n\n let description: string;\n switch (crash.reason) {\n case 'ANR':\n description = 'Application Not Responding';\n break;\n case 'CRASH':\n description = 'Application crash (Java/Kotlin)';\n break;\n case 'CRASH_NATIVE':\n description = 'Application crash (Native)';\n break;\n case 'LOW_MEMORY':\n description = 'Application terminated due to low memory';\n break;\n case 'EXCESSIVE_RESOURCE_USAGE':\n description = 'Application terminated due to excessive resource usage';\n break;\n case 'INITIALIZATION_FAILURE':\n description = 'Application failed to initialize';\n break;\n default:\n description = crash.description || 'Application crash';\n break;\n }\n\n return `${reason}: ${description}, status: ${status}`;\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { AndroidCrashReportingInstrumentation } from './AndroidCrashReportingInstrumentation';
|
|
2
|
+
export { parseAndroidCrashTrace, normalizeJavaStackTraceForRetrace } from './parseAndroidCrashTrace';
|
|
3
|
+
export { resolveCrashErrorMessage, shouldSkipCrashReport } from './crashErrorMessage';
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/instrumentations/crashReporting/android/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oCAAoC,EAAE,MAAM,wCAAwC,CAAC;AAC9F,OAAO,EAAE,sBAAsB,EAAE,iCAAiC,EAAE,MAAM,0BAA0B,CAAC;AAErG,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC","sourcesContent":["export { AndroidCrashReportingInstrumentation } from './AndroidCrashReportingInstrumentation';\nexport { parseAndroidCrashTrace, normalizeJavaStackTraceForRetrace } from './parseAndroidCrashTrace';\nexport type { ParsedAndroidCrashTrace, AndroidCrashStackFrame } from './parseAndroidCrashTrace';\nexport { resolveCrashErrorMessage, shouldSkipCrashReport } from './crashErrorMessage';\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Detect Android tombstone backtrace lines used for NDK native retrace. */
|
|
2
|
+
export function looksLikeNativeTombstoneTrace(trace) {
|
|
3
|
+
if (!(trace === null || trace === void 0 ? void 0 : trace.trim())) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
return trace.split('\n').some((line) => /^\s*#\d+\s+pc\s+(?:0x)?[0-9a-fA-F]+\s+\S+/i.test(line));
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=nativeTombstoneTrace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nativeTombstoneTrace.js","sourceRoot":"","sources":["../../../../../src/instrumentations/crashReporting/android/nativeTombstoneTrace.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,UAAU,6BAA6B,CAAC,KAAyB;IACrE,IAAI,CAAC,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,EAAE,CAAA,EAAE,CAAC;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,4CAA4C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACnG,CAAC","sourcesContent":["/** Detect Android tombstone backtrace lines used for NDK native retrace. */\nexport function looksLikeNativeTombstoneTrace(trace: string | undefined): boolean {\n if (!trace?.trim()) {\n return false;\n }\n\n return trace.split('\\n').some((line) => /^\\s*#\\d+\\s+pc\\s+(?:0x)?[0-9a-fA-F]+\\s+\\S+/i.test(line));\n}\n"]}
|