await_tree/
span.rs

1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15type SpanName = flexstr::SharedStr;
16
17#[doc(hidden)]
18pub fn fmt_span(args: std::fmt::Arguments<'_>) -> Span {
19    let name = if let Some(str) = args.as_str() {
20        SpanName::from_ref(str)
21    } else {
22        flexstr::flex_fmt(args)
23    };
24    Span::new(name)
25}
26
27/// Creates a new span with formatted name.
28///
29/// [`instrument_await`] accepts any type that implements [`AsRef<str>`] as the span name.
30/// This macro provides similar functionality to [`format!`], but with improved performance
31/// by creating the span name on the stack when possible, avoiding unnecessary allocations.
32///
33/// [`instrument_await`]: crate::InstrumentAwait::instrument_await
34#[macro_export]
35// XXX: Without this extra binding (`let res = ..`), it will make the future `!Send`.
36//      This is also how `std::format!` behaves. But why?
37macro_rules! span {
38    ($($fmt_arg:tt)*) => {{
39        let res = $crate::__private::fmt_span(format_args!($($fmt_arg)*));
40        res
41    }};
42}
43
44/// A cheaply cloneable span in the await-tree.
45#[cfg_attr(feature = "serde", derive(serde::Serialize))]
46#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
47pub struct Span {
48    pub(crate) name: SpanName,
49    pub(crate) is_verbose: bool,
50    pub(crate) is_long_running: bool,
51}
52
53impl Span {
54    fn new(name: SpanName) -> Self {
55        Self {
56            name,
57            is_verbose: false,
58            is_long_running: false,
59        }
60    }
61}
62
63impl Span {
64    /// Set the verbose attribute of the span.
65    ///
66    /// When a span is marked as verbose, it will be included in the output
67    /// only if the `verbose` flag in the [`Config`] is set.
68    ///
69    /// [`Config`]: crate::Config
70    pub fn verbose(mut self) -> Self {
71        self.is_verbose = true;
72        self
73    }
74
75    /// Set the long-running attribute of the span.
76    ///
77    /// When a span is marked as long-running, it will not be marked as "!!!"
78    /// in the formatted [`Tree`] if it takes too long to complete. The root
79    /// span is always marked as long-running.
80    ///
81    /// [`Tree`]: crate::Tree
82    pub fn long_running(mut self) -> Self {
83        self.is_long_running = true;
84        self
85    }
86}
87
88/// Convert a value into a span and set attributes.
89#[easy_ext::ext(SpanExt)]
90impl<T: Into<Span>> T {
91    /// Convert `self` into a span and set the verbose attribute.
92    ///
93    /// See [`Span::verbose`] for more details.
94    pub fn verbose(self) -> Span {
95        self.into().verbose()
96    }
97
98    /// Convert `self` into a span and set the long-running attribute.
99    ///
100    /// See [`Span::long_running`] for more details.
101    pub fn long_running(self) -> Span {
102        self.into().long_running()
103    }
104}
105
106impl<S: AsRef<str>> From<S> for Span {
107    fn from(value: S) -> Self {
108        Self::new(SpanName::from_ref(value))
109    }
110}
111
112impl std::fmt::Display for Span {
113    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114        self.name.fmt(f)
115    }
116}