BLOG-90 Intergrate error tracking with Sentry #120
10
backend/Cargo.lock
generated
10
backend/Cargo.lock
generated
@ -426,6 +426,7 @@ dependencies = [
|
||||
"actix-web",
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"common",
|
||||
"log",
|
||||
"openidconnect",
|
||||
"sentry",
|
||||
@ -619,6 +620,13 @@ dependencies = [
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"sqlx",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
@ -1743,6 +1751,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"auth",
|
||||
"common",
|
||||
"futures",
|
||||
"log",
|
||||
"sentry",
|
||||
@ -2399,6 +2408,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"auth",
|
||||
"chrono",
|
||||
"common",
|
||||
"log",
|
||||
"sentry",
|
||||
"serde",
|
||||
|
@ -1,11 +1,21 @@
|
||||
[workspace]
|
||||
members = ["server", "feature/auth", "feature/image", "feature/post"]
|
||||
members = [
|
||||
"server",
|
||||
"feature/auth",
|
||||
"feature/common",
|
||||
"feature/image",
|
||||
"feature/post",
|
||||
"feature/common",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.2.0"
|
||||
edition = "2024"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
||||
[workspace.dependencies]
|
||||
actix-multipart = "0.7.2"
|
||||
actix-session = { version = "0.10.1", features = ["redis-session"] }
|
||||
@ -41,5 +51,6 @@ utoipa-redoc = { version = "6.0.0", features = ["actix-web"] }
|
||||
|
||||
server.path = "server"
|
||||
auth.path = "feature/auth"
|
||||
common.path = "feature/common"
|
||||
image.path = "feature/image"
|
||||
post.path = "feature/post"
|
||||
|
@ -14,3 +14,5 @@ sentry.workspace = true
|
||||
serde.workspace = true
|
||||
sqlx.workspace = true
|
||||
utoipa.workspace = true
|
||||
|
||||
common.workspace = true
|
||||
|
@ -1,4 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use common::framework::error::DatabaseError;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
use crate::{
|
||||
@ -31,7 +32,7 @@ impl UserDbService for UserDbServiceImpl {
|
||||
)
|
||||
.fetch_optional(&self.db_pool)
|
||||
.await
|
||||
.map_err(|e| AuthError::Unexpected(e.into()))?;
|
||||
.map_err(|e| AuthError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
match record {
|
||||
Some(record) => Ok(record.into_mapper()),
|
||||
@ -56,7 +57,7 @@ impl UserDbService for UserDbServiceImpl {
|
||||
)
|
||||
.fetch_optional(&self.db_pool)
|
||||
.await
|
||||
.map_err(|e| AuthError::Unexpected(e.into()))?;
|
||||
.map_err(|e| AuthError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
match record {
|
||||
Some(record) => Ok(record.into_mapper()),
|
||||
@ -78,7 +79,7 @@ impl UserDbService for UserDbServiceImpl {
|
||||
)
|
||||
.fetch_one(&self.db_pool)
|
||||
.await
|
||||
.map_err(|e| AuthError::Unexpected(e.into()))?;
|
||||
.map_err(|e| AuthError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ impl AuthOidcService for AuthOidcServiceImpl {
|
||||
let token_response = self
|
||||
.oidc_client
|
||||
.exchange_code(AuthorizationCode::new(code.to_string()))
|
||||
.map_err(|e| AuthError::Unexpected(e.into()))?
|
||||
.unwrap()
|
||||
.request_async(&self.http_client)
|
||||
.await
|
||||
.map_err(|_| AuthError::InvalidAuthCode)?;
|
||||
|
7
backend/feature/common/Cargo.toml
Normal file
7
backend/feature/common/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "common"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
sqlx.workspace = true
|
1
backend/feature/common/src/framework.rs
Normal file
1
backend/feature/common/src/framework.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod error;
|
21
backend/feature/common/src/framework/error.rs
Normal file
21
backend/feature/common/src/framework/error.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IOError(pub std::io::Error);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DatabaseError(pub sqlx::Error);
|
||||
|
||||
impl std::error::Error for IOError {}
|
||||
impl Display for IOError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for DatabaseError {}
|
||||
impl Display for DatabaseError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
1
backend/feature/common/src/lib.rs
Normal file
1
backend/feature/common/src/lib.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod framework;
|
@ -16,3 +16,4 @@ sqlx.workspace = true
|
||||
utoipa.workspace = true
|
||||
|
||||
auth.workspace = true
|
||||
common.workspace = true
|
||||
|
@ -1,4 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use common::framework::error::DatabaseError;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
use crate::{
|
||||
@ -34,7 +35,7 @@ impl ImageDbService for ImageDbServiceImpl {
|
||||
|
||||
match id {
|
||||
Ok(id) => Ok(id),
|
||||
Err(e) => Err(ImageError::Unexpected(anyhow::Error::from(e))),
|
||||
Err(e) => Err(ImageError::Unexpected(DatabaseError(e).into())),
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +60,7 @@ impl ImageDbService for ImageDbServiceImpl {
|
||||
}),
|
||||
None => Err(ImageError::NotFound),
|
||||
},
|
||||
Err(e) => Err(ImageError::Unexpected(anyhow::Error::from(e))),
|
||||
Err(e) => Err(ImageError::Unexpected(DatabaseError(e).into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ use std::{
|
||||
io::Write,
|
||||
};
|
||||
|
||||
use common::framework::error::IOError;
|
||||
|
||||
use crate::{
|
||||
adapter::gateway::image_storage::ImageStorage, application::error::image_error::ImageError,
|
||||
};
|
||||
@ -22,10 +24,11 @@ impl ImageStorageImpl {
|
||||
impl ImageStorage for ImageStorageImpl {
|
||||
fn write_data(&self, id: i32, data: &[u8]) -> Result<(), ImageError> {
|
||||
let dir_path = format!("{}/images", self.sotrage_path);
|
||||
fs::create_dir_all(&dir_path).map_err(|e| ImageError::Unexpected(e.into()))?;
|
||||
fs::create_dir_all(&dir_path).map_err(|e| ImageError::Unexpected(IOError(e).into()))?;
|
||||
|
||||
let file_path = format!("{}/{}", dir_path, id);
|
||||
let mut file = File::create(&file_path).map_err(|e| ImageError::Unexpected(e.into()))?;
|
||||
let mut file =
|
||||
File::create(&file_path).map_err(|e| ImageError::Unexpected(IOError(e).into()))?;
|
||||
file.write_all(data)
|
||||
.map_err(|e| ImageError::Unexpected(e.into()))?;
|
||||
|
||||
@ -34,7 +37,7 @@ impl ImageStorage for ImageStorageImpl {
|
||||
|
||||
fn read_data(&self, id: i32) -> Result<Vec<u8>, ImageError> {
|
||||
let file_path = format!("{}/images/{}", self.sotrage_path, id);
|
||||
let data = fs::read(&file_path).map_err(|e| ImageError::Unexpected(e.into()))?;
|
||||
let data = fs::read(&file_path).map_err(|e| ImageError::Unexpected(IOError(e).into()))?;
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
@ -15,3 +15,4 @@ sqlx.workspace = true
|
||||
utoipa.workspace = true
|
||||
|
||||
auth.workspace = true
|
||||
common.workspace = true
|
||||
|
@ -1,4 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use common::framework::error::DatabaseError;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
use crate::{
|
||||
@ -31,7 +32,7 @@ impl LabelDbService for LabelDbServiceImpl {
|
||||
)
|
||||
.fetch_one(&self.db_pool)
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
@ -49,7 +50,7 @@ impl LabelDbService for LabelDbServiceImpl {
|
||||
)
|
||||
.execute(&self.db_pool)
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?
|
||||
.rows_affected();
|
||||
|
||||
if affected_rows == 0 {
|
||||
@ -71,7 +72,7 @@ impl LabelDbService for LabelDbServiceImpl {
|
||||
)
|
||||
.fetch_optional(&self.db_pool)
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
match record {
|
||||
Some(record) => Ok(record.into_mapper()),
|
||||
@ -91,7 +92,7 @@ impl LabelDbService for LabelDbServiceImpl {
|
||||
)
|
||||
.fetch_all(&self.db_pool)
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
let mappers = records
|
||||
.into_iter()
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use common::framework::error::DatabaseError;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
use crate::{
|
||||
@ -64,7 +65,7 @@ impl PostDbService for PostDbServiceImpl {
|
||||
.build_query_as::<PostInfoWithLabelRecord>()
|
||||
.fetch_all(&self.db_pool)
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
let mut post_info_mappers_map = HashMap::<i32, PostInfoMapper>::new();
|
||||
|
||||
@ -136,7 +137,7 @@ impl PostDbService for PostDbServiceImpl {
|
||||
.build_query_as::<PostWithLabelRecord>()
|
||||
.fetch_all(&self.db_pool)
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
if records.is_empty() {
|
||||
return Err(PostError::NotFound);
|
||||
@ -188,7 +189,7 @@ impl PostDbService for PostDbServiceImpl {
|
||||
.db_pool
|
||||
.begin()
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
let post_id = sqlx::query_scalar!(
|
||||
r#"
|
||||
@ -205,7 +206,7 @@ impl PostDbService for PostDbServiceImpl {
|
||||
)
|
||||
.fetch_one(&mut *tx)
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
for (order, &label_id) in label_ids.iter().enumerate() {
|
||||
sqlx::query!(
|
||||
@ -221,12 +222,12 @@ impl PostDbService for PostDbServiceImpl {
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
}
|
||||
|
||||
tx.commit()
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
Ok(post_id)
|
||||
}
|
||||
@ -236,7 +237,7 @@ impl PostDbService for PostDbServiceImpl {
|
||||
.db_pool
|
||||
.begin()
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
let affected_rows = sqlx::query!(
|
||||
r#"
|
||||
@ -258,7 +259,7 @@ impl PostDbService for PostDbServiceImpl {
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?
|
||||
.rows_affected();
|
||||
|
||||
if affected_rows == 0 {
|
||||
@ -274,7 +275,7 @@ impl PostDbService for PostDbServiceImpl {
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
for (order, &label_id) in label_ids.iter().enumerate() {
|
||||
sqlx::query!(
|
||||
@ -290,12 +291,12 @@ impl PostDbService for PostDbServiceImpl {
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
}
|
||||
|
||||
tx.commit()
|
||||
.await
|
||||
.map_err(|e| PostError::Unexpected(e.into()))?;
|
||||
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ impl SentryConfiguration {
|
||||
traces_sample_rate: 1.0,
|
||||
send_default_pii: true,
|
||||
max_request_body_size: sentry::MaxRequestBodySize::Always,
|
||||
attach_stacktrace: true,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user