Sentry 为一套开源的应用监控和错误追踪的解决方案。这套解决方案由对应各类语言的 SDK 和一套庞大的数据后台服务组成。应用须要经过与之绑定的 token 接入 Sentry SDK 完成数据上报的配置。经过 Sentry SDK 的配置,还能够上报错误关联的版本信息、发布环境。同时 Sentry SDK 会自动捕捉异常发生前的相关操做,便于后续异常追踪。异常数据上报到数据服务以后,会经过过滤、关键信息提取、概括展现在数据后台的 Web 界面中。前端
在完成接入后咱们就能够从管理系统中实时查看应用的异常,从而主动监控应用在客户端的运行状况。经过配置报警、分析异常发生趋势更主动的将异常扼杀在萌芽状态,影响更少的用户。经过异常详情分析、异常操做追踪,避免对客户端应用异常两眼一抹黑的状态,更高效的解决问题。vue
这篇文章也将会从一键部署服务开始,经过解决部署过程当中遇到的问题,分享到完成前端应用监控和异常数据使用的整个详细过程,但愿会对你的部署和使用中遇到的问题有所帮助。python
Sentry 的管理后台是基于 Python Django 开发的。这个管理后台由背后的 Postgres 数据库(管理后台默认的数据库,后续会以 Postgres 代指管理后台数据库并进行分享)、ClickHouse(存数据特征的数据库)、relay、kafka、redis 等一些基础服务或由 Sentry 官方维护的总共 23 个服务支撑运行。可见的是,若是独立的部署和维护这 23 个服务将是异常复杂和困难的。幸运的是,官方提供了基于 docker 镜像的一键部署实现 getsentry/onpremise。linux
这种部署方式依赖于 Docker 19.03.6+ 和 Compose 1.24.1+webpack
Docker 是能够用来构建和容器化应用的开源容器化技术。Compose 是用于配置和运行多 Docker 应用的工具,能够经过一个配置文件配置应用的全部服务,并一键建立和运行这些服务。nginx
在准备好 linux 服务器以后,并按照官方文档安装好对应版本的 Docker 和 Compose 以后,将 onpremise 的源代码克隆到工做台目录:git
git clone https://github.com/getsentry/onpremise.git # 切换到 20.10.1 版本,后续的分享将会基于这个版本进行 git checkout release/20.10.1
在后续部署的过程当中,须要拉取大量镜像,官方源拉取较慢,能够修改 docker 镜像源,修改或生成 /etc/docker/daemon.json
文件:github
{ "registry-mirrors": ["镜像地址"] }
而后从新加载配置,并重启 docker 服务:web
sudo systemctl daemon-reload sudo systemctl restart docker
在 onpremise 的根路径下有一个 install.sh 文件,只须要执行此脚本便可完成快速部署,脚本运行的过程当中,大体会经历如下步骤:ajax
在执行结束后,会提示建立完毕,运行 docker-compose up -d
启动服务。
在使用不添加 -d
参数运行 docker-compose up
命令后,咱们能够看到服务的启动日志,须要等待内部 web、relay、snuba、kafka 等所有启动并联动初始化后,服务才算彻底启动,此刻才可使用默认端口访问管理端默认服务地址,此时能够进行域名配置,并将 80 端口解析到服务的默认端口上,即可以使用域名进行访问。
第一次访问管理后台,能够看到欢迎页面,完成必填项的配置,便可正式访问管理后台。
/api/[id]/store/
配置到公网环境,保证数据不会泄密)。完成这部分工做后,对服务没有定制化需求的能够跳至前端接入和使用部分。
能够看到在服务运行的过程当中,会在 docker volume 数据卷挂载位置存储数据,如 Postgres、运行日志等,docker volume 默认挂载在 /var 目录下,若是你的 /var 目录容量较小,随着服务的运行会很快占满,须要对 docker volume 挂载目录进行修改。
# 在容量最大的目录下建立文件夹 mkdir -p /data/var/lib/ # 中止 docker 服务 systemctl stop docker # 将 docker 的默认数据复制到新路径下,删除旧数据并建立软链接,即便得存储实际占用磁盘为新路径 /bin/cp -a /var/lib/docker /data/var/lib/docker && rm -rf /var/lib/docker && ln -s /data/var/lib/docker /var/lib/docker # 重启 docker 服务 systemctl start docker
一键部署的 Sentry 服务总会有不符合咱们使用和维护设计的地方,这个时候,就须要经过对部署配置的修改来知足本身的需求。
在经过 docker-compose 快速部署以后,咱们先来观察下启动了哪些服务,并为后续的适配和修改分析下这些服务的做用,运行 docker 查看全部容器的命令:
docker ps
能够看到如今启动的全部服务,而且一些服务是使用的同一个镜像经过不一样的启动参数启动的,按照镜像区分而且经过笔者的研究推测,各个服务的做用以下:
nginx:1.16
sentry-onpremise-local:如下服务使用同一个镜像,即便用同一套环境变量
sentry_onpremise_worker_1
sentry_onpremise_cron_1
sentry_onpremise_web_1
sentry_onpremise_ingest-consumer_1
sentry-cleanup-onpremise-local
sentry_onpremise_sentry-cleanup_1
sentry_onpremise_snuba-cleanup_1
getsentry/relay:20.10.1
sentry_onpremise_relay_1
symbolicator-cleanup-onpremise-local
sentry_onpremise_symbolicator-cleanup_1
getsentry/snuba:20.10.1
sentry_onpremise_snuba-api_1
sentry_onpremise_snuba-consumer_1
sentry_onpremise_snuba-outcomes-consumer_1
sentry_onpremise_snuba-sessions-consumer_1
sentry_onpremise_snuba-replacer_1
tianon/exim4
sentry_onpremise_smtp_1
memcached:1.5-alpine
getsentry/symbolicator:bc041908c8259a0fd28d84f3f0b12daa066b49f6
sentry_onpremise_symbolicator_1
postgres:9.6
sentry_onpremise_postgres_1
confluentinc/cp-kafka:5.5.0
sentry_onpremise_kafka_1
redis:5.0-alpine
sentry_onpremise_redis_1
confluentinc/cp-zookeeper:5.5.0
sentry_onpremise_zookeeper_1
yandex/ClickHouse-server:19.17
sentry_onpremise_ClickHouse_1
同时,根据异常上报到服务后,日志的记录状况可知,运行机制大概以下:
要对部署和运行进行修改的话,须要找到对应的配置文件,先看下 onpremise 部署实现的主要文件结构和做用:
sentry/:sentry-onpremise-local 镜像的构建和基于此镜像启动的主服务的配置都在这个文件夹下
同时须要注意的是,一旦部署过以后,install.sh 脚本就会根据 xx.example.xx 生成实际生效的文件,并且,再次执行 install.sh 脚本时会检测这些文件存不存在,存在则不会再次生成,因此须要修改配置后从新部署的状况下,咱们最好将生成的文件删除,在 xx.example.xx 文件中修改配置。
根据服务组成和运行机制得知,主服务是基于 sentry-onpremise-local
镜像启动的,而 sentry-onpremise-local
镜像中的 sentry 配置会合并 sentry.conf.py
,此文件又是由 sentry.conf.example.py
生成,因此后续定制化服务时,会重点修改 sentry.conf.example.py
配置模板文件。
在数据库单机化部署的状况下,一旦出现机器故障,数据会损坏丢失,而 onpremise 的一键部署就是以 docker 的形式单机运行的数据库服务,且数据库数据也存储在本地。
能够看到 Sentry 的数据库有两个,Postgres 和 ClickHouse。
虽然 Sentry 不是业务应用,在宕机后不影响业务正常运行,数据的稳定并非特别重要,可是 Postgres 中存储了接入 Sentry 的业务应用的 id 和 token 与对应关系,在这些数据丢失后,业务应用必需要修改代码以修改 token 从新上线。为了不这种影响,且公司有现成的可容灾和按期备份的 Postgres 数据库,因此将数据库切换为外部数据库。
修改 sentry.conf.example.py
文件中 DATABASES
变量便可:
DATABASES = { 'default': { 'ENGINE': 'sentry.db.postgres', 'NAME': '数据库名', 'USER': '数据库用户名', 'PASSWORD': '数据库密码', 'HOST': '数据库域名', 'PORT': '数据库端口号', } }
因为再也不须要以 Docker 启动 Postgres 数据库服务,因此将 Postgres 相关信息从 docker-compose.yml 文件中删除。删掉其中的 Postgres 相关配置便可。
depends_on: - redis - postgres # 删除 # ... services: # ... # 删除开始 postgres: << : *restart_policy image: 'postgres:9.6' environment: POSTGRES_HOST_AUTH_METHOD: 'trust' volumes: - 'sentry-postgres:/var/lib/postgresql/data' # 删除结束 # ... volumes: sentry-data: external: true sentry-postgres: # 删除 external: true # 删除
同时,因为 Sentry 在启动前,初始化数据库结构的使用会 pg/citext 扩展,建立函数,因此对数据库的用户权限有必定要求,也须要将扩展提早启用,不然会致使 install.sh 执行失败。
随着数据的上报,服务器本地的磁盘占用和数据库大小会愈来愈大,在接入300万/日的流量后,磁盘总占用天天约增长 1.4G-2G,按照 Sentry 定时数据任务的配置保留 90 天来讲,全量接入后磁盘占用会维持在一个比较大的值,同时这么大的数据量对数据的查询也是一个负担。为了减轻负担,须要从服务端和业务应用端同时入手。综合考虑咱们将数据保留时长改成 7 天。修改 .env
文件便可:
SENTRY_EVENT_RETENTION_DAYS=7
也能够直接修改 sentry.conf.example.py
:
SENTRY_OPTIONS["system.event-retention-days"] = int( env("SENTRY_EVENT_RETENTION_DAYS", "90") ) # 改成 SENTRY_OPTIONS["system.event-retention-days"] = 7
须要注意的是,定时任务使用 delete 语句删除过时数据,此时磁盘空间不会被释放,若是数据库没有定时回收的机制,则须要手动进行物理删除。
# 做为参考的回收语句 vacuumdb -U [用户名] -d [数据库名] -v -f --analyze
Sentry 自己支持 SAML二、Auth0 等单点登陆方式,可是咱们须要支持 CAS3.0,Sentry 和 Django 没有对此有良好支持的插件,因此笔者组装了一个基本可用的插件 sentry_cas_ng。
使用时,须要进行插件的安装、注册和配置,插件使用 github 地址安装,须要一些前置的命令行工具,就不在 requirements.txt 文件中进行配置,直接修改 sentry/Dockerfile
文件进行安装,追加如下内容:
# 设置镜像源加速 RUN echo 'deb http://mirrors.aliyun.com/debian/ buster main non-free contrib \n\ deb http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib \n\ deb http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib \n\ deb http://mirrors.aliyun.com/debian-security/ buster/updates main non-free contrib \n\ deb-src http://mirrors.aliyun.com/debian/ buster main non-free contrib \n\ deb-src http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib \n\ deb-src http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib \n\ deb-src http://mirrors.aliyun.com/debian-security/ buster/updates main non-free contrib' > /etc/apt/sources.list # 升级和安装前置工具 RUN apt-get update && apt-get -y build-dep gcc \ && apt-get install -y -q libxslt1-dev libxml2-dev libpq-dev libldap2-dev libsasl2-dev libssl-dev sysvinit-utils procps RUN apt-get install -y git # 安装这个基本可用的 cas 登陆插件 RUN pip install git+https://github.com/toBeTheLight/sentry_cas_ng.git
同时修改 sentry.conf.example.py
文件,以进行插件的注册和配置项配置:
# 修改 session 库,解决 session 较长的问题 SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 在 django 中安装插件 INSTALLED_APPS = INSTALLED_APPS + ( 'sentry_cas_ng', ) # 注册插件中间件 MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + ( 'sentry_cas_ng.middleware.CASMiddleware', ) # 注册插件数据管理端 AUTHENTICATION_BACKENDS = ( 'sentry_cas_ng.backends.CASBackend', ) + AUTHENTICATION_BACKENDS # 配置 CAS3.0 单点登陆的登陆地址 CAS_SERVER_URL = 'https://xxx.xxx.com/cas/' # 配置 cas 版本信息 CAS_VERSION = '3' # 由于插件是使用拦截登陆页强制跳转至 SSO 页面的方式实现的 # 因此须要配置登陆拦截作跳转 SSO 登陆操做 # 须要将 pathReg 配置为你的项目的登陆 url 的正则 # 同时,当页面带有 ?admin=true 参数时,不跳转至 SSO def CAS_LOGIN_REQUEST_JUDGE(request): import re pathReg = r'.*/auth/login/.*' return not request.GET.get('admin', None) and re.match(pathReg, request.path) is not None # 配置登出拦截作登出操做 # 让插件识别当前为登出操做,销毁当前用户 session # 为固定内容,不变 def CAS_LOGOUT_REQUEST_JUDGE(request): import re pathReg = r'.*/api/0/auth/.*' return re.match(pathReg, request.path) is not None and request.method == 'DELETE' # 是否自动关联 sso cas 信息至 sentry 用户 CAS_APPLY_ATTRIBUTES_TO_USER = True # 登陆后分配的默认组织名称,必须与管理端 UI 设置的组织名相同 AUTH_CAS_DEFAULT_SENTRY_ORGANIZATION = '[组织名]' # 登陆后默认的角色权限 AUTH_CAS_SENTRY_ORGANIZATION_ROLE_TYPE = 'member' # 登陆后默认的用户邮箱后缀,如 @163.com 中的 163.com AUTH_CAS_DEFAULT_EMAIL_DOMAIN = '[邮箱后缀]'
完成配置后,须要使用 Sentry 的默认组织名 sentry,访问 xxx/auth/login/sentry?admin=true
,避过 CAS 插件拦截,以管理员身份登陆,而后修改 Sentry 设置的组织名为插件中的配置的组织名变量 AUTH_CAS_DEFAULT_SENTRY_ORGANIZATION
的值。不然新用户经过 SSO 登陆后会因为要分配的组织名和服务设置的组织名不匹配出现错误。
在登陆 Sentry 以后,能够发现异常的时间为 UTC 时间,每一个用户均可以在设置中将时区改成本地时区:
出于用户友好考虑,能够直接修改服务的默认时区,在 sentry.conf.example.py
文件中添加配置:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name SENTRY_DEFAULT_TIME_ZONE = 'Asia/Shanghai'
Sentry 会获取请求头中 X-Forwarded-For (结构为ip1,ip2,ip3
)的第一个 IP 为真实用户 IP,Sentry 一键部署启动的服务的最靠前的服务是一个 Nginx 服务,它的配置就是以前提到的 nginx/nginx.conf
文件,在其中能够看到一行 proxy_set_header X-Forwarded-For $remote_addr;
,其中 $remote_addr
表示“客户端” IP,可是这个客户端是相对于 Nginx 服务的而言的,若是前面有其余的代理服务器,那么拿到的就是代理服务器的 IP。在咱们的部署环境中,X-Forwarded-For 由前置的 Nginx 服务提供,且已经处理成须要的格式,因此删除此行便可。
在 Sentry 的默认的角色权限系统中有如下名词,在信息结构按照包含关系有组织、团队、项目、事件。
在角色层面又具备:
且角色是跟随帐号的,也就是说,一个 admin 会在他加入的全部的团队中都是 admin。
在咱们的权限设计中,但愿的是由 owner 建立团队和团队下的项目,而后给团队分配 admin。即 admin 角色管理团队下的权限配置,可是不能建立和删除团队和项目。在 Sentry 的现状下,最接近这套权限设计的状况中,只能取消 admin 对团队、项目的增删权限,而没法设置他只拥有某个团队的权限。
在 Sentry 的配置中是这么管理权限的:
SENTRY_ROLES = ( # 其余角色 # ... { 'id': 'admin', 'name': 'Admin', 'desc': '省略' 'of.', 'scopes': set( [ "org:read","org:integrations", "team:read","team:write","team:admin", "project:read", "project:write","project:admin","project:releases", "member:read", "event:read", "event:write","event:admin", ]), } )
其中 read、write 为配置读写,admin 则是增删,咱们只须要删掉 "team:admin"
和 "project:admin"
后在 sentry.conf.example.py
文件中复写 SENTRY_ROLES
变量便可。须要调整其余角色权限能够自行调整。
至此,咱们的定制化配置就完成了。
基本上全部的配置均可以经过在 sentry.conf.example.py
文件中从新赋值整个变量或某个字段的方式调整,有哪些配置项的话能够去源代码的 src/sentry/conf/server.py 文件中查询,有其余需求的话能够自行尝试修改。
后续的接入使用,咱们以 Vue 项目示范。
首先须要进行对应团队和项目的建立:
选取平台语言等信息后,能够建立团队和项目:
npm i @sentry/browser @sentry/integrations
其中 @sentry/browser
为浏览器端的接入 sdk,须要注意的是,它只支持 ie11 及以上版本的浏览器的错误上报,低版本须要使用 raven.js
,咱们就再也不介绍。
@sentry/integrations
包里是官方提供的针对前端各个框架的功能加强,后续会介绍。
在进行接入是,咱们必需要知道的是和你当前项目绑定的 DSN(客户端秘钥),可在管理端由 Settings 进入具体项目的配置中查看。
import * as Sentry from '@sentry/browser' import { Vue as VueIntegration } from '@sentry/integrations' import Vue from 'vue' Sentry.init({ // 高访问量应用能够控制上报百分比 tracesSampleRate: 0.3, // 不一样的环境上报到不一样的 environment 分类 environment: process.env.ENVIRONMENT, // 当前项目的 dsn 配置 dsn: 'https://[clientKey]@sentry.xxx.com/[id]', // 追踪 vue 错误,上报 props,保留控制台错误输出 integrations: [new VueIntegration({ Vue, attachProps: true, logErrors: true })] })
能够看到的是 VueIntegration 加强上报了 Vue 组件的 props,同时咱们还能够额外上报构建的版本信息 release。此时,Sentry 已经开始上报 console.error、ajax error、uncatch promise 等信息。同时,咱们还能够进行主动上报、关联用户。
Sentry.captureException(err) Sentry.setUser({ id: user.id })
Sentry 还提供了基于 Webpack 的 plugin:webpack-sentry-plugin 帮助完成接入,就再也不作介绍。
进入某个具体的项目后,能够看到 Sentry 根据错误的 message、stack、发生位置进行概括分类后的 Issue 列表:
在右侧,能够看到每一个错误的发生趋势、发生次数、影响用户数和指派给谁解决这个问题的按钮。咱们能够经过这些指标进行错误处理的优先级分配和指派。
经过发展趋势,咱们也能够观察到是否与某次上线有关,还能够经过左侧的 Discover 建立自定义的趋势看板,更有针对性的进行观察。
点击进入每一个 issue 后,能够看到详细信息:
从上到下,能够看到错误的名称,发生的主要环境信息,Sentry 提取的错误特征,错误堆栈,在最下面的 BREADCRUMBS
中能够看到异常发生前的前置操做有哪些,能够帮助你进行问题操做步骤的还原,协助进行问题排查。
Sentry 的入门使用到此为止。其余的功能,如报警配置、性能监控能够自行探索。
做为智联招聘的前端架构团队,咱们一直在寻找志同道合的先后端架构师和高级工程师,若是您也和咱们同样热爱技术、热爱学习、热爱探索,就请加入咱们吧!请将简历请发送至邮箱zpfe@group.zhaopin.com.cn,或者微信扫码沟通。