use core::ptr;
use std::ffi::CString;
use crate::error::LogError;
use crate::ffi;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum Level {
Default = ffi::level::DEFAULT,
Info = ffi::level::INFO,
Debug = ffi::level::DEBUG,
Error = ffi::level::ERROR,
Fault = ffi::level::FAULT,
}
pub struct Logger {
raw: ffi::os_log_t,
}
unsafe impl Send for Logger {}
unsafe impl Sync for Logger {}
impl Drop for Logger {
fn drop(&mut self) {
if !self.raw.is_null() {
unsafe { ffi::apple_log_release(self.raw) };
self.raw = ptr::null_mut();
}
}
}
impl Logger {
pub fn new(subsystem: &str, category: &str) -> Result<Self, LogError> {
let s =
CString::new(subsystem).map_err(|e| LogError::InvalidArgument(e.to_string()))?;
let c =
CString::new(category).map_err(|e| LogError::InvalidArgument(e.to_string()))?;
let raw = unsafe { ffi::apple_log_create(s.as_ptr(), c.as_ptr()) };
if raw.is_null() {
Err(LogError::CreateFailed)
} else {
Ok(Self { raw })
}
}
pub fn log(&self, level: Level, message: &str) {
let Ok(c) = CString::new(message.replace('\0', "\u{fffd}")) else {
return;
};
unsafe { ffi::apple_log_emit(self.raw, level as i32, c.as_ptr()) };
}
pub fn info(&self, message: &str) {
self.log(Level::Info, message);
}
pub fn debug(&self, message: &str) {
self.log(Level::Debug, message);
}
pub fn error(&self, message: &str) {
self.log(Level::Error, message);
}
pub fn fault(&self, message: &str) {
self.log(Level::Fault, message);
}
#[must_use]
pub fn is_enabled(&self, level: Level) -> bool {
unsafe { ffi::apple_log_type_enabled(self.raw, level as i32) }
}
#[must_use]
pub fn signpost_id(&self) -> SignpostId {
SignpostId(unsafe { ffi::apple_signpost_id_generate(self.raw) })
}
#[must_use]
pub fn signposts_enabled(&self) -> bool {
unsafe { ffi::apple_signpost_enabled(self.raw) }
}
pub fn signpost_event(&self, id: SignpostId, name: &str, message: &str) {
let Ok(n) = CString::new(name.replace('\0', "\u{fffd}")) else {
return;
};
let Ok(m) = CString::new(message.replace('\0', "\u{fffd}")) else {
return;
};
unsafe { ffi::apple_signpost_event_emit(self.raw, id.0, n.as_ptr(), m.as_ptr()) };
}
pub fn signpost_interval_begin(&self, id: SignpostId, name: &str) {
let Ok(n) = CString::new(name.replace('\0', "\u{fffd}")) else {
return;
};
unsafe { ffi::apple_signpost_interval_begin(self.raw, id.0, n.as_ptr()) };
}
pub fn signpost_interval_end(&self, id: SignpostId, name: &str) {
let Ok(n) = CString::new(name.replace('\0', "\u{fffd}")) else {
return;
};
unsafe { ffi::apple_signpost_interval_end(self.raw, id.0, n.as_ptr()) };
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SignpostId(u64);
impl SignpostId {
#[must_use]
pub const fn as_u64(self) -> u64 {
self.0
}
}
pub fn log(level: Level, message: &str) {
let Ok(c) = CString::new(message.replace('\0', "\u{fffd}")) else {
return;
};
unsafe { ffi::apple_log_emit_default(level as i32, c.as_ptr()) };
}