1#![doc = include_str!("../README.md")]
2
3use crate::helper::FakeSubscriber;
4use std::fmt::{Debug, Formatter};
5use tracing::subscriber::{set_global_default, NoSubscriber};
6
7mod helper;
8fn get_data() -> u64 {
9 set_global_default::<NoSubscriber> as *const () as u64
10}
11pub const FEATURE_LOG: u16 = (cfg!(feature = "log") as u16) << 0;
12fn get_features() -> u16 {
13 let mut feature = 0;
14 feature |= FEATURE_LOG;
15 feature
16}
17fn check_features(features: u16) {
18 let log_enabled = features & (1 << 0);
19 if log_enabled ^ FEATURE_LOG != 0 {
20 panic!(
21 "`feature = log` mismatch: executable = {}, dylib = {}",
22 log_enabled != 0,
23 FEATURE_LOG != 0
24 );
25 }
26}
27#[derive(Clone)]
28#[repr(C)]
29pub struct SharedLogger {
30 data: u64,
31 features: u16,
32 dispatch: tracing::Dispatch,
33 tracing_level: tracing::level_filters::LevelFilter,
34 #[cfg(feature = "log")]
35 logger: &'static dyn log::Log,
36 #[cfg(feature = "log")]
37 level: log::LevelFilter,
38}
39impl Debug for SharedLogger {
40 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
41 let mut dbg = f.debug_struct("SharedLogger");
42
43 dbg.field("data", &format_args!("{:p}", self.data as *const ()))
44 .field("features", &self.features)
45 .field("tracing_dispatch", &self.dispatch)
46 .field("tracing_level", &self.tracing_level);
47 #[cfg(feature = "log")]
48 dbg.field("log_logger", &format_args!("{:p}", self.logger))
49 .field("log_level", &self.level);
50 dbg.finish()
51 }
52}
53impl SharedLogger {
54 pub fn new() -> Self {
55 SharedLogger {
56 data: get_data(),
57 features: get_features(),
58 dispatch: tracing::dispatcher::get_default(|dispatch| dispatch.clone()),
59 tracing_level: tracing::level_filters::LevelFilter::current(),
60 #[cfg(feature = "log")]
61 logger: log::logger(),
62 #[cfg(feature = "log")]
63 level: log::max_level(),
64 }
65 }
66 #[inline(never)]
67 pub fn install(&self) {
68 if std::ptr::addr_eq(&self.data, get_data() as *const ()) {
69 panic!("SharedLogger can only be installed in dynamically linked modules, don't call it here");
70 }
71 check_features(self.features);
72 tracing::Dispatch::new(FakeSubscriber {
75 level: self.tracing_level,
76 });
77 let _ = tracing::dispatcher::set_global_default(self.dispatch.clone());
79
80 #[cfg(feature = "log")]
81 {
82 let _ = log::set_logger(self.logger);
84 log::set_max_level(self.level);
85 }
86 }
87}
88#[deprecated = "use SharedLogger::new() instead"]
89pub fn build_shared_logger() -> SharedLogger {
90 SharedLogger::new()
91}
92
93#[deprecated = "use setup_shared_logger_ref(&logger) instead. this is to prevent FFI boundary error"]
94pub fn setup_shared_logger(logger: SharedLogger) {
95 logger.install()
96}
97#[no_mangle]
109#[inline(never)]
110pub fn setup_shared_logger_ref(logger: &SharedLogger) {
111 logger.install()
112}