Bug 1445009: Tag errors from extensions with isExtensionError. draft
authorMichael Kelly <mkelly@mozilla.com>
Mon, 19 Mar 2018 13:40:53 -0700
changeset 770141 0f88d1072dbb66334a6790bc9c62e8ce4a57f097
parent 770140 a5af344c86e9756d4dbef761e4a6060515c87a61
push id103345
push userbmo:mkelly@mozilla.com
push dateTue, 20 Mar 2018 20:38:35 +0000
bugs1445009
milestone61.0a1
Bug 1445009: Tag errors from extensions with isExtensionError. MozReview-Commit-ID: AQrlvTfJUUS
browser/modules/BrowserErrorReporter.jsm
browser/modules/test/browser/browser_BrowserErrorReporter.js
--- a/browser/modules/BrowserErrorReporter.jsm
+++ b/browser/modules/BrowserErrorReporter.jsm
@@ -146,35 +146,37 @@ class BrowserErrorReporter {
 
     // 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 exceptionValue = {};
-    const transforms = [
-      addErrorMessage,
-      addStacktrace,
-      addModule,
-      mangleExtensionUrls,
-    ];
-    for (const transform of transforms) {
-      await transform(message, exceptionValue);
-    }
-
     const requestBody = {
       ...this.requestBodyTemplate,
       timestamp: new Date().toISOString().slice(0, -1), // Remove trailing "Z"
       project: Services.prefs.getCharPref(PREF_PROJECT_ID),
       exception: {
         values: [exceptionValue],
       },
+      tags: {},
     };
 
+    const transforms = [
+      addErrorMessage,
+      addStacktrace,
+      addModule,
+      mangleExtensionUrls,
+      tagExtensionErrors,
+    ];
+    for (const transform of transforms) {
+      await transform(message, exceptionValue, requestBody);
+    }
+
     const url = new URL(Services.prefs.getCharPref(PREF_SUBMIT_URL));
     url.searchParams.set("sentry_client", `${SDK_NAME}/${SDK_VERSION}`);
     url.searchParams.set("sentry_version", "7");
     url.searchParams.set("sentry_key", Services.prefs.getCharPref(PREF_PUBLIC_KEY));
 
     try {
       await this.fetch(url, {
         method: "POST",
@@ -290,8 +292,14 @@ function mangleExtensionUrls(message, ex
   }
 
   exceptionValue.value = mangleExtURL(exceptionValue.value, false);
   exceptionValue.module = mangleExtURL(exceptionValue.module);
   for (const frame of exceptionValue.stacktrace.frames) {
     frame.module = mangleExtURL(frame.module);
   }
 }
+
+function tagExtensionErrors(message, exceptionValue, requestBody) {
+  if (exceptionValue.module && exceptionValue.module.startsWith("moz-extension://")) {
+    requestBody.tags.isExtensionError = true;
+  }
+}
--- a/browser/modules/test/browser/browser_BrowserErrorReporter.js
+++ b/browser/modules/test/browser/browser_BrowserErrorReporter.js
@@ -401,8 +401,51 @@ add_task(async function testAddonIDMangl
   ok(
     stackFrame.module.startsWith(`moz-extension://${id}/`),
     "Stack frame filenames use the proper add-on ID instead of internal UUIDs.",
   );
 
   await extension.unload();
   reporter.uninit();
 });
+
+add_task(async function testExtensionTag() {
+  const fetchSpy = sinon.spy();
+  // Passing false here disables category checks on errors, which would
+  // otherwise block errors directly from extensions.
+  const reporter = new BrowserErrorReporter({fetch: fetchSpy, chromeOnly: false});
+  await SpecialPowers.pushPrefEnv({set: [
+    [PREF_ENABLED, true],
+    [PREF_SAMPLE_RATE, "1.0"],
+  ]});
+  resetConsole();
+  reporter.init();
+
+  // Create and install test add-on
+  const id = "browsererrorcollection@example.com";
+  const extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      applications: {
+        gecko: { id },
+      },
+    },
+    background() {
+      throw new Error("testExtensionTag error");
+    },
+  });
+  await extension.startup();
+
+  // Just in case the error hasn't been thrown before add-on startup.
+  let call = await TestUtils.waitForCondition(
+    () => fetchCallForMessage(fetchSpy, "testExtensionTag error"),
+    `Wait for error from ${id} to be logged`,
+  );
+  let body = JSON.parse(call.args[1].body);
+  ok(body.tags.isExtensionError, "Errors from extensions have an isExtensionError tag.");
+
+  await extension.unload();
+  reporter.uninit();
+
+  await reporter.observe(createScriptError({message: "testExtensionTag not from extension"}));
+  call = fetchCallForMessage(fetchSpy, "testExtensionTag not from extension");
+  body = JSON.parse(call.args[1].body);
+  is(body.tags.isExtensionError, undefined, "Normal errors do not have an isExtensionError tag.");
+});