feat: `tracing` support for component props (#1531)
This commit is contained in:
parent
d9abebb4be
commit
18deb398ca
|
@ -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"] }
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -178,8 +178,12 @@ 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") {
|
||||
let (
|
||||
tracing_instrument_attr,
|
||||
tracing_span_expr,
|
||||
tracing_guard_expr,
|
||||
tracing_props_expr,
|
||||
) = if cfg!(feature = "tracing") {
|
||||
(
|
||||
quote! {
|
||||
#[allow(clippy::let_with_type_underscore)]
|
||||
|
@ -195,9 +199,16 @@ impl ToTokens for Model {
|
|||
#[cfg(debug_assertions)]
|
||||
let _guard = span.entered();
|
||||
},
|
||||
if no_props {
|
||||
quote! {}
|
||||
} else {
|
||||
quote! {
|
||||
::leptos::leptos_dom::tracing_props![#prop_names];
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
(quote! {}, quote! {}, quote! {})
|
||||
(quote! {}, quote! {}, quote! {}, quote! {})
|
||||
};
|
||||
|
||||
let component = if *is_transparent {
|
||||
|
@ -211,6 +222,8 @@ impl ToTokens for Model {
|
|||
move |cx| {
|
||||
#tracing_guard_expr
|
||||
|
||||
#tracing_props_expr
|
||||
|
||||
#body_name(cx, #prop_names)
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue