Skip to content

Commit e072f22

Browse files
authored
Improve Labrinth Sentry integration (#5174)
* Improve Sentry integration * remove debug routes * fix ci * sentry tracing stuff * Add spans to Sentry logging * Fix CI * Redis op instrumentation * pr comments
1 parent 306eee3 commit e072f22

File tree

14 files changed

+485
-47
lines changed

14 files changed

+485
-47
lines changed

Cargo.lock

Lines changed: 1 addition & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ sentry = { version = "0.45.0", default-features = false, features = [
150150
"reqwest",
151151
"rustls",
152152
] }
153-
sentry-actix = "0.45.0"
154153
serde = "1.0.228"
155154
serde_bytes = "0.11.19"
156155
serde_cbor = "0.11.2"
@@ -239,7 +238,7 @@ manual_assert = "warn"
239238
manual_instant_elapsed = "warn"
240239
manual_is_variant_and = "warn"
241240
manual_let_else = "warn"
242-
map_unwrap_or = "warn"
241+
map_unwrap_or = "allow"
243242
match_bool = "warn"
244243
needless_collect = "warn"
245244
negative_feature_names = "warn"

apps/labrinth/.env.docker-compose

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
DEBUG=true
22
RUST_LOG=info,sqlx::query=warn
33
SENTRY_DSN=none
4+
SENTRY_ENVIRONMENT=development
5+
SENTRY_TRACES_SAMPLE_RATE=0.1
46

57
SITE_URL=http://localhost:3000
68
# This CDN URL matches the local storage backend set below, which uses MOCK_FILE_PATH

apps/labrinth/.env.local

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
DEBUG=true
22
RUST_LOG=info,sqlx::query=warn
33
SENTRY_DSN=none
4+
SENTRY_ENVIRONMENT=development
5+
SENTRY_TRACES_SAMPLE_RATE=0.1
46

57
SITE_URL=http://localhost:3000
68
# This CDN URL matches the local storage backend set below, which uses MOCK_FILE_PATH

apps/labrinth/Cargo.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ path = "src/main.rs"
1212
[dependencies]
1313
actix-cors = { workspace = true }
1414
actix-files = { workspace = true }
15-
actix-http = { workspace = true, optional = true }
15+
actix-http = { workspace = true }
1616
actix-multipart = { workspace = true }
1717
actix-rt = { workspace = true }
1818
actix-web = { workspace = true }
@@ -70,7 +70,7 @@ itertools = { workspace = true }
7070
json-patch = { workspace = true }
7171
lettre = { workspace = true }
7272
meilisearch-sdk = { workspace = true, features = ["reqwest"] }
73-
modrinth-util = { workspace = true, features = ["decimal", "utoipa"] }
73+
modrinth-util = { workspace = true, features = ["decimal", "sentry", "utoipa"] }
7474
muralpay = { workspace = true, features = ["client", "mock", "utoipa"] }
7575
murmur2 = { workspace = true }
7676
paste = { workspace = true }
@@ -95,7 +95,6 @@ rust-s3 = { workspace = true }
9595
rustls.workspace = true
9696
rusty-money = { workspace = true }
9797
sentry = { workspace = true }
98-
sentry-actix = { workspace = true }
9998
serde = { workspace = true, features = ["derive"] }
10099
serde_json = { workspace = true }
101100
serde_with = { workspace = true }
@@ -149,7 +148,7 @@ tikv-jemallocator = { workspace = true, features = [
149148
] }
150149

151150
[features]
152-
test = ["dep:actix-http"]
151+
test = []
153152

154153
[lints]
155154
workspace = true

apps/labrinth/src/auth/validate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ where
7171
Ok((scopes, db_user))
7272
}
7373

74+
#[tracing::instrument(skip(req, executor, redis, session_queue))]
7475
pub async fn get_user_from_headers<'a, E>(
7576
req: &HttpRequest,
7677
executor: E,

apps/labrinth/src/database/redis.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,15 @@ impl RedisPool {
128128
Ok(())
129129
}
130130

131+
#[tracing::instrument(skip(self))]
131132
pub async fn connect(&self) -> Result<RedisConnection, DatabaseError> {
132133
Ok(RedisConnection {
133134
connection: self.pool.get().await?,
134135
meta_namespace: self.meta_namespace.clone(),
135136
})
136137
}
137138

