Sentry 基础
自建 Sentry 服务器步骤
Sentry 是一套运行在服务器上的日志系统,自行搭建 Sentry 服务的流程为(以 Python 环境为例,Docker 环境可参考官方文档):
- 本机安装
Sentry依赖的两个数据库:Redis和PostgreSQL; - 两个数据库的初始化及运行;
- 新建
Python虚拟环境(本文使用的Python均运行在虚拟环境中); pip install sentry;Sentry初始化配置:sentry init /etc/sentry(路径可自行定义,Sentry运行时默认搜索的路径为~/.sentry)- 根据需求修改配置文件(主要是两个数据库的配置);
- 数据库
Sentry相关表初始化(建db及表); - 通过
sentry命令运行三个组件:web,worker,cron。
搭建好之后访问 Sentry 网页,新建 Project,页面上会提示如何在Python中给 Sentry发日志(主要使用Sentry官方提供的 Raven 包)。
具体细节本文不再赘述,数据库安装和初始化可参考相关平台文档,Sentry相关步骤可参考官方文档 。
Sentry 概念及结构
Sentry 整个框架有以下几个组成部分:
- 服务器端
Sentry程序,又分为以下三个部分:Web:运行 Web server,收/发 http 请求。此部分使用了Django+uWSGI;Worker: 使用Celery异步处理一些任务(如数据库读写);Cron: 运行定期任务。
- SDK : 各语言向
Sentry发送日志的接口组件,Python 中是Raven包。 - API :除了
Web页面,Sentry还提供了可以直接读写数据库中已有日志的接口。
开发环境搭建
本文搭建环境为 CentOS 7 。
运行环境
拷贝源码:
git clone https://github.com/getsentry/sentry
运行源码的环境跟自建服务器环境类似,只需要多安装一些依赖包:
pip install -r requirements-base.txt
运行入口
在 setup.py 可以找到运行入口:
1 | entry_points={ |
即 sentry.runner.__init__.py 下的 main:
1 | def main(): |
cli 函数:
1 |
|
Sentry 使用 click 模块来提供终端接口。
此处我们跳过中间的一些调用逻辑,直接看特定命令调用的最终接口,比如sentry run web命令,调用的是 sentry.runner.commands.run.py 下的 web 函数:
1 |
|
函数在一些初始化操作之后调用 SentryHTTPServer 运行 Web Server。看下 SentryHTTPServer 类:
1 | class SentryHTTPServer(Service): |
run 方法调用了 uwsgi ,实际应用接口定义在 options.setdefault('module', 'sentry.wsgi:application'), 即 sentry.wsgi.application, 实际上调用的是 Django 的 WSGI 接口。
接下来就是交给 Django 处理 Web 请求,并调用 urlconf 中对应的接口。urlconf 定义在sentry.web.urls下,其中 api/0/ 路径的配置指向 sentry.api.urls。
源码修改
本文以给单 Event 添加删除接口为例说明如何修改源码。
已有接口源码
先看下已有的接口怎么做的。
根据 API文档,删除 issue 接口为:DELETE /api/0/issues/*{issue_id}*/ , sentry.api.urls.py 中对应的配置为:
1 | url( |
对应的类(.GroupDetailsEndpoint)方法:
1 |
|
此方法可用文字描述为:
1 |
|
实际删除步骤并不在这里,而是把删除任务放到 Redis队列中,交由 worker 组件主动处理。
新增接口
要给单条 Event 添加类似此方法的删除接口有两个难点:
Event模型对应的sentry_message无status字段;Event没有对应的delete_event函数。
为了尽量减少代码改动,先写一个同步方式删除 Event 的简单接口:
1 | # `sentry.api.endpoints.project_event_details.ProjectEventDetailsEndpoint` |
"""
# from sentry.tasks.deletion import delete_event
try:
# 此处参照当前类的 get 方法获取 event 对象
event = Event.objects.get(
event_id=event_id,
project_id=project.id,
)
# TODO: Since other api use apply_async
# for sending task to redis, this method
# should rewrite with apply_async.
event.delete() # 直接调用模型对象的 delete 方法删除
except Event.DoesNotExist:
return Response({'detail': 'Event not found'}, status=404)
transaction_id = uuid4().hex
self.create_audit_entry(
request=request,
organization_id=project.organization_id if project else None,
target_object=event.id,
transaction_id=transaction_id,
)
delete_logger.info(
'object.delete.queued',
extra={
'object_id': event.id,
'transaction_id': transaction_id,
'model': type(event).__name__,
}
)
return Response(status=202)
1 |
|
不过如果想在运行时打断点调试这样就不行了,因为 sentry 使用的 uWSGI 无法直接断点调试。我们可以重写入口:
1 | # run_simple_server.py |
这样运行的服务无法处理静态资源,也就是打不开 sentry 网页,不过调试 API 足够了。
安装到环境
开发完成后就可以把源码安装到当前环境。
基础工具:
sudo yum install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel python-devel gcc-c++
sudo yum install npm
如果你改的是 9.0.x 分支代码,此版本的 requirements-base.txt 要做如下改动:
redis-py-cluster>=1.3.4,<1.4.0
改为:
redis-py-cluster==1.3.4
(因为最新版(1.3.5版)的 redis-py-cluster 要求 redis 模块版本不低于 1.3.6,但 sentry 要求 redis 不高于1.3.5,会造成冲突无法正常安装,出现pkg_resources.ContextualVersionConflict: (redis 2.10.5 (/home/postgres/.local/share/virtualenvs/sentry-U-p3B7ZI/lib/python2.7/site-packages), Requirement.parse('redis>=2.10.6'), set(['redis-py-cluster'])) 的报错 。)
进入源码目录:
pip install --editable .
然后就可以和平常一样使用 sentry 命令了。