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
命令了。