znlgis 博客

GIS开发与技术分享 — GDAL · GeoServer · PostGIS · QGIS · OpenLayers · Cesium · FreeCAD · NPOI

第四章:Sentry 开发环境搭建

Sentry 是一个拥有超过 17 年历史的复杂项目,其开发环境集成了 Python(Django)、TypeScript(React)、PostgreSQL、Redis、Kafka、ClickHouse 等多语言多服务的生态系统。本章基于 Sentry 主仓库的实际代码,提供一份详尽的开发环境搭建指南。

版本说明:本章内容基于 Sentry 代码库在写作时的最新版本(setup.cfg 显示 26.8.0.dev0)。Sentry 的基础设施工具(devenv、devservices、prek 等)持续迭代,如果某个命令的行为与本章描述不符,请以仓库中的 AGENTS.mdMakefile 为准。


4.1 环境要求

4.1.1 操作系统与硬件

Sentry 的开发环境官方支持 macOSLinux(基于 apt 的发行版)。Windows 不在官方支持范围内,但可以通过 WSL2 使用 Linux 环境进行开发。

硬件建议:

资源 最低配置 推荐配置
内存 16 GB 32 GB 或更高
CPU 4 核 8 核或更高
磁盘 50 GB 可用空间 100 GB 可用空间(SSD)

开发环境启动后,Docker 容器中会运行 PostgreSQL、Redis、Kafka、ClickHouse(通过 Snuba)、Relay 等多个服务,对内存和 CPU 的需求较高。在 macOS 上,建议为 Docker 分配至少 8 GB 内存。

4.1.2 Python 与 Node.js 版本

Sentry 对 Python 和 Node.js 有精确的版本要求。这些版本由仓库根目录下的 .python-version.node-version 文件定义:

.python-version 内容:

3.13.1

.node-version 内容:

24.14.0

这意味着:

  • Python 需要 3.13.1 及以上(setup.cfg 中声明了 python_requires = >=3.13)。Sentry 使用 Python 3.13 的新特性,包括 msgspec 等现代库。
  • Node.js 需要 24.14.0。这是 Sentry 当前使用的 Node.js 版本,由 devenv 自动下载和管理(见 devenv/config.ini 中的预编译二进制下载地址)。

需要特别注意的是,Sentry 要求的 Python 3.13 是较新的版本。在通过 devenv 管理环境之前,确保系统中已安装 CPython 3.13,否则 uv 创建虚拟环境时会失败。

4.1.3 系统依赖

macOS 依赖(由 Brewfile 定义):

brew install uv docker docker-buildx watchman

这些依赖的作用:

包名 用途
uv Python 包管理器和虚拟环境工具,替代 pip + virtualenv + pip-tools
docker Docker CLI,用于构建镜像和与 devservices 通信
docker-buildx Docker 增强构建工具
watchman 文件监视服务,pnpm 测试的快照更新功能需要

Linux 依赖(由 devenv/post_fetch.py 定义):

sudo apt install watchman chromium-chromedriver

此外,devenv 工具自身也需要安装。Sentry 使用一个名为 devenv 的内部工具来协调整个开发环境的初始化。安装方法如下:

# macOS
brew install getsentry/tools/devenv

# Linux (需要 Go 工具链)
go install github.com/getsentry/devenv@latest

或参考官方安装指南:https://github.com/getsentry/devenv#install

4.1.4 Docker 环境

Sentry 的开发服务(数据库、缓存、消息队列等)全部通过 Docker 容器运行,由 devservices 工具(一个基于 Docker Compose 的服务编排器)管理。

macOS:推荐使用 Colima 或 OrbStack 作为 Docker 运行时(devenv/post_fetch.py 中提及了 colima 相关逻辑)。如果使用 Docker Desktop,确保分配足够的内存(至少 8 GB)。

Linux:直接安装 Docker Engine,确保当前用户在 docker 组中或配置了 rootless Docker。

验证 Docker 安装:

docker run --rm hello-world

4.2 克隆代码与项目结构总览

4.2.1 克隆仓库

Sentry 主仓库托管在 GitHub 上:

git clone https://github.com/getsentry/sentry.git
cd sentry

克隆完成后,仓库根目录下的 .envrc 文件会被 direnv 检测到。如果已安装 direnv,运行:

direnv allow

direnv 会验证 Python 虚拟环境、Node.js、pnpm 依赖等是否就绪,如果不完整会给出需要执行的命令提示。

关于 direnv:direnv 不是必需的,但它极大地提高了开发体验 —— 每次进入项目目录时自动激活虚拟环境、设置环境变量(如 PYTHONUNBUFFERED=1NODE_OPTIONS="--max-old-space-size=5120"SENTRY_UI_HOT_RELOAD=1)。不使用 direnv 则需要手动执行 source .venv/bin/activate 和设置环境变量。

4.2.2 顶层目录结构

Sentry 仓库的顶层结构如下:

sentry/
├── .agents/              # AI agent 技能文件(AGENTS.md 的辅助目录)
├── .github/              # GitHub Actions CI/CD 工作流
├── api-docs/             # OpenAPI 文档生成脚本
├── bin/                  # Shell 辅助脚本(迁移合并、目录操作)
├── build-utils/          # 构建工具脚本(gettext 提取等)
├── config/               # 开发服务配置(commit-template、hooks)
├── devenv/               # 开发环境引导器
│   ├── config.ini        # devenv 配置(Node.js 二进制地址)
│   ├── post_fetch.py     # git clone 后执行的钩子
│   └── sync.py           # 核心同步逻辑(env 初始化)
├── devservices/          # Docker 服务定义
│   ├── config.yml        # 主配置文件(服务定义、模式)
│   └── config/           # 各服务的补充配置文件
├── fixtures/             # 测试夹具
├── scripts/              # 开发辅助脚本
│   ├── do.sh             # Makefile 目标的分发脚本
│   ├── test.js           # Jest 测试启动器
│   ├── lib.sh            # .envrc 公用函数库
│   └── dev-ui-server.ts  # 仅前端开发服务器
├── self-hosted/          # 自托管部署配置
├── src/                  # 后端 Python 源代码
│   ├── sentry/           # 核心 Django 应用
│   ├── social_auth/      # 第三方认证模块
│   └── sudo/             # Sudo 模式模块
├── static/               # 前端 TypeScript/React 源代码
│   ├── app/              # 主前端应用
│   └── ...
├── tests/                # Python 测试套件
├── tools/                # 开发工具
│   ├── fast_editable.py  # 快速可编辑安装
│   ├── flake8_plugin.py  # 自定义 flake8 规则
│   └── migrations/       # 迁移辅助工具
├── Brewfile              # macOS Homebrew 依赖声明
├── Makefile              # 顶层构建目标
├── pyproject.toml        # Python 项目元数据 + uv + ruff 配置
├── setup.cfg             # Python 打包元数据(版本、入口点等)
├── package.json          # Node.js 项目配置(pnpm workspaces)
├── pnpm-lock.yaml        # pnpm 锁定文件
├── pnpm-workspace.yaml   # pnpm monorepo 工作区配置
├── tsconfig.json         # TypeScript 主配置
├── rspack.config.ts      # Rspack 打包器配置
├── uv.lock               # uv 锁定文件(Python 依赖)
├── .python-version       # Python 版本声明
├── .node-version         # Node.js 版本声明
├── .envrc                # direnv 配置
├── .pre-commit-config.yaml  # pre-commit 钩子
└── AGENTS.md             # AI 代理开发指南

4.2.3 后端源码结构

后端代码集中在 src/sentry/ 目录下,这是一个典型的 Django 应用结构:

src/sentry/
├── __main__.py           # CLI 入口点(sentry 命令)
├── api/                  # REST API 端点
├── auth/                 # 认证系统(SSO、2FA、OAuth)
├── conf/                 # Django 设置和配置
├── features/             # 功能标志(FlagPole)
├── ingest/               # 事件摄入管道
├── integrations/         # 第三方集成(GitHub、Slack、Jira 等)
├── issues/               # 问题(Issues)核心逻辑
├── models/               # Django 数据模型
├── migrations/           # 数据库迁移文件
├── monitors/             # Cron 监控
├── plugins/              # 插件系统
├── relay/                # Relay 接口
├── search/               # 搜索引擎后端
├── snuba/                # Snuba(ClickHouse)查询抽象
├── tasks/                # 后台任务(Celery 替代)
├── templates/            # Django 模板
├── testutils/            # 测试工具函数
└── utils/                # 通用工具函数

Sentry 的入口点定义在 setup.cfg 中:

[options.entry_points]
console_scripts =
    sentry = sentry.__main__:main

这意味着安装后可以直接使用 sentry 命令来执行 Django 管理命令、运行开发服务器等。

4.2.4 前端源码结构

前端代码集中在 static/app/ 目录下,使用 React 19 + TypeScript + Rspack 构建:

static/app/
├── components/           # 可复用 UI 组件
├── views/                # 页面视图(路由对应的组件)
├── data/                 # 数据层(API 客户端、状态管理)
├── utils/                # 工具函数
├── actionCreators/       # Redux action creators
├── stores/               # 状态存储
├── bootstrap/            # 应用初始化
├── serviceWorker/        # Service Worker(有独立 tsconfig)
└── index.tsx             # 应用入口

前端使用了丰富的自定义依赖生态:@sentry/browser(Sentry 自身 SDK)、@sentry-internal/rrweb(会话回放)、@emotion/react(CSS-in-JS)、@tanstack/react-query(数据获取)等。


4.3 Python 环境配置

4.3.1 uv 包管理器

Sentry 使用 uv 作为 Python 包管理器,取代了传统的 pip + virtualenv + pip-tools 组合。uv 是一个由 Rust 编写的高性能 Python 包管理器,提供依赖解析、虚拟环境管理和锁定文件等功能。

验证 uv 是否安装:

uv --version

devenv/sync.py 在同步开始时检查 uv 是否在 PATH 中:

if not shutil.which("uv"):
    print("\n\n\ndevenv is no longer managing uv; please run `brew install uv`.\n\n\n")
    return 1

4.3.2 pyproject.toml 与依赖管理

Sentry 的 pyproject.toml 承担了多种角色:

项目元数据

[project]
name = "sentry"
version = "0.0.0"
dependencies = [
  "django>=5.2.14",
  "djangorestframework>=3.16.1",
  "confluent-kafka>=2.8.0",
  "redis>=3.4.1",
  "celery[redis]",
  ...
]

uv 配置

[tool.uv]
environments = ["sys_platform == 'darwin' or sys_platform == 'linux'"]

[[tool.uv.index]]
url = "https://pypi.devinfra.sentry.io/simple"
default = true

这里有两个关键配置:

  1. 平台限制:仅支持 macOS 和 Linux。这是因为某些依赖(如 symbolic)在这两个平台之外没有预编译的 wheel。
  2. 私有 PyPI 镜像:Sentry 不使用公共 PyPI,而是通过 https://pypi.devinfra.sentry.io/simple 获取依赖。这确保依赖版本的一致性和供应链安全。

