项目技术栈:next@13.2.4、@sentry/nextjs@^7.65.0、@reduxjs/toolkit@^1.9.3
本文并不搬运官方文档中已有的内容,只是对实践中觉得有用的部分加以说明总结
基础配置
官方文档:docs.sentry.io/platforms/j…
-
setUser:上报用户信息。可以设置用户登录后的ID或邮箱,这样当某个用户反馈问题的时候可以按用户筛选
-
Source map 对于定位异常所在的源码位置很有用。实践中很多异常是无法定位到具体位置的,并非是source map不生效,而是异常的位置出现在项目依赖包中(更准确的表达是,不是当前nextjs项目负责编译并打包的那部分代码),这一类很可能是噪音,这个后面会讨论
-
如果需要手动配置要上传source map的文件,可以通过以下方式配置:
include: [ { paths: ['./.next/static/chunks'], urlPrefix: '~/sign/_next/static/chunks', }, // ... ], ``` -
但是@sentry/nextjs可能会默认上传一些所需文件的sourcemap,所以可能是无需额外配置的
-
其中urlPrefix是指上传到sentry服务的source map文件前缀,在项目设置中可以看到:
Sentry根据文件路径匹配source map文件,例如当浏览器中出现异常的文件为
<your_website_host>/sign/_next/static/chunks/681-c6678eff4302fed3.js,那么Sentry会去查找source map文件<sentry_host>/sign/_next/static/chunks/681-c6678eff4302fed3.js.map
-
-
排除噪音
- ignoreErrors
- denyUrls
[ // Chrome extensions /extensions//i, /extension://i, /^chrome:///i, // 依赖的 sdk /posthog\// // 其它 ... ]
主动上报的场景
如果觉得sentry的噪音很多,可以先在核心功能的代码增加手动上报,优先解决手动上报的异常
外部模块异常处理(npm包、浏览器接口等)
外部模块抛出异常不会有source map,通常也难以定位异常是否对用户带来影响。上报方式有
- 提前检查传入传出参数是否异常
- 在调用处加try catch
- 对于React组件则可以在外部加一层Error Boundaries。通过全局Error Boundaries兜底
Redux方法异常
thunk方法的异常容易被吞,如:
extraReducers: builder => {
builder
.addCase(fetchData.pending, state => {
state.status = 'loading';
})
.addCase(fetchData.fulfilled, state => {
state.status = 'succeeded';
})
.addCase(fetchData.rejected, (state, action) => {
// 如果没加这个case, 那么fetchData抛出异常不会被调用者捕获,只是函数返回值为undefined
// 可在此处上报异常
console.log('Error:', action.error.message);
state.status = 'failed';
});
},
主动上报的方法
自定义事务
例子:
const transaction = startTransaction('上传文件');
// 业务代码
// 这里的错误都会归为事务“上传文件”
// ...
transaction?.finish();
Sentry默认会以页面为维度作为一个事务.
主动上报异常
用captureException方法
自动上报的level默认为error,主动上报的level可以设为fatal,方便筛选
captureMessage方法没有调用栈和source map信息,不要用。
自动上报的规则
接入sentry后所有未被捕获的异常都会自动上报。
这样会自动上报
function errorFunction1() {
throw new Error('custom error');
}
function errorFunction2() {
Promise.reject('custom error');
}
errorFunction1();
errorFunction2();
这样不会自动上报
function errorFunction1() {
try {
throw new Error('custom error');
} catch (error) {
console.error(error);
}
}
function errorFunction2() {
Promise.reject('custom error').catch((error) => {
console.error(error);
});
}
errorFunction1();
errorFunction2();
结论:理想情况下不应该出现未被捕获的异常,所有异常都应该在代码中捕获处理并手动上报。但现实是不太可能的,很多历史代码或者依赖的库会有一些异常噪音
离线版处理方案
Sentry提供断网的方案,即断网时会将异常对象序列化后存本地或indexDB,联网则自动上报并删除本地异常信息。
对于无法连外网的设备,可以通过钩子获取异常,手动存储在本地日志或indexDB中:
beforeSend: (event) => {
if(isSelfHost()) {
saveLogs(JSON.stringify(event))
}
},
还有一些有意思的功能
问卷 docs.sentry.io/platforms/j…
截屏 docs.sentry.io/platforms/j…
上传异常附件(Attachments),对客户端软件可能有用
Code owner 自动分配issue docs.sentry.io/product/iss…
看看Distributed Tracing能否用在后端接口异常监控: sentry.io/features/di…