fix sentry logging (#982)

This commit is contained in:
Gabriel Gordon-Hall
2025-10-09 11:45:23 +01:00
committed by GitHub
parent f2cc538a8f
commit e52ced99e0
12 changed files with 86 additions and 75 deletions

View File

@@ -30,13 +30,12 @@ use services::services::{
git::{GitService, GitServiceError}, git::{GitService, GitServiceError},
image::{ImageError, ImageService}, image::{ImageError, ImageService},
pr_monitor::PrMonitorService, pr_monitor::PrMonitorService,
sentry::SentryService,
worktree_manager::WorktreeError, worktree_manager::WorktreeError,
}; };
use sqlx::{Error as SqlxError, types::Uuid}; use sqlx::{Error as SqlxError, types::Uuid};
use thiserror::Error; use thiserror::Error;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use utils::msg_store::MsgStore; use utils::{msg_store::MsgStore, sentry as sentry_utils};
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum DeploymentError { pub enum DeploymentError {
@@ -82,8 +81,6 @@ pub trait Deployment: Clone + Send + Sync + 'static {
fn config(&self) -> &Arc<RwLock<Config>>; fn config(&self) -> &Arc<RwLock<Config>>;
fn sentry(&self) -> &SentryService;
fn db(&self) -> &DBService; fn db(&self) -> &DBService;
fn analytics(&self) -> &Option<AnalyticsService>; fn analytics(&self) -> &Option<AnalyticsService>;
@@ -113,8 +110,7 @@ pub trait Deployment: Clone + Send + Sync + 'static {
let config = self.config().read().await; let config = self.config().read().await;
let username = config.github.username.as_deref(); let username = config.github.username.as_deref();
let email = config.github.primary_email.as_deref(); let email = config.github.primary_email.as_deref();
sentry_utils::configure_user_scope(user_id, username, email);
self.sentry().update_scope(user_id, username, email).await;
Ok(()) Ok(())
} }

View File

@@ -31,8 +31,6 @@ regex = "1.11.1"
notify-rust = "4.11" notify-rust = "4.11"
notify = "8.2.0" notify = "8.2.0"
notify-debouncer-full = "0.5.0" notify-debouncer-full = "0.5.0"
sentry = { version = "0.41.0", features = ["anyhow", "backtrace", "panic", "debug-images"] }
sentry-tracing = { version = "0.41.0", features = ["backtrace"] }
reqwest = { version = "0.12", features = ["json"] } reqwest = { version = "0.12", features = ["json"] }
futures = "0.3" futures = "0.3"
async-stream = "0.3" async-stream = "0.3"

View File