139+
#[tracing::instrument(skip(self, closure))]
138140
pub async fn get_cached_keys<F, Fut, T, K>(
139141
&self,
140142
namespace: &str,
@@ -162,6 +164,7 @@ impl RedisPool {
162164
.collect())
163165
}
164166

167+
#[tracing::instrument(skip(self, closure))]
165168
pub async fn get_cached_keys_raw<F, Fut, T, K>(
166169
&self,
167170
namespace: &str,
@@ -197,6 +200,7 @@ impl RedisPool {
197200
.await
198201
}
199202

203+
#[tracing::instrument(skip(self, closure))]
200204
pub async fn get_cached_keys_with_slug<F, Fut, T, I, K, S>(
201205
&self,
202206
namespace: &str,
@@ -233,6 +237,7 @@ impl RedisPool {
233237
.collect())
234238
}
235239

240+
#[tracing::instrument(skip(self, closure))]
236241
pub async fn get_cached_keys_raw_with_slug<F, Fut, T, I, K, S>(
237242
&self,
238243
namespace: &str,
@@ -585,6 +590,7 @@ impl RedisPool {
585590
}
586591

587592
impl RedisConnection {
593+
#[tracing::instrument(skip(self))]
588594
pub async fn set(
589595
&mut self,
590596
namespace: &str,
@@ -607,6 +613,7 @@ impl RedisConnection {
607613
Ok(())
608614
}
609615

616+
#[tracing::instrument(skip(self, id, data))]
610617
pub async fn set_serialized_to_json<Id, D>(
611618
&mut self,
612619
namespace: &str,
@@ -627,6 +634,7 @@ impl RedisConnection {
627634
.await
628635
}
629636

637+
#[tracing::instrument(skip(self))]
630638
pub async fn get(
631639
&mut self,
632640
namespace: &str,
@@ -642,6 +650,7 @@ impl RedisConnection {
642650
Ok(res)
643651
}
644652

653+
#[tracing::instrument(skip(self))]
645654
pub async fn get_many(
646655
&mut self,
647656
namespace: &str,
@@ -659,6 +668,7 @@ impl RedisConnection {
659668
Ok(res)
660669
}
661670

671+
#[tracing::instrument(skip(self))]
662672
pub async fn get_deserialized_from_json<R>(
663673
&mut self,
664674
namespace: &str,
@@ -673,6 +683,7 @@ impl RedisConnection {
673683
.and_then(|x| serde_json::from_str(&x).ok()))
674684
}
675685

686+
#[tracing::instrument(skip(self))]
676687
pub async fn get_many_deserialized_from_json<R>(
677688
&mut self,
678689
namespace: &str,
@@ -689,6 +700,7 @@ impl RedisConnection {
689700
.collect::<Vec<_>>())
690701
}
691702

703+
#[tracing::instrument(skip(self, id))]
692704
pub async fn delete<T1>(
693705
&mut self,
694706
namespace: &str,
@@ -707,6 +719,7 @@ impl RedisConnection {
707719
Ok(())
708720
}
709721

722+
#[tracing::instrument(skip(self, iter))]
710723
pub async fn delete_many(
711724
&mut self,
712725
iter: impl IntoIterator<Item = (&str, Option<String>)>,
@@ -731,6 +744,7 @@ impl RedisConnection {
731744
Ok(())
732745
}
733746

747+
#[tracing::instrument(skip(self, value))]
734748
pub async fn lpush(
735749
&mut self,
736750
namespace: &str,
@@ -742,6 +756,7 @@ impl RedisConnection {
742756
Ok(())
743757
}
744758

759+
#[tracing::instrument(skip(self))]
745760
pub async fn brpop(
746761
&mut self,
747762
namespace: &str,

apps/labrinth/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,8 @@ pub fn check_env_vars() -> bool {
375375
check
376376
}
377377

378+
failed |= check_var::<String>("SENTRY_ENVIRONMENT");
379+
failed |= check_var::<String>("SENTRY_TRACES_SAMPLE_RATE");
378380
failed |= check_var::<String>("SITE_URL");
379381
failed |= check_var::<String>("CDN_URL");
380382
failed |= check_var::<String>("LABRINTH_ADMIN_KEY");

apps/labrinth/src/main.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,7 @@ struct Args {
5454
run_background_task: Option<BackgroundTask>,
5555
}
5656

57-
#[actix_rt::main]
58-
async fn main() -> std::io::Result<()> {
59-
let args = Args::parse();
60-
57+
fn main() -> std::io::Result<()> {
6158
color_eyre::install().expect("failed to install `color-eyre`");
6259
dotenvy::dotenv().ok();
6360
modrinth_util::log::init().expect("failed to initialize logging");
@@ -67,15 +64,17 @@ async fn main() -> std::io::Result<()> {
6764
std::process::exit(1);
6865
}
6966

70-
rustls::crypto::aws_lc_rs::default_provider()
71-
.install_default()
72-
.unwrap();
73-
67+
// Sentry must be set up before the async runtime is started
68+
// <https://docs.sentry.io/platforms/rust/guides/actix-web/>
7469
// DSN is from SENTRY_DSN env variable.
7570
// Has no effect if not set.
7671
let sentry = sentry::init(sentry::ClientOptions {
7772
release: sentry::release_name!(),
78-
traces_sample_rate: 0.1,
73+
traces_sample_rate: dotenvy::var("SENTRY_TRACES_SAMPLE_RATE")
74+
.unwrap()
75+
.parse()
76+
.expect("failed to parse `SENTRY_TRACES_SAMPLE_RATE` as number"),
77+
environment: Some(dotenvy::var("SENTRY_ENVIRONMENT").unwrap().into()),
7978
..Default::default()
8079
});
8180
if sentry.is_enabled() {
@@ -85,6 +84,20 @@ async fn main() -> std::io::Result<()> {
8584
}
8685
}
8786

87+
actix_rt::System::new().block_on(app())?;
88+
89+
// Sentry guard must live until the end of the app
90+
drop(sentry);
91+
Ok(())
92+
}
93+
94+
async fn app() -> std::io::Result<()> {
95+
let args = Args::parse();
96+
97+
rustls::crypto::aws_lc_rs::default_provider()
98+
.install_default()
99+
.unwrap();
100+
88101
if args.run_background_task.is_none() {
89102
info!(
90103
"Starting labrinth on {}",
@@ -245,7 +258,12 @@ async fn main() -> std::io::Result<()> {
245258
.wrap(prometheus.clone())
246259
.wrap(from_fn(rate_limit_middleware))
247260
.wrap(actix_web::middleware::Compress::default())
248-
.wrap(sentry_actix::Sentry::new())
261+
// Sentry integration
262+
// `sentry_actix::Sentry` provides an Actix middleware for making
263+
// transactions out of HTTP requests. However, we have to use our
264+
// own - See `sentry::SentryErrorReporting` for why.
265+
.wrap(labrinth::util::sentry::SentryErrorReporting)
266+
// Use `utoipa` for OpenAPI generation
249267
.into_utoipa_app()
250268
.configure(|cfg| utoipa_app_config(cfg, labrinth_config.clone()))
251269
.openapi_service(|api| SwaggerUi::new("/docs/swagger-ui/{_:.*}")
@@ -280,11 +298,11 @@ impl utoipa::Modify for SecurityAddon {
280298
fn log_error(err: &actix_web::Error) {
281299
if err.as_response_error().status_code().is_client_error() {
282300
tracing::debug!(
283-
"Error encountered while processing the incoming HTTP request: {err:#?}"
301+
"Error encountered while processing the incoming HTTP request: {err:#}"
284302
);
285303
} else {
286304
tracing::error!(
287-
"Error encountered while processing the incoming HTTP request: {err:#?}"
305+
"Error encountered while processing the incoming HTTP request: {err:#}"
288306
);
289307
}
290308
}

apps/labrinth/src/util/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ pub mod ip;
1616
pub mod ratelimit;
1717
pub mod redis;
1818
pub mod routes;
19+
pub mod sentry;
1920
pub mod validate;
2021
pub mod webhook;

0 commit comments

Comments
 (0)