diff --git a/packages/tauri/src/bin.rs b/packages/tauri/src/bin.rs index 121415266..8fb1ce2d6 100644 --- a/packages/tauri/src/bin.rs +++ b/packages/tauri/src/bin.rs @@ -5,24 +5,13 @@ use tauri::{generate_context, Manager}; use gblib::{ analytics, app, assets, bookmarks, commands, database, deltas, github, keys, logs, projects, - sessions, storage, users, virtual_branches, watcher, zip, + sentry, sessions, storage, users, virtual_branches, watcher, zip, }; fn main() { let tauri_context = generate_context!(); - let _guard = sentry::init(("https://9d407634d26b4d30b6a42d57a136d255@o4504644069687296.ingest.sentry.io/4504649768108032", sentry::ClientOptions { - release: Some(tauri_context.package_info().version.to_string().into()), - environment: Some(match tauri_context.package_info().name.as_str() { - "GitButler" => "production", - "GitButler Nightly" => "nightly", - "GitButler Dev" => "development", - _ => "unknown", - }.into()), - attach_stacktrace: true, - default_integrations: true, - ..Default::default() - })); + let _guard = sentry::init(tauri_context.package_info()); tokio::runtime::Builder::new_multi_thread() .enable_all() @@ -141,9 +130,7 @@ fn main() { app_handle.manage(keys_controller); let users_controller = users::Controller::from(&app_handle); - if let Some(user) = users_controller.get_user().context("failed to get user")? { - sentry::configure_scope(|scope| scope.set_user(Some(user.clone().into()))); - } + sentry::configure_scope(users_controller.get_user().context("failed to get user")?.as_ref()); app_handle.manage(users_controller); let app: app::App = app::App::try_from(&tauri_app.app_handle()) diff --git a/packages/tauri/src/lib.rs b/packages/tauri/src/lib.rs index f0180579c..acd27db1a 100644 --- a/packages/tauri/src/lib.rs +++ b/packages/tauri/src/lib.rs @@ -22,6 +22,7 @@ pub mod paths; pub mod project_repository; pub mod projects; pub mod reader; +pub mod sentry; pub mod sessions; pub mod storage; pub mod users; diff --git a/packages/tauri/src/logs.rs b/packages/tauri/src/logs.rs index e395ae34c..0c70590cc 100644 --- a/packages/tauri/src/logs.rs +++ b/packages/tauri/src/logs.rs @@ -4,7 +4,7 @@ use tauri::{AppHandle, Manager}; use tracing::{metadata::LevelFilter, subscriber::set_global_default}; use tracing_subscriber::{fmt::format::FmtSpan, layer::SubscriberExt, Layer}; -use crate::paths::LogsDir; +use crate::{paths::LogsDir, sentry}; pub fn init(app_handle: &AppHandle) { let logs_dir = LogsDir::try_from(app_handle) @@ -45,7 +45,7 @@ pub fn init(app_handle: &AppHandle) { .with_span_events(FmtSpan::CLOSE) .with_filter(log_level_filter), ) - .with(sentry_tracing::layer()) + .with(sentry::tracing_layer()) .with( // subscriber that writes spans to a file tracing_subscriber::fmt::layer() diff --git a/packages/tauri/src/sentry.rs b/packages/tauri/src/sentry.rs new file mode 100644 index 000000000..bfb5dacdd --- /dev/null +++ b/packages/tauri/src/sentry.rs @@ -0,0 +1,53 @@ +use std::sync::Arc; + +use sentry::ClientInitGuard; +use sentry_tracing::SentryLayer; +use tauri::PackageInfo; +use tracing::Subscriber; +use tracing_subscriber::registry::LookupSpan; + +use crate::users; + +/// Should be called once on application startup, and the returned guard should be kept alive for +/// the lifetime of the application. +pub fn init(package_info: &PackageInfo) -> ClientInitGuard { + sentry::init(("https://9d407634d26b4d30b6a42d57a136d255@o4504644069687296.ingest.sentry.io/4504649768108032", sentry::ClientOptions { + environment: Some(match package_info.name.as_str() { + "GitButler" => "production", + "GitButler Nightly" => "nightly", + "GitButler Dev" => "development", + _ => "unknown", + }.into()), + release: Some(package_info.version.to_string().into()), + before_send: Some(Arc::new(|event| { + Some(event) + })), + attach_stacktrace: true, + default_integrations: true, + ..Default::default() + })) +} + +/// Sets the current user in the Sentry scope. +/// There is only one scope in the application, so this will overwrite any previous user. +pub fn configure_scope(user: Option<&users::User>) { + sentry::configure_scope(|scope| { + scope.set_user(user.map(|user| sentry::User { + id: Some(user.id.to_string()), + username: Some(user.name.clone()), + email: Some(user.email.clone()), + ..Default::default() + })); + }); +} + +/// Returns a tracing layer that will send all errors to Sentry. +pub fn tracing_layer() -> SentryLayer +where + S: Subscriber + for<'a> LookupSpan<'a>, +{ + sentry_tracing::layer().event_filter(|md| match md.level() { + &tracing::Level::ERROR => sentry_tracing::EventFilter::Event, + _ => sentry_tracing::EventFilter::Ignore, + }) +} diff --git a/packages/tauri/src/users/commands.rs b/packages/tauri/src/users/commands.rs index c1cc3310d..70cef0153 100644 --- a/packages/tauri/src/users/commands.rs +++ b/packages/tauri/src/users/commands.rs @@ -1,7 +1,7 @@ use tauri::{AppHandle, Manager}; use tracing::instrument; -use crate::{assets, error::Error}; +use crate::{assets, error::Error, sentry}; use super::{ controller::{self, Controller, GetError}, @@ -50,7 +50,7 @@ pub async fn set_user(handle: AppHandle, user: User) -> Result { app.set_user(&user)?; - sentry::configure_scope(|scope| scope.set_user(Some(user.clone().into()))); + sentry::configure_scope(Some(&user)); Ok(proxy.proxy_user(user).await) } @@ -73,7 +73,7 @@ pub async fn delete_user(handle: AppHandle) -> Result<(), Error> { app.delete_user()?; - sentry::configure_scope(|scope| scope.set_user(None)); + sentry::configure_scope(None); Ok(()) } diff --git a/packages/tauri/src/users/user.rs b/packages/tauri/src/users/user.rs index 603a090ea..0255222a1 100644 --- a/packages/tauri/src/users/user.rs +++ b/packages/tauri/src/users/user.rs @@ -19,17 +19,6 @@ pub struct User { pub github_username: Option, } -impl From for sentry::User { - fn from(val: User) -> Self { - sentry::User { - id: Some(val.id.to_string()), - username: Some(val.name), - email: Some(val.email), - ..Default::default() - } - } -} - impl TryFrom for git::Signature<'_> { type Error = git::Error;