用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tomevault-io/skills-registry --skill sentry-selfhosted命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
| Use when this capability is needed.
> Use when this capability is needed.
Review architecture and API design for the vfs-s3 project. Use when the user mentions @architect, asks to review an issue's design, discuss module boundaries, API shape, or architectural decisions for vfs-s3. Also trigger when the user wants to create an ADR (Architecture Decision Record) or evaluate a technical approach for the project. Intended for dispatch from Codex automation or Claude routines; GitHub trigger phrase: @vfs-s3-bot please prepare design doc Use when this capability is needed.
基于 SOC 职业分类
正在显示 SKILL.md
| name | sentry-selfhosted |
| description | | Use when this capability is needed. |
Deep Knowledge: Use
mcp__documentation__fetch_docswith technology:sentry.
For wallet apps (BHODL-style) and any privacy-respecting product, sending crash data to a third party is a non-starter:
Self-hosted Sentry:
For BHODL: Sentry is the right choice if crash reporting is enabled by user opt-in, telemetry routes via Tor, and PII is scrubbed.
| Tool | Comparison |
|---|---|
| GlitchTip | Lightweight Sentry-API-compatible alternative, MIT licensed, simpler ops. Uses same SDKs. Best for small/medium apps. |
| Bugsnag self-hosted | Closed source after acquisition; not recommended |
| Custom backend | Receive raw events, store in DB. Lots of work. |
| Cloud Sentry | Easy setup, SaaS — wrong for privacy-respecting apps |
For BHODL-scale: GlitchTip if Sentry is overkill. Sentry self-hosted if you need full feature set (release health, performance, distributed tracing).
Sentry official self-host: https://github.com/getsentry/self-hosted
git clone https://github.com/getsentry/self-hosted.git sentry
cd sentry
git checkout 24.10.0 # latest stable
# Requires: Docker + Docker Compose, ≥4GB RAM, ≥20GB disk
./install.sh
Installation creates:
docker compose up -d
docker compose run --rm web createuser # create admin
Access at http://localhost:9000.
For production: front with reverse proxy (Caddy, nginx), TLS via Let's Encrypt, restrict access.
For low-volume wallet app: 4GB VPS works fine.
# docker-compose.yml
services:
glitchtip:
image: glitchtip/glitchtip:latest
environment:
DATABASE_URL: postgres://glitchtip:secret@postgres/glitchtip
SECRET_KEY: <random-32-bytes>
EMAIL_URL: consolemail://
ports: ["8000:8000"]
postgres:
image: postgres:16
environment:
POSTGRES_USER: glitchtip
POSTGRES_PASSWORD: secret
POSTGRES_DB: glitchtip
volumes: ["pgdata:/var/lib/postgresql/data"]
volumes: { pgdata: }
GlitchTip uses Sentry's protocol — all SDKs work unchanged. ~512MB RAM.
[dependencies]
sentry = "0.34"
sentry-tracing = "0.34" # bridge from tracing
fn main() {
let _guard = sentry::init(sentry::ClientOptions {
dsn: "https://abc@sentry.example.com/1".parse().ok(),
release: sentry::release_name!(),
environment: Some("production".into()),
sample_rate: 1.0, // 100% errors
traces_sample_rate: 0.1, // 10% performance
send_default_pii: false, // CRITICAL: never send PII
before_send: Some(Arc::new(|event| {
// Scrub addresses, balances, etc.
Some(scrub_event(event))
})),
..Default::default()
});
// Bridge tracing events to Sentry
let subscriber = tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer())
.with(sentry_tracing::layer());
tracing::subscriber::set_global_default(subscriber).unwrap();
// App
if let Err(e) = run_app() {
sentry::capture_error(&*e);
}
}
( event: sentry::protocol::Event<>) sentry::protocol::Event<> {
sentry::protocol::Value;
event.user = ;
event.server_name = ;
event.message = event.message.(|m| (&m));
& event.breadcrumbs {
crumb.message = crumb.message.().(|m| (m));
crumb.data.(|k, _| !(k));
}
event
}
(s: &) {
= regex::Regex::().();
re.(s, ).()
}
(k: &) {
matches!(k, | | | | | )
}
match risky_operation() {
Ok(v) => v,
Err(e) => {
sentry::with_scope(
|scope| {
scope.set_tag("operation", "wallet_sync");
scope.set_level(Some(sentry::Level::Warning));
},
|| sentry::capture_error(&e),
);
return Err(e);
}
}
let tx = sentry::start_transaction(sentry::TransactionContext::new("wallet.sync", "task"));
sentry::configure_scope(|s| s.set_span(Some(tx.clone().into())));
// ... work ...
tx.finish();
// app/build.gradle.kts
dependencies {
implementation("io.sentry:sentry-android:7.18.0")
implementation("io.sentry:sentry-android-fragment:7.18.0") // optional
implementation("io.sentry:sentry-compose:7.18.0") // Compose
implementation("io.sentry:sentry-android-okhttp:7.18.0") // network
}
AndroidManifest.xml:
<application>
<meta-data android:name="io.sentry.dsn" android:value="https://abc@sentry.example.com/1" />
<meta-data android:name="io.sentry.environment" android:value="production" />
<meta-data android:name="io.sentry.send-default-pii" android:value="false" />
</application>
For programmatic init (recommended for opt-in pattern):
class BHODLApp : Application() {
override fun onCreate() {
super.onCreate()
if (prefs.getBoolean("crash_reports_enabled", false)) {
SentryAndroid.init(this) { options ->
options.dsn = "https://abc@sentry.example.com/1"
options.environment = "production"
options.tracesSampleRate = 0.1
options.isSendDefaultPii = false
options.beforeSend = SentryOptions.BeforeSendCallback { event, hint ->
scrubEvent(event)
}
options.beforeBreadcrumb = SentryOptions.BeforeBreadcrumbCallback { breadcrumb, hint ->
scrubBreadcrumb(breadcrumb)
}
}
}
}
}
private fun scrubEvent(event: SentryEvent): SentryEvent {
event.user = null
event.serverName = null
event.message?.message?.let { event.message?.message = scrubAddresses(it) }
return event
}
For Compose:
@Composable
fun App() {
SentryTraced(tag = "App") {
// your composables — auto-traced
}
}
// Package.swift
.package(url: "https://github.com/getsentry/sentry-cocoa.git", from: "8.41.0")
import Sentry
@main
struct BHODLApp: App {
init() {
if UserDefaults.standard.bool(forKey: "crash_reports_enabled") {
SentrySDK.start { options in
options.dsn = "https://abc@sentry.example.com/1"
options.environment = "production"
options.tracesSampleRate = 0.1
options.sendDefaultPii = false
options.beforeSend = { event in
self.scrubEvent(event)
}
}
}
}
var body: some Scene { WindowGroup { ContentView() } }
func scrubEvent(_ event: Event) -> Event? {
event.user = nil
event.serverName = nil
if let message = event.message?.formatted {
event.message = SentryMessage(formatted: scrubAddresses(message))
}
return event
}
}
Never enable crash reporting by default. Settings → "Help us improve" → toggle.
Use regex to redact Bitcoin addresses, large numbers, hashes. Apply in beforeSend and beforeBreadcrumb.
Never call Sentry.setUser(...) with real ID. Use anonymous device hash if needed for correlation:
options.isAttachStacktrace = true
options.isSendDefaultPii = false
options.setBeforeSend { event, _ ->
event.user = User().apply { id = anonymousDeviceHash() } // hashed device ID
event
}
For ultra-privacy: route Sentry traffic through Arti (network/arti):
let arti_client = ...;
let sentry_url = "http://sentry.your.onion".to_string();
// Configure HTTP client to use Arti proxy
let transport = SentryTransport::with_http_client(custom_arti_client);
For BHODL:
options.isEnableAutoSessionTracking = false
options.isAttachServerName = false
options.isEnableUserInteractionBreadcrumbs = false // user actions are sensitive
// Before sending, hold in queue and ask user
options.beforeSend = SentryOptions.BeforeSendCallback { event, hint ->
queueForUserApproval(event)
null // skip auto-send
}
For meaningful stack traces, upload symbols.
// app/build.gradle.kts
sentry {
autoUploadProguardMapping.set(true)
includeProguardMapping.set(true)
autoInstallation { sentryVersion.set("7.18.0") }
}
# In Xcode Build Phases, add Run Script:
sentry-cli upload-dif --org bhodl --project ios "$DWARF_DSYM_FOLDER_PATH"
sentry-cli upload-dif --org bhodl --project rust target/release/bhodl
Track crash-free rate per release:
options.release = "bhodl@${BuildConfig.VERSION_NAME}+${BuildConfig.VERSION_CODE}"
options.environment = "production"
options.isEnableAutoSessionTracking = true // OK for non-sensitive sessions
Sentry dashboard shows: % users without crash, % sessions without crash, regressions per release.
For BHODL: opt-in users only, but useful even with small sample.
In Sentry UI: Alerts → New Rule.
Examples:
For a small team: a single Slack channel for high-severity errors is enough.
Self-hosted = your responsibility:
# Backup Postgres
docker compose exec -T postgres pg_dump -U postgres > backup.sql
# Backup ClickHouse (events)
docker compose exec clickhouse clickhouse-client --query "BACKUP ALL TO Disk('backups', 'sentry-$(date +%F)')"
For a small wallet app, daily backup to S3-compatible storage is fine.
| Anti-pattern | Why it's bad | Correct approach |
|---|---|---|
| Crash reports on by default | Violates user trust | Opt-in only |
Sending PII (sendDefaultPii = true) | Leaks user data | Always false; scrub manually |
No beforeSend hook | Default events contain wallet state | Always implement scrubber |
| Logging full stack with secret variables | Stack frames may include args | Mark sensitive args with @redact annotations or strip in beforeSend |
| Using cloud Sentry for wallet app | Third-party data leak | Self-host (or GlitchTip) |
| Storing Sentry DSN in source | Allows others to spam your project | Env var or runtime config |
| 100% trace sample rate | Heavy ingestion + cost on self-host | 1-10% for production |
| Forgetting to upload symbols | Useless stack traces | Automate symbol upload in CI |
| No retention policy | Disk fills | Set retention (e.g., 30 days for events) |
| Single admin account, no MFA | Security risk | Multi-user, MFA, restricted access |
| Symptom | Cause | Fix |
|---|---|---|
Self-host install fails (Insufficient memory) | <4GB RAM | Resize VPS or use GlitchTip |
| Events not appearing | DSN wrong, beforeSend returning null | Check Sentry network logs |
| Stack traces unsymbolicated | Symbols not uploaded | Run sentry-cli upload-dif |
| ClickHouse disk full | No retention | Configure event retention period |
| Slow Sentry web UI | Resource limits | Increase Docker resource quotas |
| Crash report includes wallet seed | Scrubbing missed it | Audit beforeSend thoroughly; redact strings broadly |
| Auto-session tracking enabled in privacy mode | Sessions tracked even when reports off | isEnableAutoSessionTracking = false for opt-out users |
| Network calls fail (firewall) | Sentry endpoint not whitelisted | Allow outbound to your Sentry server only |
| Compose / SwiftUI traces too verbose | Auto-instrumentation noisy | Disable auto-tracing; manual transaction wrapping |
| GitHub PR shows error trends | sentry-github integration | OK; or disable if too noisy |
Old events stay in SaaS — manual export if needed.
| Scenario | Use Instead |
|---|---|
| Logging (informational) | observability/rust-tracing or platform logger |
| Metrics (counters, histograms) | Prometheus / OpenMetrics |
| Distributed tracing only | OpenTelemetry |
| Cloud Sentry SaaS | Cloud Sentry docs (different threat model) |
| Apple's MetricKit | iOS-specific built-in |
| Google Crashlytics (Firebase) | Firebase docs (Google-hosted, similar privacy concerns) |
Source: claude-dev-suite/claude-dev-suite — distributed by TomeVault.