ruff 代码风格配置

[tool.ruff]
line-length = 100
target-version = "py313"

[tool.ruff.format]
quote-style = "double"
indent-style = "space"

[tool.ruff.lint]
select = ["E", "W", "F", "B", "LOG", "I", "T20", "UP"]

Sentry 使用 ruff 替代了 isort、flake8 等工具的大部分规则,仅保留自定义的 S* 规则(tools/flake8_plugin.py)给 flake8 处理。

4.3.3 虚拟环境与 devenv 同步

Sentry 使用 devenv sync 命令来初始化整个开发环境。该命令在 devenv/sync.py 中定义,执行以下步骤:

步骤 1:安装系统依赖(macOS)

if constants.DARWIN:
    brew.install()
    proc.run((f"{constants.homebrew_bin}/brew", "bundle"), cwd=reporoot)

步骤 2:安装 Node.js

node.install(cfg["node"]["version"], ...)

devenv 从 devenv/config.ini 中读取 Node.js 的预编译二进制地址,不同架构和平台有不同的下载源。例如 darwin_arm64 的二进制来自 https://storage.googleapis.com/sentry-dev-infra-assets/node/node-v24.14.0-darwin-arm64.tar.xz

步骤 3:安装 pnpm

pnpm_version = package_json["packageManager"].split("@")[-1]
install_pnpm(pnpm_version, reporoot)

pnpm 版本由 package.json 中的 packageManager 字段定义(当前为 pnpm@10.30.2)。安装后,pnpm 被放在 .devenv/bin/node-env/bin/pnpm

步骤 4:安装 JavaScript 依赖

("javascript dependencies", ("pnpm", "install", "--frozen-lockfile", ...), ...)

步骤 5:同步 Python 依赖

("python dependencies", ("uv", "sync", "--frozen", "--inexact", "--quiet", "--active", ...), ...)

uv sync --frozen 使用 uv.lock 锁定文件安装精确版本,保证所有开发者使用一致的依赖。

步骤 6:安装开发工具链

("prek dependencies", ("prek", "install", "--prepare-hooks", "-f"), {})
("fast editable", ("python3", "-m", "tools.fast_editable", "--path", "."), {})

完整同步命令

# 完整同步(包括迁移和用户创建)
devenv sync

# 仅同步依赖和前端,跳过数据库迁移(适合只需要运行测试的场景)
SENTRY_DEVENV_FRONTEND_ONLY=1 devenv sync

# 跳过前端依赖安装
SENTRY_DEVENV_SKIP_FRONTEND=1 devenv sync

4.3.4 direnv 自动激活

Sentry 仓库根目录下的 .envrc 文件负责自动激活开发环境。它执行以下检查:

  1. 验证 devenv 是否安装
  2. 验证 Python 虚拟环境是否存在.venv/ 目录)
  3. 验证 Node.js 版本(与 .node-version 对比)
  4. 验证 pnpm 依赖node_modules/ 目录是否存在)
  5. 验证 prek、agent skills 是否就绪
  6. 添加虚拟环境和工具到 PATH
  7. 设置环境变量
    • VIRTUAL_ENV="${PWD}/.venv"
    • PYTHONUNBUFFERED=1
    • NODE_OPTIONS="--max-old-space-size=5120"
    • SENTRY_UI_HOT_RELOAD=1(默认开启前端热模块替换)

direnv 允许后,每次进入 sentry 目录都会自动完成上述检查和激活:

# 首次使用
direnv allow

# 如果 .envrc 有改动,重新允许
direnv allow

4.3.5 Sentry 配置文件生成

devenv sync 完成后会自动检查 ~/.sentry/ 目录下是否存在配置文件。如果没有,会执行:

proc.run((f"{venv_dir}/bin/sentry", "init", "--dev"))

这会在 ~/.sentry/ 下生成两个核心配置文件:

  • ~/.sentry/config.yml:Sentry 的 YAML 格式配置(数据库连接、Redis 地址、Kafka broker 等)
  • ~/.sentry/sentry.conf.py:Python 格式的 Django 设置覆盖文件

手动生成配置的方法:

sentry init --dev

--dev 标志告诉 Sentry 使用开发环境友好的默认值,例如连接 localhost 上的 devservices。

4.3.6 快速可编辑安装

传统的 pip install -e . 方式在 Sentry 这样的大型项目中会非常慢。Sentry 使用了一个自定义的 tools/fast_editable.py 脚本来加速可编辑安装。这个脚本通过在 site-packages 中创建精确的 .pth 文件和 shim 来让 Python 能够找到 src/sentry 模块,而不需要运行完整的构建系统(setup.py/pyproject.toml build)。

devenv/sync.py 中的注释说明了设计意图:

# Note: instead of using a build system, we use tools/fast_editable.py
# to install sentry editably as well as console scripts.
# Otherwise, you need to define a build system (uv_build)
# and console scripts here, and call uv sync then uv pip install -e .

这保证了每次 devenv sync 后,源代码修改立即可用,无需重新安装。


4.4 前端环境配置

4.4.1 pnpm 工作区

Sentry 前端使用 pnpm 作为包管理器。package.json 中声明了包管理器的版本:

"packageManager": "pnpm@10.30.2"

pnpm 的版本由 devenv/sync.py 自动管理 —— 它读取 packageManager 字段,通过 npm 全局安装对应版本的 pnpm 到 .devenv/bin/node-env/bin/pnpm

