Sentry 入门

Sentry 入门

前言

​ 错误日志监控也可称为业务逻辑监控,旨在对业务系统运行过程中产生的错误日志进行收集收纳和监控告警。Sentry 所做的就是收集应用底层代码的崩溃信息,便于我们排除代码异常。

既有方案

  1. 单台服务器上每个系统服务自己维护自己的日志,方便自己查看
  2. 同台服务器上多个日志集中存放到同个目录,方便集中管理
  3. 使用 ELK 系统,将所有日志输出到 ELK 系统,使用 GUI 进行管理展示

存在问题

  1. 无法第一时间感知错误

    脚本日志的拉取不是实时的,web端用户的反馈也存在滞后的问题,从出现问题到解决问题周期会很长,容易是工作陷入被动

  2. 错误信息的获取比较低效

    用户反馈的信息及可能有的邮件报警信息都非常有限且不够准确,最终开发人员还是得在日志文件中大量的翻看上下文查看关联信息。更困难的是错误不能重现的话,还需要不断埋点测试去获取变量数据,十分难以定位问题。

  3. 日志处理方式不够灵活

    通常来说,除了程序运行出错,我们也比较关心其他异常情况,比如数据污染,非法请求,第三方 API 调用异常等等。如果将辞了等同错误全部记录下来,很容易就会使告警信息泛滥,无法及时获得有效信息。但是如果不处理此类异常,迟早会导致严重问题。所以我们需要对不同的日志内容有不同的处理方式,相同的日志内容也可以根据不同的业务场景进行不同的处理。

  4. 监控覆盖面有限

    完整的监控应该是包含脚本,前端以及后端的,但是当前后端分离以后,很多前端的问题无法被统一记录下来

Sentry 基本介绍

Sentry 是一个现代化的错误日志记录以及聚合平台。支持几乎所有的主流开发语言及平台,并提供现代化 UI。

