use crate::binder::TransactionCode;
#[cfg(any(feature = "tracing", test))]
use std::fmt;
#[cfg(any(feature = "tracing", test))]
pub(crate) struct AidlSpanName<'a> {
pub(crate) descriptor: &'a str,
pub(crate) method: Option<&'a str>,
pub(crate) code: TransactionCode,
pub(crate) server: bool,
}
#[cfg(any(feature = "tracing", test))]
impl fmt::Display for AidlSpanName<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "AIDL::rust::{}::", self.descriptor)?;
match self.method {
Some(method) => f.write_str(method)?,
None => write!(f, "#{}", self.code)?,
}
f.write_str(if self.server { "::server" } else { "::client" })
}
}
#[doc(hidden)]
#[must_use]
pub struct __ClientSpan {
#[cfg(feature = "tracing")]
span: tracing::Span,
}
impl __ClientSpan {
#[inline]
pub fn in_scope<R>(&self, f: impl FnOnce() -> R) -> R {
#[cfg(feature = "tracing")]
{
self.span.in_scope(f)
}
#[cfg(not(feature = "tracing"))]
{
f()
}
}
}
#[doc(hidden)]
#[inline]
pub fn __trace_client(
descriptor: &'static str,
method: &'static str,
code: TransactionCode,
) -> __ClientSpan {
#[cfg(feature = "tracing")]
{
let name = AidlSpanName {
descriptor,
method: Some(method),
code,
server: false,
};
__ClientSpan {
span: tracing::trace_span!(target: "rsbinder::aidl", "aidl", name = %name),
}
}
#[cfg(not(feature = "tracing"))]
{
let _ = (descriptor, method, code);
__ClientSpan {}
}
}
#[cfg(feature = "tracing")]
pub use tracing_observer::TracingObserver;
#[cfg(feature = "tracing")]
mod tracing_observer {
use super::AidlSpanName;
use crate::observe::{TransactionObserver, TxnContext};
use crate::Result;
use std::any::Any;
use std::time::Duration;
#[derive(Debug, Default, Clone, Copy)]
pub struct TracingObserver;
impl TransactionObserver for TracingObserver {
fn on_transact(&self, ctx: &TxnContext<'_>) -> Option<Box<dyn Any + Send>> {
let name = AidlSpanName {
descriptor: ctx.descriptor,
method: ctx.method,
code: ctx.code,
server: true,
};
let span = tracing::trace_span!(target: "rsbinder::aidl", "aidl", name = %name);
span.with_subscriber(|(id, dispatch)| dispatch.enter(id))?;
Some(Box::new(span))
}
fn on_reply(
&self,
_ctx: &TxnContext<'_>,
tag: Option<Box<dyn Any + Send>>,
_result: &Result<()>,
_elapsed: Duration,
) {
if let Some(span) = tag.and_then(|tag| tag.downcast::<tracing::Span>().ok()) {
span.with_subscriber(|(id, dispatch)| dispatch.exit(id));
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn span_name_follows_aosp() {
let name = |method, code, server| {
AidlSpanName {
descriptor: "a.b.IFoo",
method,
code,
server,
}
.to_string()
};
assert_eq!(
name(Some("bar"), 1, true),
"AIDL::rust::a.b.IFoo::bar::server"
);
assert_eq!(
name(Some("bar"), 1, false),
"AIDL::rust::a.b.IFoo::bar::client"
);
assert_eq!(
name(None, 0x5f504e47, true),
"AIDL::rust::a.b.IFoo::#1599098439::server"
);
}
}