工作区配置pnpm-workspace.yaml)定义了 monorepo 中的子包位置。pnpm-lock.yaml 锁定所有依赖的精确版本。

包安装命令

# 按锁定文件安装(开发时标准用法)
pnpm install --frozen-lockfile

# 修改依赖后更新锁定文件
pnpm install

关键依赖概览

类别 核心包
UI 框架 react 19.2.3, react-dom 19.2.3, react-router-dom 6.30.3
构建工具 rspack 2.1.3, @rspack/core 2.1.3, @rspack/cli 2.1.3
CSS 方案 @emotion/react 11.14.0, @emotion/css 11.13.5
数据管理 @tanstack/react-query 5.96.0, mobx 6.13.7
Sentry SDK @sentry/browser 10.69.0, @sentry/react 10.69.0
类型检查 typescript 6.0.2(通过 npm alias 安装)
测试 jest 30.4.2, @testing-library/react 16.3.2
代码质量 eslint 9.34.0, oxfmt 0.58.0, stylelint 16.10.0

4.4.2 Rspack 构建系统

Sentry 在 2024 年从 Webpack 迁移到了 Rspack,这是一个基于 Rust 的高性能 JavaScript 打包器,提供与 Webpack 兼容的 API 但构建速度快 5-10 倍。

配置文件rspack.config.ts

关键构建脚本(来自 package.json):

{
  "dev": "pnpm install --frozen-lockfile && sentry devserver",
  "dev-ui": "SENTRY_UI_DEV_ONLY=1 SENTRY_UI_HOT_RELOAD=1 node scripts/dev-ui-server.ts",
  "dev-acceptance": "NO_DEV_SERVER=1 NODE_ENV=development rspack --watch",
  "build": "NODE_OPTIONS='--max-old-space-size=4096' rspack --config ./rspack.config.ts",
  "build-production": "NODE_ENV=production rspack --mode production --config ./rspack.config.ts",
  "build-acceptance": "IS_ACCEPTANCE_TEST=1 NODE_ENV=production pnpm run build"
}

Rspack 支持开发模式下的 HMR(Hot Module Replacement),由 @rspack/plugin-react-refresh 插件提供。

4.4.3 TypeScript 配置

Sentry 前端的 TypeScript 配置分布在多个文件中:

  • tsconfig.json:主配置,定义编译选项、路径映射和包含的文件
  • tsconfig.mdx.json:MDX 文件(Markdown + JSX)的编译配置
  • static/app/serviceWorker/worker/tsconfig.json:Service Worker 专用配置

类型检查命令:

# 完整类型检查(检查主项目和 Service Worker)
pnpm run typecheck
# 等价于:tsc --build tsconfig.json static/app/serviceWorker/worker/tsconfig.json --builders 2

# 类型覆盖率统计
pnpm run type-coverage

# 类型覆盖率差异(与基准对比)
pnpm run type-coverage-diff

注意:不要直接使用 tsc 命令,应通过 pnpm typecheck 运行。AGENTS.md 明确指示了这一点。

4.4.4 前端开发模式

Sentry 提供了三种前端开发模式:

模式 1:完整开发服务器

pnpm run dev

启动完整的开发环境(等价于先安装依赖再执行 sentry devserver)。后端 API 和前端资源都由本地服务器提供,访问 http://dev.getsentry.net:8000

模式 2:仅前端 UI 开发(推荐前端开发者使用)

pnpm run dev-ui

设置 SENTRY_UI_DEV_ONLY=1SENTRY_UI_HOT_RELOAD=1,启动一个独立的 UI 开发服务器,它将 API 请求代理到生产环境的 sentry.io。访问 https://sentry.dev.getsentry.net:7999/

这个模式的优势是不需要运行 devservices(跳过数据库、Redis、Kafka 等),因此资源消耗极低。适合纯前端 UI 改动。

模式 3:验收测试构建

pnpm run dev-acceptance

以 watch 模式编译前端资源,供验收测试使用。

前端口令与 HTTPS

# 生成本地 SSL 证书(dev-ui 模式需要 HTTPS)
pnpm run mkcert-localhost

4.5 开发服务启动

4.5.1 devservices 概述

devservices 是 Sentry 自研的 Docker 服务编排工具,定义在 devservices/config.yml 中。它比 Docker Compose 更轻量,专为本地开发场景设计,支持”模式”(mode)概念,可以按需启动不同的服务子集。

核心命令:

# 以默认模式启动服务
devservices up

# 指定模式启动
devservices up --mode <mode>

# 停止所有服务
devservices down

# 查看运行中的服务状态
devservices status

devservices/config.yml 定义了三种类型的组件:

  1. 远程依赖服务(Remote Dependencies):从其他 Sentry 仓库(如 snuba、relay)拉取的容器化服务
  2. Docker Compose 服务(Services):直接在 YAML 中定义的 Docker 容器(如 bigtable、redis-cluster)
  3. Supervisor 程序(Programs):由 sentry devserver 内部启动的本地进程(如 kafka consumers、taskworker)

4.5.2 核心基础服务

PostgreSQL

PostgreSQL 是 Sentry 的主数据库,存储用户、组织、项目、事件元数据等。在 devservices 中,PostgreSQL 是一个远程依赖,来自 getsentry/sentry-shared-postgres 仓库:

postgres:
  description: Shared instance of postgres used by sentry services
  remote:
    repo_name: sentry-shared-postgres
    branch: main
    repo_link: https://github.com/getsentry/sentry-shared-postgres.git

多个 Sentry 子仓库共享同一个 PostgreSQL 实例,避免在每个仓库中启动独立的数据库容器。

Redis

Redis 用作缓存和消息代理。与 PostgreSQL 类似,它也是一个共享服务:

redis:
  description: Shared instance of redis used by sentry services
  remote:
    repo_name: sentry-shared-redis
    branch: main
    repo_link: https://github.com/getsentry/sentry-shared-redis.git

4.5.3 数据存储服务

Snuba / ClickHouse

Snuba 是 Sentry 的事件搜索引擎,底层使用 ClickHouse 列式数据库。Snuba 提供三种容器化模式:

snuba:
  description: Service that provides fast aggregation and query capabilities on top of Clickhouse
  remote:
    repo_name: snuba
    branch: master
    repo_link: https://github.com/getsentry/snuba.git
    mode: containerized

snuba-profiling:
  mode: containerized-profiles       # 包含 profiling consumer

snuba-metrics:
  mode: containerized-metrics-dev    # 包含 metrics consumer

Snuba 负责事件的快速聚合查询和发现(Discover)功能。没有 Snuba,Sentry 的事件搜索将无法工作。

Bigtable 模拟器(仅 CI/测试):

bigtable:
  description: Bigtable emulator
  image: 'ghcr.io/getsentry/cbtemulator:d28ad6b63e461e8c05084b8c83f1c06627068c04'
  ports:
    - '127.0.0.1:8086:8086'

用于测试 Google Cloud Bigtable 相关功能。

Redis Cluster(仅测试):

redis-cluster:
  description: Redis cluster used for testing
  image: ghcr.io/getsentry/docker-redis-cluster:7.0.10
  ports:
    - '127.0.0.1:7000:7000'
    - '127.0.0.1:7001:7001'
    # ... 6 个节点

Memcached

memcached:
  description: Memcached used for caching
  image: ghcr.io/getsentry/image-mirror-library-memcached:1.5-alpine
  ports:
    - '127.0.0.1:11211:11211'

用于替代 Redis 作为缓存后端(特定模式启用)。

Objectstore

objectstore:
  description: Storage for files and blobs
  remote:
    repo_name: objectstore
    branch: main
    repo_link: https://github.com/getsentry/objectstore.git
    mode: containerized

模拟 Google Cloud Storage 的对象存储服务,用于存储文件附件和事件载荷。

4.5.4 消息队列与流处理

Relay

Relay 是 Sentry 的事件接收和转发网关。所有 SDK 上报的事件首先到达 Relay,由其进行过滤、采样、速率限制和数据脱敏,然后再转发给 Sentry 后端处理。

relay:
  description: Service event forwarding and ingestion service
  remote:
    repo_name: relay
    branch: master
    repo_link: https://github.com/getsentry/relay.git
    mode: containerized

Taskbroker

Taskbroker 是 Sentry 的异步任务系统,基于 gRPC 通信,取代了传统的 Celery:

taskbroker:
  description: Service used to process asynchronous tasks
  remote:
    repo_name: taskbroker
    branch: main
    repo_link: https://github.com/getsentry/taskbroker.git
    mode: containerized

taskbroker-sentry:
  description: Sentry's own taskbroker for tasks internal to Sentry

taskbroker-sentry 是 Sentry 专用的 taskbroker 实例(端口 50052),处理 raw-mode 主题(如 ingest-profiles、subscription results、replay recordings)。

Kafka

Kafka 本身由 Snuba 的容器化模式自带,不需要在 devservices 中单独声明。Kafka 是 Sentry 事件管道中连接各个处理阶段的纽带。

4.5.5 事件处理管道

Sentry 的事件处理由多个 Kafka Consumer 分工协作。这些 Consumer 在 devservices 中定义为 programs(由 sentry devserver 内部的 honcho 启动和管理),而非独立容器:

x-programs:
  ingest-events:
    command: sentry run consumer ingest-events --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset
  ingest-attachments:
    command: sentry run consumer ingest-attachments --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset
  ingest-transactions:
    command: sentry run consumer ingest-transactions --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset
  ingest-monitors:
    command: sentry run consumer ingest-monitors --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset
  # ... 更多 consumer

关键 Consumer 列表:

Consumer 名称 用途
ingest-events 处理错误事件摄入
ingest-transactions 处理性能事务摄入
ingest-attachments 处理附件摄入
ingest-metrics 处理指标摄入
ingest-generic-metrics 处理通用指标摄入
ingest-monitors 处理 Cron 监控签到摄入
ingest-occurrences 处理问题出现次数摄入
ingest-feedback-events 处理用户反馈摄入
process-spans 处理 Span 数据
process-segments 处理性能段数据
post-process-forwarder-errors 错误事件后处理转发
post-process-forwarder-transactions 事务事件后处理转发
post-process-forwarder-issue-platform Issue Platform 后处理转发
monitors-clock-tick 监控时钟 tick 消费者
monitors-clock-tasks 监控时钟任务消费者
monitors-incident-occurrences 监控告警事件消费者
billing-metrics-consumer 计费指标消费者
uptime-results 正常运行时间监控结果消费者

Taskworker 负责消费 taskbroker 分发的异步任务:

taskworker:
  command: sentry run taskworker
taskworker-sentry:
  command: sentry run taskworker --rpc-host localhost:50052
taskworker-scheduler:
  command: sentry run taskworker-scheduler

4.5.6 启动模式选择

devservices/config.yml 定义了多种启动模式,可以精确控制启动哪些服务:

modes:
  default: [snuba, postgres, relay, spotlight, objectstore]
  migrations: [postgres, redis]
  minimal: [postgres, snuba]
  backend-ci: [snuba, postgres, redis, bigtable, redis-cluster, symbolicator, objectstore]
  symbolicator-tests: [postgres, snuba, objectstore]
  # ... 更多模式

使用情景参考

情景 推荐模式命令 启动的服务
日常开发 devservices up snuba, postgres, relay, spotlight, objectstore
仅运行数据库迁移 devservices up --mode migrations postgres, redis
仅运行测试(最少量) devservices up --mode minimal postgres, snuba
运行后端 CI 测试 devservices up --mode backend-ci snuba, postgres, redis, bigtable, redis-cluster, symbolicator, objectstore
调试事件摄入管道 devservices up --mode ingest snuba, postgres, relay, spotlight, objectstore, taskbroker, taskworker, 多个 kafka consumers
调试 Tracing 相关功能 devservices up --mode tracing postgres, snuba-metrics, relay, spotlight, 多个 kafka consumers
调试 Cron 监控 devservices up --mode crons postgres, snuba, relay, spotlight, ingest-monitors, monitors-*
调试 Profiling devservices up --mode profiling postgres, snuba-profiling, relay, vroom, spotlight
全部服务(高资源消耗) devservices up --mode full 所有可用服务

4.5.7 常见服务组合

仅后端测试的最小化设置

# 1. 仅安装依赖(跳过迁移)
SENTRY_DEVENV_FRONTEND_ONLY=1 devenv sync

# 2. 启动最小化服务
devservices up --mode minimal

# 3. 直接运行测试
pytest tests/sentry/api/test_base.py --reuse-db

完整开发环境

# 1. 完整同步(依赖 + 迁移 + 创建用户)
devenv sync

# 2. 启动默认模式服务
devservices up

# 3. 启动开发服务器
sentry devserver

4.6 运行 Sentry 开发服务器

4.6.1 sentry devserver 命令

Sentry 开发服务器的入口是 sentry devserver 命令。它不是简单的 Django runserver,而是一个集成多个进程的编排管理器。

启动命令:

sentry devserver

等效方式:

pnpm run dev

pnpm run dev 的定义是:

"dev": "pnpm install --frozen-lockfile && sentry devserver"

4.6.2 honcho 进程管理

sentry devserver 内部使用 honcho(一个 Python 实现的 Procfile 运行器,类似于 Foreman)来管理多个并发进程。这些进程包括:

  1. granian web server:Sentry 使用 granian(一个 Rust 编写的 ASGI/WSGI 服务器)替代了 Gunicorn,支持 pname(进程命名)、reload(自动重载)和 uvloop(高性能事件循环)。pyproject.toml 中的依赖为 "granian[pname,reload,uvloop]>=2.7"
  2. rspack dev server:前端资源编译和 HMR 服务
  3. taskworker:异步任务消费者
  4. kafka consumers:事件管道中的各个 Consumer 进程(根据启动模式加载)
  5. taskworker-scheduler:定时任务调度器

这些进程的位置和配置由 devservices/config.ymlx-programs 段定义。

4.6.3 开发日志文件

当 devserver 运行时,所有进程的完整控制台输出(包括 server、taskworker、kafka consumers、webpack/watchers 等)被同时写入 .artifacts/dev.log 文件中。这是 ANSI 去除后的纯文本文件,且被 gitignore,不用担心提交到仓库。

查看运行状态:

# 实时跟踪日志输出
tail -f .artifacts/dev.log

# 搜索特定的日志条目
grep "ERROR" .artifacts/dev.log
grep "WARNING" .artifacts/dev.log

# 查看启动过程
head -n 100 .artifacts/dev.log

日志文件在每次 devserver 进程启动时被截断(--workers 模式的重载会持续追加)。可以通过环境变量 SENTRY_DEV_LOG_FILE 自定义日志文件的路径。

4.6.4 访问地址

模式 URL 说明
完整开发 http://dev.getsentry.net:8000 后端 API + 前端 UI
仅前端 UI https://sentry.dev.getsentry.net:7999/ 仅前端,API 代理到生产环境

4.6.5 创建管理员用户

devenv sync 在完成迁移后会自动检查数据库中是否已存在 admin@sentry.io 用户,如果不存在则自动创建:

proc.run((
    f"{venv_dir}/bin/sentry", "createuser",
    "--superuser", "--email", "admin@sentry.io",
    "--password", "admin", "--no-input",
))

手动创建用户:

sentry createuser --superuser --email admin@sentry.io --password admin --no-input

登录时使用:

  • 邮箱:admin@sentry.io
  • 密码:admin

4.7 开发模式与调试技巧

4.7.1 仅前端开发模式

对于纯前端改动,使用仅 UI 模式可以大幅降低资源消耗:

pnpm run dev-ui

该模式设置的环境变量:

  • SENTRY_UI_DEV_ONLY=1:跳过所有后端初始化
  • SENTRY_UI_HOT_RELOAD=1:启用 React Fast Refresh

此模式下,所有 API 请求被代理到生产环境的 sentry.io。因此不需要本地 devservices,也不需要数据库。

对应的访问地址是 https://sentry.dev.getsentry.net:7999/。首次使用需要生成本地 SSL 证书:

pnpm run mkcert-localhost

4.7.2 仅后端开发模式

当只需要修改后端代码时,可以跳过前端构建:

SENTRY_DEVENV_SKIP_FRONTEND=1 devenv sync
devservices up
sentry devserver

或者设置环境变量 SENTRY_DEVENV_FRONTEND_ONLY 的逆逻辑,通过跳过前端编译来加速启动。更简单的做法是预先构建前端资源一次,之后直接启动 Django(虽然不推荐,但在调试简单 API 时可行):

# 启动 devservices
devservices up

# 直接使用 Django runserver(注意:不会启动 kafka consumers 等)
sentry run web --reload

4.7.3 前端热模块替换

Sentry 使用 @rspack/plugin-react-refresh(版本 2.0.2)实现 React 组件的热模块替换。在开发模式下(SENTRY_UI_HOT_RELOAD=1),修改组件后浏览器会立即反映变化,无需手动刷新。

环境变量 SENTRY_UI_HOT_RELOAD.envrc 中默认开启:

export SENTRY_UI_HOT_RELOAD=1

4.7.4 granian 服务器与自动重载

Sentry 使用 granian 作为 WSGI/ASGI 服务器。granian 支持 reload 功能,在 Python 文件改动后自动重启 worker 进程。在 devserver 模式下,granian 以 --reload 参数启动。

granian 的 pname 扩展允许给 worker 进程命名,便于在进程列表中识别。

4.7.5 数据库调试

连接到 PostgreSQL

# 通过 Docker exec 直接连接
docker exec -it postgres-postgres-1 psql sentry postgres

# 查看所有表
\dt

# 查看表结构
\d sentry_project

# 执行查询
SELECT id, slug, name FROM sentry_project LIMIT 10;

查看迁移状态

sentry django showmigrations

Django Shell

sentry django shell

重置数据库(清除所有数据并重新迁移):

make reset-db

make reset-db 会调用 ./scripts/do.sh reset-db,依次执行 drop-db、create-db 和 apply-migrations。

4.7.6 Git 工作树并行开发

当需要同时开发多个分支时,Git 工作树(worktree)是一个优雅的解决方案。每个工作树拥有独立的 .venv 目录。

创建新工作树:

# 创建一个新的工作树
git worktree add ../sentry-feature-branch feature-branch

# 进入新工作树
cd ../sentry-feature-branch

post-checkout 钩子会自动在新工作树中运行 devenv sync。如果没有自动运行,手动执行:

devenv sync
direnv allow

每个工作树拥有独立的虚拟环境、node_modules 和配置文件,互不干扰。


4.8 常用开发命令

4.8.1 Python 代码质量检查

Sentry 使用 prek 作为所有 lint、format 和 type-checking 工具的统一入口。

运行所有检查

.venv/bin/prek run -q

prek 自动检测变更文件,只运行相关的检查。-q 标志表示安静模式,只输出错误信息。

运行特定检查

# 对指定文件运行 mypy 类型检查
SENTRY_MYPY_PRE_PUSH=1 .venv/bin/prek run -q mypy --files src/sentry/foo/bar.py --stage pre-push

# 对指定文件运行 ruff 代码风格检查
.venv/bin/prek run -q ruff --files src/sentry/foo/bar.py

直接使用底层工具

# ruff 代码风格检查
ruff check src/sentry/foo/bar.py

# ruff 自动修复
ruff check --fix src/sentry/foo/bar.py

# mypy 类型检查
mypy src/sentry/foo/bar.py

# flake8(仅 S* 规则,不处理 E/W/F/B 等已由 ruff 覆盖的规则)
flake8 src/sentry/foo/bar.py

4.8.2 前端代码质量检查

JavaScript/TypeScript 代码检查

# 完整 lint(包括格式、JS、CSS)
pnpm run lint

# JavaScript/TypeScript linting
pnpm run lint:js

# 对特定文件 lint
pnpm run lint:js components/avatar.tsx

# 自动修复
pnpm run fix

# 仅修复 ESLint 问题
pnpm run fix:eslint

# 仅修复格式(使用 oxfmt)
pnpm run fix:format

# CSS/样式检查
pnpm run lint:css

类型检查

# 全项目类型检查
pnpm run typecheck

# 查看类型覆盖率
pnpm run type-coverage

4.8.3 测试命令

Python 测试

# 运行所有测试(不推荐,需要很长时间)
pytest

# 运行特定测试文件(推荐)
.venv/bin/pytest -n3 -svv --reuse-db tests/sentry/api/test_base.py

# 运行特定测试函数
.venv/bin/pytest tests/sentry/api/test_base.py::SomeTest::test_something --reuse-db

# 使用 -n 指定并行 worker 数量(-n3 表示 3 个并行线程)
.venv/bin/pytest -n4 --reuse-db tests/sentry/

# 标记(marker)筛选
.venv/bin/pytest -m symbolicator --reuse-db tests/sentry/

# Acceptance 测试
make test-acceptance

# CI 风格的测试
make test-python-ci

关键参数说明:

参数 说明
--reuse-db 复用测试数据库,避免每次测试都执行迁移(首次运行或迁移变更后仍需重建)
-n3 使用 pytest-xdist 并行运行测试,3 个 worker
-svv 显示测试输出和详细失败信息
-m 按标记筛选测试

JavaScript 测试

# 运行所有 JS 测试(CI 模式)
pnpm test-ci

# 运行特定文件
pnpm test-ci components/avatar.spec.tsx

# 交互式 watch 模式
pnpm test

# pre-commit 模式(仅运行关联的测试)
pnpm test-precommit

# 仅运行暂存文件相关的测试
pnpm test-staged

选择性测试(基于变更文件)

make test-selective

该命令使用覆盖率数据,仅运行与当前分支变更相关的测试,大幅缩短测试时间。

4.8.4 数据库迁移命令

