diff --git a/.changes/tracing.md b/.changes/tracing.md new file mode 100644 index 000000000..27ccb5b2b --- /dev/null +++ b/.changes/tracing.md @@ -0,0 +1,5 @@ +--- +"wry": patch +--- + +Added tracing spans for `evaluate_script`, `ipc_handler` and `custom_protocols` behind the `tracing` feature flag. diff --git a/Cargo.toml b/Cargo.toml index 461d0b565..47359d88b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,10 +32,12 @@ devtools = [ ] transparent = [ ] fullscreen = [ ] linux-headers = [ "webkit2gtk/v2_36" ] +tracing = [ "dep:tracing" ] [dependencies] libc = "0.2" log = "0.4" +tracing = { version = "0.1", optional = true } once_cell = "1" serde = { version = "1.0", features = [ "derive" ] } serde_json = "1.0" diff --git a/src/lib.rs b/src/lib.rs index 375682585..f17d614ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,6 +66,7 @@ //! libraries and prevent from building documentation on doc.rs fails. //! - `linux-headers`: Enables headers support of custom protocol request on Linux. Requires //! webkit2gtk v2.36 or above. +//! - `tracing`: enables [tracing] for `evaluate_script`, `ipc_handler` and `custom_protocols. //! //! [tao]: https://crates.io/crates/tao //! [`EventLoop`]: crate::application::event_loop::EventLoop @@ -73,6 +74,7 @@ //! [`WebView`]: crate::webview::WebView //! [`with_file_drop_handler`]: crate::webview::WebView::with_file_drop_handler //! [`with_custom_protocol`]: crate::webview::WebView::with_custom_protocol +//! [tracing]: https://docs.rs/tracing/latest/tracing/ #![allow(clippy::new_without_default)] #![allow(clippy::wrong_self_convention)] diff --git a/src/webview/webkitgtk/mod.rs b/src/webview/webkitgtk/mod.rs index d3f270f21..dd4305338 100644 --- a/src/webview/webkitgtk/mod.rs +++ b/src/webview/webkitgtk/mod.rs @@ -89,6 +89,9 @@ impl InnerWebView { // Connect before registering as recommended by the docs manager.connect_script_message_received(None, move |_m, msg| { + #[cfg(feature = "tracing")] + let _span = tracing::info_span!("wry::ipc::handle").entered(); + if let Some(js) = msg.js_value() { if let Some(ipc_handler) = &ipc_handler { ipc_handler(&w, js.to_string()); @@ -401,7 +404,17 @@ impl InnerWebView { pending_scripts.push(js.into()); } else { let cancellable: Option<&Cancellable> = None; - self.webview.run_javascript(js, cancellable, |_| ()); + #[cfg(feature = "tracing")] + { + let span = SendEnteredSpan(tracing::debug_span!("wry::eval").entered()); + self.webview.run_javascript(js, cancellable, move |_| { + drop(span); + }); + } + #[cfg(not(feature = "tracing"))] + { + self.webview.run_javascript(js, cancellable, |_| ()); + } } Ok(()) } @@ -490,3 +503,10 @@ pub fn platform_webview_version() -> Result { }; Ok(format!("{}.{}.{}", major, minor, patch)) } + +// SAFETY: only use this when you are sure the span will be dropped on the same thread it was entered +#[cfg(feature = "tracing")] +struct SendEnteredSpan(tracing::span::EnteredSpan); + +#[cfg(feature = "tracing")] +unsafe impl Send for SendEnteredSpan {} diff --git a/src/webview/webkitgtk/web_context.rs b/src/webview/webkitgtk/web_context.rs index b0cca7aaf..2e4c97bb6 100644 --- a/src/webview/webkitgtk/web_context.rs +++ b/src/webview/webkitgtk/web_context.rs @@ -287,9 +287,16 @@ where .register_uri_scheme_as_secure(name); context.register_uri_scheme(name, move |request| { + #[cfg(feature = "tracing")] + let span = + tracing::info_span!("wry::custom_protocol::handle", uri = tracing::field::Empty).entered(); + if let Some(uri) = request.uri() { let uri = uri.as_str(); + #[cfg(feature = "tracing")] + span.record("uri", uri); + // FIXME: Read the body (forms post) #[allow(unused_mut)] let mut http_request = Request::builder().uri(uri).method("GET"); @@ -325,7 +332,12 @@ where } }; - match handler(&http_request) { + let res = { + #[cfg(feature = "tracing")] + let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered(); + handler(&http_request) + }; + match res { Ok(http_response) => { let buffer = http_response.body(); let input = gio::MemoryInputStream::from_bytes(&glib::Bytes::from(buffer)); diff --git a/src/webview/webview2/mod.rs b/src/webview/webview2/mod.rs index 5d2f16f63..fd169dcb7 100644 --- a/src/webview/webview2/mod.rs +++ b/src/webview/webview2/mod.rs @@ -358,6 +358,8 @@ window.addEventListener('mousemove', (e) => window.chrome.webview.postMessage('_ } if let Some(ipc_handler) = &ipc_handler { + #[cfg(feature = "tracing")] + let _span = tracing::info_span!("wry::ipc::handle").entered(); ipc_handler(&window, js); } } @@ -514,6 +516,10 @@ window.addEventListener('mousemove', (e) => window.chrome.webview.postMessage('_ webview .add_WebResourceRequested( &WebResourceRequestedEventHandler::create(Box::new(move |_, args| { + #[cfg(feature = "tracing")] + let span = + tracing::info_span!("wry::custom_protocol::handle", uri = tracing::field::Empty) + .entered(); if let Some(args) = args { let webview_request = args.Request()?; let mut request = Request::builder(); @@ -570,6 +576,9 @@ window.addEventListener('mousemove', (e) => window.chrome.webview.postMessage('_ webview_request.Uri(&mut uri)?; let uri = take_pwstr(uri); + #[cfg(feature = "tracing")] + span.record("uri", &uri); + if let Some(custom_protocol) = custom_protocols .iter() .find(|(name, _)| uri.starts_with(&format!("{scheme}://{name}."))) @@ -589,7 +598,12 @@ window.addEventListener('mousemove', (e) => window.chrome.webview.postMessage('_ Err(_) => return Err(E_FAIL.into()), }; - return match (custom_protocol.1)(&final_request) { + let res = { + #[cfg(feature = "tracing")] + let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered(); + (custom_protocol.1)(&final_request) + }; + return match res { Ok(sent_response) => { let content = sent_response.body(); let status_code = sent_response.status(); @@ -801,9 +815,15 @@ window.addEventListener('mousemove', (e) => window.chrome.webview.postMessage('_ fn execute_script(webview: &ICoreWebView2, js: String) -> windows::core::Result<()> { unsafe { + #[cfg(feature = "tracing")] + let span = tracing::debug_span!("wry::eval").entered(); webview.ExecuteScript( PCWSTR::from_raw(encode_wide(js).as_ptr()), - &ExecuteScriptCompletedHandler::create(Box::new(|_, _| (Ok(())))), + &ExecuteScriptCompletedHandler::create(Box::new(|_, _| { + #[cfg(feature = "tracing")] + drop(span); + Ok(()) + })), ) } } diff --git a/src/webview/wkwebview/mod.rs b/src/webview/wkwebview/mod.rs index 58c1d64cb..6752e15df 100644 --- a/src/webview/wkwebview/mod.rs +++ b/src/webview/wkwebview/mod.rs @@ -93,6 +93,9 @@ impl InnerWebView { extern "C" fn did_receive(this: &Object, _: Sel, _: id, msg: id) { // Safety: objc runtime calls are unsafe unsafe { + #[cfg(feature = "tracing")] + let _span = tracing::info_span!("wry::ipc::handle").entered(); + let function = this.get_ivar::<*mut c_void>("function"); if !function.is_null() { let function = @@ -113,6 +116,9 @@ impl InnerWebView { // Task handler for custom protocol extern "C" fn start_task(this: &Object, _: Sel, _webview: id, task: id) { unsafe { + #[cfg(feature = "tracing")] + let span = tracing::info_span!("wry::custom_protocol::handle", uri = tracing::field::Empty) + .entered(); let function = this.get_ivar::<*mut c_void>("function"); if !function.is_null() { let function = &mut *(*function @@ -122,10 +128,14 @@ impl InnerWebView { let request: id = msg_send![task, request]; let url: id = msg_send![request, URL]; - let nsstring = { + let uri_nsstring = { let s: id = msg_send![url, absoluteString]; NSString(s) }; + let uri = uri_nsstring.to_str(); + + #[cfg(feature = "tracing")] + span.record("uri", uri); // Get request method (GET, POST, PUT etc...) let method = { @@ -134,9 +144,7 @@ impl InnerWebView { }; // Prepare our HttpRequest - let mut http_request = Request::builder() - .uri(nsstring.to_str()) - .method(method.to_str()); + let mut http_request = Request::builder().uri(uri).method(method.to_str()); // Get body let mut sent_form_body = Vec::new(); @@ -181,7 +189,12 @@ impl InnerWebView { // send response match http_request.body(sent_form_body) { Ok(final_request) => { - if let Ok(sent_response) = function(&final_request) { + let res = { + #[cfg(feature = "tracing")] + let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered(); + function(&final_request) + }; + if let Ok(sent_response) = res { let content = sent_response.body(); // default: application/octet-stream, but should be provided by the client let wanted_mime = sent_response.headers().get(CONTENT_TYPE); @@ -854,7 +867,21 @@ r#"Object.defineProperty(window, 'ipc', { } else { // Safety: objc runtime calls are unsafe unsafe { - let _: id = msg_send![self.webview, evaluateJavaScript:NSString::new(js) completionHandler:null::<*const c_void>()]; + #[cfg(feature = "tracing")] + { + let span = Mutex::new(Some(tracing::debug_span!("wry::eval").entered())); + let handler = block::ConcreteBlock::new(move |_object, _error| { + span.lock().unwrap().take(); + }); + // Put the block on the heap + let handler = handler.copy(); + let completion_handler: &block::Block<(id, id), ()> = &handler; + + let _: id = msg_send![self.webview, evaluateJavaScript:NSString::new(js) completionHandler:completion_handler]; + } + #[cfg(not(feature = "tracing"))] + let _: id = + msg_send![self.webview, evaluateJavaScript:NSString::new(js) completionHandler:nil]; } } Ok(())