image-20191017165847184

  1. 优势

    接入 Sentry 前;

    • 用户A: 发布功能用不了
    • 开发者A: 哪个页面? 截个图
    • 用户A: (发截图)
    • 开发者A发现bug可以重现, 登录服务器查看错误日志, 确认程序逻辑无问题, 查看数据库数据, 发现有脏数据. 联系开发者B检查负责更新数据的python脚本C.py.
    • 开发者B登录服务器查看错误日志, 发现一个逻辑错误导致脚本罢工, 已持续了一个小时. 影响了数千条数据

    接入 Sentry 后:

    • 开发者A,B同时收到邮件告警, 一分钟前脚本C.py异常退出.
    • 开发者B进入sentry后台查看错误信息, 定位问题并将其修复, 再清理受影响的数十条数据.
    • 在此过程中没有用户受到影响, 无需开发者A介入
  2. 概念

    • event

      可操作数据的基本单位,每一次日志输出就会产生一个 event。event并不一定是错误,如果日志级别设置的很低,那么后台就会产生非常多的 event,所以正确的设置日志的级别 非常的重要。

    • issue

      同意类 event 的聚合,某一个错误可能因为重复执行而被记录多次,在 sentry系统会自动聚合到一起,方便处理,通常我们操作的对象也就是 issue。

    • DNS

      DNS 及时客户端密匙,用来进行客户端和服务端的通信。DNS 是一个 URL,包含一个公匙,一个私匙,项目标记及服务器地址

    • raven

      整个错误日志监控系统包含客户端和服务端,Sentry 是服务端的名称,客户端名称为 Raven,需要两者配合才能工作。

  3. 创建项目流程

    1. 登录 Sentry 系统

      image-20191024093908660
    2. 点击创建项目

      image-20191024094042431
    3. 选择框架

      image-20191024094257179
    4. 根据指示下载安装包并进行配置

      image-20191024095325581

    在 flask 中的配置有两种方式,可以自由选择

    第一种:

    1
    2
    3
    from raven.contrib.flask import Sentry
    sentry = Sentry()
    sentry.init_app(app,dsn="https://facc2ededdfa45ba955dca1eb485915a@sentry.xxx.org/7",logging=True, level=logging.ERROR)

    第二种:

    1
    2
    3
    4
    import sentry_sdk
    from sentry_sdk.integrations.flask import FlaskIntegration
    sentry_sdk.init(dsn="https://facc2ededdfa45ba955dca1eb485915a@sentry.xxx.org/7",
    integrations=[FlaskIntegration()])

    gunicorn 与 Sentry 结合配置

    使用 yaml 文件进行 logging 配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    # Logging configuration

    [loggers]
    keys = root, gunicorn.access, gunicorn.error

    [handlers]
    keys = access, error, sentry

    [formatters]
    keys = json, generic

    # Root logger
    # The root logger sends messages to the console and to Sentry.
    [logger_root]
    handlers = error, sentry

    # Gunicorn loggers
    # Gunicorn logging is configured with two loggers: 'gunicorn.access' and 'gunicorn.error'.
    # The access log is sent to stdout and the error log is sent to stderr, both without propagation.
    # Only the critical logger has a handler to send messages to Sentry.

    [logger_gunicorn.access]
    handlers = access
    qualname = gunicorn.access
    level = INFO
    propagate = 0

    [logger_gunicorn.error]
    handlers = error, sentry
    qualname = gunicorn.error
    level = ERROR
    propagate = 0

    [handler_access]
    class = StreamHandler
    formatter = json
    args = (sys.stdout,)

    [handler_error]
    class = StreamHandler
    formatter = json
    args = (sys.stderr,)

    [handler_sentry]
    class = raven.handlers.logging.SentryHandler
    level = CRITICAL
    formatter = generic
    args = ("https://facc2ededdfa45ba955dca1eb485915a@sentry.xxx.org/7",)

    [formatter_generic]
    format = [bs-whatweb][%(levelname)s] [%(name)s]: %(message)s
    [formatter_json]
    class = project.api.utils.logger.JSONFormatter

Docker 部署

Sentry 官方还提供了 Docker 镜像以及部署方案,用起来非常方便。

  1. 首先安装并启动 Docker 服务,然后拉取最新的 Sentry 镜像:docker pull sentry
  2. 启动一个 redis 服务作为消息 broker:docker run -d --name sentry-redis redis
  3. 设置数据库密码作为环境变量,之后的命令都会用到:export DBPW='<your-postgres-db-password>'
  4. 启动一个 Postgres 数据库服务作为存储数据库:docker run -d --name sentry-postgres -e POSTGRES_PASSWORD='$(DBPW)' -e POSTGRES_USER=sentry postgres,这里推荐使用 Volume 将数据库文件单独挂载出来。
  5. migrate 数据库结构至最新:docker run -it --rm -e SENTRY_SECRET_KEY='$(DBPW)' --link sentry-postgres:postgres --link sentry-redis:redis sentry upgrade
  6. 启动 Sentry 服务并链接以上服务: docker run -d --name sentry-app -e SENTRY_SECRET_KEY='$(DBPW)' --link sentry-redis:redis --link sentry-postgres:postgres -p 8080:9000 sentry
  7. 运行一个 cron 容器用于定时任务:docker run -d --name sentry-cron -e SENTRY_SECRET_KEY='$(DBPW)' --link sentry-postgres:postgres --link sentry-redis:redis sentry run cron
  8. 运行一个 worker 容器用于后台任务:docker run -d --name sentry-worker-1 -e SENTRY_SECRET_KEY='$(DBPW)' --link sentry-postgres:postgres --link sentry-redis:redis sentry run worker

如果没有什么错误发生,使用 docker ps 命令将会得到 sentry-appsentry-posgressentry-redissentry-cronsentry-worker-1 5 个正在运行的容器。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!