bp3d_tracing/
lib.rs

1// Copyright (c) 2022, BlockProject 3D
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without modification,
6// are permitted provided that the following conditions are met:
7//
8//     * Redistributions of source code must retain the above copyright notice,
9//       this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above copyright notice,
11//       this list of conditions and the following disclaimer in the documentation
12//       and/or other materials provided with the distribution.
13//     * Neither the name of BlockProject 3D nor the names of its contributors
14//       may be used to endorse or promote products derived from this software
15//       without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29use std::any::Any;
30use std::sync::atomic::{AtomicUsize, Ordering};
31use bp3d_fs::dirs::App;
32use tracing::subscriber::set_global_default;
33use crate::core::{Tracer, TracingSystem};
34use crate::logger::Logger;
35use crate::profiler::Profiler;
36
37mod core;
38mod util;
39mod logger;
40mod profiler;
41
42/// The guard to ensure proper termination of logging and tracing systems.
43pub struct Guard(Option<Box<dyn Any>>);
44
45impl Guard {
46    /// Run the following closure then terminate logging and tracing systems.
47    pub fn run<R, F: FnOnce() -> R>(self, func: F) -> R {
48        func()
49    }
50}
51
52fn load_system<T: 'static + Tracer + Sync + Send>(system: TracingSystem<T>) -> Guard {
53    set_global_default(system.system).expect("bp3d-tracing can only be initialized once!");
54    Guard(system.destructor)
55}
56
57/// Initialize the logging and tracing systems for the given application.
58///
59/// The function returns a guard which must be maintained for the duration of the application.
60pub fn initialize<T: AsRef<str>>(app: T) -> Guard {
61    {
62        let app = App::new(app.as_ref());
63        if let Ok(v) = app.get_documents().map(|v| v.join("environment")) {
64            bp3d_env::add_override_path(&v);
65        }
66    }
67    let profiler = bp3d_env::get_bool("PROFILER").unwrap_or(false);
68    if profiler {
69        Profiler::new(app.as_ref()).map(load_system).unwrap_or_else(|_| load_system(Logger::new(app.as_ref())))
70    } else {
71        load_system(Logger::new(app.as_ref()))
72    }
73}
74
75static LOG_BUFFER_RC: AtomicUsize = AtomicUsize::new(0);
76
77static STDOUT_DISABLE_RC: AtomicUsize = AtomicUsize::new(0);
78
79/// A struct to automate management of the in-memory log buffer.
80///
81/// When a new instance of this struct is created, the log buffer is automatically enabled if not
82/// already. Inversely, when all instances of this struct are dropped, the log buffer is disabled.
83pub struct LogBuffer(bp3d_logger::LogBuffer);
84
85impl LogBuffer {
86    /// Creates a new access to the in-memory log buffer.
87    pub fn new() -> LogBuffer {
88        if LOG_BUFFER_RC.fetch_add(1, Ordering::Relaxed) == 0 {
89            //If no previous buffers were created, enable the log buffer.
90            bp3d_logger::enable_log_buffer();
91        }
92        LogBuffer(bp3d_logger::get_log_buffer())
93    }
94
95    /// Attempts to pull a message from the in-memory log buffer.
96    pub fn pull(&self) -> Option<bp3d_logger::LogMsg> {
97        self.0.try_recv().ok()
98    }
99}
100
101impl Drop for LogBuffer {
102    fn drop(&mut self) {
103        if LOG_BUFFER_RC.fetch_sub(1, Ordering::Relaxed) == 1 {
104            //If no more log buffers exists after this one, disable the log buffer.
105            bp3d_logger::disable_log_buffer();
106        }
107    }
108}
109
110/// A struct to automate enabling and disabling of the stdout/stderr logger.
111///
112/// When a new instance of this struct is created, the stdout/stderr logger is automatically
113/// disabled if not already. Inversely, when all instances of this struct are dropped, the
114/// stdout/stderr logger is re-enabled.
115pub struct DisableStdoutLogger;
116
117impl DisableStdoutLogger {
118    /// Temporarily disables stdout/stderr logging for the lifespan of this struct.
119    pub fn new() -> DisableStdoutLogger {
120        if STDOUT_DISABLE_RC.fetch_add(1, Ordering::Relaxed) == 0 {
121            //If no previous instances were created, disable the stdout/stderr logger.
122            //First, flush any waiting message.
123            bp3d_logger::flush();
124            //Then disable the backend.
125            bp3d_logger::disable_stdout();
126        }
127        DisableStdoutLogger
128    }
129}
130
131impl Drop for DisableStdoutLogger {
132    fn drop(&mut self) {
133        if STDOUT_DISABLE_RC.fetch_sub(1, Ordering::Relaxed) == 1 {
134            //If no more instances exists after this one, re-enable the stdout/stderr logger.
135            bp3d_logger::enable_stdout();
136        }
137    }
138}