use std::any::Any;
use std::fmt::{Debug, Display};
use crate::components::trace::OneTrace;
use crate::components::level::Level;
use std::sync::{OnceLock};
use time::OffsetDateTime;
use crate::components::hbacktrace::Hbacktrace;
use crate::components::context::Context;
use crate::context_manager::ContextManager;
use crate::thread_manager::{ThreadManager, MAIN_THREAD};
use std::{mem, thread};
use std::thread::sleep;
use std::time::Duration;
use singletonThread::SingletonThread;
use parking_lot::RwLock;
#[cfg(any(feature = "tracing_consumer",feature = "log_consumer"))]
use crate::crates::bridge::HtraceBridge;
pub struct HTracer
{
_deferredTraces: RwLock<Vec<OneTrace>>,
_threadWriting: RwLock<SingletonThread>
}
static CONTEXTSET: OnceLock<RwLock<bool>> = OnceLock::new();
static SINGLETON: OnceLock<HTracer> = OnceLock::new();
impl HTracer
{
pub fn singleton() -> &'static HTracer
{
if(*CONTEXTSET.get_or_init(|| RwLock::new(false)).read() == false) {
panic!("[Htrace] globalContext_set() must be called before singleton()");
}
return SINGLETON.get_or_init(|| {
HTracer::new()
});
}
pub fn globalContext_set(mut context: Context,
#[cfg(any(feature = "tracing_consumer",feature = "log_consumer"))]
bridge: HtraceBridge)
{
let contextSet = CONTEXTSET.get_or_init(|| RwLock::new(false));
if(context.threadName_get().is_none())
{
context.threadName_set(MAIN_THREAD);
}
if(*contextSet.read() == false)
{
#[cfg(feature = "log_consumer")]
{
if let Some(minlevel) = context.level_getMin()
{
log::set_max_level(crate::crates::log::LogHtraceToLogLevelMapper(minlevel).to_level_filter());
}
if let Err(err) = log::set_boxed_logger(Box::new(bridge.clone()))
{
log::warn!("[Htrace] global default tracing-subscriber is already set : {}",err);
}
}
#[cfg(feature = "tracing_consumer")]
{
use tracing_subscriber::layer::SubscriberExt;
let subscriber = tracing_subscriber::Registry::default()
.with(bridge.filtered());
if let Err(err) = tracing::subscriber::set_global_default(subscriber)
{
tracing::warn!("[Htrace] global default tracing-subscriber is already set : {}",err);
}
}
}
ContextManager::singleton().global_set(context);
ThreadManager::local_setName(MAIN_THREAD);
*contextSet.write() = true;
HTracer::singleton();
}
pub fn trace<T>(rawEntry : &T, level: Level, file: &str, line: u32, backtraces: Vec<Hbacktrace>)
where T: Any + Debug {
let anyEntry = rawEntry as &dyn Any;
let tmp = if let Some(content) = anyEntry.downcast_ref::<String>() {
content.to_string()
}
else
{
if let Some(content) = anyEntry.downcast_ref::<&str>()
{
content.to_string()
}
else
{
if let Some(content)= anyEntry.downcast_ref::<Box<dyn Display>>()
{
format!("{}", content)
}
else
{
format!("{:?}", rawEntry)
}
}
};
let context = ContextManager::singleton().resolve();
if(level.tou8() < context.level_getMin().unwrap_or(&Level::DEBUG).tou8()) {
return;
}
let trace = OneTrace {
message: tmp.clone(),
date: OffsetDateTime::now_utc(),
level,
context,
filename: file.to_string(),
fileline: line,
backtraces,
};
thread::spawn(move ||{
Self::singleton()._deferredTraces.write().push(trace);
Self::singleton()._threadWriting.write().thread_launch_delayabe();
});
}
pub fn backtrace(base: &str) -> Vec<Hbacktrace>
{
let mut internal = true;
let mut returning = Vec::new();
let bt = backtrace::Backtrace::new();
let thisBTName = bt.frames()[0].symbols()[0].name().map(|x| x.to_string()).unwrap_or_default();
backtrace::trace(|x|{
backtrace::resolve_frame(x, |symbol| {
let name = symbol.name().map(|sbname| sbname.to_string());
let filename = symbol.filename().map(|x| x.to_str().unwrap_or_default().to_string());
let line = symbol.lineno();
let Some(name) = name else {return;};
let mut normalizedName = name.clone();
if let Some((splitted,_)) = name.rsplit_once("::")
{
normalizedName = format!("{}()",splitted);
}
match &filename
{
None => {
if(name == thisBTName)
{
internal = false;
return; }
}
Some(filename) => {
if(filename.ends_with(base))
{
internal = false;
}
if(filename.starts_with("/rustc/")) {
return;
}
}
}
if !internal
{
returning.push(Hbacktrace {
funcName: normalizedName,
fileName: filename,
line,
});
}
});
true
});
return returning;
}
pub fn drop()
{
sleep(Duration::from_millis(1));
Self::singleton()._threadWriting.write().loop_set(false);
let _ = Self::singleton()._threadWriting.write().wait();
let remainTraces = Self::singleton()._deferredTraces.read().len();
if(remainTraces > 0)
{
Self::singleton().internal_writeTraces();
}
}
fn new() -> HTracer {
let thread = SingletonThread::new(||{
Self::singleton().internal_writeTraces();
});
return HTracer {
_deferredTraces: RwLock::new(vec![]),
_threadWriting: RwLock::new(thread),
};
}
fn internal_writeTraces(&self)
{
let mut getWritingStuff = {
let mut binding = Self::singleton()._deferredTraces.write();
mem::replace(&mut *binding,vec![])
};
getWritingStuff.sort_by(|a,b| a.date.cmp(&b.date));
for x in getWritingStuff {
x.emit();
}
}
}