Skip to content

feat: pi 2.9 遥测 - #295

Merged
MistEO merged 3 commits into
MistEO:mainfrom
zmdyy0318:feat/2026072201
Jul 28, 2026
Merged

feat: pi 2.9 遥测#295
MistEO merged 3 commits into
MistEO:mainfrom
zmdyy0318:feat/2026072201

Conversation

@zmdyy0318

@zmdyy0318 zmdyy0318 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

opus 5.0
MaaXYZ/MaaFramework#1414
默认开启
7928f5513c7f9804208e1361b61ca8e5

Summary by Sourcery

添加由 Sentry 驱动的可选匿名遥测功能,在调试/开发构建中进行基于构建类型的拦截,并在前端和 Tauri 后端对任务生命周期进行监控。

New Features:

  • 引入一个面向用户的“帮助改进软件”设置,用于控制匿名崩溃报告和任务统计上报。
  • 通过新的基于 telemetry.sentry DSN 的配置容器,支持从项目接口进行遥测配置。
  • 在 Tauri 应用中,基于接口与配置数据初始化 Sentry 遥测,在构建类型允许且数据可用时启用。

Enhancements:

  • 跟踪任务运行生命周期(批次开始、单个任务开始/结束、运行完成/取消),在不影响核心任务执行的前提下生成结构化遥测事件。
  • 扩展任务运行状态以持久化任务入口名称,用于遥测,同时尽量减少运行时锁的使用。
  • 在应用和后端中新增专用的遥测日志与命令接线,实现遥测操作的集中处理。

Build:

  • 在 Tauri Rust 项目依赖中添加 Sentry 及相关系统信息库,以支持遥测功能。

Documentation:

  • 为遥测可选设置及其在调试/开发构建中的限制新增本地化说明,覆盖所有支持的语言。
Original summary in English

Summary by Sourcery

Add opt-in anonymous telemetry powered by Sentry, with build-based blocking in debug/dev and task lifecycle instrumentation across frontend and Tauri backend.

New Features:

  • Introduce a user-facing “Help Improve the Software” setting that controls anonymous crash and task statistics reporting.
  • Support telemetry configuration from project interfaces via a new telemetry.sentry DSN-based config container.
  • Initialize Sentry-based telemetry in the Tauri app using interface and config data when available and allowed by build type.

Enhancements:

  • Track task run lifecycle (batch start, per-task start/finish, run completion/cancellation) to feed structured telemetry events without affecting core task execution.
  • Extend task run state to persist task entry names for telemetry purposes while keeping runtime locks minimal.
  • Add dedicated telemetry logging and command wiring in the app and backend for centralized handling of telemetry operations.

Build:

  • Add Sentry and supporting system information libraries to the Tauri Rust project dependencies for telemetry support.

Documentation:

  • Add localized descriptions for the telemetry opt-in setting and its debug/dev build restrictions across supported languages.

Summary by Sourcery

在前端和 Tauri 后端中添加基于 Sentry 的可选匿名遥测,以及任务生命周期的埋点,根据构建类型和新的用户设置进行控制。

New Features:

  • 引入一个面向用户的“帮助改进软件”设置,用于控制匿名崩溃和任务统计数据的上报。
  • 允许各接口通过新的 telemetry.sentry 容器声明 Sentry 遥测配置,包括 DSN 和追踪选项。
  • 在 Tauri 应用中,根据接口和配置数据,在构建类型允许的情况下初始化基于 Sentry 的遥测。

Enhancements:

  • 在前端和后端对任务运行及每个任务的选项进行埋点,在不影响核心执行的前提下发送结构化遥测 span。
  • 为每个任务追踪控制器元数据和节点级故障,以丰富遥测中的故障位置信息和运行级标签。
  • 添加集中式遥测日志记录,并在前端与 Tauri 后端之间接通与遥测相关的命令,用于配置和生命周期控制。

