> For the complete documentation index, see [llms.txt](https://docs.ipcheck.ing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ipcheck.ing/developer/zh/configuration/error-monitoring.md).

# 错误监控（Sentry）

MyIP 附带可选的 [Sentry](https://sentry.io/) 应用的两部分都配有监控埋点。它完全由环境变量控制。

{% hint style="success" %}
**如果你不设置这些变量中的任何一个，你的部署行为就会完全像一个从未集成过 Sentry 的版本。** 前端包中不包含任何 Sentry 代码， `@sentry/node` 后端从不导入它，而且隧道路由也不会挂载。不会向任何地方发送任何内容。
{% endhint %}

| 变量                         | 部分      | 读取时                 |
| -------------------------- | ------- | ------------------- |
| `VITE_SENTRY_DSN_FRONTEND` | 前端 + 后端 | **构建时** 用于包，运行时用于隧道 |
| `SENTRY_DSN_BACKEND`       | 后端      | 运行时                 |
| `SENTRY_ENVIRONMENT`       | 后端      | 运行时（源码映射还包括构建时）     |
| `SENTRY_ORG`               | 构建工具链   | 构建时                 |
| `SENTRY_PROJECT_FRONTEND`  | 构建工具链   | 构建时                 |
| `SENTRY_AUTH_TOKEN`        | 构建工具链   | 构建时                 |

两部分是相互独立的。仅启用后端监控是完全正常的配置，并且对 Docker 用户来说是最简单的。

## 各部分如何协同

```
浏览器（Vue SPA）
   │  错误、链路追踪、回放
   ▼
POST /api/monitoring   ← 第一方隧道，同源
   │  （后端验证信封的 DSN，然后转发）
   ▼
Sentry  ◀── 直接连接 ── Express 后端（错误、链路追踪、warn+ 日志）
```

## 后端 — `SENTRY_DSN_BACKEND`

设置 DSN 并重启。就这么简单。

{% code title=".env" %}

```bash
SENTRY_DSN_BACKEND="https://<key>@oNNNNN.ingest.sentry.io/<project-id>"
```

{% endcode %}

会启用：

* **未捕获错误和 5xx 响应** 来自任意 `/api/*` 路由，通过 Sentry 的 Express 错误处理器。
* **性能追踪** 以 100% 采样率——按路由的延迟、吞吐量和错误率。
* **日志转发。** 共享的 pino 日志器会镜像 `warn` 及以上级别到 Sentry Logs； `错误` 及以上级别还会额外变成可分组、可告警的 Issue。所以 `logger.error({ err }, '…')` 各处的调用 `api/` 是有意发出的信号，而不只是日志行。参见 [日志](/developer/zh/configuration/logging.md).
* **Cron 监控** 用于定时的数据集任务（MaxMind 自动更新、CAIDA 刷新、服务状态轮询）。监控项会在首次签入时创建——无需在 Sentry UI 中预先创建任何内容。

SDK 通过以下方式引导启动： `node --import ./sentry-instrument.js`，它会在 Express 加载之前注册 loader hooks。 `dev`, `启动`，而 pm2 start 命令已经传递了该标志，所以无需添加任何内容。

{% hint style="info" %}
启动时会打印 `🛰️ 已启用 Sentry 后端监控` 当已接收到 DSN 时。没有这行就表示未检测到 DSN。
{% endhint %}

## 前端 — `VITE_SENTRY_DSN_FRONTEND`

这个是一个 **构建时** 变量。Vite 会将其内联为常量，而 Sentry 模块的动态导入则位于该常量之后。没有它，死代码消除会移除该分支，SDK chunk 甚至不会被生成。

```bash
VITE_SENTRY_DSN_FRONTEND="https://<key>@oNNNNN.ingest.sentry.io/<project-id>"
pnpm run build
```

会启用：

* 未捕获异常和 `console.error()` 调用，按消息分组。
* 路由级性能追踪，10% 采样，并包含 Web Vitals。
* 仅错误模式的 Session Replay——只有在发生错误时才会记录。

{% hint style="warning" %}
**同一个值在运行时也必须存在。** 后端读取 `VITE_SENTRY_DSN_FRONTEND` 用来决定是否挂载 `/api/monitoring` 并据此知道它允许转发哪个 DSN。构建时带上它但忘了传给运行中的进程，那么浏览器 SDK 就会把内容 POST 到一个 `404`.
{% endhint %}

### 回放与隐私

页面文本会被刻意 **不** 在回放中进行遮罩：此应用的整个界面就是访客自己的网络信息，这正是调试它所需的上下文。键入的输入内容仍会被遮罩。在公开的 IPCheck.ing 实例中，这一点已在隐私政策中披露——如果你为自己的用户开启前端监控，也请同样披露。

两部分都以 `sendDefaultPii: false`，因此访客的 IP 和请求头不会被 SDK 自动附加。看起来像凭据的查询参数（`key`, `api_key`, `token`, `secret`, `password`, `auth`）会在任何内容发送之前，从 breadcrumbs、spans 和请求上下文中剥离——上游 URL 会携带你的 API 密钥，而 Sentry 会在多个位置记录 URL。

## 这个 `/api/monitoring` 隧道

广告拦截器和隐私扩展会阻止对以下地址的请求： `*.ingest.sentry.io`。对于熟悉网络的用户来说，这占了很大一部分访客，并且会悄无声息地删除你大部分错误数据。

因此浏览器 SDK 不会直接与 Sentry 通信。它会将其信封 POST 到 `/api/monitoring` 你自己的源上，然后由后端转发它们。

该路由的行为如下：

* **仅在 `VITE_SENTRY_DSN_FRONTEND` 已设置** 在运行时。否则，该路径只是一个普通的 `404`.
* **不是开放式转发。** 信封头中携带着浏览器 SDK 配置时使用的 DSN。如果它与以下内容不完全匹配 `VITE_SENTRY_DSN_FRONTEND`，请求会被拒绝并返回 `403`。
* **其自身的速率限制**：每个 IP 每 20 分钟 600 个请求，并且它 **不受全局 `/api` 限流器**。共享应用配额的遥测正是报告悄然失效的原因——一次 `429` ，浏览器 SDK 会在接下来的一分钟内丢弃所有事件。
* **访客 IP 写入**：一旦信封离开转发器，Sentry 看到的就只有你的服务器地址。后端会写入访客的真实 IP（来自 `CF-Connecting-IP`，在存在且有效时）到事件项中，然后再转发。
* **失败是软性的**：转发错误会返回 `502` 并记录一条 `warn`。

## `SENTRY_ENVIRONMENT`

为后端事件添加标签，以便你在 Sentry UI 中按生产与开发进行筛选。

* 未设置表示 `production`.
* Set `SENTRY_ENVIRONMENT="development"` 在开发机器上。这也会禁用 cron 签入，因此合上笔记本电脑不会因为“missed”告警而呼叫你。
* 前端会根据 Vite 构建模式自动打标签——无需设置任何内容。

{% hint style="info" %}
“为什么 Sentry 里没有数据？”很多时候并不是配置坏了，而是 Sentry UI 中的环境筛选器。先检查它，再检查你的配置。
{% endhint %}

## 源码映射 — `SENTRY_ORG` / `SENTRY_PROJECT_FRONTEND` / `SENTRY_AUTH_TOKEN`

没有源码映射，前端堆栈跟踪只会指向压缩后的 bundle 偏移位置。构建过程可以将它们上传到 Sentry，以便追踪能还原到真实的源文件。

{% code title=".env" %}

```bash
SENTRY_ORG="your-org-slug"
SENTRY_PROJECT_FRONTEND="your-frontend-project-slug"
SENTRY_AUTH_TOKEN="sntrys_..."
```

{% endcode %}

上传仅在以下情况下运行 **两个** 条件满足：

1. `SENTRY_AUTH_TOKEN` 已设置，并且
2. `SENTRY_ENVIRONMENT` 是 `production` （或未设置，这表示生产环境）。

因此，开发和测试构建既不会生成也不会上传映射。

{% hint style="danger" %}
`SENTRY_AUTH_TOKEN` 是真正的机密，而且仅在构建时使用。它绝不会被内联进 bundle，也绝不会到达浏览器。请不要把它放进镜像、仓库，并将其作用域限制为源码映射上传。
{% endhint %}

映射会以隐藏源码映射的形式生成、上传，然后从 `dist/` ——访客无法下载它们。

## Docker

后端监控很简单；前端监控则不然，而其中原因值得理解。

{% tabs %}
{% tab title="仅后端（推荐）" %}

```bash
docker run -d -p 18966:18966 \
  -e SENTRY_DSN_BACKEND="https://<key>@oNNNNN.ingest.sentry.io/<id>" \
  -e SENTRY_ENVIRONMENT="production" \
  --name myip \\
  jason5ng32/myip:latest
```

在运行时读取。适用于官方预构建镜像，无需重新构建。
{% endtab %}

{% tab title="前端（需要自定义构建）" %}
`VITE_SENTRY_DSN_FRONTEND` 被以下内容使用 `pnpm run build` **在……内部** 镜像构建。通过以下方式传递它 `docker run -e` 因此无法把 Sentry 注入到已经构建好的 bundle 中。

官方镜像构建时不包含任何 DSN，因此其前端会永久保持不含 Sentry。要启用前端监控，你必须构建自己的镜像，并让该值对构建阶段可见——例如通过添加一个 `ARG` / `ENV` 对 `Dockerfile` 之前 `RUN pnpm run build`.

然后在运行时也传递相同的 DSN，这样隧道路由才会挂载：

```bash
docker run -d -p 18966:18966 \
  -e VITE_SENTRY_DSN_FRONTEND="https://<key>@oNNNNN.ingest.sentry.io/<id>" \
  --name myip \\
  your-image:latest
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
`.env` 会被排除在 Docker 构建上下文之外，因此普通的 `docker build` 绝不会意外地从中获取到 DSN。
{% endhint %}

## 验证你的设置

* **后端**：查找 `🛰️ 已启用 Sentry 后端监控` 在启动日志中。
* **隧道**: `POST /api/monitoring` 不应返回 `404`。 `404` 表示运行时没有看到 `VITE_SENTRY_DSN_FRONTEND`.
* **前端 bundle**：如果构建时没有 DSN， `dist/assets/` 。
* **没有内容到达**：按顺序检查 Sentry UI 中的环境筛选器、项目选择器和时间范围。

## 相关页面

* [日志](/developer/zh/configuration/logging.md) — 为 Sentry Logs 和 Issues 提供数据的 pino 级别
* [安全选项](/developer/zh/configuration/security-options.md) — 为什么隧道不受全局限流器限制
* [环境变量](/developer/zh/reference/environment-variables.md) ——完整列表
* [使用 Docker 部署](/developer/zh/getting-started/deploy-with-docker.md) — 构建和运行时基础


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ipcheck.ing/developer/zh/configuration/error-monitoring.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
