> 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 > Install Sentry SDK` 点击菜单后，Package Manager 会安装 Sentry Unity SDK。若已安装，则菜单会变为禁用。

如果要手动添加， `Packages/manifest.json`写入。

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

最低要求版本为 `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` 会添加一个名为

```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"
}
```

与标签不同，这个对象 **即使无法获取值的项也 `unavailable` 用字符串填充。** 这样就能从事件中直接读取是哪个 API 失败了。这里也没有标签中没有的提交哈希，而标签中才有的 `current_scene`这里也没有。

#### Breadcrumb

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

| 字段       | 值                                              |
| -------- | ---------------------------------------------- |
| 消息       | `Scene loaded: MainMenu`                       |
| category | `scene`                                        |
| level    | `Info`                                         |
| data     | `scene_name`, `scene_build_index`, `load_mode` |

### Analytics 集成

`AITSentryAnalytics`是一个包装器，它会把 Analytics API 调用一并作为 Sentry breadcrumb 记录下来。 `AIT.AnalyticsScreen`如果直接改为调用它，那么相同的调用也会作为 Sentry 事件的上下文保留下来。

```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" });
```

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

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

启用后， `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 checkout 中实际创建文件。

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

`SENTRY_ENVIRONMENT` / `SENTRY_RELEASE`如果不提供 `AITSentryReleaseResolver`会从 SDK 版本推导出这两个值。Sentry 的 `environment`/`release`是仅在初始化时可用的选项，不能在运行时通过 scope 修改，因此除了在构建时烘焙之外没有办法。

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

* **目的**：beta 试运行构建的错误不会 `environment:beta`分离出来，不会污染 stable 的分流处理、通知和 release-health。stable 构建不设置 environment，因此保留原有行为。
* **优先级**：如果指定了环境变量， **始终会覆盖自动派生。**
* **release 一致性**：推导出的 release 使用与发布工作流创建的 Sentry release 标识符相同的规则，因此 release-health 和 `Fixes` 基于 trailer 的自动解析关联能够对上。

如果无法得知 SDK 版本，则两者都不会烘焙进去，并会留下警告。这时 Sentry 会使用默认值，因此如果是 prerelease 构建，事件可能会流向 stable triage。

#### sentry-cli

用于上传调试符号和 source map 的值。不是 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`                |

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

### 工作原理

#### 条件编译

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# 文件·行号信息。

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

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

### 问题排查

#### 事件未发送

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

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

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

```
[AITSentry] Initialized - AIT 上下文会自动附加到 Sentry 事件。
```

如果是 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`可以再加上同样的声明来补强。

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

#### 部分上下文 unavailable

平台 API 调用失败时就是这种情况。不会重试，而是将其确认为 `unavailable`unavailable

。在 Mock bridge 环境中，部分 API 不受支持，出现这个值属于正常情况。在这种情况下，标签中根本不会有对应项， `apps_in_toss` 只会在上下文里 `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.
