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, Scope, 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/// Convenience macro for creating an instant event.
44///
45/// See `fuchsia_trace::instant!` for more details.
46#[macro_export]
47macro_rules! instant {
48    ($category:expr, $name:expr, $scope: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::instant(&context, $name, $scope,
54                                        &[$($crate::__backend::ArgValue::of($key, $val)),*])
55        }
56    }}
57}
58
59/// Writes a flow begin event with the specified id.
60///
61/// See `fuchsia_trace::flow_begin!` for more details.
62#[macro_export]
63macro_rules! flow_begin {
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_begin(&context, $name, ($flow_id).into(),
70                                          &[$($crate::__backend::ArgValue::of($key, $val)),*])
71        }
72    }}
73}
74
75/// Writes a flow step event with the specified id.
76///
77/// See `fuchsia_trace::flow_step!` for more details.
78#[macro_export]
79macro_rules! flow_step {
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_step(&context, $name, ($flow_id).into(),
86                                         &[$($crate::__backend::ArgValue::of($key, $val)),*])
87        }
88    }}
89}
90
91/// Writes a flow end event with the specified id.
92///
93/// See `fuchsia_trace::flow_end!` for more details.
94#[macro_export]
95macro_rules! flow_end {
96    ($category:expr, $name:expr, $flow_id:expr $(, $key:expr => $val:expr)*) => {{
97        static CACHE: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
98        if let Some(context) =
99            $crate::__backend::TraceCategoryContext::acquire_cached($category, &CACHE)
100        {
101            $crate::__backend::flow_end(&context, $name, ($flow_id).into(),
102                                        &[$($crate::__backend::ArgValue::of($key, $val)),*])
103        }
104    }}
105}
106
107/// Constructs a `TraceFutureArgs` object to be passed to `TraceFutureExt::trace`.
108///
109/// See `fuchsia_trace::trace_future_args!` for more details.
110#[macro_export]
111macro_rules! trace_future_args {
112    ($category:expr, $name:expr $(, $key:expr => $val:expr)*) => {{
113        static CACHE: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
114        let context = $crate::__backend::TraceCategoryContext::acquire_cached($category, &CACHE);
115        let args = if context.is_some() {
116            vec![$($crate::__backend::ArgValue::of($key, $val)),*]
117        } else {
118            vec![]
119        };
120        $crate::__backend::trace_future_args(context, $category, $name, args)
121    }}
122}
123
124#[cfg(test)]
125mod tests {
126    use crate::{Scope, TraceFutureExt};
127
128    #[fuchsia::test]
129    fn test_duration() {
130        let trace_only_var = 6;
131        duration!(c"category", c"name");
132        duration!(c"category", c"name", "arg" => 5);
133        duration!(c"category", c"name", "arg" => 5, "arg2" => trace_only_var);
134    }
135
136    #[fuchsia::test]
137    fn test_instant() {
138        let trace_only_var = 6;
139        instant!(c"category", c"name", Scope::Thread);
140        instant!(c"category", c"name", Scope::Thread, "arg" => 5);
141        instant!(c"category", c"name", Scope::Thread, "arg" => 5, "arg2" => trace_only_var);
142    }
143
144    #[fuchsia::test]
145    fn test_flow_begin() {
146        let trace_only_var = 6;
147        let flow_id = 5u64;
148        flow_begin!(c"category", c"name", flow_id);
149        flow_begin!(c"category", c"name", flow_id, "arg" => 5);
150        flow_begin!(c"category", c"name", flow_id, "arg" => 5, "arg2" => trace_only_var);
151    }
152
153    #[fuchsia::test]
154    fn test_flow_step() {
155        let trace_only_var = 6;
156        let flow_id = 5u64;
157        flow_step!(c"category", c"name", flow_id);
158        flow_step!(c"category", c"name", flow_id, "arg" => 5);
159        flow_step!(c"category", c"name", flow_id, "arg" => 5, "arg2" => trace_only_var);
160    }
161
162    #[fuchsia::test]
163    fn test_flow_end() {
164        let trace_only_var = 6;
165        let flow_id = 5u64;
166        flow_end!(c"category", c"name", flow_id);
167        flow_end!(c"category", c"name", flow_id, "arg" => 5);
168        flow_end!(c"category", c"name", flow_id, "arg" => 5, "arg2" => trace_only_var);
169    }
170
171    #[fuchsia::test]
172    async fn test_trace_future() {
173        let value = async move { 5 }.trace(trace_future_args!(c"category", c"name")).await;
174        assert_eq!(value, 5);
175
176        let value =
177            async move { 5 }.trace(trace_future_args!(c"category", c"name", "arg1" => 6)).await;
178        assert_eq!(value, 5);
179
180        let trace_only_var = 7;
181        let value = async move { 5 }
182            .trace(trace_future_args!(c"category", c"name", "arg1" => 6, "ar2" => trace_only_var))
183            .await;
184        assert_eq!(value, 5);
185    }
186
187    #[fuchsia::test]
188    fn test_arg_types() {
189        duration!(c"category", c"name", "bool" => true);
190        duration!(c"category", c"name", "i32" => 5i32, "u32" => 5u32);
191        duration!(c"category", c"name", "i64" => 5i64, "u64" => 5u64);
192        duration!(c"category", c"name", "isize" => 5isize, "usize" => 5usize);
193        duration!(c"category", c"name", "f64" => 5f64);
194
195        let owned_str = "test-str".to_owned();
196        duration!(c"category", c"name", "str" => owned_str.as_str());
197
198        let mut value = 5u64;
199        duration!(c"category", c"name", "const-ptr" => &value as *const u64);
200        duration!(c"category", c"name", "mut-ptr" => &mut value as *mut u64);
201    }
202}