Build:

  • 在 Tauri Rust 项目中添加 Sentry、sysinfo、machine-uid 和 sha2 依赖,以支持遥测数据采集和匿名化处理。

Documentation:

  • 在所有支持的语言中本地化新的遥测设置,以及其在调试/开发构建中的限制说明。
Original summary in English

Summary by Sourcery

Add optional Sentry-based anonymous telemetry with task lifecycle instrumentation across frontend and Tauri backend, gated by build type and a new user setting.

New Features:

  • Introduce a user-facing “Help Improve the Software” setting to control anonymous crash and task statistics reporting.
  • Allow interfaces to declare Sentry telemetry configuration via a new telemetry.sentry container, including DSN and tracing options.
  • Initialize Sentry-powered telemetry in the Tauri app using interface and config data when available and permitted by build type.

Enhancements:

  • Instrument task runs and per-task options on both frontend and backend to emit structured telemetry spans without affecting core execution.
  • Track controller metadata and node-level failures for each task to enrich telemetry with failure locations and run-level tags.
  • Add centralized telemetry logging and wire telemetry-related commands between frontend and Tauri backend for configuration and lifecycle control.

Build:

  • Add Sentry, sysinfo, machine-uid, and sha2 dependencies to the Tauri Rust project to support telemetry collection and anonymization.

Documentation:

  • Localize the new telemetry setting and its debug/dev build restrictions across supported languages.

@zmdyy0318
zmdyy0318 marked this pull request as draft July 22, 2026 15:26

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

嗨——我已经审查了你的改动,一切看起来都很棒!


Sourcery 对开源项目是免费的——如果你觉得我们的评审有帮助,请考虑分享它 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@zmdyy0318
zmdyy0318 marked this pull request as ready for review July 27, 2026 16:30

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我这边发现了两个问题,并给了一些整体性的反馈:

  • telemetry.rs 里的 PostingGuard 结构体存了一个 MutexGuard<'static, ...>,这在编译时会失败,因为这个 guard 的生命周期并不是 'static。可以考虑让 PostingGuard 对生命周期做泛型(例如 PostingGuard<'a> { runs: MutexGuard<'a, ...> }),或者重新设计,使得互斥锁的 guard 不需要用 'static 生命周期存储。
  • telemetry_set_enabled(false) 中,你清除了 TELEMETRY_GUARDRUNS,但保留了 TELEMETRY_CONFIG。如果关闭遥测的目的是真正完全退出收集,建议考虑同时清理或标记缓存的配置,这样在同一进程中之后再次启用时,不会在没有显式初始化的情况下意外复用旧配置。
给 AI Agent 的提示
请根据这次代码评审中的评论进行修改:

## 总体评论
- `telemetry.rs` 里的 `PostingGuard` 结构体存了一个 `MutexGuard<'static, ...>`,这在编译时会失败,因为这个 guard 的生命周期并不是 `'static`。可以考虑让 `PostingGuard` 对生命周期做泛型(例如 `PostingGuard<'a> { runs: MutexGuard<'a, ...> }`),或者重新设计,使得互斥锁的 guard 不需要用 `'static` 生命周期存储。
-`telemetry_set_enabled(false)` 中,你清除了 `TELEMETRY_GUARD``RUNS`,但保留了 `TELEMETRY_CONFIG`。如果关闭遥测的目的是真正完全退出收集,建议考虑同时清理或标记缓存的配置,这样在同一进程中之后再次启用时,不会在没有显式初始化的情况下意外复用旧配置。

## 逐条评论

