diff --git a/src/extensions/default/HealthData/HealthDataManager.js b/src/extensions/default/HealthData/HealthDataManager.js
index 45515e36a5..bd43e0ab6f 100644
--- a/src/extensions/default/HealthData/HealthDataManager.js
+++ b/src/extensions/default/HealthData/HealthDataManager.js
@@ -109,6 +109,19 @@ define(function (require, exports, module) {
isPowerUserFn: isPowerUser
});
healthDataDisabled = !prefs.get("healthDataTracking");
+ if (healthDataDisabled && !Phoenix.healthTrackingDisabled) {
+ // Phoenix.healthTrackingDisabled is initialized at boot using localStorage.
+ // However, there's a theoretical edge case where the browser may have cleared
+ // localStorage, causing a mismatch between the boot-time flag and the actual
+ // persisted user preference.
+ //
+ // This means we might unintentionally log some metrics during the short window
+ // before the real preference is loaded and applied.
+ //
+ // To track this discrepancy, we emit a one-time metric just before disabling tracking,
+ // so we’re aware of this inconsistency and can address it if needed.
+ Metrics.countEvent(Metrics.PLATFORM, "metricBoot", "disableErr");
+ }
Metrics.setDisabled(healthDataDisabled);
SendToAnalytics.sendPlatformMetrics();
SendToAnalytics.sendThemesMetrics();
diff --git a/src/extensions/default/HealthData/SendToAnalytics.js b/src/extensions/default/HealthData/SendToAnalytics.js
index a2d1d46900..459f41c331 100644
--- a/src/extensions/default/HealthData/SendToAnalytics.js
+++ b/src/extensions/default/HealthData/SendToAnalytics.js
@@ -21,7 +21,7 @@
*
*/
-/*global Phoenix*/
+/*global AppConfig*/
define(function (require, exports, module) {
const Metrics = brackets.getModule("utils/Metrics"),
PreferencesManager = brackets.getModule("preferences/PreferencesManager"),
@@ -29,6 +29,8 @@ define(function (require, exports, module) {
NodeUtils = brackets.getModule("utils/NodeUtils"),
themesPref = PreferencesManager.getExtensionPrefs("themes");
+ const BugsnagPerformance = window.BugsnagPerformance;
+
const PLATFORM = Metrics.EVENT_TYPE.PLATFORM,
PERFORMANCE = Metrics.EVENT_TYPE.PERFORMANCE,
STORAGE = Metrics.EVENT_TYPE.STORAGE;
@@ -133,17 +135,34 @@ define(function (require, exports, module) {
_sendStorageMetrics();
}
+ let bugsnagPerformanceInited = false;
+ function _initBugsnagPerformance() {
+ bugsnagPerformanceInited = true;
+ BugsnagPerformance.start({
+ apiKey: '94ef94f4daf871ca0f2fc912c6d4764d',
+ appVersion: AppConfig.version,
+ releaseStage: window.__TAURI__ ?
+ `tauri-${AppConfig.config.bugsnagEnv}-${Phoenix.platform}` : AppConfig.config.bugsnagEnv,
+ autoInstrumentRouteChanges: false,
+ autoInstrumentNetworkRequests: false,
+ autoInstrumentFullPageLoads: false
+ });
+ }
+
function _bugsnagPerformance(key, valueMs) {
- if(Metrics.isDisabled() || !window.BugsnagPerformance || Phoenix.isTestWindow){
+ if(Metrics.isDisabled() || !BugsnagPerformance || Phoenix.isTestWindow){
return;
}
+ if(!bugsnagPerformanceInited) {
+ _initBugsnagPerformance();
+ }
let activityStartTime = new Date();
let activityEndTime = new Date(activityStartTime.getTime() + valueMs);
- window.BugsnagPerformance
+ BugsnagPerformance
.startSpan(key, { startTime: activityStartTime })
.end(activityEndTime);
}
-
+
// Performance
function sendStartupPerformanceMetrics() {
const healthReport = PerfUtils.getHealthReport();
diff --git a/src/extensions/default/HealthData/htmlContent/healthdata-preview-dialog.html b/src/extensions/default/HealthData/htmlContent/healthdata-preview-dialog.html
index e6d4e8185c..4ed36a6ae2 100644
--- a/src/extensions/default/HealthData/htmlContent/healthdata-preview-dialog.html
+++ b/src/extensions/default/HealthData/htmlContent/healthdata-preview-dialog.html
@@ -9,6 +9,10 @@
{{{content}}}
diff --git a/src/index.html b/src/index.html
index 220bb1237e..c13f595ff0 100644
--- a/src/index.html
+++ b/src/index.html
@@ -341,6 +341,7 @@
} else if (navigator.platform && navigator.platform.indexOf("Linux") >= 0) {
platform = "linux";
}
+ // window.Phoenix should never be reassigned as code may cache references to this object.
window.Phoenix = {
PHOENIX_INSTANCE_ID: "PH-" + Math.round( Math.random()*1000000000000),
browser: getBrowserDetails(),
@@ -372,6 +373,12 @@
Phoenix.isSupportedBrowser = Phoenix.isNativeApp ||
(Phoenix.browser.isDeskTop && ("serviceWorker" in navigator));
window.testEnvironment = window.Phoenix.isTestWindow;
+ const healthDisabled = localStorage.getItem("PH_HEALTH_DISABLED");
+ window.Phoenix.healthTrackingDisabled = (healthDisabled === "true");
+ window.Phoenix._setHealthTrackingDisabled = function (isDisabled) {
+ window.Phoenix.healthTrackingDisabled = isDisabled;
+ localStorage.setItem("PH_HEALTH_DISABLED", String(isDisabled));
+ };
// now setup PhoenixBaseURL, which if of the form https://phcode.dev/ or tauri://localhost/
const url = new URL(window.location.href);
@@ -394,14 +401,6 @@
diff --git a/src/loggerSetup.js b/src/loggerSetup.js
index f58b06c3ee..9e2469c52a 100644
--- a/src/loggerSetup.js
+++ b/src/loggerSetup.js
@@ -40,7 +40,7 @@
}
}
const urlParams = new URLSearchParams(window.location.search || "");
- const isBugsnagEnabled = (!window.testEnvironment && isBugsnagLoggableURL);
+ const isBugsnagEnabled = (!window.testEnvironment && isBugsnagLoggableURL && !Phoenix.healthTrackingDisabled);
const MAX_ERR_SENT_RESET_INTERVAL = 60000,
MAX_ERR_SENT_FIRST_MINUTE = 10,
MAX_ERR_ALLOWED_IN_MINUTE = 2;
diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js
index b019c5745f..cd3f9855ce 100644
--- a/src/nls/root/strings.js
+++ b/src/nls/root/strings.js
@@ -891,6 +891,7 @@ define({
"HEALTH_DATA_NOTIFICATION_MESSAGE": "{APP_NAME}
does not collect or process any personally identifiable information, but
collects anonymous usage statistics to guard your privacy. Anonymous data is exempt from GDPR/CCPA notification requirements, but we believe you need to have a choice to opt out of anonymous data collection as well.
You can see your data or
choose not to share any anonymous data by selecting
Help > Health Report. These
anonymous app usage statistics and error reports helps prioritize features, find bugs, and spot usability issues for improving your experience with {APP_NAME}. Without this data, we would not know what features it is worth building for you!
",
"HEALTH_DATA_PREVIEW": "{APP_NAME} Health Report",
"HEALTH_DATA_PREVIEW_INTRO": "
{APP_NAME} does not collect or process any personally identifiable information, but collects anonymous usage statistics to guard your privacy. These anonymous app usage statistics and error reports helps prioritize features, find bugs, and spot usability issues for improving your experience with {APP_NAME}.
Below is a preview of the data that will be sent in your next Health Report if it is enabled. (Also see developer console for error logs marked 'Caught Critical error'.)
",
+ "HEALTH_DATA_PREVIEW_NECESSARY": "Security/app updates, analytics library initialization, user counts, and usage time are always anonymously collected as necessary app health indicators. These are aggregate statistics and no personal data is sent/logged.",
// extensions/default/InlineTimingFunctionEditor
"INLINE_TIMING_EDITOR_TIME": "Time",
@@ -1556,4 +1557,4 @@ define({
// surveys
"SURVEY_TITLE_VOTE_FOR_FEATURES_YOU_WANT": "Vote for the features you want to see next!"
-});
\ No newline at end of file
+});
diff --git a/src/utils/Metrics.js b/src/utils/Metrics.js
index c1b15bdeef..d502892d2a 100644
--- a/src/utils/Metrics.js
+++ b/src/utils/Metrics.js
@@ -403,6 +403,7 @@ define(function (require, exports, module) {
}
function setDisabled(shouldDisable) {
+ Phoenix._setHealthTrackingDisabled(shouldDisable);
disabled = shouldDisable;
}
diff --git a/test/SpecRunner.html b/test/SpecRunner.html
index 351d64df47..02a4d7bb3a 100644
--- a/test/SpecRunner.html
+++ b/test/SpecRunner.html
@@ -293,6 +293,12 @@
Phoenix.isSupportedBrowser = Phoenix.isNativeApp ||
(Phoenix.browser.isDeskTop && ("serviceWorker" in navigator));
window.testEnvironment = window.Phoenix.isTestWindow;
+ const healthDisabled = localStorage.getItem("PH_HEALTH_DISABLED");
+ window.Phoenix.healthTrackingDisabled = (healthDisabled === "true");
+ window.Phoenix._setHealthTrackingDisabled = function (isDisabled) {
+ window.Phoenix.healthTrackingDisabled = isDisabled;
+ localStorage.setItem("PH_HEALTH_DISABLED", String(isDisabled));
+ };
// now setup PhoenixBaseURL, which if of the form https://phcode.dev/ or tauri://localhost/
const url = new URL(window.location.href);