#[err_span]Expand description
Error-case-only tracing for an FFI-exported fn: a trace-level skip_all
span carrying sentry.op = "ffi" / sentry.name = "<fn_name>", plus an
ERROR event on an Err return.
The span is trace-level, so under normal filters the success path emits
nothing, and skip_all keeps arguments (keys, pins, paths) off the span.
sentry.op/sentry.name are static vendor hints, as in [span].
An async fn gets more than the attribute: its body is rewritten into a
nested async move bound to a per-call Sentry Hub (bind_task_hub), so
concurrent FFI calls keep separate breadcrumb trails, and the ERROR event is
emitted by hand inside that hub instead of by instrument(err) — err
fires only after the awaited body returns, by which point the task hub is
gone and the event Sentry promotes to an issue carries none of its
breadcrumbs. A sync fn keeps plain instrument(.., err) (rare at FFI).
Unlike [span], this is napi-safe: napi-rs clones every method attribute
onto the extern "C" wrapper it generates (which returns a raw
napi_value, not Result), so a bare #[tracing::instrument(err)] on an
exported method fails to compile. This macro detects the wrapper by its
extern ABI and passes it through untouched, instrumenting only the real
method.
#[napi]
#[xmtp_common::err_span]
pub async fn sync(&self) -> Result<()> { .. }