Docker-Sentry

Docker  搭建 Sentry 监控 vue 前端报错

基本镜像

  • redis
  • postgres
  • sentry

生成 sentry 的 secret key

docker run –rm sentry config generate-secret-key

这个 key 要保存好

启动 redis

docker run -d –name sentry-redis redis

启动 postgres

docker run -d –name sentry-postgres -e POSTGRES_PASSWORD=secret -e POSTGRES_USER=sentry postgres

创建 sentry 用户

docker run -it –rm -e SENTRY_SECRET_KEY=’‘ –link sentry-postgres:postgres –link sentry-redis:redis sentry upgrade

启动 sentry 实例

docker run -d --name my-sentry \
-p 9000:9000 \
-e SENTRY_SERVER_EMAIL=xxx@qq.com \
-e SENTRY_EMAIL_HOST=smtp.qq.com \
-e SENTRY_EMAIL_PORT=587 \
-e SENTRY_EMAIL_USER=xxx@qq.com \
-e SENTRY_EMAIL_PASSWORD=xxx \
-e SENTRY_EMAIL_USE_TLS=true \
-e SENTRY_SECRET_KEY='xxxxx' \
--link sentry-redis:redis \
--link sentry-postgres:postgres sentry

启动 cron

docker run -d --name sentry-cron \
-e SENTRY_SERVER_EMAIL=xxx@qq.com \
-e SENTRY_EMAIL_HOST=smtp.qq.com \
-e SENTRY_EMAIL_PORT=587 \
-e SENTRY_EMAIL_USER=xxx@qq.com \
-e SENTRY_EMAIL_PASSWORD=xxx \
-e SENTRY_EMAIL_USE_TLS=true \
-e SENTRY_SECRET_KEY='xxx' \
--link sentry-postgres:postgres \
--link sentry-redis:redis sentry run cron

启动 worker

docker run -d --name sentry-worker-1 \
-e SENTRY_SERVER_EMAIL=xxx@qq.com \
-e SENTRY_EMAIL_HOST=smtp.qq.com \
-e SENTRY_EMAIL_PORT=587 \
-e SENTRY_EMAIL_USER=xxx@qq.com \
-e SENTRY_EMAIL_PASSWORD=xxx \
-e SENTRY_EMAIL_USE_TLS=true \
-e SENTRY_SECRET_KEY='xxxm' \
--link sentry-postgres:postgres --link sentry-redis:redis sentry run worker

进入系统

localhost:9000 进入 sentry, 创建 js 项目 获取到 sdk 要注册的地址

Vue 配置

安装 raven-js

npm install raven-js –save

插件

根据 raven-js/vue 的插件改了下,添加了 warnHandler, 因为 vue 内部的一些 warning 特别是一些  因为数据结构不对导致的渲染不出来报错,我们肯定也需要捕获

function formatComponentName(vm: any) {
if (vm.$root === vm) {
return "root instance";
}
var name = vm._isVue
? vm.$options.name || vm.$options._componentTag
: vm.name;
return (
(name ? "component <" + name + ">" : "anonymous component") +
(vm._isVue && vm.$options.__file ? " at " + vm.$options.__file : "")
);
}
//@ts-ignore
function vuePlugin(Raven, Vue: any) {
Vue = Vue || (window as any).Vue;

// quit if Vue isn't on the page
if (!Vue || !Vue.config) return;

var _oldOnError = Vue.config.errorHandler;
Vue.config.errorHandler = function VueErrorHandler(
error: any,
vm: any,
info: any
) {
var metaData: any = {};

// vm and lifecycleHook are not always available
if (Object.prototype.toString.call(vm) === "[object Object]") {
metaData.componentName = formatComponentName(vm);
metaData.propsData = vm.$options.propsData;
}

if (typeof info !== "undefined") {
metaData.lifecycleHook = info;
}

Raven.captureException(error, {
extra: metaData
});
console.error(error, info);
if (typeof _oldOnError === "function") {
_oldOnError.call(this, error, vm, info);
}
};

Vue.config.warnHandler = Vue.config.errorHandler;
}

export default vuePlugin;

注入 Vue

import Raven from "raven-js"
import RavenVue from "@/utils/sentry"
//@ts-ignore
const RavenPlugin: Raven.RavenPlugin = RavenVue
Raven.config("http://xxx@localhost:9000/2", {
environment: process.env.NODE_ENV,
captureUnhandledRejections: true
})
.addPlugin(RavenPlugin, Vue)
.install()

Vue.use(Element)
Vue.config.productionTip = false

Raven.context(function() {
new Vue({
router,
render: h => h(App)
}).$mount("#app")
})

在相应拦截出也可以,进行捕获:

http.interceptors.response.use(
config => {
return config.data || {}
},
(error: any) => {
// loadingInstance.close();
// 登录失败|禁用|token失效等相关问题返回401,此处做跳转登录页动作
if (error.response.status === 401) {
Notification({
type: "error",
title: HTTP_STATUS_TITLE_ERROR,
message: error.response.data.message || HTTP_STATUS_MSG_401,
duration: 3000
})
router.push({ path: PATH_LOGIN })
} else if (error.response.status >= 400 && error.response.status < 500) {
Notification({
type: "error",
title: HTTP_STATUS_TITLE_ERROR,
message: error.response.data.message || HTTP_STATUS_TITLE_ERROR,
duration: 3000
})
} else {
Notification({
// 基于axiosCreate中validateStatus配置的区间判断此时状态码>=500 或者 浏览器直接报错(比如跨域) 走此弹框。
type: "error",
title: HTTP_STATUS_TITLE_5XX,
message: HTTP_STATUS_MSG_5XX,
duration: 3000
})
Raven.captureException(error)
}

return Promise.reject(error.response)
}
)

配置邮箱通知

上面 启动 sentry 相关容器的时候有几个环境变量

-e SENTRY_SERVER_EMAIL=xxx@qq.com \
-e SENTRY_EMAIL_HOST=smtp.qq.com \
-e SENTRY_EMAIL_PORT=587 \
-e SENTRY_EMAIL_USER=xxx@qq.com \
-e SENTRY_EMAIL_PASSWORD=xxx \

SENTRY_SERVER_EMAIL 要和 SENTRY_EMAIL_USER 地址一样
我这里用的 qq 邮箱

注意:
SENTRY_EMAIL_PASSWORD 是开启设置里面的 smtp 控制的时候,通过短信获得的授权码,不是你的登录密码

到此配置完成,当遇到报错的时候,会直接推送给 sentry. sentry 会通过邮件通知