diff --git a/Cargo.lock b/Cargo.lock index 24193b8e..e6278b3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -47,6 +58,23 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" +[[package]] +name = "android_log-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" + +[[package]] +name = "android_logger" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b07e8e73d720a1f2e4b6014766e6039fd2e96a4fa44e2a78d0e1fa2ff49826" +dependencies = [ + "android_log-sys", + "env_filter", + "log", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -62,6 +90,12 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "async-stream" version = "0.3.5" @@ -211,6 +245,18 @@ dependencies = [ "serde", ] +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block" version = "0.1.6" @@ -235,6 +281,30 @@ dependencies = [ "objc2", ] +[[package]] +name = "borsh" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d4d6dafc1a3bb54687538972158f07b2c948bc57d5890df22c0739098b3028" +dependencies = [ + "borsh-derive", + "cfg_aliases 0.1.1", +] + +[[package]] +name = "borsh-derive" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4918709cc4dd777ad2b6303ed03cb37f3ca0ccede8c1b0d28ac6db8f4710e0" +dependencies = [ + "once_cell", + "proc-macro-crate 2.0.2", + "proc-macro2", + "quote", + "syn 2.0.66", + "syn_derive", +] + [[package]] name = "brotli" version = "3.5.0" @@ -262,6 +332,39 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byte-unit" +version = "5.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ac19bdf0b2665407c39d82dbc937e951e7e2001609f0fb32edd0af45a2d63e" +dependencies = [ + "rust_decimal", + "serde", + "utf8-width", +] + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bytemuck" version = "1.16.0" @@ -389,6 +492,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "cfg_aliases" version = "0.2.1" @@ -652,6 +761,7 @@ dependencies = [ "futures", "http 0.2.12", "hyper 0.14.28", + "log", "prost-types", "ringbuf", "thiserror", @@ -821,6 +931,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_filter" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6dc8c8ff84895b051f07a0e65f975cf225131742531338752abfb324e4449ff" +dependencies = [ + "log", + "regex", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -862,6 +982,15 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "fern" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee" +dependencies = [ + "log", +] + [[package]] name = "field-offset" version = "0.3.6" @@ -930,6 +1059,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futf" version = "0.1.5" @@ -1360,6 +1495,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] [[package]] name = "hashbrown" @@ -1878,6 +2016,9 @@ name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +dependencies = [ + "value-bag", +] [[package]] name = "loom" @@ -2133,6 +2274,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "objc" version = "0.2.7" @@ -2690,6 +2840,26 @@ dependencies = [ "prost", ] +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "quick-xml" version = "0.31.0" @@ -2708,6 +2878,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.7.3" @@ -2865,6 +3041,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + [[package]] name = "reqwest" version = "0.11.27" @@ -2967,6 +3152,51 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rkyv" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rust_decimal" +version = "1.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3095,6 +3325,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "selectors" version = "0.22.0" @@ -3297,6 +3533,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + [[package]] name = "siphasher" version = "0.3.11" @@ -3335,7 +3577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d09e57a5a6b300bf917329da0ff30a58737d83abb7b14f99a419c23e83007cb8" dependencies = [ "bytemuck", - "cfg_aliases", + "cfg_aliases 0.2.1", "core-graphics", "foreign-types", "js-sys", @@ -3464,6 +3706,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "sync_wrapper" version = "0.1.2" @@ -3554,6 +3808,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "target-lexicon" version = "0.12.14" @@ -3668,6 +3928,7 @@ dependencies = [ "tauri", "tauri-build", "tauri-plugin-devtools", + "tauri-plugin-log", "tokio", "tracing", ] @@ -3714,6 +3975,7 @@ dependencies = [ "devtools-core", "futures", "local-ip-address", + "log", "objc", "serde", "serde_json", @@ -3727,6 +3989,26 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "tauri-plugin-log" +version = "2.0.0-beta.8" +dependencies = [ + "android_logger", + "byte-unit", + "cocoa", + "fern", + "log", + "objc", + "serde", + "serde_json", + "serde_repr", + "swift-rs", + "tauri", + "tauri-plugin", + "thiserror", + "time", +] + [[package]] name = "tauri-runtime" version = "2.0.0-beta.20" @@ -3883,7 +4165,9 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa 1.0.11", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", @@ -4380,6 +4664,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + [[package]] name = "uuid" version = "1.8.0" @@ -4395,6 +4685,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "value-bag" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" + [[package]] name = "version-compare" version = "0.2.0" @@ -5045,6 +5341,15 @@ dependencies = [ "x11-dl", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x11" version = "2.21.0" diff --git a/README.md b/README.md index 50fb50fb..42ee8424 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ tauri-build = "1.5.0" The primary export of the devtools crate is a Tauri Plugin that interfaces with the system, therefore you will need to initialize and register the plugin with Tauri itself before you can use the DevTools. To do that, edit your main.rs file like so: ```rust -fn main() { +fn run() { let devtools = devtools::init(); // initialize the plugin as early as possible tauri::Builder::default() @@ -68,8 +68,6 @@ tauri = "2.0.0-beta.3" tauri-build = "2.0.0-beta" ``` -### Plugin Initialization - Then add the following snippet to your tauri initialization code: ```rust @@ -98,6 +96,83 @@ And then run your app as usual, if everything is set up correctly devtools will You can click or copy & paste the link into your browser to open up the UI. Alternatively you can navigate to https://devtools.crabnebula.dev and connect from there. +### Usage with other logging systems + +If you're running the DevTools plugin next to another tracing or logging system, you will face a crash +stating you cannot define multiple logging systems on the same process: + +``` +thread 'main' panicked at src/main.rs:24:10: +error while running tauri application: PluginInitialization("log", "attempted to set a logger after the logging system was already initialized") +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +``` + +An alternative is to use tauri-plugin-devtools in debug builds (`tauri dev` and `tauri build --debug` modes) +and use a separate logging system in production (such as `fern` or `tauri-plugin-log`) letting you persist logs or have custom functionality: + +```rust +fn run() { + let mut builder = tauri::Builder::default(); + + #[cfg(debug_assertions)] + { + let devtools = tauri_plugin_devtools::init(); + builder = builder.plugin(devtools); + } + + #[cfg(not(debug_assertions))] + { + use tauri_plugin_log::{Builder, Target, TargetKind}; + + let log_plugin = Builder::default() + .targets([ + Target::new(TargetKind::Stdout), + Target::new(TargetKind::LogDir { file_name: None }), + Target::new(TargetKind::Webview), + ]) + .build(); + + builder = builder.plugin(log_plugin); + } + + builder + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} +``` + +Another approach is to pipe other logging system through `tauri-plugin-devtools` via the `attach_logger` function, +which register the logging system to receive log records propagated by this plugin's tracing subscriber. +The following snippet demonstrates how to use the `attach_logger` function for compatibility between +`tauri-plugin-devtools` and `tauri-plugin-log`: + +```rust +fn run() { + tauri::Builder::default() + .setup(|app| { + // create the log plugin as usual, but call split() instead of build() + let (tauri_plugin_log, max_level, logger) = tauri_plugin_log::Builder::new().split(app.handle())?; + + // on debug builds, set up the DevTools plugin and pipe the logger from tauri-plugin-log + #[cfg(debug_assertions)] + { + let mut devtools_builder = tauri_plugin_devtools::Builder::default(); + devtools_builder.attach_logger(logger); + app.handle().plugin(devtools_builder.init())?; + } + // on release builds, only attach the logger from tauri-plugin-log + #[cfg(not(debug_assertions))] + { + tauri_plugin_log::attach_logger(max_level, logger); + } + + app.handle().plugin(tauri_plugin_log)?; + + Ok(()) + }) +} +``` + ### Android The Android emulator runs behind a virtual router that isolates it from the development machine network interfaces. diff --git a/crates/devtools-core/Cargo.toml b/crates/devtools-core/Cargo.toml index 9493ff9c..63d663e4 100644 --- a/crates/devtools-core/Cargo.toml +++ b/crates/devtools-core/Cargo.toml @@ -31,3 +31,4 @@ async-stream = "0.3.5" http = "0.2" hyper = "0.14" tower = "0.4" +log = "0.4" diff --git a/crates/devtools-core/src/bridge_layer.rs b/crates/devtools-core/src/bridge_layer.rs new file mode 100644 index 00000000..d64c43b5 --- /dev/null +++ b/crates/devtools-core/src/bridge_layer.rs @@ -0,0 +1,48 @@ +use std::str::FromStr; + +use tracing_subscriber::layer::Context; + +use crate::visitors::EventVisitor; + +pub struct BridgeLayer { + loggers: Vec>, +} + +impl BridgeLayer { + #[must_use] + pub fn new(loggers: Vec>) -> Self { + Self { loggers } + } + + pub fn add_logger(&mut self, logger: Box) { + self.loggers.push(logger); + } +} + +impl tracing_subscriber::layer::Layer for BridgeLayer +where + S: tracing_core::Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>, +{ + fn on_event(&self, event: &tracing_core::Event<'_>, _ctx: Context<'_, S>) { + let metadata = event.metadata(); + + let mut visitor = EventVisitor::new(metadata as *const _ as u64); + event.record(&mut visitor); + let (message, _fields) = visitor.result(); + + if let Some(message) = message { + for logger in &self.loggers { + logger.log( + &log::Record::builder() + .level(log::Level::from_str(metadata.level().as_str()).unwrap()) + .target(metadata.target()) + .file(metadata.file()) + .line(metadata.line()) + .module_path(metadata.module_path()) + .args(format_args!("{message}")) + .build(), + ); + } + } + } +} diff --git a/crates/devtools-core/src/lib.rs b/crates/devtools-core/src/lib.rs index 60edc953..ff8fa837 100644 --- a/crates/devtools-core/src/lib.rs +++ b/crates/devtools-core/src/lib.rs @@ -8,6 +8,7 @@ //! and [`tracing`](https://docs.rs/tracing/latest/tracing/) ecosystems out-of-the-box. pub mod aggregator; +pub mod bridge_layer; mod error; pub mod layer; pub mod server; diff --git a/crates/devtools/Cargo.toml b/crates/devtools/Cargo.toml index 5c9242a6..4a4e8a92 100644 --- a/crates/devtools/Cargo.toml +++ b/crates/devtools/Cargo.toml @@ -36,6 +36,7 @@ futures = "0.3.30" bytes = "1.5.0" async-stream = "0.3.5" local-ip-address = "0.5" +log = "0.4" [target."cfg(target_os = \"ios\")".dependencies] swift-rs = "1.0.6" diff --git a/crates/devtools/src/lib.rs b/crates/devtools/src/lib.rs index c3045cf8..f2030237 100644 --- a/crates/devtools/src/lib.rs +++ b/crates/devtools/src/lib.rs @@ -1,6 +1,7 @@ mod server; use devtools_core::aggregator::Aggregator; +use devtools_core::bridge_layer::BridgeLayer; use devtools_core::layer::Layer; use devtools_core::server::wire::tauri::tauri_server::TauriServer; use devtools_core::server::{Server, ServerHandle}; @@ -159,6 +160,7 @@ pub struct Builder { port: u16, publish_interval: Duration, strict_port: bool, + bridge_layer: BridgeLayer, } impl Default for Builder { @@ -171,6 +173,7 @@ impl Default for Builder { port: 3000, publish_interval: Duration::from_millis(200), strict_port: false, + bridge_layer: BridgeLayer::new(Vec::new()), } } } @@ -207,6 +210,16 @@ impl Builder { self } + /// Attaches the given logger to our tracing subscriber. + /// + /// Internally we will bridge all log events to this logger. + /// + /// This is particularly useful to have compatibility with tauri-plugin-log. + pub fn attach_logger(&mut self, logger: Box) -> &mut Self { + self.bridge_layer.add_logger(logger); + self + } + /// The interval in which updates are sent to the connected UI. /// /// You can tweak this setting to reduce the time between updates, when for example your app @@ -291,6 +304,10 @@ impl Builder { // initialize early so we don't miss any spans tracing_subscriber::registry() .with(layer.with_filter(tracing_subscriber::filter::LevelFilter::TRACE)) + .with( + self.bridge_layer + .with_filter(tracing_subscriber::filter::LevelFilter::TRACE), + ) .try_init() .map_err(devtools_core::Error::from)?;