Sentry监控Django应用并使用email+钉钉通知

5,039 阅读4分钟
原文链接: mp.weixin.qq.com

Sentry是一个开源的程序异常跟踪系统,基本上主流的语言,Sentry都支持,Sentry是用Django+DRF+Celery+Celery-Beat开发的,如果你是Pythoner,并且对这些技术栈都相当熟悉,你可以阅读一下相关的源码,定有不少的收获,这里值得一提的是Sentry在部署的时候只支持Python2,不支持Python3。

这篇文章我们将会以 Docker的方式部署  Sentry,这也是官方推荐的部署方式,并且我们会写一个简单的  Django应用,使用  email +钉钉 的方式进行通知,一旦出现异常,开发人员可以及时收到并处理。

环境

我在 vultr上开了一台云服务器供这次测试使用,用的是  CentOS7的系统。

初始化操作

安装epel源

  1. $ yum install epel-release -y

更新系统

  1. $ yum update -y

安装一些工具包

  1. $ yum install python-pip vim git -y

建议重启下系统

  1. $ reboot

基本配置

  • 内存

  1. $ free -h

  2.              total        used        free      shared  buff/cache   available

  3. Mem:           3.7G         95M        3.4G        8.4M        168M        3.4G

  4. Swap:            0B          0B          0B

  • CPU

  1. $ cat /proc/cpuinfo | grep processor | wc -l

  2. 2

配置也就是 2H4G,如果你是  1G内存的服务器,貌似我在腾讯云上面跑起来比较艰难,感觉至少还是要  2G把。

安装Docker

CentOS系列的安装文档放在:https://docs.docker.com/install/linux/docker-ce/centos/ ,感兴趣的就可以去阅读,我这里就简化一些操作。

  • 安装一些软件包

  1. $ yum install -y yum-utils device-mapper-persistent-data lvm2

  • 添加docker的repo源

  1. $ yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

  • 安装docker

  1. $ yum install docker-ce -y

  • 启动docker

  1. $ systemctl start docker

  • 开机自启动

  1. $ systemctl enable docker

  • 查看docker版本

  1. $ docker --version

  2. Docker version 18.03.1-ce, build 9ee9f40

  • 运行一个 hello -world

  1. $ docker run hello-world

  2. Unable to find image 'hello-world:latest' locally

  3. latest: Pulling from library/hello-world

  4. 9db2ca6ccae0: Pull complete

  5. Digest: sha256:4b8ff392a12ed9ea17784bd3c9a8b1fa3299cac44aca35a85c90c5e3c7afacdc

  6. Status: Downloaded newer image for hello-world:latest

  7. Hello from Docker!

  8. This message shows that your installation appears to be working correctly.

  9. To generate this message, Docker took the following steps:

  10. 1. The Docker client contacted the Docker daemon.

  11. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.

  12.    (amd64)

  13. 3. The Docker daemon created a new container from that image which runs the

  14.    executable that produces the output you are currently reading.

  15. 4. The Docker daemon streamed that output to the Docker client, which sent it

  16.    to your terminal.

  17. To try something more ambitious, you can run an Ubuntu container with:

  18. $ docker run -it ubuntu bash

  19. Share images, automate workflows, and more with a free Docker ID:

  20. https://hub.docker.com/

  21. For more examples and ideas, visit:

  22. https://docs.docker.com/engine/userguide/

如果你运行之后出现的结果和我一样,那么,OK,docker已经安装完成了.

如果你使用的是国内的服务器,可能在 pull镜像的时候,异常的慢,所以官方就提供了国内的docker镜像加速,点我点我,配置好之后一定要记得重启下docker的服务,不然无法加载配置,重启命令如下:

                                
  1. $ systemctl restart docker

安装docker-compose

  1. $ curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

  2. $ chmod +x /usr/local/bin/docker-compose

我装的是 1.21.2版本,通常你安装的  docker和  docker -compose是最新的版本都不会有什么问题,查看一下  docker -compose版本

                                    
  1. $ docker -compose -- version

  2. docker -compose version 1.21 .2, build a133471

