feat: add sentry error logging to dotnet-api and rust crates

This commit is contained in:
alyssa 2025-02-23 18:49:31 +00:00
parent 8266100155
commit 63777bf810
8 changed files with 86 additions and 38 deletions

60
Cargo.lock generated
View file

@ -1490,7 +1490,7 @@ dependencies = [
"http 1.1.0", "http 1.1.0",
"hyper 1.5.0", "hyper 1.5.0",
"hyper-util", "hyper-util",
"rustls 0.23.10", "rustls 0.23.23",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
"tokio-rustls 0.26.0", "tokio-rustls 0.26.0",
@ -1698,6 +1698,7 @@ dependencies = [
"metrics", "metrics",
"metrics-exporter-prometheus", "metrics-exporter-prometheus",
"sentry", "sentry",
"sentry-tracing",
"serde", "serde",
"serde_json", "serde_json",
"sqlx", "sqlx",
@ -2349,7 +2350,7 @@ dependencies = [
"quinn-proto", "quinn-proto",
"quinn-udp", "quinn-udp",
"rustc-hash", "rustc-hash",
"rustls 0.23.10", "rustls 0.23.23",
"socket2 0.5.7", "socket2 0.5.7",
"thiserror", "thiserror",
"tokio", "tokio",
@ -2366,7 +2367,7 @@ dependencies = [
"rand", "rand",
"ring 0.17.8", "ring 0.17.8",
"rustc-hash", "rustc-hash",
"rustls 0.23.10", "rustls 0.23.23",
"slab", "slab",
"thiserror", "thiserror",
"tinyvec", "tinyvec",
@ -2599,7 +2600,7 @@ dependencies = [
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"quinn", "quinn",
"rustls 0.23.10", "rustls 0.23.23",
"rustls-pemfile 2.1.2", "rustls-pemfile 2.1.2",
"rustls-pki-types", "rustls-pki-types",
"serde", "serde",
@ -2809,25 +2810,24 @@ version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432"
dependencies = [ dependencies = [
"log",
"ring 0.17.8", "ring 0.17.8",
"rustls-pki-types", "rustls-pki-types",
"rustls-webpki 0.102.4", "rustls-webpki 0.102.8",
"subtle", "subtle",
"zeroize", "zeroize",
] ]
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.10" version = "0.23.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395"
dependencies = [ dependencies = [
"log", "log",
"once_cell", "once_cell",
"ring 0.17.8", "ring 0.17.8",
"rustls-pki-types", "rustls-pki-types",
"rustls-webpki 0.102.4", "rustls-webpki 0.102.8",
"subtle", "subtle",
"zeroize", "zeroize",
] ]
@ -2882,9 +2882,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.102.4" version = "0.102.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
dependencies = [ dependencies = [
"ring 0.17.8", "ring 0.17.8",
"rustls-pki-types", "rustls-pki-types",
@ -3002,13 +3002,13 @@ checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]] [[package]]
name = "sentry" name = "sentry"
version = "0.34.0" version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5484316556650182f03b43d4c746ce0e3e48074a21e2f51244b648b6542e1066" checksum = "3a7332159e544e34db06b251b1eda5e546bd90285c3f58d9c8ff8450b484e0da"
dependencies = [ dependencies = [
"httpdate", "httpdate",
"reqwest 0.12.8", "reqwest 0.12.8",
"rustls 0.22.4", "rustls 0.23.23",
"sentry-backtrace", "sentry-backtrace",
"sentry-contexts", "sentry-contexts",
"sentry-core", "sentry-core",
@ -3022,9 +3022,9 @@ dependencies = [
[[package]] [[package]]
name = "sentry-backtrace" name = "sentry-backtrace"
version = "0.34.0" version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40aa225bb41e2ec9d7c90886834367f560efc1af028f1c5478a6cce6a59c463a" checksum = "565ec31ad37bab8e6d9f289f34913ed8768347b133706192f10606dabd5c6bc4"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"once_cell", "once_cell",
@ -3034,9 +3034,9 @@ dependencies = [
[[package]] [[package]]
name = "sentry-contexts" name = "sentry-contexts"
version = "0.34.0" version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a8dd746da3d16cb8c39751619cefd4fcdbd6df9610f3310fd646b55f6e39910" checksum = "e860275f25f27e8c0c7726ce116c7d5c928c5bba2ee73306e52b20a752298ea6"
dependencies = [ dependencies = [
"hostname", "hostname",
"libc", "libc",
@ -3048,9 +3048,9 @@ dependencies = [
[[package]] [[package]]
name = "sentry-core" name = "sentry-core"
version = "0.34.0" version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "161283cfe8e99c8f6f236a402b9ccf726b201f365988b5bb637ebca0abbd4a30" checksum = "653942e6141f16651273159f4b8b1eaeedf37a7554c00cd798953e64b8a9bf72"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"rand", "rand",
@ -3061,9 +3061,9 @@ dependencies = [
[[package]] [[package]]
name = "sentry-debug-images" name = "sentry-debug-images"
version = "0.34.0" version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc6b25e945fcaa5e97c43faee0267eebda9f18d4b09a251775d8fef1086238a" checksum = "2a60bc2154e6df59beed0ac13d58f8dfaf5ad20a88548a53e29e4d92e8e835c2"
dependencies = [ dependencies = [
"findshlibs", "findshlibs",
"once_cell", "once_cell",
@ -3072,9 +3072,9 @@ dependencies = [
[[package]] [[package]]
name = "sentry-panic" name = "sentry-panic"
version = "0.34.0" version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc74f229c7186dd971a9491ffcbe7883544aa064d1589bd30b83fb856cd22d63" checksum = "105e3a956c8aa9dab1e4087b1657b03271bfc49d838c6ae9bfc7c58c802fd0ef"
dependencies = [ dependencies = [
"sentry-backtrace", "sentry-backtrace",
"sentry-core", "sentry-core",
@ -3082,9 +3082,9 @@ dependencies = [
[[package]] [[package]]
name = "sentry-tracing" name = "sentry-tracing"
version = "0.34.0" version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd3c5faf2103cd01eeda779ea439b68c4ee15adcdb16600836e97feafab362ec" checksum = "64e75c831b4d8b34a5aec1f65f67c5d46a26c7c5d3c7abd8b5ef430796900cf8"
dependencies = [ dependencies = [
"sentry-backtrace", "sentry-backtrace",
"sentry-core", "sentry-core",
@ -3094,9 +3094,9 @@ dependencies = [
[[package]] [[package]]
name = "sentry-types" name = "sentry-types"
version = "0.34.0" version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d68cdf6bc41b8ff3ae2a9c4671e97426dcdd154cc1d4b6b72813f285d6b163f" checksum = "2d4203359e60724aa05cf2385aaf5d4f147e837185d7dd2b9ccf1ee77f4420c8"
dependencies = [ dependencies = [
"debugid", "debugid",
"hex", "hex",
@ -3819,7 +3819,7 @@ version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
dependencies = [ dependencies = [
"rustls 0.23.10", "rustls 0.23.23",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
] ]
@ -4233,7 +4233,7 @@ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"log", "log",
"once_cell", "once_cell",
"rustls 0.23.10", "rustls 0.23.23",
"rustls-pki-types", "rustls-pki-types",
"url", "url",
"webpki-roots 0.26.6", "webpki-roots 0.26.6",

View file

@ -15,13 +15,13 @@ futures = "0.3.30"
lazy_static = "1.4.0" lazy_static = "1.4.0"
metrics = "0.23.0" metrics = "0.23.0"
reqwest = { version = "0.12.7" , default-features = false, features = ["rustls-tls", "trust-dns"]} reqwest = { version = "0.12.7" , default-features = false, features = ["rustls-tls", "trust-dns"]}
sentry = { version = "0.34.0", default-features = false, features = ["backtrace", "contexts", "panic", "debug-images", "reqwest", "rustls"] } # replace native-tls with rustls sentry = { version = "0.36.0", default-features = false, features = ["backtrace", "contexts", "panic", "debug-images", "reqwest", "rustls"] } # replace native-tls with rustls
serde = { version = "1.0.196", features = ["derive"] } serde = { version = "1.0.196", features = ["derive"] }
serde_json = "1.0.117" serde_json = "1.0.117"
signal-hook = "0.3.17" signal-hook = "0.3.17"
sqlx = { version = "0.8.2", features = ["runtime-tokio", "postgres", "time", "macros", "uuid"] } sqlx = { version = "0.8.2", features = ["runtime-tokio", "postgres", "time", "macros", "uuid"] }
tokio = { version = "1.36.0", features = ["full"] } tokio = { version = "1.36.0", features = ["full"] }
tracing = "0.1.40" tracing = "0.1"
tracing-subscriber = { version = "0.3.16", features = ["env-filter", "json"] } tracing-subscriber = { version = "0.3.16", features = ["env-filter", "json"] }
uuid = { version = "1.7.0", features = ["serde"] } uuid = { version = "1.7.0", features = ["serde"] }

View file

@ -31,6 +31,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.11" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.1.0" />
<PackageReference Include="Sentry" Version="4.13.0" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" /> <PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -14,6 +14,16 @@ public class Program
await BuildInfoService.LoadVersion(); await BuildInfoService.LoadVersion();
var host = CreateHostBuilder(args).Build(); var host = CreateHostBuilder(args).Build();
var config = host.Services.GetRequiredService<CoreConfig>(); var config = host.Services.GetRequiredService<CoreConfig>();
// Initialize Sentry SDK, and make sure it gets dropped at the end
using var _ = SentrySdk.Init(opts =>
{
opts.Dsn = config.SentryUrl ?? "";
opts.Release = BuildInfoService.FullVersion;
opts.AutoSessionTracking = true;
// opts.DisableTaskUnobservedTaskExceptionCapture();
});
await host.Services.GetRequiredService<RedisService>().InitAsync(config); await host.Services.GetRequiredService<RedisService>().InitAsync(config);
await host.RunAsync(); await host.RunAsync();
} }

View file

@ -62,8 +62,13 @@ public class Startup
await ctx.Response.WriteJSON(400, "{\"message\":\"400: Bad Request\",\"code\":0}"); await ctx.Response.WriteJSON(400, "{\"message\":\"400: Bad Request\",\"code\":0}");
else if (exc.Error is not PKError) else if (exc.Error is not PKError)
{
await ctx.Response.WriteJSON(500, "{\"message\":\"500: Internal Server Error\",\"code\":0}"); await ctx.Response.WriteJSON(500, "{\"message\":\"500: Internal Server Error\",\"code\":0}");
var sentryEvent = new SentryEvent(exc.Error);
SentrySdk.CaptureEvent(sentryEvent);
}
// for some reason, if we don't specifically cast to ModelParseError, it uses the base's ToJson method // for some reason, if we don't specifically cast to ModelParseError, it uses the base's ToJson method
else if (exc.Error is ModelParseError fe) else if (exc.Error is ModelParseError fe)
await ctx.Response.WriteJSON(fe.ResponseCode, JsonConvert.SerializeObject(fe.ToJson())); await ctx.Response.WriteJSON(fe.ResponseCode, JsonConvert.SerializeObject(fe.ToJson()));

View file

@ -28,6 +28,12 @@
"Microsoft.AspNetCore.Mvc.Versioning": "5.1.0" "Microsoft.AspNetCore.Mvc.Versioning": "5.1.0"
} }
}, },
"Sentry": {
"type": "Direct",
"requested": "[4.13.0, )",
"resolved": "4.13.0",
"contentHash": "Wfw3M1WpFcrYaGzPm7QyUTfIOYkVXQ1ry6p4WYjhbLz9fPwV23SGQZTFDpdox67NHM0V0g1aoQ4YKLm4ANtEEg=="
},
"Serilog.AspNetCore": { "Serilog.AspNetCore": {
"type": "Direct", "type": "Direct",
"requested": "[9.0.0, )", "requested": "[9.0.0, )",

View file

@ -21,3 +21,4 @@ uuid = { workspace = true }
config = "0.14.0" config = "0.14.0"
json-subscriber = { version = "0.2.2", features = ["env-filter"] } json-subscriber = { version = "0.2.2", features = ["env-filter"] }
metrics-exporter-prometheus = { version = "0.15.3", default-features = false, features = ["tokio", "http-listener", "tracing"] } metrics-exporter-prometheus = { version = "0.15.3", default-features = false, features = ["tokio", "http-listener", "tracing"] }
sentry-tracing = "0.36.0"

View file

@ -5,6 +5,8 @@ use metrics_exporter_prometheus::PrometheusBuilder;
use sentry::IntoDsn; use sentry::IntoDsn;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
use sentry_tracing::event_from_event;
pub mod db; pub mod db;
pub mod state; pub mod state;
pub mod util; pub mod util;
@ -14,8 +16,20 @@ pub use crate::_config::CONFIG as config;
// functions in this file are only used by the main function below // functions in this file are only used by the main function below
pub fn init_logging(component: &str) -> anyhow::Result<()> { pub fn init_logging(component: &str) {
// todo: clean up the sentry duplication
if config.json_log { if config.json_log {
let sentry_layer =
sentry_tracing::layer().event_mapper(|md, ctx| match md.metadata().level() {
&tracing::Level::ERROR => {
// for some reason this works, but letting the library handle it doesn't
let event = event_from_event(md, ctx);
sentry::capture_event(event);
sentry_tracing::EventMapping::Ignore
}
_ => sentry_tracing::EventMapping::Ignore,
});
let mut layer = json_subscriber::layer(); let mut layer = json_subscriber::layer();
layer.inner_layer_mut().add_static_field( layer.inner_layer_mut().add_static_field(
"component", "component",
@ -23,15 +37,26 @@ pub fn init_logging(component: &str) -> anyhow::Result<()> {
); );
tracing_subscriber::registry() tracing_subscriber::registry()
.with(layer) .with(layer)
.with(sentry_layer)
.with(EnvFilter::from_default_env()) .with(EnvFilter::from_default_env())
.init(); .init();
} else { } else {
tracing_subscriber::fmt() let sentry_layer =
.with_env_filter(EnvFilter::from_default_env()) sentry_tracing::layer().event_mapper(|md, ctx| match md.metadata().level() {
&tracing::Level::ERROR => {
// for some reason this works, but letting the library handle it doesn't
let event = event_from_event(md, ctx);
sentry::capture_event(event);
sentry_tracing::EventMapping::Ignore
}
_ => sentry_tracing::EventMapping::Ignore,
});
tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer())
.with(sentry_layer)
.init(); .init();
} }
Ok(())
} }
pub fn init_metrics() -> anyhow::Result<()> { pub fn init_metrics() -> anyhow::Result<()> {
@ -61,7 +86,7 @@ macro_rules! main {
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
let _sentry_guard = libpk::init_sentry(); let _sentry_guard = libpk::init_sentry();
// we might also be able to use env!("CARGO_CRATE_NAME") here // we might also be able to use env!("CARGO_CRATE_NAME") here
libpk::init_logging($component)?; libpk::init_logging($component);
tokio::runtime::Builder::new_multi_thread() tokio::runtime::Builder::new_multi_thread()
.enable_all() .enable_all()
.build() .build()