mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-18 13:40:55 -04:00
feat(ffi): add support for sentry logging
This commit is contained in:
172
Cargo.lock
generated
172
Cargo.lock
generated
@@ -1207,6 +1207,7 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
@@ -2060,6 +2061,12 @@ version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.12.4"
|
||||
@@ -2078,6 +2085,17 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hostname"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.29.0"
|
||||
@@ -3096,6 +3114,8 @@ dependencies = [
|
||||
"once_cell",
|
||||
"paranoid-android",
|
||||
"ruma",
|
||||
"sentry",
|
||||
"sentry-tracing",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.11",
|
||||
@@ -3623,6 +3643,17 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "os_info"
|
||||
version = "3.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a604e53c24761286860eba4e2c8b23a0161526476b1de520139d69cdb85a6b5"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
@@ -4301,6 +4332,7 @@ dependencies = [
|
||||
"async-compression",
|
||||
"base64",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
@@ -4744,6 +4776,114 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sentry"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a7332159e544e34db06b251b1eda5e546bd90285c3f58d9c8ff8450b484e0da"
|
||||
dependencies = [
|
||||
"httpdate",
|
||||
"native-tls",
|
||||
"reqwest",
|
||||
"sentry-backtrace",
|
||||
"sentry-contexts",
|
||||
"sentry-core",
|
||||
"sentry-debug-images",
|
||||
"sentry-panic",
|
||||
"sentry-tracing",
|
||||
"tokio",
|
||||
"ureq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-backtrace"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "565ec31ad37bab8e6d9f289f34913ed8768347b133706192f10606dabd5c6bc4"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"sentry-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-contexts"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e860275f25f27e8c0c7726ce116c7d5c928c5bba2ee73306e52b20a752298ea6"
|
||||
dependencies = [
|
||||
"hostname",
|
||||
"libc",
|
||||
"os_info",
|
||||
"rustc_version",
|
||||
"sentry-core",
|
||||
"uname",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-core"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "653942e6141f16651273159f4b8b1eaeedf37a7554c00cd798953e64b8a9bf72"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"rand",
|
||||
"sentry-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-debug-images"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a60bc2154e6df59beed0ac13d58f8dfaf5ad20a88548a53e29e4d92e8e835c2"
|
||||
dependencies = [
|
||||
"findshlibs",
|
||||
"once_cell",
|
||||
"sentry-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-panic"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "105e3a956c8aa9dab1e4087b1657b03271bfc49d838c6ae9bfc7c58c802fd0ef"
|
||||
dependencies = [
|
||||
"sentry-backtrace",
|
||||
"sentry-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-tracing"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e75c831b4d8b34a5aec1f65f67c5d46a26c7c5d3c7abd8b5ef430796900cf8"
|
||||
dependencies = [
|
||||
"sentry-backtrace",
|
||||
"sentry-core",
|
||||
"tracing-core",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-types"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d4203359e60724aa05cf2385aaf5d4f147e837185d7dd2b9ccf1ee77f4420c8"
|
||||
dependencies = [
|
||||
"debugid",
|
||||
"hex",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 1.0.63",
|
||||
"time",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
@@ -5613,6 +5753,15 @@ dependencies = [
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uname"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unarray"
|
||||
version = "0.1.4"
|
||||
@@ -5827,6 +5976,19 @@ version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "ureq"
|
||||
version = "2.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"log",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
@@ -6153,6 +6315,16 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
|
||||
@@ -78,6 +78,8 @@ ruma = { git = "https://github.com/ruma/ruma", rev = "a8fd1b0322649bf59e2a5cfc73
|
||||
"unstable-msc4278",
|
||||
] }
|
||||
ruma-common = { git = "https://github.com/ruma/ruma", rev = "a8fd1b0322649bf59e2a5cfc73ab4fe46b21edd7" }
|
||||
sentry = "0.36.0"
|
||||
sentry-tracing = "0.36.0"
|
||||
serde = "1.0.217"
|
||||
serde_html_form = "0.2.7"
|
||||
serde_json = "1.0.138"
|
||||
|
||||
@@ -19,6 +19,8 @@ Breaking changes:
|
||||
|
||||
Additions:
|
||||
|
||||
- Support for adding a Sentry layer to the FFI bindings has been added. Only `tracing` statements with
|
||||
the field `sentry=true` will be forwarded to Sentry, in addition to default Sentry filters.
|
||||
- Add room topic string to `StateEventContent`
|
||||
- Add `UploadSource` for representing upload data - this is analogous to `matrix_sdk_ui::timeline::AttachmentSource`
|
||||
- Add `Client::observe_account_data_event` and `Client::observe_room_account_data_event` to
|
||||
|
||||
@@ -34,6 +34,8 @@ matrix-sdk-ui = { workspace = true, features = ["uniffi"] }
|
||||
mime = "0.3.16"
|
||||
once_cell = { workspace = true }
|
||||
ruma = { workspace = true, features = ["html", "unstable-unspecified", "unstable-msc3488", "compat-unset-avatar", "unstable-msc3245-v1-compat", "unstable-msc4278"] }
|
||||
sentry = { workspace = true }
|
||||
sentry-tracing = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
use std::sync::{atomic::AtomicBool, Arc, OnceLock};
|
||||
|
||||
use tracing::warn;
|
||||
use tracing_appender::rolling::{RollingFileAppender, Rotation};
|
||||
use tracing_core::Subscriber;
|
||||
use tracing_subscriber::{
|
||||
@@ -8,19 +11,13 @@ use tracing_subscriber::{
|
||||
time::FormatTime,
|
||||
FormatEvent, FormatFields, FormattedFields,
|
||||
},
|
||||
layer::SubscriberExt,
|
||||
layer::SubscriberExt as _,
|
||||
registry::LookupSpan,
|
||||
util::SubscriberInitExt,
|
||||
EnvFilter, Layer,
|
||||
util::SubscriberInitExt as _,
|
||||
Layer,
|
||||
};
|
||||
|
||||
use crate::tracing::LogLevel;
|
||||
|
||||
pub fn log_panics() {
|
||||
std::env::set_var("RUST_BACKTRACE", "1");
|
||||
|
||||
log_panics::init();
|
||||
}
|
||||
use crate::{error::ClientError, tracing::LogLevel};
|
||||
|
||||
fn text_layers<S>(config: TracingConfiguration) -> impl Layer<S>
|
||||
where
|
||||
@@ -343,6 +340,20 @@ impl TraceLogPacks {
|
||||
}
|
||||
}
|
||||
|
||||
struct SentryLoggingCtx {
|
||||
/// The Sentry client guard, which keeps the Sentry context alive.
|
||||
_guard: sentry::ClientInitGuard,
|
||||
|
||||
/// Whether the Sentry layer is enabled or not, at a global level.
|
||||
enabled: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
struct LoggingCtx {
|
||||
sentry: Option<SentryLoggingCtx>,
|
||||
}
|
||||
|
||||
static LOGGING: OnceLock<LoggingCtx> = OnceLock::new();
|
||||
|
||||
#[derive(uniffi::Record)]
|
||||
pub struct TracingConfiguration {
|
||||
/// The desired log level.
|
||||
@@ -363,6 +374,89 @@ pub struct TracingConfiguration {
|
||||
|
||||
/// If set, configures rotated log files where to write additional logs.
|
||||
write_to_files: Option<TracingFileConfiguration>,
|
||||
|
||||
/// If set, the Sentry DSN to use for error reporting.
|
||||
sentry_dsn: Option<String>,
|
||||
}
|
||||
|
||||
impl TracingConfiguration {
|
||||
/// Sets up the tracing configuration and return a [`Logger`] instance
|
||||
/// holding onto it.
|
||||
fn build(mut self) -> LoggingCtx {
|
||||
// Show full backtraces, if we run into panics.
|
||||
std::env::set_var("RUST_BACKTRACE", "1");
|
||||
|
||||
// Log panics.
|
||||
log_panics::init();
|
||||
|
||||
// Prepare the Sentry layer, if a DSN is provided.
|
||||
let (sentry_layer, sentry_logging_ctx) = if let Some(sentry_dsn) = self.sentry_dsn.take() {
|
||||
// Initialize the Sentry client with the given options.
|
||||
let sentry_guard = sentry::init((
|
||||
sentry_dsn,
|
||||
sentry::ClientOptions {
|
||||
traces_sample_rate: 0.0,
|
||||
attach_stacktrace: true,
|
||||
..sentry::ClientOptions::default()
|
||||
},
|
||||
));
|
||||
|
||||
let sentry_enabled = Arc::new(AtomicBool::new(true));
|
||||
|
||||
// Add a Sentry layer to the tracing subscriber.
|
||||
//
|
||||
// Pass custom event and span filters, which will ignore anything, if the Sentry
|
||||
// support has been globally disabled, or if the statement doesn't include a
|
||||
// `sentry` field set to `true`.
|
||||
let sentry_layer = sentry_tracing::layer()
|
||||
.event_filter({
|
||||
let enabled = sentry_enabled.clone();
|
||||
|
||||
move |metadata| {
|
||||
if enabled.load(std::sync::atomic::Ordering::SeqCst)
|
||||
&& metadata.fields().field("sentry").is_some()
|
||||
{
|
||||
sentry_tracing::default_event_filter(metadata)
|
||||
} else {
|
||||
// Ignore the event.
|
||||
sentry_tracing::EventFilter::Ignore
|
||||
}
|
||||
}
|
||||
})
|
||||
.span_filter({
|
||||
let enabled = sentry_enabled.clone();
|
||||
|
||||
move |metadata| {
|
||||
if enabled.load(std::sync::atomic::Ordering::SeqCst) {
|
||||
sentry_tracing::default_span_filter(metadata)
|
||||
} else {
|
||||
// Ignore, if sentry is globally disabled.
|
||||
false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
(
|
||||
Some(sentry_layer),
|
||||
Some(SentryLoggingCtx { _guard: sentry_guard, enabled: sentry_enabled }),
|
||||
)
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let env_filter = build_tracing_filter(&self);
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(tracing_subscriber::EnvFilter::new(&env_filter))
|
||||
.with(crate::platform::text_layers(self))
|
||||
.with(sentry_layer)
|
||||
.init();
|
||||
|
||||
// Log the log levels 🧠.
|
||||
tracing::info!(env_filter, "Logging has been set up");
|
||||
|
||||
LoggingCtx { sentry: sentry_logging_ctx }
|
||||
}
|
||||
}
|
||||
|
||||
fn build_tracing_filter(config: &TracingConfiguration) -> String {
|
||||
@@ -407,24 +501,38 @@ fn build_tracing_filter(config: &TracingConfiguration) -> String {
|
||||
/// the NSE process on iOS). Otherwise, this can remain false, in which case a
|
||||
/// multithreaded tokio runtime will be set up.
|
||||
#[matrix_sdk_ffi_macros::export]
|
||||
pub fn init_platform(config: TracingConfiguration, use_lightweight_tokio_runtime: bool) {
|
||||
log_panics();
|
||||
|
||||
let env_filter = build_tracing_filter(&config);
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(EnvFilter::new(&env_filter))
|
||||
.with(text_layers(config))
|
||||
.init();
|
||||
|
||||
// Log the log levels 🧠.
|
||||
tracing::info!(env_filter, "Logging has been set up");
|
||||
pub fn init_platform(
|
||||
config: TracingConfiguration,
|
||||
use_lightweight_tokio_runtime: bool,
|
||||
) -> Result<(), ClientError> {
|
||||
LOGGING.set(config.build()).map_err(|_| ClientError::Generic {
|
||||
msg: "logger already initialized".to_owned(),
|
||||
details: None,
|
||||
})?;
|
||||
|
||||
if use_lightweight_tokio_runtime {
|
||||
setup_lightweight_tokio_runtime();
|
||||
} else {
|
||||
setup_multithreaded_tokio_runtime();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the global enablement level for the Sentry layer (after the logs have
|
||||
/// been set up).
|
||||
#[matrix_sdk_ffi_macros::export]
|
||||
pub fn enable_sentry_logging(enabled: bool) {
|
||||
if let Some(ctx) = LOGGING.get() {
|
||||
if let Some(sentry_ctx) = &ctx.sentry {
|
||||
sentry_ctx.enabled.store(enabled, std::sync::atomic::Ordering::SeqCst);
|
||||
} else {
|
||||
warn!("Sentry logging is not enabled");
|
||||
}
|
||||
} else {
|
||||
// Can't use log statements here, since logging hasn't been enabled yet 🧠
|
||||
eprintln!("Logging hasn't been enabled yet");
|
||||
};
|
||||
}
|
||||
|
||||
fn setup_multithreaded_tokio_runtime() {
|
||||
@@ -479,6 +587,7 @@ mod tests {
|
||||
extra_targets: vec!["super_duper_app".to_owned()],
|
||||
write_to_stdout_or_system: true,
|
||||
write_to_files: None,
|
||||
sentry_dsn: None,
|
||||
};
|
||||
|
||||
let filter = build_tracing_filter(&config);
|
||||
@@ -515,6 +624,7 @@ mod tests {
|
||||
extra_targets: vec!["super_duper_app".to_owned(), "some_other_span".to_owned()],
|
||||
write_to_stdout_or_system: true,
|
||||
write_to_files: None,
|
||||
sentry_dsn: None,
|
||||
};
|
||||
|
||||
let filter = build_tracing_filter(&config);
|
||||
@@ -552,6 +662,7 @@ mod tests {
|
||||
extra_targets: vec!["super_duper_app".to_owned()],
|
||||
write_to_stdout_or_system: true,
|
||||
write_to_files: None,
|
||||
sentry_dsn: None,
|
||||
};
|
||||
|
||||
let filter = build_tracing_filter(&config);
|
||||
|
||||
Reference in New Issue
Block a user