### Comment 1
<location path="src-tauri/src/commands/telemetry.rs" line_range="538-539" />
<code_context>
+}
+
+/// 提交任务期间的元数据登记句柄,持有遥测状态锁。
+pub struct PostingGuard {
+    runs: std::sync::MutexGuard<'static, BTreeMap<String, RunState>>,
+    instance_id: String,
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** 避免在 `PostingGuard` 中存储带有 `'static` 生命周期的 `MutexGuard`

`RUNS.lock()` 不可能返回一个生命周期为 `'static``MutexGuard`,因此这个字段类型无法通过编译,也会鼓励不安全的生命周期处理方式。请避免预设 `'static` 生命周期:可以让 `PostingGuard` 对 guard 的生命周期做泛型,或者只存一个 `Arc<Mutex<_>>` 加上 `instance_id`,并在每次 `register` 调用中再获取锁。鉴于临界区很小,每次调用重新加锁是可以接受的,同时可以保持 API 的内存安全。
</issue_to_address>

### Comment 2
<location path="src/services/telemetryService.ts" line_range="38-46" />
<code_context>
+const MAX_OPTION_VALUE_LENGTH = 64;
+
+/** 自由文本类输入只上报是否填写,避免把路径 / URL / 进程名等隐私内容带出去。 */
+const summarizeInputValue = (
+  value: string,
+  pipelineType?: 'string' | 'int' | 'bool',
+  inputType?: 'text' | 'file' | 'time',
+): string => {
+  const isSafeToReport =
+    pipelineType === 'int' || pipelineType === 'bool' || (inputType === 'time' && !!value);
+  if (isSafeToReport) return value;
+  return value ? 'filled' : 'empty';
+};
+
</code_context>
<issue_to_address>
**🚨 suggestion (security):** 请考虑从隐私角度看,原始整数输入值是否适合直接上报

对 `pipeline_type === 'int'` 的情况,目前会直接上报原始值。如果这些整数可能包含用户或账号标识(例如 ID、手机号片段),即使有匿名化策略,依然可能泄露敏感信息。除非你能保证这些整数永远是非敏感内容(如小范围枚举或计数),否则可以考虑像其他自由文本一样处理(只上报 `filled`/`empty`,或按区间粗粒度分桶),以降低隐私风险。

建议实现:

```typescript
import { isDebugVersion } from '@/services/updateService';

```

```typescript
import { isDebugVersion } from '@/services/updateService';
import { createDefaultOptionValue, sanitizeOptionValue } from '@/stores/helpers';
import type {
  OptionDefinition,
  OptionValue,
  ProjectInterface,
  SelectedTask,
} from '@/types/interface';
import { loggers } from '@/utils/logger';
import { findSwitchCase } from '@/utils/optionHelpers';

/** 单个任务上报的选项条目上限,避免异常配置撑大事件。 */
const MAX_OPTION_ENTRIES = 30;
/** 单个选项值的长度上限。 */
const MAX_OPTION_VALUE_LENGTH = 64;

/** 自由文本类输入只上报是否填写,避免把路径 / URL / 进程名等隐私内容带出去。 */
const summarizeInputValue = (
  value: string,
  pipelineType?: 'string' | 'int' | 'bool',
  inputType?: 'text' | 'file' | 'time',
): string => {
  const isSafeToReport =
    pipelineType === 'bool' || (inputType === 'time' && !!value);

  if (isSafeToReport) return value;
  return value ? 'filled' : 'empty';
};

```
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得这些评审有帮助,欢迎分享 ✨
请帮我变得更有用!欢迎在每条评论上点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • The PostingGuard struct in telemetry.rs stores a MutexGuard<'static, ...>, which won’t compile because the guard’s lifetime is not 'static; make PostingGuard generic over a lifetime (e.g. PostingGuard<'a> { runs: MutexGuard<'a, ...> }) or redesign it so the mutex guard does not need to be stored with a 'static lifetime.
  • In telemetry_set_enabled(false) you clear TELEMETRY_GUARD and RUNS but keep TELEMETRY_CONFIG; if the intent of disabling is to fully opt out, consider also clearing or marking the cached config so it isn't reused accidentally on a later enable in the same process without an explicit init.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `PostingGuard` struct in `telemetry.rs` stores a `MutexGuard<'static, ...>`, which won’t compile because the guard’s lifetime is not `'static`; make `PostingGuard` generic over a lifetime (e.g. `PostingGuard<'a> { runs: MutexGuard<'a, ...> }`) or redesign it so the mutex guard does not need to be stored with a `'static` lifetime.
- In `telemetry_set_enabled(false)` you clear `TELEMETRY_GUARD` and `RUNS` but keep `TELEMETRY_CONFIG`; if the intent of disabling is to fully opt out, consider also clearing or marking the cached config so it isn't reused accidentally on a later enable in the same process without an explicit init.

## Individual Comments

### Comment 1
<location path="src-tauri/src/commands/telemetry.rs" line_range="538-539" />
<code_context>
+}
+
+/// 提交任务期间的元数据登记句柄,持有遥测状态锁。
+pub struct PostingGuard {
+    runs: std::sync::MutexGuard<'static, BTreeMap<String, RunState>>,
+    instance_id: String,
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** Avoid storing a `MutexGuard` with a `'static` lifetime in `PostingGuard`

`RUNS.lock()` cannot return a `MutexGuard` with a `'static` lifetime, so this field type will not compile and encourages unsound lifetime handling. Instead, avoid a baked-in `'static` lifetime: make `PostingGuard` generic over the guard’s lifetime, or store an `Arc<Mutex<_>>` plus `instance_id` and acquire the lock in each `register` call. Given the small critical section, re-locking per call is acceptable and keeps the API sound.
</issue_to_address>

### Comment 2
<location path="src/services/telemetryService.ts" line_range="38-46" />
<code_context>
+const MAX_OPTION_VALUE_LENGTH = 64;
+
+/** 自由文本类输入只上报是否填写,避免把路径 / URL / 进程名等隐私内容带出去。 */
+const summarizeInputValue = (
+  value: string,
+  pipelineType?: 'string' | 'int' | 'bool',
+  inputType?: 'text' | 'file' | 'time',
+): string => {
+  const isSafeToReport =
+    pipelineType === 'int' || pipelineType === 'bool' || (inputType === 'time' && !!value);
+  if (isSafeToReport) return value;
+  return value ? 'filled' : 'empty';
+};
+
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Consider whether raw integer input values are safe to report from a privacy perspective

For `pipeline_type === 'int'`, values are currently sent as-is. If these integers can include user or account identifiers (e.g., IDs, phone fragments), this may expose sensitive data despite the anonymization strategy. Unless you can guarantee these are always non-sensitive (e.g., small bounded enums or counts), consider handling them like other free-text inputs (only `filled`/`empty` or coarse numeric buckets) to reduce privacy risk.

Suggested implementation:

```typescript
import { isDebugVersion } from '@/services/updateService';

```

```typescript
import { isDebugVersion } from '@/services/updateService';
import { createDefaultOptionValue, sanitizeOptionValue } from '@/stores/helpers';
import type {
  OptionDefinition,
  OptionValue,
  ProjectInterface,
  SelectedTask,
} from '@/types/interface';
import { loggers } from '@/utils/logger';
import { findSwitchCase } from '@/utils/optionHelpers';

/** 单个任务上报的选项条目上限,避免异常配置撑大事件。 */
const MAX_OPTION_ENTRIES = 30;
/** 单个选项值的长度上限。 */
const MAX_OPTION_VALUE_LENGTH = 64;

/** 自由文本类输入只上报是否填写,避免把路径 / URL / 进程名等隐私内容带出去。 */
const summarizeInputValue = (
  value: string,
  pipelineType?: 'string' | 'int' | 'bool',
  inputType?: 'text' | 'file' | 'time',
): string => {
  const isSafeToReport =
    pipelineType === 'bool' || (inputType === 'time' && !!value);

  if (isSafeToReport) return value;
  return value ? 'filled' : 'empty';
};

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src-tauri/src/commands/telemetry.rs
Comment thread src/services/telemetryService.ts
@MistEO
MistEO merged commit 969957d into MistEO:main Jul 28, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants