Skip to main content

[WebService] Bugsnag API 使用筆記

使用版本 @ 7.0.0

安裝(搭配 React)

$ npm install --save @bugsnag/js @bugsnag/plugin-react

載入:

// ES module-style import
import Bugsnag from '@bugsnag/js';
import BugsnagPluginReact from '@bugsnag/plugin-react';

使用:

Bugsnag.start({
apiKey: 'YOUR_API_KEY',
plugins: [new BugsnagPluginReact(React)],
otherOptions: value,
});

套用到 React:

const ErrorBoundary = Bugsnag.getPlugin('react');

回報錯誤訊息(notify)

Reporting handled errors

// Bugsnag.notify(err, onError, cb)
import Bugsnag from '@bugsnag/js';

Bugsnag.notify(new Error('Something broke!'));

// 使用 onError function
Bugsnag.notify(new Error('Bad, but not fatal'), (event) => {
// return false 就不會送出
if (event.getUser().id === '1') return false;

event.severity = 'info';
event.context = 'component-space-246';
event.setUser('1', 'bugs.nag@bugsnag.com', 'B. Nag');
event.addMetadata('hyperflopz', { count: 23 });
});

// 使用 callback
Bugsnag.notify(new Error('uh oh'), null, function (err, event) {
if (err) {
console.log('Failed to send report because of:\n' + err.stack);
} else {
console.log('Successfully sent report "' + event.errors[0].errorMessage + '"');
}
});

客製化錯誤訊息(metadata)

Customizing error reports @ Bugsnag Docs

Bugsnag.addMetadata(section, key, value)
Bugsnag.addMetadata(section, { [key]: value,})

在 v7 之後,原本的 beforeSend 改名為 onError,裡面接收的參數從 report 改名為 event;原先的 updateMetaData 也改為 addMetadata。詳細的說明可以參考升級指南(Upgrading)

⚠️ 留意原本是用大駝峰的 metaData 修正為 metadata

export const bugsnagClient = bugsnag({
apiKey: BUGSNAG_API_KEY,
onError: (event) => {
// 透過 addMetadata 更新資料到 metadata 中,如此不會覆蓋原有的 metadata
// 添加 user 資料
event.setUser(id, email, name);
event.addMetadata('user', state?.personalInfo);

// 添加 device 資料
event.addMetadata('device', state?.deviceInfo);

// 添加其他客製化資料
event.addMetadata('project', state?.app);
event.addMetadata('networkQuality', state?.webRTC?.networkQuality);
},
});

客製化 breadcrumb

Customizing breadcrumbs @ Bugsnag Docs

Bugsnag.leaveBreadcrumb('Preference updated', metadata, 'state');

透過 onBreadcrumb

Bugsnag.start({
apiKey: BUGSNAG_API_KEY,
onError: (event) => {
/*...*/
},
onBreadcrumb: (breadcrumb) => {
/* breadcrumb 物件 { message, metadata, timestamp, type } */
if (breadcrumb.type === 'navigation' && breadcrumb.metadata.to === '/home') {
return false;
}
breadcrumb.metadata.to = stripQueryString(breadcrumb.metadata.to);
breadcrumb.metadata.path = state?.path;
},
});

⚠️ 如果在 log 會留下 breadcrumb 的話,在 onBreadcrumb 中使用 console.log 可能會導致無窮迴圈。

客製化 logger

Configuration options > logger @ bugsnag

const logger = {
debug: (message) => console.log('[bugsnag] debug: ', message),
info: (message) => console.info('[bugsnag] info: ', message),
warn: (message) => console.warn('[bugsnag] warn: ', message),
error: (message) => console.error('[bugsnag] error: ', message),
};

Bugsnag.start({
apiKey: BUGSNAG_API_KEY,
...(process.env.NODE_ENV === 'development' && { logger }),
});

上傳 SourceMap

uploading source maps @ BugSnag > Build & deploy integrations > Node.js/npm scripts

問題解決

在 Chrome Extension 或第三方服務使用 Bugsnag

如果有使用 Bugsnag 這類第三方的錯誤通知程式,需要留意使用的方式略有不同:

參考:How can I get error reports from browser extensions? @ bugsnag docs

For v.7x.x

// v7.x.x
export const bugsnagClient = Bugsnag.createClient({
//...
onError: (event) => {
event.errors.map((error) => {
return error.stacktrace.map(function (frame) {
frame.file = frame.file.replace(
/chrome-extension:/g,
'chrome_extension:'
);
return frame;
});
});
}
})

module.export bugsnagClient;

另外,由於在 Chrome Extension 中有可能需要同時在 content-script 和 background 中使用 bugsnagClient,因此需使用 createClient 並 export 這個 client,並可以在 onError 的時候透過不同的 context 來區別:

export const bugsnagClient = Bugsnag.createClient({
apiKey: BUGSNAG_API_KEY,
plugins: [new BugsnagPluginReact(React)],
appVersion,
releaseStage: process.env.NODE_ENV || 'development',
// FIXME:
// enabledReleaseStages: ['production'],
...(process.env.NODE_ENV === 'development' && { logger }),
onError: (event) => {
event.errors.map((error) => {
// ...
});

// 使用 context 來區分是在 background 或 front (content-script, iframe) 被呼叫
if (event.context.includes('background')) {
event.context = 'background';
} else if (event.context.includes('index')) {
event.context = 'front-side';
}
},
});

⚠️ 即使 background 和 front-side(content-script, iframe)是 import 同一支檔案的 bugsnagClient,但因為是在不同的環境下,所以載到的 bugsnagClient 會是獨立的,也就是在不同的 execution context。

For v6.x.x

// v6.x.x
bugsnag({
beforeSend: function (report) {
report.stacktrace = report.stacktrace.map(function (frame) {
frame.file = frame.file.replace(/chrome-extension:/g, 'chrome_extension:');
return frame;
});
},
});