Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/extensions/default/HealthData/HealthDataManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
27 changes: 23 additions & 4 deletions src/extensions/default/HealthData/SendToAnalytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@
*
*/

/*global Phoenix*/
/*global AppConfig*/
define(function (require, exports, module) {
const Metrics = brackets.getModule("utils/Metrics"),
PreferencesManager = brackets.getModule("preferences/PreferencesManager"),
PerfUtils = brackets.getModule("utils/PerfUtils"),
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;
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ <h1 class="dialog-title">{{Strings.HEALTH_DATA_PREVIEW}}</h1>
<input type="checkbox" data-target="hdPref" {{#hdPref}}checked{{/hdPref}} />
{{Strings.HEALTH_DATA_DO_TRACK}}
</label>
<div style="display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px; border-left: 3px solid #aaa; font-size: 13px; color: #666; margin: 8px 0;">
<span style="flex-shrink: 0;">ℹ️</span>
<span>{{Strings.HEALTH_DATA_PREVIEW_NECESSARY}}</span>
</div>
</div>
<div class="dialog-message preview-content-container">
<p class="preview-content">{{{content}}}</p>
Expand Down
15 changes: 7 additions & 8 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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);
Expand All @@ -394,14 +401,6 @@
<script src="appConfig.js"></script>
<script type="module">
import BugsnagPerformance from "./thirdparty/bugsnag-performance.min.js";
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
});
window.BugsnagPerformance = BugsnagPerformance;
</script>
<script src="loggerSetup.js"></script>
Expand Down
2 changes: 1 addition & 1 deletion src/loggerSetup.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/nls/root/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,7 @@ define({
"HEALTH_DATA_NOTIFICATION_MESSAGE": "{APP_NAME} <strong>does not collect or process any personally identifiable information</strong>, but <strong>collects anonymous usage statistics</strong> 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.<br><br> You can see your data or <strong>choose not to share any anonymous data</strong> by selecting <strong>Help > Health Report</strong>. These <strong>anonymous</strong> 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! <br>",
"HEALTH_DATA_PREVIEW": "{APP_NAME} Health Report",
"HEALTH_DATA_PREVIEW_INTRO": "<p>{APP_NAME} <strong>does not collect or process any personally identifiable information</strong>, but <strong>collects anonymous usage statistics</strong> to guard your privacy. These <strong>anonymous</strong> app usage statistics and error reports helps prioritize features, find bugs, and spot usability issues for improving your experience with {APP_NAME}.</p> <p>Below is a preview of the data that will be sent in your next Health Report <em>if</em> it is enabled. (Also see developer console for error logs marked 'Caught Critical error'.)</p>",
"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",
Expand Down Expand Up @@ -1556,4 +1557,4 @@ define({

// surveys
"SURVEY_TITLE_VOTE_FOR_FEATURES_YOU_WANT": "Vote for the features you want to see next!"
});
});
1 change: 1 addition & 0 deletions src/utils/Metrics.js
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ define(function (require, exports, module) {
}

function setDisabled(shouldDisable) {
Phoenix._setHealthTrackingDisabled(shouldDisable);
disabled = shouldDisable;
}

Expand Down
6 changes: 6 additions & 0 deletions test/SpecRunner.html
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading