> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/unity/add-features/sentry-integration.md).

# Sentry 集成

[Sentry Unity SDK](https://docs.sentry.io/platforms/unity/)安装后，SDK 会自动将 Apps in Toss 平台上下文附加到崩溃·错误事件并发送。本文说明如何开启此集成，以及自动附加的值具体是什么。

在未安装 Sentry SDK 的项目中，集成代码 **根本不会编译。** 没有运行时开销也没有编译错误，所以如果不使用，就不必读本文。

### 安装

`AIT > 安装 Sentry SDK` 点击菜单后，Package Manager 会安装 Sentry Unity SDK。若已安装，则菜单会被禁用。

若要手动添加 `Packages/manifest.json`中写入。

{% code collapsedlinecount="10" %}

```json
{
  "dependencies": {
    "io.sentry.unity": "https://github.com/getsentry/unity.git#4.1.0"
  }
}
```

{% endcode %}

最低要求版本是 `io.sentry.unity` **4.0.0**。菜单安装的版本是 **4.1.0**。

安装后 `Tools > Sentry`打开并输入 DSN 即可。AIT 集成本身没有需要配置的内容。DSN 可在 Sentry 项目的 `Settings > Client Keys (DSN)`中查看。输入的值会保存到 `Assets/Resources/Sentry/SentryOptions.asset`中。

### 自动附加的上下文

#### 标签

| 标签                     | 来源                              | 示例                      |
| ---------------------- | ------------------------------- | ----------------------- |
| `ait.sdk_version`      | `AITVersion.FullVersion`        | `2.4.7`                 |
| `ait.unity_version`    | `Application.unityVersion`      | `6000.3.3f1`            |
| `ait.commit_hash`      | `AITVersion.CommitHash`         | `9d42c0b`               |
| `ait.current_scene`    | 当前激活的场景                         | `MainMenu`              |
| `ait.device_id`        | `AIT.GetDeviceId`               | `abc123...`             |
| `ait.platform_os`      | `AIT.GetPlatformOS`             | `iOS`, `Android`        |
| `ait.locale`           | `AIT.GetLocale`                 | `ko-KR`                 |
| `ait.toss_app_version` | `AIT.GetTossAppVersion`         | `5.80.0`                |
| `ait.environment`      | `AIT.GetOperationalEnvironment` | `production`, `staging` |
| `ait.deployment_id`    | `AIT.EnvGetDeploymentId`        | `deploy-xyz`            |

前四个是同步立即设置的， `ait.device_id` 后六个则通过异步调用平台 API 填充。

`ait.commit_hash`在无法确认提交哈希的构建中， **根本不会设置。** 若其他平台标签也无法取得值，则不会附加该标签——没有值与 `unavailable`这个字符串作为值是不同的，这里指的是前者。

`ait.current_scene`会在每次加载场景时更新，因此指向事件发生时的场景。

#### 用户

仅在能够获取设备 ID 时才会把 `User.Id`填入该值。若无法获取设备 ID，则 `用户`不会修改它。

#### 上下文对象

`apps_in_toss` 的自定义上下文会被添加。

{% code collapsedlinecount="10" %}

```json
{
  "sdk_version": "2.4.7",
  "unity_version": "6000.3.3f1",
  "device_id": "abc123...",
  "platform_os": "iOS",
  "locale": "ko-KR",
  "toss_app_version": "5.80.0",
  "environment": "production",
  "deployment_id": "deploy-xyz"
}
```

{% endcode %}

与标签不同，这个对象会 **连未能取得值的项也会 `unavailable` 填成字符串。** 这是为了能在事件中直接读出是哪个 API 失败了。这里也没有标签中没有的提交哈希，而仅有标签里的 `current_scene`也不在这里。

#### Breadcrumb

每次加载场景都会记录 breadcrumb。

| 字段       | 值                                              |
| -------- | ---------------------------------------------- |
| message  | `场景已加载：MainMenu`                               |
| category | `scene`                                        |
| level    | `信息`                                           |
| data     | `scene_name`, `scene_build_index`, `load_mode` |

### Analytics 集成

`AITSentryAnalytics`是一个包装器，会将 Analytics API 调用一并记录为 Sentry breadcrumb。 `AIT.AnalyticsScreen`如果改用它而不是直接调用，Sentry 事件上下文中也会留下同样的调用记录。

{% code collapsedlinecount="10" %}

```csharp
using AppsInToss.Sentry;

// AIT.AnalyticsScreen 调用 + 记录 Sentry breadcrumb
await AITSentryAnalytics.TrackScreen(new { screen_name = "MainMenu" });
await AITSentryAnalytics.TrackImpression(new { item_id = "banner_1" });
await AITSentryAnalytics.TrackClick(new { button = "start" });
```

{% endcode %}

如果想在每次场景切换时自动记录屏幕，只需打开一个标志位。

{% code collapsedlinecount="10" %}

```csharp
AITSentryAnalytics.AutoScreenTrackingEnabled = true;
```

{% endcode %}

开启后 `SceneManager.sceneLoaded`中 `TrackScreen(new { screen_name = 场景名 })`会自动调用。此时每加载一个场景，breadcrumb 会有 **两个** 条——上面的 `scene` breadcrumb 和这里产生的 `analytics` breadcrumb。

调用累计会以 `ait_analytics` 上下文对象的形式附加到事件中。

| 字段                                                  | 说明                              |
| --------------------------------------------------- | ------------------------------- |
| `screen_count` / `impression_count` / `click_count` | 各类型的累计调用次数                      |
| `last_screen`                                       | 最后一次记录屏幕的场景名称（若无则 `none`)       |
| `auto_tracking`                                     | `AutoScreenTrackingEnabled` 当前值 |

> **参考**: `AIT` 与主体 API 一样，返回类型会因 Unity 版本而不同。Unity 6 及以上为 `Awaitable`，以下则为 `Task`。详情请参考 [API 使用模式](https://developers-apps-in-toss.toss.im/documentation/unity/first-steps/api-usage-patterns)。

### CI 环境变量

#### 构建时注入 DSN

由于 WebGL 是浏览器沙箱，运行时无法读取环境变量。因此 `AITSentryDsnInjector`会在构建预处理阶段读取环境变量并 `SentryOptions.asset`烘焙进去。

| 变量                   | 用途                   | 示例                          |
| -------------------- | -------------------- | --------------------------- |
| `SENTRY_DSN`         | DSN。若没有此值，则跳过注入      | `https://key@sentry.io/123` |
| `SENTRY_ENVIRONMENT` | 强制指定 environment（可选） | `production`, `staging`     |
| `SENTRY_RELEASE`     | 强制指定 release（可选）     | `my-app@1.0.0`              |

注入 **仅在 WebGL 构建中** 运行，并且 `SentryOptions.asset`如果该文件已存在，为保护用户设置会跳过。也就是说，这条路径只会在没有 asset 的 CI 检出中真正创建文件。

#### environment 和 release 的自动派生

`SENTRY_ENVIRONMENT` / `SENTRY_RELEASE`如果不提供 `AITSentryReleaseResolver`会从 SDK 版本派生出这两个值。Sentry 的 `environment`/`release`是仅在初始化时可设的选项，因此无法在运行时的 scope 中更改，除了在构建时烘焙进去之外没有别的办法。

| SDK 版本  | environment                       | release                   |
| ------- | --------------------------------- | ------------------------- |
| stable  | *（未设置 → Sentry 默认值 `production`)* | `apps-in-toss.unity@{版本}` |
| 预发布     | `beta`                            | `apps-in-toss.unity@{版本}` |
| unknown | *（未设置）*                           | *（未设置）*                   |

* **目的**：beta 试点构建中的错误会被 `environment:beta`隔离，不会污染 stable 的分流、通知和 release-health。stable 构建不设置 environment，因此现有行为不会改变。
* **优先级**：如果显式指定了环境变量， **总会优先于自动派生。**
* **release 一致性**：派生出的 release 使用与发布工作流生成的 Sentry release 标识符相同的规则，因此能与 release-health 和 `Fixes` 基于 trailer 的自动解析关联对上。

如果无法得知 SDK 版本，则两个值都不会烘焙，并会记录警告。此时 Sentry 会使用默认值，所以如果是预发布构建，事件可能会流入 stable 分流。

#### sentry-cli

用于上传调试符号和 sourcemap 的值。不是 SDK 读取，而是 CLI 读取。

| 变量                  | 用途                 | 示例                             |
| ------------------- | ------------------ | ------------------------------ |
| `SENTRY_AUTH_TOKEN` | API 认证令牌           | `sntrys_...`                   |
| `SENTRY_ORG`        | 组织 slug            | `my-org`                       |
| `SENTRY_PROJECT`    | 项目 slug            | `unity-game`                   |
| `SENTRY_URL`        | 自托管 Sentry URL（可选） | `https://sentry.mycompany.com` |
| `SENTRY_LOG_LEVEL`  | CLI 日志级别（可选）       | `info`, `debug`                |

{% code collapsedlinecount="10" %}

```yaml
env:
  SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
  SENTRY_ORG: my-org
  SENTRY_PROJECT: unity-game
```

{% endcode %}

### 工作原理

#### 条件编译

Sentry 集成程序集 `AIT_SENTRY_AVAILABLE` 仅在存在 define 时才会编译。

1. `io.sentry.unity` 安装 4.0.0 及以上后 `versionDefines`会 `AIT_SENTRY_AVAILABLE`自动启用
2. `AppsInToss.Sentry`和 `AppsInToss.Sentry.Editor`的 `defineConstraints`要求此 define。
3. 若没有 Sentry SDK，这两个程序集会完全从编译中移除。

#### 自动初始化

`[RuntimeInitializeOnLoadMethod(AfterSceneLoad)]`进行初始化。由于 Sentry SDK 和 SDK 本体都在 `BeforeSceneLoad`时初始化，所以之后的 `AfterSceneLoad`是双方都能安全访问的第一个时机。

1. `SentrySdk.IsEnabled`用于检查 Sentry 是否启用——若关闭，则到此结束
2. 版本·提交哈希标签设置
3. 订阅场景加载事件
4. 通过异步调用平台 API 收集其余上下文
5. Analytics 集成初始化

第 4 步是 fire-and-forget，因此各 API 会独立失败。即使某个失败，其余上下文也会正常附加。

#### IL2CPP 剥离保护

为了避免在 WebGL(IL2CPP) 构建中集成代码被整个删掉，我们用三层防护。

| 保护手段                             | 作用            |
| -------------------------------- | ------------- |
| `[assembly: AlwaysLinkAssembly]` | 防止程序集本身被链接器移除 |
| `[Preserve]`                     | 保留单个类型·方法     |
| `link.xml`                       | 声明保留程序集内所有类型  |

`AlwaysLinkAssembly`是关键。由于没有其他程序集引用这个程序集，如果没有这个特性，IL2CPP 链接器会把它判断为“没有人使用的程序集”并整体移除。

#### Unity 6 及以上的堆栈跟踪精度

在 Unity 6 及以上构建 WebGL 时 `AITSentryBuildProcessor`会为 IL2CPP 堆栈跟踪开启 C# 文件·行号信息。

{% code collapsedlinecount="10" %}

```csharp
PlayerSettings.SetIl2CppStacktraceInformation(WebGL, MethodFileLineNumber)
```

{% endcode %}

借此在 Sentry 中能看到准确的源码行，定位崩溃位置。Unity 2021.3/2022.3 没有这个 API，会自动跳过，即使设置失败，构建也会继续。

### 问题排查

#### 事件未发送

如果 Console 中有以下日志，说明 Sentry SDK 本身处于禁用状态。这不是 AIT 集成问题，而是 DSN 问题。

{% code collapsedlinecount="10" %}

```
[AITSentry] Sentry SDK 处于禁用状态。跳过 AIT 上下文集成。（请检查 DSN 设置：Tools > Sentry）
```

{% endcode %}

如果正常附加，会出现这条日志。

{% code collapsedlinecount="10" %}

```
[AITSentry] 已初始化 - AIT 上下文将自动追加到 Sentry 事件中。
```

{% endcode %}

如果是 CI 构建，请在构建日志中查找以 `已创建 SentryOptions.asset`开头的行。其下方会显示被打码的 DSN 以及自动派生出的 Environment·Release。若没有这行，说明 `SENTRY_DSN`为空，或 asset 已存在因此跳过了注入。

#### IL2CPP 构建中没有 AIT 标签

这是因为剥离导致集成代码被移除了。保留声明已随 SDK 一起提供在 `Runtime/Sentry/link.xml`中，所以 **无需手动添加。** 即便如此仍没有标签，通常是构建缓存所致。

`Library/Bee/artifacts/WebGL/`并进行干净构建。缓存结果中不会反映 `link.xml` 更改。

如果项目侧另外调整了剥离设置，可以在 `Assets/link.xml`中追加相同声明加以补强。

{% code collapsedlinecount="10" %}

```xml
<linker>
    <assembly fullname="AppsInToss.Sentry" preserve="all"/>
</linker>
```

{% endcode %}

#### 部分上下文为 unavailable

这是平台 API 调用失败的情况。不会重试，而是将其固定为 `unavailable`确定为。

在 Mock 桥接环境中，部分 API 不受支持，因此出现此值属正常情况。此时标签中会完全没有该项， `apps_in_toss` 只会留在上下文中 `unavailable`unavailable

### 相关文档

* [SDK 事件日志记录](https://developers-apps-in-toss.toss.im/documentation/unity/add-features/metrics) —— SDK 自动收集的运行时事件
* [开始使用](https://developers-apps-in-toss.toss.im/documentation/unity/first-steps/getting-started) — SDK 安装与基本设置
* [问题排查](https://developers-apps-in-toss.toss.im/documentation/unity/first-steps/faq) — 常见问题排查
* [Sentry Unity SDK 文档](https://docs.sentry.io/platforms/unity/) — Sentry 官方文档


---

# 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://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/unity/add-features/sentry-integration.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.
