feat(sentry): split errors into per-surface projects (react, core, tauri) (#1032)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
CodeGhost21
2026-04-29 15:57:41 -07:00
committed by GitHub
co-authored by Claude Opus 4.7
parent 975614d0ec
commit e943a1ad1b
6 changed files with 494 additions and 24 deletions
+66 -18
View File
@@ -464,6 +464,8 @@ jobs:
CORE_MANIFEST: ${{ steps.core-paths.outputs.core_manifest }}
CORE_BIN_NAME: ${{ steps.core-paths.outputs.core_bin_name }}
OPENHUMAN_APP_ENV: ${{ inputs.build_target == 'staging' && 'staging' || 'production' }}
# Core (Rust openhuman sidecar) Sentry DSN — separate Sentry project
# from the React frontend and the Tauri shell.
OPENHUMAN_SENTRY_DSN: ${{ vars.OPENHUMAN_CORE_SENTRY_DSN }}
# Sentry release tracking (#405): `option_env!("OPENHUMAN_BUILD_SHA")`
# in src/main.rs bakes the short SHA into the release tag
@@ -511,7 +513,17 @@ jobs:
# (`vite build`) bakes Sentry + debug flags into the final bundle.
# Vite is invoked via tauri.conf.json's beforeBuildCommand during
# `cargo tauri build`, so these env vars must be present here.
# React frontend Sentry DSN — separate Sentry project.
VITE_SENTRY_DSN: ${{ vars.OPENHUMAN_REACT_SENTRY_DSN }}
# Tauri shell (desktop host) Sentry DSN — separate Sentry project
# from the React frontend and the Rust core. Baked into the shell
# binary via `option_env!("OPENHUMAN_TAURI_SENTRY_DSN")` at compile
# time so the released desktop app reports to its own project.
OPENHUMAN_TAURI_SENTRY_DSN: ${{ vars.OPENHUMAN_TAURI_SENTRY_DSN }}
# Bake the build SHA into the Tauri shell so its Sentry release tag
# (`openhuman@<version>+<sha>`) matches the React bundle and core
# sidecar — events across all three surfaces group under one release.
OPENHUMAN_BUILD_SHA: ${{ needs.prepare-build.outputs.sha }}
VITE_DEBUG: ${{ vars.VITE_DEBUG }}
# Sentry release tracking (#405) — must match the Vite build triggered
# by Tauri so source maps uploaded there resolve correctly against the
@@ -522,7 +534,12 @@ jobs:
needs.prepare-build.outputs.sha }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT_FRONTEND }}
# SENTRY_PROJECT here is consumed by sentry-vite-plugin during the
# Vite build that runs inside `cargo tauri build` (beforeBuildCommand)
# — it uploads frontend source maps to the React Sentry project.
# Core and Tauri-shell debug symbols are uploaded to their own
# projects in the dedicated steps below.
SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT_REACT }}
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD || secrets.UPDATER_PRIVATE_KEY_PASSWORD }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY || secrets.UPDATER_PRIVATE_KEY }}
@@ -540,9 +557,11 @@ jobs:
# Upload Rust debug info to Sentry so backend + Tauri-shell stack traces
# symbolicate in production. The frontend source maps are handled by
# sentry-vite-plugin in the build step above; this is the Rust half.
# Keyed by debug-ID, so it's safe to run per-matrix-target without
# collisions — Sentry merges artifacts across platforms.
- name: Upload Rust debug symbols to Sentry
# Core sidecar and Tauri shell go to **separate Sentry projects**
# (matching their separate DSNs) so events show up in the right place.
# Symbols are keyed by debug-ID, so it's safe to run per-matrix-target
# without collisions — Sentry merges artifacts across platforms.
- name: Upload core sidecar debug symbols to Sentry
if:
needs.prepare-build.outputs.release_enabled == 'true' && env.SENTRY_AUTH_TOKEN
!= ''
@@ -550,24 +569,53 @@ jobs:
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }}
SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT_CORE }}
# Must match the release tag the running core binary reports
# (`openhuman@<version>+<sha>`, see `build_release_tag` in
# src/main.rs). If this drifts, DIFs attach to a different
# release than events and stack traces stay un-symbolicated.
SENTRY_RELEASE:
openhuman@${{ needs.prepare-build.outputs.version }}+${{
needs.prepare-build.outputs.sha }}
VERSION: ${{ needs.prepare-build.outputs.version }}
MATRIX_TARGET: ${{ matrix.settings.target }}
run: |
set -euo pipefail
# Core crate deps (sidecar symbols) + Tauri shell deps (app binary
# symbols) both live under the per-target release dir. upload-dif
# scans recursively.
for deps_dir in \
"target/${MATRIX_TARGET}/release/deps" \
"app/src-tauri/target/${MATRIX_TARGET}/release/deps"; do
if [ -d "$deps_dir" ]; then
echo "==> Uploading symbols from $deps_dir"
bash scripts/upload_sentry_symbols.sh "$VERSION" "$deps_dir"
else
echo "==> Skipping $deps_dir (not present)"
fi
done
deps_dir="target/${MATRIX_TARGET}/release/deps"
if [ -d "$deps_dir" ]; then
echo "==> Uploading core symbols from $deps_dir to ${SENTRY_PROJECT}"
bash scripts/upload_sentry_symbols.sh "$VERSION" "$deps_dir"
else
echo "==> Skipping $deps_dir (not present)"
fi
- name: Upload Tauri shell debug symbols to Sentry
if:
needs.prepare-build.outputs.release_enabled == 'true' && env.SENTRY_AUTH_TOKEN
!= ''
shell: bash
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT_TAURI }}
# Must match the release tag the running shell binary reports
# (`openhuman@<version>+<sha>`, see `build_sentry_release_tag` in
# app/src-tauri/src/lib.rs). If this drifts, DIFs attach to a
# different release than events and stack traces stay
# un-symbolicated.
SENTRY_RELEASE:
openhuman@${{ needs.prepare-build.outputs.version }}+${{
needs.prepare-build.outputs.sha }}
VERSION: ${{ needs.prepare-build.outputs.version }}
MATRIX_TARGET: ${{ matrix.settings.target }}
run: |
set -euo pipefail
deps_dir="app/src-tauri/target/${MATRIX_TARGET}/release/deps"
if [ -d "$deps_dir" ]; then
echo "==> Uploading Tauri shell symbols from $deps_dir to ${SENTRY_PROJECT}"
bash scripts/upload_sentry_symbols.sh "$VERSION" "$deps_dir"
else
echo "==> Skipping $deps_dir (not present)"
fi
# tauri-action previously uploaded non-macOS installer assets directly
# to the release. Replicate that for Linux + Windows here (macOS goes
+300 -1
View File
@@ -18,7 +18,7 @@ dependencies = [
"futures-util",
"log",
"mac-notification-sys",
"nix",
"nix 0.29.0",
"notify-rust",
"objc2",
"objc2-app-kit",
@@ -29,6 +29,7 @@ dependencies = [
"rusqlite",
"rustls",
"semver",
"sentry",
"serde",
"serde_json",
"tar",
@@ -47,6 +48,15 @@ dependencies = [
"zip 2.4.2",
]
[[package]]
name = "addr2line"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
dependencies = [
"gimli",
]
[[package]]
name = "adler2"
version = "2.0.1"
@@ -302,6 +312,43 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "aws-lc-rs"
version = "1.16.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f"
dependencies = [
"aws-lc-sys",
"zeroize",
]
[[package]]
name = "aws-lc-sys"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7"
dependencies = [
"cc",
"cmake",
"dunce",
"fs_extra",
]
[[package]]
name = "backtrace"
version = "0.3.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-link 0.2.1",
]
[[package]]
name = "base64"
version = "0.21.7"
@@ -485,6 +532,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1"
dependencies = [
"find-msvc-tools",
"jobserver",
"libc",
"shlex",
]
@@ -902,6 +951,16 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "debugid"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
dependencies = [
"serde",
"uuid",
]
[[package]]
name = "deranged"
version = "0.5.8"
@@ -1391,6 +1450,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "fs_extra"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "futf"
version = "0.1.5"
@@ -1408,6 +1473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
@@ -1637,6 +1703,12 @@ dependencies = [
"wasip3",
]
[[package]]
name = "gimli"
version = "0.32.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
[[package]]
name = "gio"
version = "0.18.4"
@@ -1803,6 +1875,25 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "h2"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
dependencies = [
"atomic-waker",
"bytes",
"fnv",
"futures-core",
"futures-sink",
"http",
"indexmap 2.13.0",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -1863,6 +1954,17 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hostname"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd"
dependencies = [
"cfg-if",
"libc",
"windows-link 0.2.1",
]
[[package]]
name = "html5ever"
version = "0.29.1"
@@ -1924,6 +2026,12 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
name = "httpdate"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "1.8.1"
@@ -1934,6 +2042,7 @@ dependencies = [
"bytes",
"futures-channel",
"futures-core",
"h2",
"http",
"http-body",
"httparse",
@@ -2316,6 +2425,16 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "jobserver"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [
"getrandom 0.3.4",
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.92"
@@ -2683,6 +2802,18 @@ dependencies = [
"libc",
]
[[package]]
name = "nix"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [
"bitflags 2.11.0",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]]
name = "nodrop"
version = "0.1.14"
@@ -2954,9 +3085,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
dependencies = [
"bitflags 2.11.0",
"block2",
"objc2",
"objc2-cloud-kit",
"objc2-core-data",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-core-image",
"objc2-core-location",
"objc2-core-text",
"objc2-foundation",
"objc2-quartz-core",
"objc2-user-notifications",
]
[[package]]
@@ -2988,6 +3128,15 @@ dependencies = [
"objc2-security",
]
[[package]]
name = "object"
version = "0.37.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.21.4"
@@ -3044,6 +3193,22 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "os_info"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4022a17595a00d6a369236fdae483f0de7f0a339960a53118b818238e132224"
dependencies = [
"android_system_properties",
"log",
"nix 0.30.1",
"objc2",
"objc2-foundation",
"objc2-ui-kit",
"serde",
"windows-sys 0.61.2",
]
[[package]]
name = "osakit"
version = "0.3.1"
@@ -3553,6 +3718,7 @@ version = "0.11.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
dependencies = [
"aws-lc-rs",
"bytes",
"getrandom 0.3.4",
"lru-slab",
@@ -3854,8 +4020,10 @@ checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"http-body-util",
@@ -3866,6 +4034,7 @@ dependencies = [
"log",
"percent-encoding",
"pin-project-lite",
"quinn",
"rustls",
"rustls-pki-types",
"rustls-platform-verifier",
@@ -3923,6 +4092,12 @@ dependencies = [
"ordered-multimap",
]
[[package]]
name = "rustc-demangle"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
[[package]]
name = "rustc-hash"
version = "2.1.2"
@@ -3957,6 +4132,7 @@ version = "0.23.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
dependencies = [
"aws-lc-rs",
"log",
"once_cell",
"ring",
@@ -4021,6 +4197,7 @@ version = "0.103.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
dependencies = [
"aws-lc-rs",
"ring",
"rustls-pki-types",
"untrusted",
@@ -4171,6 +4348,103 @@ dependencies = [
"serde_core",
]
[[package]]
name = "sentry"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb25f439f97d26fea01d717fa626167ceffcd981addaa670001e70505b72acbb"
dependencies = [
"cfg_aliases",
"httpdate",
"reqwest 0.13.2",
"rustls",
"sentry-backtrace",
"sentry-contexts",
"sentry-core",
"sentry-panic",
"sentry-tracing",
"tokio",
"ureq",
]
[[package]]
name = "sentry-backtrace"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46a8c2c1bd5c1f735e84f28b48e7d72efcaafc362b7541bc8253e60e8fcdffc6"
dependencies = [
"backtrace",
"regex",
"sentry-core",
]
[[package]]
name = "sentry-contexts"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b88a90baa654d7f0e1f4b667f6b434293d9f72c71bef16b197c76af5b7d5803"
dependencies = [
"hostname",
"libc",
"os_info",
"rustc_version",
"sentry-core",
"uname",
]
[[package]]
name = "sentry-core"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ac170a5bba8bec6e3339c90432569d89641fa7a3d3e4f44987d24f0762e6adf"
dependencies = [
"rand 0.9.2",
"sentry-types",
"serde",
"serde_json",
"url",
]
[[package]]
name = "sentry-panic"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6127d3d304ba5ce0409401e85aae538e303a569f8dbb031bf64f9ba0f7174346"
dependencies = [
"sentry-backtrace",
"sentry-core",
]
[[package]]
name = "sentry-tracing"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27701acc51e68db5281802b709010395bfcbcb128b1d0a4e5873680d3b47ff0c"
dependencies = [
"bitflags 2.11.0",
"sentry-backtrace",
"sentry-core",
"tracing-core",
"tracing-subscriber",
]
[[package]]
name = "sentry-types"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56780cb5597d676bf22e6c11d1f062eb4def46390ea3bfb047bcbcf7dfd19bdb"
dependencies = [
"debugid",
"hex",
"rand 0.9.2",
"serde",
"serde_json",
"thiserror 2.0.18",
"time",
"url",
"uuid",
]
[[package]]
name = "serde"
version = "1.0.228"
@@ -5428,6 +5702,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
dependencies = [
"tracing-core",
]
[[package]]
@@ -5499,6 +5783,15 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "uname"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8"
dependencies = [
"libc",
]
[[package]]
name = "unic-char-property"
version = "0.9.0"
@@ -5670,6 +5963,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "vcpkg"
version = "0.2.15"
+8
View File
@@ -90,6 +90,14 @@ zip = { version = "2", default-features = false, features = ["deflate"] }
log = "0.4"
env_logger = "0.11"
# Sentry for the Tauri shell (desktop host) process — separate Sentry project
# from the React frontend and the Rust core sidecar. DSN is baked at compile
# time via `option_env!("OPENHUMAN_TAURI_SENTRY_DSN")` in `lib.rs::run()` and
# can be overridden at runtime via the same env var. Feature set mirrors the
# core sidecar (`Cargo.toml` at repo root) minus `tracing` since the shell
# uses `log` + `env_logger`.
sentry = { version = "0.47.0", default-features = false, features = ["backtrace", "contexts", "panic", "reqwest", "rustls"] }
# Used by the imessage_scanner module.
anyhow = "1.0"
parking_lot = "0.12"
+92
View File
@@ -870,6 +870,56 @@ fn teardown_cef_prewarm<R: tauri::Runtime>(app: &AppHandle<R>) -> Result<(), Str
}
pub fn run() {
// Initialize Sentry for the Tauri shell (desktop host) process before any
// other startup work. Reads `OPENHUMAN_TAURI_SENTRY_DSN` at runtime first,
// then falls back to the value baked in at compile time via the release
// workflow. Missing/empty DSN ⇒ `sentry::init` returns a no-op guard.
//
// The guard is held for the entire lifetime of `run()` so events queued
// during shutdown still flush. Only invoked here (and not in `main.rs`)
// so renderer/GPU CEF helper subprocesses (re-exec'd via
// `tauri::cef_entry_point`) and the `OpenHuman core …` in-process core
// path do NOT spin up a second client — those have their own reporting
// surfaces.
let _sentry_guard = sentry::init(sentry::ClientOptions {
dsn: std::env::var("OPENHUMAN_TAURI_SENTRY_DSN")
.ok()
.filter(|s| !s.is_empty())
.or_else(|| option_env!("OPENHUMAN_TAURI_SENTRY_DSN").map(|s| s.to_string()))
.filter(|s| !s.is_empty())
.and_then(|s| s.parse().ok()),
release: Some(std::borrow::Cow::Owned(build_sentry_release_tag())),
environment: Some(std::borrow::Cow::Owned(resolve_sentry_environment())),
send_default_pii: false,
before_send: Some(std::sync::Arc::new(|mut event| {
// Strip server_name (hostname) to avoid leaking machine identity.
event.server_name = None;
event.user = None;
Some(event)
})),
sample_rate: 1.0,
..sentry::ClientOptions::default()
});
// Optional smoke trigger for verifying the Sentry pipeline end-to-end.
// Run with `OPENHUMAN_TAURI_SENTRY_TEST=panic` to fire a panic, or
// `=message` to send a captured-message event. No-op when unset.
if let Ok(mode) = std::env::var("OPENHUMAN_TAURI_SENTRY_TEST") {
match mode.as_str() {
"panic" => panic!("OPENHUMAN_TAURI_SENTRY_TEST=panic — local Sentry smoke test"),
"message" => {
sentry::capture_message(
"OPENHUMAN_TAURI_SENTRY_TEST=message — local Sentry smoke test",
sentry::Level::Error,
);
let _ = sentry::Hub::current().client().map(|c| c.flush(None));
}
other => log::warn!(
"OPENHUMAN_TAURI_SENTRY_TEST={other:?} — unknown mode (use 'panic' or 'message')"
),
}
}
let daemon_mode = is_daemon_mode();
let default_filter = std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string());
@@ -1575,6 +1625,48 @@ pub fn run_core_from_args(args: &[String]) -> Result<(), String> {
Ok(())
}
// ---------------------------------------------------------------------------
// Sentry release / environment resolution (Tauri shell)
// ---------------------------------------------------------------------------
/// Canonical release tag: `openhuman@<version>[+<short_sha>]`.
///
/// Mirrors `build_release_tag` in the core sidecar's `src/main.rs` and the
/// `SENTRY_RELEASE` value computed in `app/vite.config.ts` so events from
/// every surface (React frontend, core sidecar, Tauri shell) group under the
/// same release in Sentry and benefit from the same source-map / debug-info
/// upload.
fn build_sentry_release_tag() -> String {
let version = env!("CARGO_PKG_VERSION");
let sha = option_env!("OPENHUMAN_BUILD_SHA").unwrap_or("").trim();
let sha_short: String = sha.chars().take(12).collect();
if sha_short.is_empty() {
format!("openhuman@{version}")
} else {
format!("openhuman@{version}+{sha_short}")
}
}
/// Resolve the Sentry environment tag from `OPENHUMAN_APP_ENV` (runtime) or
/// `VITE_OPENHUMAN_APP_ENV` (compile-time fallback). Defaults to
/// `production` so unmarked release builds don't pollute the dev/staging
/// streams.
fn resolve_sentry_environment() -> String {
if let Ok(value) = std::env::var("OPENHUMAN_APP_ENV") {
let trimmed = value.trim();
if !trimmed.is_empty() {
return trimmed.to_string();
}
}
if let Some(value) = option_env!("VITE_OPENHUMAN_APP_ENV") {
let trimmed = value.trim();
if !trimmed.is_empty() {
return trimmed.to_string();
}
}
"production".to_string()
}
#[cfg(test)]
mod tests {
use super::*;
+13 -3
View File
@@ -39,12 +39,22 @@ function maybeSentryPlugin(): PluginOption | null {
project: process.env.SENTRY_PROJECT,
release: { name: computeSentryRelease() },
sourcemaps: {
// Vite emits hashed asset files under dist/assets/ — upload every
// Vite emits hashed asset files into `app/dist/assets/`. Upload every
// .js / .map the build produces.
assets: ["../dist/**/*.js", "../dist/**/*.map"],
//
// `assets` is resolved by sentry-vite-plugin against `process.cwd()`,
// not the Vite `root` — so a relative path like `../dist/**` would
// miss when `pnpm tauri build` runs with cwd=`app/` and silently emit
// `Didn't find any matching sources for debug ID upload`. Use absolute
// paths anchored at this config file's directory (`app/`) to be
// immune to whatever cwd the parent process sets.
assets: [
resolve(__dirname, "dist/**/*.js"),
resolve(__dirname, "dist/**/*.map"),
],
// Never ship raw .map files to end users; the upload keeps a copy
// server-side for symbolication while the bundled app strips them.
filesToDeleteAfterUpload: ["../dist/**/*.map"],
filesToDeleteAfterUpload: [resolve(__dirname, "dist/**/*.map")],
},
// Release tagging + commits are handled by sentry-cli / the plugin
// itself when AUTH_TOKEN and CI env (GITHUB_SHA etc.) are present.
+15 -2
View File
@@ -169,7 +169,14 @@ upload_symbols() {
exit 1
fi
local release_name="openhuman@${version}"
# Honor SENTRY_RELEASE if set so DIFs attach to the same release name
# the running binaries report (`openhuman@<version>+<sha>`). Without this,
# CI uploads to `openhuman@<version>` while events are tagged
# `openhuman@<version>+<sha>` — a different release, so Sentry never
# joins frames to symbols and stack traces stay un-symbolicated.
# Falls back to the bare-version tag for local invocations that don't
# set SENTRY_RELEASE.
local release_name="${SENTRY_RELEASE:-openhuman@${version}}"
log_info "Uploading Rust debug symbols for release: ${release_name}"
log_info "Symbols path: ${symbols_path}"
@@ -180,12 +187,18 @@ upload_symbols() {
# Use --ignore-missing for shallow clones or CI environments
sentry-cli releases set-commits --auto --ignore-missing "${release_name}" || true
# Upload debug symbols
# Upload debug symbols + source bundles. `--include-sources` makes
# `sentry-cli` package the referenced source files into a `.src.zip`
# alongside the DIF, so Sentry renders surrounding source lines in
# Rust stack traces instead of bare `function + 0xNNN`. CI runs from a
# full workspace checkout, so the source paths embedded in the DWARF
# resolve and the bundle is built correctly.
log_info "Uploading debug symbols..."
local upload_args=(
"upload-dif"
"--org" "${SENTRY_ORG}"
"--project" "${SENTRY_PROJECT}"
"--include-sources"
"--log-level=warning"
)