Skip to content

Commit

Permalink
feat: tracing support for component props (#1531)
Browse files Browse the repository at this point in the history
  • Loading branch information
luoxiaozero authored Aug 18, 2023
1 parent d9abebb commit 18deb39
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 20 deletions.
1 change: 1 addition & 0 deletions leptos_dom/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ smallvec = "1"
tracing = "0.1"
wasm-bindgen = { version = "0.2", features = ["enable-interning"] }
wasm-bindgen-futures = "0.4.31"
serde = "1"

[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2", features = ["js"] }
Expand Down
2 changes: 2 additions & 0 deletions leptos_dom/src/macro_helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ mod into_attribute;
mod into_class;
mod into_property;
mod into_style;
#[doc(hidden)]
pub mod tracing_property;
pub use into_attribute::*;
pub use into_class::*;
pub use into_property::*;
Expand Down
166 changes: 166 additions & 0 deletions leptos_dom/src/macro_helpers/tracing_property.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
use wasm_bindgen::UnwrapThrowExt;

#[macro_export]
/// Use for tracing property
macro_rules! tracing_props {
() => {
::leptos::leptos_dom::tracing::span!(
::leptos::leptos_dom::tracing::Level::INFO,
"leptos_dom::tracing_props",
props = String::from("[]")
);
};
($($prop:tt),+ $(,)?) => {
{
use ::leptos::leptos_dom::tracing_property::{Match, SerializeMatch, DefaultMatch};
let mut props = String::from('[');
$(
let prop = (&&Match {
name: stringify!{$prop},
value: std::cell::Cell::new(Some(&$prop))
}).spez();
props.push_str(&format!("{prop},"));
)*
props.pop();
props.push(']');
::leptos::leptos_dom::tracing::span!(
::leptos::leptos_dom::tracing::Level::INFO,
"leptos_dom::tracing_props",
props
);
}
};
}

// Implementation based on spez
// see https://github.com/m-ou-se/spez

pub struct Match<T> {
pub name: &'static str,
pub value: std::cell::Cell<Option<T>>,
}

pub trait SerializeMatch {
type Return;
fn spez(&self) -> Self::Return;
}
impl<T: serde::Serialize> SerializeMatch for &Match<&T> {
type Return = String;
fn spez(&self) -> Self::Return {
let name = self.name;
serde_json::to_string(self.value.get().unwrap_throw()).map_or_else(
|err| format!(r#"{{"name": "{name}", "error": "{err}"}}"#),
|value| format!(r#"{{"name": "{name}", "value": {value}}}"#),
)
}
}

pub trait DefaultMatch {
type Return;
fn spez(&self) -> Self::Return;
}
impl<T> DefaultMatch for Match<&T> {
type Return = String;
fn spez(&self) -> Self::Return {
let name = self.name;
format!(
r#"{{"name": "{name}", "error": "The trait `serde::Serialize` is not implemented"}}"#
)
}
}

#[test]
fn match_primitive() {
// String
let test = String::from("string");
let prop = (&&Match {
name: stringify! {test},
value: std::cell::Cell::new(Some(&test)),
})
.spez();
assert_eq!(prop, r#"{"name": "test", "value": "string"}"#);

// &str
let test = "string";
let prop = (&&Match {
name: stringify! {test},
value: std::cell::Cell::new(Some(&test)),
})
.spez();
assert_eq!(prop, r#"{"name": "test", "value": "string"}"#);

// u128
let test: u128 = 1;
let prop = (&&Match {
name: stringify! {test},
value: std::cell::Cell::new(Some(&test)),
})
.spez();
assert_eq!(prop, r#"{"name": "test", "value": 1}"#);

// i128
let test: i128 = -1;
let prop = (&&Match {
name: stringify! {test},
value: std::cell::Cell::new(Some(&test)),
})
.spez();
assert_eq!(prop, r#"{"name": "test", "value": -1}"#);

// f64
let test = 3.14;
let prop = (&&Match {
name: stringify! {test},
value: std::cell::Cell::new(Some(&test)),
})
.spez();
assert_eq!(prop, r#"{"name": "test", "value": 3.14}"#);

// bool
let test = true;
let prop = (&&Match {
name: stringify! {test},
value: std::cell::Cell::new(Some(&test)),
})
.spez();
assert_eq!(prop, r#"{"name": "test", "value": true}"#);
}

#[test]
fn match_serialize() {
use serde::Serialize;
#[derive(Serialize)]
struct CustomStruct {
field: &'static str,
}

let test = CustomStruct { field: "field" };
let prop = (&&Match {
name: stringify! {test},
value: std::cell::Cell::new(Some(&test)),
})
.spez();
assert_eq!(prop, r#"{"name": "test", "value": {"field":"field"}}"#);
// Verification of ownership
assert_eq!(test.field, "field");
}

#[test]
fn match_no_serialize() {
struct CustomStruct {
field: &'static str,
}

let test = CustomStruct { field: "field" };
let prop = (&&Match {
name: stringify! {test},
value: std::cell::Cell::new(Some(&test)),
})
.spez();
assert_eq!(
prop,
r#"{"name": "test", "error": "The trait `serde::Serialize` is not implemented"}"#
);
// Verification of ownership
assert_eq!(test.field, "field");
}
53 changes: 33 additions & 20 deletions leptos_macro/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,27 +178,38 @@ impl ToTokens for Model {

let component_fn_prop_docs = generate_component_fn_prop_docs(props);

let (tracing_instrument_attr, tracing_span_expr, tracing_guard_expr) =
if cfg!(feature = "tracing") {
(
quote! {
#[allow(clippy::let_with_type_underscore)]
#[cfg_attr(
any(debug_assertions, feature="ssr"),
::leptos::leptos_dom::tracing::instrument(level = "info", name = #trace_name, skip_all)
)]
},
quote! {
let span = ::leptos::leptos_dom::tracing::Span::current();
},
let (
tracing_instrument_attr,
tracing_span_expr,
tracing_guard_expr,
tracing_props_expr,
) = if cfg!(feature = "tracing") {
(
quote! {
#[allow(clippy::let_with_type_underscore)]
#[cfg_attr(
any(debug_assertions, feature="ssr"),
::leptos::leptos_dom::tracing::instrument(level = "info", name = #trace_name, skip_all)
)]
},
quote! {
let span = ::leptos::leptos_dom::tracing::Span::current();
},
quote! {
#[cfg(debug_assertions)]
let _guard = span.entered();
},
if no_props {
quote! {}
} else {
quote! {
#[cfg(debug_assertions)]
let _guard = span.entered();
},
)
} else {
(quote! {}, quote! {}, quote! {})
};
::leptos::leptos_dom::tracing_props![#prop_names];
}
},
)
} else {
(quote! {}, quote! {}, quote! {}, quote! {})
};

let component = if *is_transparent {
quote! {
Expand All @@ -211,6 +222,8 @@ impl ToTokens for Model {
move |cx| {
#tracing_guard_expr

#tracing_props_expr

#body_name(cx, #prop_names)
}
)
Expand Down

0 comments on commit 18deb39

Please sign in to comment.