Bug 1439193: Include extension metadata in error reports. r?mkelly draft
authorKris Maglione <maglione.k@gmail.com>
Sat, 17 Feb 2018 23:40:45 -0800
changeset 756795 cb35bf408003ee2fcf3ae9037f8cbf89d6200507
parent 756794 13aea3b64e17ad4994e327bb6c551d8dcdd81799
push id99551
push usermaglione.k@gmail.com
push dateSun, 18 Feb 2018 07:41:03 +0000
reviewersmkelly
bugs1439193
milestone60.0a1
Bug 1439193: Include extension metadata in error reports. r?mkelly MozReview-Commit-ID: 85ihvsnNPW0
browser/modules/BrowserErrorReporter.jsm
--- a/browser/modules/BrowserErrorReporter.jsm
+++ b/browser/modules/BrowserErrorReporter.jsm
@@ -113,34 +113,46 @@ class BrowserErrorReporter {
     } else {
       try {
         Services.console.unregisterListener(this);
       } catch (err) {} // It probably wasn't registered.
     }
   }
 
   async observe(message) {
-    try {
-      message.QueryInterface(Ci.nsIScriptError);
-    } catch (err) {
+    if (!(message instanceof Ci.nsIScriptError)) {
       return; // Not an error
     }
 
     const isWarning = message.flags & message.warningFlag;
     const isFromChrome = REPORTED_CATEGORIES.has(message.category);
     if (!isFromChrome || isWarning) {
       return;
     }
 
     // Sample the amount of errors we send out
     const sampleRate = Number.parseFloat(Services.prefs.getCharPref(PREF_SAMPLE_RATE));
     if (!Number.isFinite(sampleRate) || (Math.random() >= sampleRate)) {
       return;
     }
 
+    const extensions = new Map();
+    for (let extension of WebExtensionPolicy.getActiveExtensions()) {
+      extensions.set(extension.mozExtensionHostname, extension);
+    }
+
+    function mangleExtURL(string, anchored = true) {
+      let re = new RegExp(`${anchored ? "^" : ""}moz-extension://([^/]+)/`, "g");
+
+      return string.replace(re, (m0, m1) => {
+        let id = extensions.has(m1) ? extensions.get(m1).id : m1;
+        return `moz-extension://${id}/`;
+      });
+    }
+
     // Parse the error type from the message if present (e.g. "TypeError: Whoops").
     let errorMessage = message.errorMessage;
     let errorName = "Error";
     if (message.errorMessage.match(ERROR_PREFIX_RE)) {
       const parts = message.errorMessage.split(":");
       errorName = parts[0];
       errorMessage = parts.slice(1).join(":").trim();
     }
@@ -148,40 +160,43 @@ class BrowserErrorReporter {
     // Pull and normalize stacktrace frames from the message
     const frames = [];
     let frame = message.stack;
 
     // Avoid an infinite loop by limiting traces to 100 frames.
     while (frame && frames.length < 100) {
       frames.push({
         function: frame.functionDisplayName,
-        filename: frame.source,
+        filename: mangleExtURL(frame.source),
         lineno: frame.line,
         colno: frame.column,
         in_app: true,
       });
       frame = frame.parent;
     }
 
     // Sentry-compatible request body copied from an example generated by Raven.js 3.22.1.
     const requestBody = Object.assign({}, this.requestBodyTemplate, {
       project: Services.prefs.getCharPref(PREF_PROJECT_ID),
       exception: {
         values: [
           {
             type: errorName,
             // Error messages may contain PII; see bug 1426482 for privacy
             // review and server-side mitigation.
-            value: errorMessage,
+            value: mangleExtURL(errorMessage, false),
             stacktrace: {
               frames,
             }
           },
         ],
       },
+      extra: {
+        extensions: Array.from(extensions.values(), ext => ext.debugName),
+      },
       culprit: message.sourceName,
     });
     requestBody.request.url = message.sourceName;
 
     const url = new URL(Services.prefs.getCharPref(PREF_SUBMIT_URL));
     url.searchParams.set("sentry_client", "firefox-error-reporter/1.0.0");
     url.searchParams.set("sentry_version", "7");
     url.searchParams.set("sentry_key", Services.prefs.getCharPref(PREF_PUBLIC_KEY));