安装Sentry

终于到了关键的步骤, Sentry,官方提供了一整套  docker的部署方式来运行  Sentry

  • 下载项目

  1. $ cd /opt/

  2. $ git clone https://github.com/getsentry/onpremise.git sentry

  3. $ cd sentry

  • 创建数据库和Sentry配置目录

  1. $ mkdir -p data/{sentry,postgres}

  • 添加一些依赖库

  1. $ vim requirements.txt

  2. # Add plugins here

  3. sentry-dingding~=0.0.1  # 钉钉通知插件

  4. django-smtp-ssl~=1.0  # 发邮件支持SSL协议

  • 构建Docker镜像

  1. $ docker-compose build

  • 生成密钥

  1. $ docker-compose run --rm web config generate-secret-key

  2. ......

  3. # 最后一行会输出类似如下的秘钥串

  4. kbjodp(id&b0^kbnxijn11&2e6xu&vy1(oini!-zl)pl610n&v

把上面的秘钥添加到 docker-compose.yml文件的  SENTRY_SECRET_KEY环境变量中

                                            
  1. $ vim docker -compose. yml

  2. ......

  3. SENTRY_SECRET_KEY : 'kbjodp(id&b0^kbnxijn11&2e6xu&vy1(oini!-zl)pl610n&v'

  • 生成数据库表并创建管理员用户

  1. $ docker-compose run --rm web upgrade

  2. ......

  3. Would you like to create a user account now? [Y/n]: y  # 创建用户

  4. Email: ianshengme@gmail.com  # 邮箱

  5. Password:  # 密码

  6. Repeat for confirmation:  # 确认密码

  7. Should this user be a superuser? [y/N]: y  # 为超级管理员用户

  • 启动服务

  1. $ docker-compose up -d

可以通过 docker-compose ps查看一下启动了那些容器

                                                
  1. $ docker -compose ps

  2.       Name                     Command               State           Ports

  3. ------------------------------------------------------------------------------------

  4. sentry_cron_1         /entrypoint. sh run cron          Up      9000 /tcp

  5. sentry_memcached_1   docker -entrypoint. sh memcached   Up      11211 /tcp

  6. sentry_postgres_1    docker -entrypoint. sh postgres    Up      5432 /tcp

  7. sentry_redis_1       docker -entrypoint. sh redis ...   Up      6379 /tcp

  8. sentry_smtp_1        docker -entrypoint. sh tini  ...   Up      25 /tcp

  9. sentry_web_1         /entrypoint. sh run web           Up      0.0 .0.0:9000 ->9000 /tcp

  10. sentry_worker_1       /entrypoint. sh run worker        Up      9000 /tcp

上面的几个服务,介绍如下:

名称 描述
sentry_cron 定时任务,使用的是 celery-beat
sentry_memcached memcached
sentry_postgres pgsql数据库
sentry_redis 运行celery需要的服务
sentry_smtp 发邮件
sentry_web 使用 django+drf写的一套  Sentry Web 界面
sentry_worker celery的worker服务,用来跑异步任务的

服务启动之后,默认会监听 9000端口,如果你想更改,可以在  docker -compose .yml中进行更改。

我将我的域名 ansheng.me添加了一条  A记录,记录值是  sentry,指向这台sentry的云服务器,所以可以通过  sentry .ansheng .me进行访问。

Sentry的基本设置

浏览器打开 http://sentry.ansheng.me:9000/,输入邮箱和密码进行登录

登录成功之后,输入对应的 RootURL和  Admin Email,然后点击  Continue

点击之后就进入了 Sentry的主界面

添加一个Python项目

点击右上角的 Addnew,选择  Project

然后创建项目

项目创建完成之后,会出现一个使用的界面

测试Python程序

按照上面的步骤 ,我们来一步一步的操作,我在我这台服务器上面操作,Python版本如下:

  1. $ python -V

  2. Python 2.7.5

  • 安装raven

  1. $ pip install raven --upgrade

  • 添加测试代码

  1. $ vim sentry_python_test.py

  2. from raven import Client

  3. client = Client('http://ce5502f746a4484f9b2c391a54d2d1c4:bca94f6b330a4dd183e68243b2a1b99c@sentry.ansheng.me:9000/2')

  4. try:

  5.    1 / 0

  6. except ZeroDivisionError:

  7.    client.captureException()

  • 运行

  1. $ python sentry_python_test.py

  2. Sentry is attempting to send 1 pending error messages

  3. Waiting up to 10 seconds

  4. Press Ctrl-C to quit

查看异常

在上面的使用界面中,点击 Gotit~Takeme to theIssueStream.进入到项目的  Issue页面,也就是错误页面

可以看到已经有一条异常了,这个异常就是我们刚测时捕获的报错,点击 ZeroDivisionError大标题,进入异常的详细页面。

在项目页面中我们可以看到 MESSAGE和  EXCEPTION这两块,输出了具体的错误详情

基本上的步骤就像上面一样,流程都差不多

添加Django项目并进行监控

根据上面创建 PythonSentry项目的步骤添加一个名为  cash,是  Django框架的项目,并把  DSN的记录值保存下来

http://9ad8168873a94fb1927e14111b9bca1e:29ea550781e24ca2ba0c0ee4829dfc96@sentry.ansheng.me:9000/3

创建django项目

django的项目我在我的电脑上创建.

  • 添加一个名为 cash的虚拟环境

  1. $ pyenv virtualenv 3.6.5 cash

  • 切换虚拟环境

  1. $ pyenv activate cash

  • 安装django

  1. $ pip install django

  • 创建project

  1. $ cd /tmp

  2. $ django-admin startproject cash

  3. $ cd cash

  4. $ python manage.py migrate

  • 启动项目

  1. $ python manage.py runserver 0:9999

  2. Performing system checks...

  3. System check identified no issues (0 silenced).

  4. July 17, 2018 - 03:35:05

  5. Django version 2.0.7, using settings 'cash.settings'

  6. Starting development server at http://0:9999/

  7. Quit the server with CONTROL-C.

端口监听在 9999,可以通过curl进行访问测试

                                                                                                                                            
  1. $ curl -I http ://127.0 .0.1 :9999

  2. HTTP /1.1 200 OK

  3. ......

状态是200表示运行没问题

  • 查看目录结构

  1. ➜  cash tree ./

  2. ./

  3. ├── cash

  4. │   ├── __init__.py

  5. │   ├── settings.py

  6. │   ├── urls.py

  7. │   ├── views.py

  8. │   └── wsgi.py

  9. ├── db.sqlite3

  10. └── manage.py

  • 编写一个简单的views

  1. $ vim cash/views.py

  2. from django.http import HttpResponse

  3. def success(request):

  4.    return HttpResponse("OK")

  5. def error(request):

  6.    1 / 0

  7.    return HttpResponse("Not OK")

  • 添加url

  1. $ vim cash/urls.py

  2. from django.urls import path

  3. from . import views

  4. urlpatterns = [

  5.    path('success', views.success, name='success'),

  6.    path('error', views.error, name='error'),

  7. ]

  • 访问测试

访问可以返回成功的API

  1. $ curl http://127.0.0.1:9999/success

  2. OK

访问会报错的API

  1. $ curl -I http://127.0.0.1:9999/error

  2. HTTP/1.1 500 Internal Server Error

  3. ......

报了一个 500的错误,日志输出如下

                                                                                                                                                
  1. Internal Server Error : /error

  2. Traceback ( most recent call last ):

  3.   File "/Users/shengan/.pyenv/versions/cash/lib/python3.6/site-packages/django/core/handlers/exception.py" , line 35, in inner

  4.    response = get_response (request )

  5.   File "/Users/shengan/.pyenv/versions/cash/lib/python3.6/site-packages/django/core/handlers/base.py" , line 128, in _get_response

  6.    response = self. process_exception_by_middleware( e, request)

  7.   File "/Users/shengan/.pyenv/versions/cash/lib/python3.6/site-packages/django/core/handlers/base.py" , line 126, in _get_response

  8.    response = wrapped_callback (request , *callback_args , **callback_kwargs )

  9.   File "/private/tmp/cash/cash/views.py", line 8 , in error

  10.     1 / 0

  11. ZeroDivisionError : division by zero

  12. [ 17/ Jul/ 2018 03: 50: 55] "HEAD /error HTTP/1.1" 500 60675

集成Sentry

  • 安装raven

  1. $ pip install raven --upgrade

  • 在 INSTALLED_APPS中添加  raven .contrib .django .raven_compat

  1. INSTALLED_APPS = (

  2.    ......

  3.    'raven.contrib.django.raven_compat',

  4. )

  • 在setting内添加sentry配置

  1. import os

  2. import raven

  3. RAVEN_CONFIG = {

  4.    'dsn': 'http://9ad8168873a94fb1927e14111b9bca1e:29ea550781e24ca2ba0c0ee4829dfc96@sentry.ansheng.me:9000/3'  # DSN输入我们刚才记录下来的DSN

  5. }

  • 配置完成之后,我我们再来进行下测试

访问错误的API

  1. $ curl -I http://127.0.0.1:9999/error

  • 异常列表

  • 异常详情

配置email通知

我这里使用的是网易邮箱,具体操作如下

  • 修改config.yml文件添加 Mail Server的配置

  1. $ vim config.yml

  2. mail.backend: 'django_smtp_ssl.SSLEmailBackend'  # Use dummy if you want to disable email entirely

  3. mail.host: 'smtp.163.com'

  4. mail.port: 465

  5. mail.username: 'anshengme@163.com'

  6. mail.password: '14RJg5vzGFWUNKiP'  # 这里的密码,不是登录密码,是"客户端授权密码"

  7. mail.use-tls: false

  8. # The email address to send on behalf of

  9. mail.from: 'anshengme@163.com'

  • 重新build镜像

  1. $ docker-compose build

  2. $ docker-compose up -d

重启之后可以在 Admin==>  邮件下面找到邮箱的配置

然后点击下面的 向ianshengme@gmail.com发送一份测试邮件,然后进入你的邮箱,查看是否收到了邮件

我这里是可以成功收到发送过来的测试邮件,通常邮箱配置完成之后就可以接收到异常通知了。

  • 验证用户的邮箱

找到 Settings=>Account=>Emails

然后点击 Resendverification,会收到一封验证邮件

点击 Confirm确认邮箱。

  • 异常通知测试

然后呢,我们在访问一下错误的API

  1. $ curl -I http://127.0.0.1:9999/error

  2. HTTP/1.1 500 Internal Server Error

  • 查看邮箱收到的报警邮件

基本上你收到的错误邮件就和上面的差不多,不知道为什么那个头像不显示,不管它,如果你要查看错误详情,点击 ViewonSentry就可以打开异常详情了。

配置钉钉通知

我们都知道,邮箱通知的时效性太差,不能够即使传递,所以我们重点介绍下 钉钉机器人的群通知。

  • 创建钉钉群组添加自定义机器人并获取到 access_token

我这里获取到的 access_token是  4dadfa77dfc3fe3b34e91237665afbef165e745dd93ec191c48bf4843b1ad63c

  • 配置

找到cash项目的所有集成

然后找到 DingDing这个插件,  启用插件,然后点击  Configure Plugin配置插件

输入刚刚获取到的 access_token,点击  Save Changes以保存更改

  • 测试异常通知

然后我们访问以下异常的API

  1. $ curl -I http://127.0.0.1:9999/error

  2. HTTP/1.1 500 Internal Server Error

  3. ......

此时你的钉钉机器人应该会发送如下的报错

点击上面的 href就可以跳转到错误详情页面,到此,本篇文章也就结束了。