@@ -16,21 +16,18 @@ use services::services::{
filesystem::FilesystemService, filesystem::FilesystemService,
git::GitService, git::GitService,
image::ImageService, image::ImageService,
sentry::SentryService,
}; };
use tokio::sync::RwLock; use tokio::sync::RwLock;
use utils::{assets::config_path, msg_store::MsgStore}; use utils::{assets::config_path, msg_store::MsgStore};
use uuid::Uuid; use uuid::Uuid;
use crate::container::LocalContainerService; use crate::container::LocalContainerService;
mod command; mod command;
pub mod container; pub mod container;
#[derive(Clone)] #[derive(Clone)]
pub struct LocalDeployment { pub struct LocalDeployment {
config: Arc<RwLock<Config>>, config: Arc<RwLock<Config>>,
sentry: SentryService,
user_id: String, user_id: String,
db: DBService, db: DBService,
analytics: Option<AnalyticsService>, analytics: Option<AnalyticsService>,
@@ -74,7 +71,6 @@ impl Deployment for LocalDeployment {
save_config_to_file(&raw_config, &config_path()).await?; save_config_to_file(&raw_config, &config_path()).await?;
let config = Arc::new(RwLock::new(raw_config)); let config = Arc::new(RwLock::new(raw_config));
let sentry = SentryService::new();
let user_id = generate_user_id(); let user_id = generate_user_id();
let analytics = AnalyticsConfig::new().map(AnalyticsService::new); let analytics = AnalyticsConfig::new().map(AnalyticsService::new);
let git = GitService::new(); let git = GitService::new();
@@ -131,7 +127,6 @@ impl Deployment for LocalDeployment {
Ok(Self { Ok(Self {
config, config,
sentry,
user_id, user_id,
db, db,
analytics, analytics,
@@ -160,10 +155,6 @@ impl Deployment for LocalDeployment {
&self.config &self.config
} }
fn sentry(&self) -> &SentryService {
&self.sentry
}
fn db(&self) -> &DBService { fn db(&self) -> &DBService {
&self.db &self.db
} }

View File

@@ -34,8 +34,6 @@ rmcp = { version = "0.5.0", features = ["server", "transport-io"] }
schemars = { workspace = true } schemars = { workspace = true }
regex = "1.11.1" regex = "1.11.1"
toml = "0.8" toml = "0.8"
sentry = { version = "0.41.0", features = ["anyhow", "backtrace", "panic", "debug-images"] }
sentry-tracing = { version = "0.41.0", features = ["backtrace"] }
reqwest = { version = "0.12", features = ["json"] } reqwest = { version = "0.12", features = ["json"] }
strip-ansi-escapes = "0.2.1" strip-ansi-escapes = "0.2.1"
thiserror = { workspace = true } thiserror = { workspace = true }

View File

@@ -1,25 +1,13 @@
use rmcp::{ServiceExt, transport::stdio}; use rmcp::{ServiceExt, transport::stdio};
use server::mcp::task_server::TaskServer; use server::mcp::task_server::TaskServer;
use tracing_subscriber::{EnvFilter, prelude::*}; use tracing_subscriber::{EnvFilter, prelude::*};
use utils::{port_file::read_port_file, sentry::sentry_layer}; use utils::{
port_file::read_port_file,
sentry::{self as sentry_utils, SentrySource, sentry_layer},
};
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
let environment = if cfg!(debug_assertions) { sentry_utils::init_once(SentrySource::Mcp);
"dev"
} else {
"production"
};
let _guard = sentry::init((
"https://1065a1d276a581316999a07d5dffee26@o4509603705192449.ingest.de.sentry.io/4509605576441937",
sentry::ClientOptions {
release: sentry::release_name!(),
environment: Some(environment.into()),
..Default::default()
},
));
sentry::configure_scope(|scope| {
scope.set_tag("source", "mcp");
});
tokio::runtime::Builder::new_multi_thread() tokio::runtime::Builder::new_multi_thread()
.enable_all() .enable_all()
.build() .build()
@@ -67,9 +55,9 @@ fn main() -> anyhow::Result<()> {
let service = TaskServer::new(&base_url) let service = TaskServer::new(&base_url)
.serve(stdio()) .serve(stdio())
.await .await
.inspect_err(|e| { .map_err(|e| {
tracing::error!("serving error: {:?}", e); tracing::error!("serving error: {:?}", e);
sentry::capture_error(e); e
})?; })?;
service.waiting().await?; service.waiting().await?;

View File

@@ -6,7 +6,10 @@ use strip_ansi_escapes::strip;
use thiserror::Error; use thiserror::Error;
use tracing_subscriber::{EnvFilter, prelude::*}; use tracing_subscriber::{EnvFilter, prelude::*};
use utils::{ use utils::{
assets::asset_dir, browser::open_browser, port_file::write_port_file, sentry::sentry_layer, assets::asset_dir,
browser::open_browser,
port_file::write_port_file,
sentry::{self as sentry_utils, SentrySource, sentry_layer},
}; };
#[derive(Debug, Error)] #[derive(Debug, Error)]
@@ -23,6 +26,8 @@ pub enum VibeKanbanError {
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), VibeKanbanError> { async fn main() -> Result<(), VibeKanbanError> {
sentry_utils::init_once(SentrySource::Backend);
let log_level = std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string()); let log_level = std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string());
let filter_string = format!( let filter_string = format!(
"warn,server={level},services={level},db={level},executors={level},deployment={level},local_deployment={level},utils={level}", "warn,server={level},services={level},db={level},executors={level},deployment={level},local_deployment={level},utils={level}",

View File

@@ -1,5 +1,6 @@
use axum::{ use axum::{
Router, Router,
middleware::from_fn_with_state,
routing::{IntoMakeService, get}, routing::{IntoMakeService, get},
}; };
@@ -39,6 +40,10 @@ pub fn router(deployment: DeploymentImpl) -> IntoMakeService<Router> {
.merge(events::router(&deployment)) .merge(events::router(&deployment))
.merge(approvals::router()) .merge(approvals::router())
.nest("/images", images::routes()) .nest("/images", images::routes())
.layer(from_fn_with_state(
deployment.clone(),
auth::sentry_user_context_middleware,
))
.with_state(deployment); .with_state(deployment);
Router::new() Router::new()

View File

@@ -39,8 +39,6 @@ regex = "1.11.1"
notify-rust = "4.11" notify-rust = "4.11"
octocrab = "0.44" octocrab = "0.44"
os_info = "3.12.0" os_info = "3.12.0"
sentry = { version = "0.41.0", features = ["anyhow", "backtrace", "panic", "debug-images"] }
sentry-tracing = { version = "0.41.0", features = ["backtrace"] }
reqwest = { version = "0.12", features = ["json"] } reqwest = { version = "0.12", features = ["json"] }
lazy_static = "1.4" lazy_static = "1.4"
futures-util = "0.3" futures-util = "0.3"

View File

@@ -16,5 +16,4 @@ pub mod github_service;
pub mod image; pub mod image;
pub mod notification; pub mod notification;
pub mod pr_monitor; pub mod pr_monitor;
pub mod sentry;
pub mod worktree_manager; pub mod worktree_manager;

View File

@@ -1,33 +0,0 @@
#[derive(Clone)]
pub struct SentryService {}
impl Default for SentryService {
fn default() -> Self {
Self::new()
}
}
impl SentryService {
pub fn new() -> Self {
SentryService {}
}
pub async fn update_scope(&self, user_id: &str, username: Option<&str>, email: Option<&str>) {
let sentry_user = match (username, email) {
(Some(user), Some(email)) => sentry::User {
id: Some(user_id.to_string()),
username: Some(user.to_string()),
email: Some(email.to_string()),
..Default::default()
},
_ => sentry::User {
id: Some(user_id.to_string()),
..Default::default()
},
};
sentry::configure_scope(|scope| {
scope.set_user(Some(sentry_user));
});
}
}

View File

@@ -19,6 +19,7 @@ rust-embed = "8.2"
directories = "6.0.0" directories = "6.0.0"
open = "5.3.2" open = "5.3.2"
regex = "1.11.1" regex = "1.11.1"
sentry = { version = "0.41.0", features = ["anyhow", "backtrace", "panic", "debug-images"] }
sentry-tracing = { version = "0.41.0", features = ["backtrace"] } sentry-tracing = { version = "0.41.0", features = ["backtrace"] }
lazy_static = "1.4" lazy_static = "1.4"
futures-util = "0.3" futures-util = "0.3"

View File

@@ -1,6 +1,71 @@
use std::sync::OnceLock;
use sentry_tracing::{EventFilter, SentryLayer}; use sentry_tracing::{EventFilter, SentryLayer};
use tracing::Level; use tracing::Level;
const SENTRY_DSN: &str = "https://1065a1d276a581316999a07d5dffee26@o4509603705192449.ingest.de.sentry.io/4509605576441937";
static INIT_GUARD: OnceLock<sentry::ClientInitGuard> = OnceLock::new();
#[derive(Clone, Copy, Debug)]
pub enum SentrySource {
Backend,
Mcp,
}
impl SentrySource {
fn tag(self) -> &'static str {
match self {
SentrySource::Backend => "backend",
SentrySource::Mcp => "mcp",
}
}
}
fn environment() -> &'static str {
if cfg!(debug_assertions) {
"dev"
} else {
"production"
}
}
pub fn init_once(source: SentrySource) {
INIT_GUARD.get_or_init(|| {
sentry::init((
SENTRY_DSN,
sentry::ClientOptions {
release: sentry::release_name!(),
environment: Some(environment().into()),
..Default::default()
},
))
});
sentry::configure_scope(|scope| {
scope.set_tag("source", source.tag());
});
}
pub fn configure_user_scope(user_id: &str, username: Option<&str>, email: Option<&str>) {
let mut sentry_user = sentry::User {
id: Some(user_id.to_string()),
..Default::default()
};
if let Some(username) = username {
sentry_user.username = Some(username.to_string());
}
if let Some(email) = email {
sentry_user.email = Some(email.to_string());
}
sentry::configure_scope(|scope| {
scope.set_user(Some(sentry_user));
});
}
pub fn sentry_layer<S>() -> SentryLayer<S> pub fn sentry_layer<S>() -> SentryLayer<S>
where where
S: tracing::Subscriber, S: tracing::Subscriber,