1#![allow(clippy::missing_panics_doc, clippy::should_implement_trait)]
2
3use core::ffi::c_void;
4use std::ptr::NonNull;
5
6use crate::bridge_support::{bridge_ptr_result, c_string_arg, sanitized_c_string};
7use crate::error::LogError;
8use crate::ffi;
9use crate::os_log::{Level, OSLog};
10use crate::os_signpost_id::OSSignpostId;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum Privacy {
15 Public,
16 Private,
17}
18
19impl Privacy {
20 const fn raw(self) -> i32 {
21 match self {
22 Self::Public => 0,
23 Self::Private => 1,
24 }
25 }
26}
27
28const fn severity_for_level(level: Level) -> i32 {
29 match level {
30 Level::Default => 0,
31 Level::Debug => 2,
32 Level::Info => 3,
33 Level::Error => 6,
34 Level::Fault => 8,
35 }
36}
37
38pub struct Logger {
40 ptr: NonNull<c_void>,
41}
42
43impl Logger {
44 fn bridge_default() -> Self {
45 Self {
46 ptr: NonNull::new(unsafe { ffi::apple_log_logger_default() })
47 .expect("Swift bridge never returns NULL for Logger.default"),
48 }
49 }
50
51 pub fn new(subsystem: &str, category: &str) -> Result<Self, LogError> {
57 let subsystem = c_string_arg("subsystem", subsystem)?;
58 let category = c_string_arg("category", category)?;
59 let ptr = bridge_ptr_result("Logger::new", |error_out| unsafe {
60 ffi::apple_log_logger_create(subsystem.as_ptr(), category.as_ptr(), error_out)
61 })?;
62 Ok(Self { ptr })
63 }
64
65 pub fn from_os_log(log: &OSLog) -> Result<Self, LogError> {
71 let ptr = bridge_ptr_result("Logger::from_os_log", |error_out| unsafe {
72 ffi::apple_log_logger_from_os_log(log.as_ptr(), error_out)
73 })?;
74 Ok(Self { ptr })
75 }
76
77 #[must_use]
79 pub fn default() -> Self {
80 Self::bridge_default()
81 }
82
83 #[must_use]
85 pub fn disabled() -> Self {
86 Self {
87 ptr: NonNull::new(unsafe { ffi::apple_log_logger_disabled() })
88 .expect("Swift bridge never returns NULL for Logger.disabled"),
89 }
90 }
91
92 fn write(&self, severity: i32, privacy: Privacy, message: &str) {
93 let message = sanitized_c_string(message);
94 unsafe {
95 ffi::apple_log_logger_log(self.ptr.as_ptr(), severity, privacy.raw(), message.as_ptr());
96 }
97 }
98
99 pub fn log(&self, level: Level, message: &str) {
101 self.write(severity_for_level(level), Privacy::Public, message);
102 }
103
104 pub fn log_with_privacy(&self, level: Level, message: &str, privacy: Privacy) {
106 self.write(severity_for_level(level), privacy, message);
107 }
108
109 pub fn trace(&self, message: &str) {
110 self.write(1, Privacy::Public, message);
111 }
112
113 pub fn debug(&self, message: &str) {
114 self.write(2, Privacy::Public, message);
115 }
116
117 pub fn info(&self, message: &str) {
118 self.write(3, Privacy::Public, message);
119 }
120
121 pub fn notice(&self, message: &str) {
122 self.write(4, Privacy::Public, message);
123 }
124
125 pub fn warning(&self, message: &str) {
126 self.write(5, Privacy::Public, message);
127 }
128
129 pub fn error(&self, message: &str) {
130 self.write(6, Privacy::Public, message);
131 }
132
133 pub fn critical(&self, message: &str) {
134 self.write(7, Privacy::Public, message);
135 }
136
137 pub fn fault(&self, message: &str) {
138 self.write(8, Privacy::Public, message);
139 }
140
141 #[must_use]
143 pub fn is_enabled(&self, level: Level) -> bool {
144 unsafe { ffi::apple_log_logger_is_enabled(self.ptr.as_ptr(), level as u8) }
145 }
146
147 #[must_use]
149 pub fn signpost_id(&self) -> OSSignpostId {
150 OSSignpostId::from_u64(unsafe { ffi::apple_log_logger_signpost_id(self.ptr.as_ptr()) })
151 }
152
153 #[must_use]
155 pub fn signpost_id_from_pointer<T>(&self, pointer: *const T) -> OSSignpostId {
156 OSSignpostId::from_u64(unsafe {
157 ffi::apple_log_logger_signpost_id_from_pointer(self.ptr.as_ptr(), pointer.cast())
158 })
159 }
160
161 #[must_use]
163 pub fn signposts_enabled(&self) -> bool {
164 unsafe { ffi::apple_log_logger_signposts_enabled(self.ptr.as_ptr()) }
165 }
166
167 pub fn signpost_event(&self, id: OSSignpostId, name: &str, message: &str) {
168 let name = sanitized_c_string(name);
169 let message = sanitized_c_string(message);
170 unsafe {
171 ffi::apple_log_logger_signpost_event(
172 self.ptr.as_ptr(),
173 id.as_u64(),
174 name.as_ptr(),
175 message.as_ptr(),
176 );
177 }
178 }
179
180 pub fn signpost_interval_begin(&self, id: OSSignpostId, name: &str) {
181 let name = sanitized_c_string(name);
182 unsafe {
183 ffi::apple_log_logger_signpost_interval_begin(
184 self.ptr.as_ptr(),
185 id.as_u64(),
186 name.as_ptr(),
187 );
188 }
189 }
190
191 pub fn signpost_animation_interval_begin(&self, id: OSSignpostId, name: &str) {
192 let name = sanitized_c_string(name);
193 unsafe {
194 ffi::apple_log_logger_signpost_animation_interval_begin(
195 self.ptr.as_ptr(),
196 id.as_u64(),
197 name.as_ptr(),
198 );
199 }
200 }
201
202 pub fn signpost_interval_end(&self, id: OSSignpostId, name: &str) {
203 let name = sanitized_c_string(name);
204 unsafe {
205 ffi::apple_log_logger_signpost_interval_end(self.ptr.as_ptr(), id.as_u64(), name.as_ptr());
206 }
207 }
208
209 pub(crate) const fn as_ptr(&self) -> *mut c_void {
210 self.ptr.as_ptr()
211 }
212}
213
214impl Default for Logger {
215 fn default() -> Self {
216 Self::bridge_default()
217 }
218}
219
220impl Drop for Logger {
221 fn drop(&mut self) {
222 unsafe { ffi::apple_log_logger_release(self.ptr.as_ptr()) };
223 }
224}