storage_trace/
lib.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#[cfg(feature = "tracing")]
6mod fuchsia;
7#[cfg(feature = "tracing")]
8pub mod __backend {
9    pub use crate::fuchsia::*;
10}
11
12#[cfg(not(feature = "tracing"))]
13mod noop;
14#[cfg(not(feature = "tracing"))]
15pub mod __backend {
16    pub use crate::noop::*;
17}
18
19pub use __backend::{Id, TraceFutureExt};
20
21/// Convenience macro for creating a trace duration event from this macro invocation to the end of
22/// the current scope.
23///
24/// See `fuchsia_trace::duration!` for more details.
25#[macro_export]
26macro_rules! duration {
27    ($category:expr, $name:expr $(, $key:expr => $val:expr)*) => {
28        let args;
29        let _scope = {
30            static CACHE: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
31            if $crate::__backend::TraceCategoryContext::acquire_cached($category, &CACHE)
32                .is_some()
33            {
34                args = [$($crate::__backend::ArgValue::of($key, $val)),*];
35                Some($crate::__backend::duration($category, $name, &args))
36            } else {
37                None
38            }
39        };
40    }
41}
42
43/// Writes a flow begin event with the specified id.
44///
45/// See `fuchsia_trace::flow_begin!` for more details.
46#[macro_export]
47macro_rules! flow_begin {
48    ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
49        static CACHE: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
50        if let Some(context) =
51            $crate::__backend::TraceCategoryContext::acquire_cached($category, &CACHE)
52        {
53            $crate::__backend::flow_begin(&context, $name, ($flow_id).into(),
54                                          &[$($crate::__backend::ArgValue::of($key, $val)),*])
55        }
56    }}
57}
58
59/// Writes a flow step event with the specified id.
60///
61/// See `fuchsia_trace::flow_step!` for more details.
62#[macro_export]
63macro_rules! flow_step {
64    ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
65        static CACHE: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
66        if let Some(context) =
67            $crate::__backend::TraceCategoryContext::acquire_cached($category, &CACHE)
68        {
69            $crate::__backend::flow_step(&context, $name, ($flow_id).into(),
70                                         &[$($crate::__backend::ArgValue::of($key, $val)),*])
71        }
72    }}
73}
74
75/// Writes a flow end event with the specified id.
76///
77/// See `fuchsia_trace::flow_end!` for more details.
78#[macro_export]
79macro_rules! flow_end {
80    ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
81        static CACHE: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
82        if let Some(context) =
83            $crate::__backend::TraceCategoryContext::acquire_cached($category, &CACHE)
84        {
85            $crate::__backend::flow_end(&context, $name, ($flow_id).into(),
86                                        &[$($crate::__backend::ArgValue::of($key, $val)),*])
87        }
88    }}
89}
90
91/// Constructs a `TraceFutureArgs` object to be passed to `TraceFutureExt::trace`.
92///
93/// See `fuchsia_trace::trace_future_args!` for more details.
94#[macro_export]
95macro_rules! trace_future_args {
96    ($category:expr, $name:expr $(, $key:expr => $val:expr)*) => {{
97        static CACHE: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
98        let context = $crate::__backend::TraceCategoryContext::acquire_cached($category, &CACHE);
99        let args = if context.is_some() {
100            vec![$($crate::__backend::ArgValue::of($key, $val)),*]
101        } else {
102            vec![]
103        };
104        $crate::__backend::trace_future_args(context, $category, $name, args)
105    }}
106}
107
108#[cfg(test)]
109mod tests {
110    use crate::TraceFutureExt;
111
112    #[fuchsia::test]
113    fn test_duration() {
114        let trace_only_var = 6;
115        duration!(c"category", c"name");
116        duration!(c"category", c"name", "arg" => 5);
117        duration!(c"category", c"name", "arg" => 5, "arg2" => trace_only_var);
118    }
119
120    #[fuchsia::test]
121    fn test_flow_begin() {
122        let trace_only_var = 6;
123        let flow_id = 5u64;
124        flow_begin!(c"category", c"name", flow_id);
125        flow_begin!(c"category", c"name", flow_id, "arg" => 5);
126        flow_begin!(c"category", c"name", flow_id, "arg" => 5, "arg2" => trace_only_var);
127    }
128
129    #[fuchsia::test]
130    fn test_flow_step() {
131        let trace_only_var = 6;
132        let flow_id = 5u64;
133        flow_step!(c"category", c"name", flow_id);
134        flow_step!(c"category", c"name", flow_id, "arg" => 5);
135        flow_step!(c"category", c"name", flow_id, "arg" => 5, "arg2" => trace_only_var);
136    }
137
138    #[fuchsia::test]
139    fn test_flow_end() {
140        let trace_only_var = 6;
141        let flow_id = 5u64;
142        flow_end!(c"category", c"name", flow_id);
143        flow_end!(c"category", c"name", flow_id, "arg" => 5);
144        flow_end!(c"category", c"name", flow_id, "arg" => 5, "arg2" => trace_only_var);
145    }
146
147    #[fuchsia::test]
148    async fn test_trace_future() {
149        let value = async move { 5 }.trace(trace_future_args!(c"category", c"name")).await;
150        assert_eq!(value, 5);
151
152        let value =
153            async move { 5 }.trace(trace_future_args!(c"category", c"name", "arg1" => 6)).await;
154        assert_eq!(value, 5);
155
156        let trace_only_var = 7;
157        let value = async move { 5 }
158            .trace(trace_future_args!(c"category", c"name", "arg1" => 6, "ar2" => trace_only_var))
159            .await;
160        assert_eq!(value, 5);
161    }
162
163    #[fuchsia::test]
164    fn test_arg_types() {
165        duration!(c"category", c"name", "bool" => true);
166        duration!(c"category", c"name", "i32" => 5i32, "u32" => 5u32);
167        duration!(c"category", c"name", "i64" => 5i64, "u64" => 5u64);
168        duration!(c"category", c"name", "isize" => 5isize, "usize" => 5usize);
169        duration!(c"category", c"name", "f64" => 5f64);
170
171        let owned_str = "test-str".to_owned();
172        duration!(c"category", c"name", "str" => owned_str.as_str());
173
174        let mut value = 5u64;
175        duration!(c"category", c"name", "const-ptr" => &value as *const u64);
176        duration!(c"category", c"name", "mut-ptr" => &mut value as *mut u64);
177    }
178}