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}