Skip to content

Fixes #70: Ignore errors created from browser extensions #123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 23, 2023
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
1 change: 1 addition & 0 deletions example/browser/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ <h1>Error Submission</h1>
<button onclick="throwReferenceError('function-does-exist')">Throw uncaught reference error</button>
<button id="throw-jquery-ajax-error">Throw jQuery ajax error</button>
<button id="throw-promise-unhandled-rejection">Throw promise unhandled rejection</button>
<button id="throw-browser-extension-error">Throw brower extension error</button>

<h1>Log Submission</h1>
<button class="submit-log">Submit log event</button>
Expand Down
9 changes: 9 additions & 0 deletions example/browser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ document.addEventListener("DOMContentLoaded", () => {
await builder.submit();
});

document
.querySelector("#throw-browser-extension-error")
.addEventListener("click", () => {
const error = new Error("A Browser Extension Error");
error.stack = "at <anonymous>() in chrome-extension://bmagokdooijbeehmkpknfglimnifench/firebug-lite.js:line 9716:col 29"

throw error;
});

document
.querySelector("#throw-custom-error")
.addEventListener("click", () => {
Expand Down
2 changes: 2 additions & 0 deletions packages/browser/src/BrowserExceptionlessClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Configuration, ExceptionlessClient, SimpleErrorPlugin } from "@exceptio

import { BrowserErrorPlugin } from "./plugins/BrowserErrorPlugin.js";
import { BrowserGlobalHandlerPlugin } from "./plugins/BrowserGlobalHandlerPlugin.js";
import { BrowserIgnoreExtensionErrorsPlugin } from "./plugins/BrowserIgnoreExtensionErrorsPlugin.js";
import { BrowserLifeCyclePlugin } from "./plugins/BrowserLifeCyclePlugin.js";
import { BrowserModuleInfoPlugin } from "./plugins/BrowserModuleInfoPlugin.js";
import { BrowserRequestInfoPlugin } from "./plugins/BrowserRequestInfoPlugin.js";
Expand All @@ -13,6 +14,7 @@ export class BrowserExceptionlessClient extends ExceptionlessClient {
config.useLocalStorage();

config.addPlugin(new BrowserGlobalHandlerPlugin());
config.addPlugin(new BrowserIgnoreExtensionErrorsPlugin());
config.addPlugin(new BrowserLifeCyclePlugin());
config.addPlugin(new BrowserModuleInfoPlugin());
config.addPlugin(new BrowserRequestInfoPlugin());
Expand Down
1 change: 1 addition & 0 deletions packages/browser/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { BrowserErrorPlugin } from "./plugins/BrowserErrorPlugin.js"
export { BrowserGlobalHandlerPlugin } from "./plugins/BrowserGlobalHandlerPlugin.js";
export { BrowserIgnoreExtensionErrorsPlugin } from "./plugins/BrowserIgnoreExtensionErrorsPlugin.js";
export { BrowserLifeCyclePlugin } from "./plugins/BrowserLifeCyclePlugin.js";
export { BrowserModuleInfoPlugin } from "./plugins/BrowserModuleInfoPlugin.js";
export { BrowserRequestInfoPlugin } from "./plugins/BrowserRequestInfoPlugin.js";
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/src/plugins/BrowserGlobalHandlerPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class BrowserGlobalHandlerPlugin implements IEventPlugin {
void this._client?.submitNotFound(settings.url);
} else if (xhr.status !== 401) {
// TODO: Handle async
void this._client?.createUnhandledException(toError(error) as Error, "JQuery.ajaxError")
void this._client?.createUnhandledException(toError(error), "JQuery.ajaxError")
.setSource(settings.url)
.setProperty("status", xhr.status)
.setProperty("request", settings.data)
Expand Down
20 changes: 20 additions & 0 deletions packages/browser/src/plugins/BrowserIgnoreExtensionErrorsPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
EventPluginContext,
IEventPlugin
} from "@exceptionless/core";

export class BrowserIgnoreExtensionErrorsPlugin implements IEventPlugin {
public priority = 15;
public name = "BrowserIgnoreExtensionErrorsPlugin";

public async run(context: EventPluginContext): Promise<void> {
const exception = context.eventContext.getException();
if (exception?.stack && exception.stack.includes("-extension://")) {
// Handles all extensions like chrome-extension://, moz-extension://, ms-browser-extension://, safari-extension://
context.log.info("Ignoring event with error stack containing browser extension");
context.cancelled = true;
}

return Promise.resolve();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { describe, test } from "@jest/globals";
import { expect } from "expect";

import {
EventContext,
EventPluginContext,
ExceptionlessClient
} from "@exceptionless/core";

import { BrowserIgnoreExtensionErrorsPlugin } from "../../src/plugins/BrowserIgnoreExtensionErrorsPlugin.js";

describe("BrowserIgnoreExtensionErrorsPlugin", () => {
let client: ExceptionlessClient;
let plugin: BrowserIgnoreExtensionErrorsPlugin;

beforeEach(() => {
client = new ExceptionlessClient();
plugin = new BrowserIgnoreExtensionErrorsPlugin();
});

const run = async (stackTrace?: string | undefined): Promise<EventPluginContext> => {
const error = new Error("Test");
if (stackTrace) {
error.stack = stackTrace;
}

const eventContext = new EventContext();
eventContext.setException(error);

const context = new EventPluginContext(client, { type: "error" }, eventContext);

await plugin.run(context);
return context;
}

test("should not cancel empty stack trace", async () => {
const context = await run();
expect(context.cancelled).toBe(false);
});

test("should not cancel normal stack trace", async () => {
const context = await run("at t() in https://test/Content/js/Exceptionless/exceptionless.min.js:line 1:col 260");
expect(context.cancelled).toBe(false);
});

test("should cancel browser extension stack trace", async () => {
const context = await run("at Object.initialize() in chrome-extension://bmagokdooijbeehmkpknfglimnifench/firebug-lite.js:line 6289:col 29");
expect(context.cancelled).toBe(true);
});
});