# 应用所有待执行的迁移
sentry django migrate

# 创建新迁移文件
sentry django makemigrations

# 查看迁移状态
sentry django showmigrations

# 处理 rebase 冲突后的迁移
./bin/update-migration <migration_name_or_number> <app_label>
# 示例:
./bin/update-migration 0101_workflow_when_condition_group_unique workflow_engine

./bin/update-migration 脚本处理迁移文件的重命名、依赖关系更新和 migrations_lockfile.txt 的更新。在 rebase 后与主分支的迁移发生冲突时非常有用。

# 重置数据库
make reset-db

4.8.5 环境维护命令

# 刷新依赖(不重新安装,仅检查是否有更新)
devenv sync

# 更新 uv 锁定文件(添加/升级依赖后)
uv lock
# 或使用 Makefile 目标:
make freeze-requirements

# 构建前端生产资源
pnpm run build-production

# 清除构建产物
make clean

# 生成 API 文档
make build-api-docs

# 构建国际化翻译文件
make compile-locale

4.9 常见问题排错

4.9.1 devenv sync 失败

症状devenv sync 报告错误,无法完成环境初始化。

排查步骤

  1. 检查 uv 是否安装devenv sync 要求 uv 在 PATH 中。
which uv
uv --version

如未安装:

brew install uv
  1. 检查 Python 版本:确保系统中有 Python 3.13.1。
python3 --version

如果版本不符,使用 pyenv 或直接从 python.org 安装正确版本。

  1. 检查网络连接:Sentry 使用私有 PyPI 镜像 https://pypi.devinfra.sentry.io/simple。如果在公司网络或 VPN 中,可能需要配置代理。
# 测试连接
curl -I https://pypi.devinfra.sentry.io/simple
  1. 使用 verbose 模式获取详细错误
SENTRY_DEVENV_VERBOSE=1 devenv sync
  1. 清除缓存重试
rm -rf .venv node_modules .devenv
devenv sync

4.9.2 开发服务无法启动

症状devservices up 失败或服务启动后立即退出。

排查步骤

  1. 确认 Docker 正在运行
docker info
  1. 检查端口占用
# 查看哪些端口被占用
lsof -i :5432   # PostgreSQL
lsof -i :6379   # Redis
lsof -i :9092   # Kafka
lsof -i :8000   # Sentry web
  1. 查看特定服务日志
docker logs postgres-postgres-1
docker logs sentry-relay-1
  1. 清理 Docker 资源
# 停止所有 devservices 容器
devservices down

# 清理未使用的镜像和卷
docker system prune -a
  1. 内存不足:macOS 用户检查 Docker Desktop 或 Colima 的内存分配。建议至少 8 GB。

4.9.3 Python 导入错误

症状ModuleNotFoundError: No module named 'sentry' 或类似的导入错误。

排查步骤

  1. 确认虚拟环境已激活
# 检查是否在虚拟环境中
echo $VIRTUAL_ENV
# 应输出类似 /path/to/sentry/.venv

# 检查 sentry 模块是否可导入
python -c "import sentry; print(sentry.__file__)"
  1. 重新运行 devenv sync
devenv sync
  1. 检查 fast_editable 安装
# 查看 site-packages 中的 .pth 文件
ls .venv/lib/python3.13/site-packages/*.pth
# 应包含指向 src/ 目录的路径
  1. 验证 sentry 入口点
which sentry
# 应输出 .venv/bin/sentry

4.9.4 数据库连接问题

症状django.db.utils.OperationalError: could not connect to server 或迁移失败。

排查步骤

  1. 确认 PostgreSQL 容器在运行
docker ps | grep postgres
  1. 测试连接
docker exec postgres-postgres-1 psql -U postgres -c "SELECT 1"
  1. 检查配置文件

查看 ~/.sentry/config.yml 中数据库连接配置是否正确。开发环境默认应指向 localhost:5432

  1. 重建数据库
make reset-db
  1. 检查 /etc/hosts

确保 127.0.0.1 localhost 存在。

4.9.5 前端编译错误

症状:Rspack 构建失败、TypeScript 类型错误、模块未找到。

排查步骤

  1. 重新安装依赖
rm -rf node_modules
devenv sync
  1. 检查 Node.js 版本
node --version
# 应输出 v24.14.0
  1. 清除 Rspack 缓存
rm -rf node_modules/.cache
  1. 运行完整类型检查
pnpm run typecheck
  1. 检查 pnpm 版本
pnpm --version
# 应输出 10.30.2

4.9.6 端口冲突

症状Address already in use 或服务绑定端口失败。

Sentry 使用的关键端口

端口 服务
8000 Sentry web 服务器
7899 Relay edge(cell-routing)
7900 Relay cell
7999 前端 dev-ui 服务器
8969 Spotlight 调试工具
50052 taskbroker-sentry (gRPC)
5432 PostgreSQL
6379 Redis
7000-7005 Redis Cluster
8086 Bigtable 模拟器
11211 Memcached

排查方法

# 查找占用的进程
lsof -i :8000
# 或
netstat -anp | grep 8000

解决冲突

  1. 如果端口被其他 devservices 实例占用,先执行 devservices down
  2. 如果被其他进程占用,终止该进程或修改配置。
  3. 对于 Spotligh 等非关键服务,可以在配置中临时注释掉。

以上是 Sentry 开发环境搭建的完整指南。随着项目的发展,某些工具链和配置可能会发生变化,始终以仓库中的最新文件(AGENTS.mdMakefilepyproject.tomldevservices/config.ymldevenv/sync.py)为权威参考。