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 {
47 ffi::apple_log_logger_default()
51 })
52 .expect("Swift bridge never returns NULL for Logger.default"),
53 }
54 }
55
56 pub fn new(subsystem: &str, category: &str) -> Result<Self, LogError> {
62 let subsystem = c_string_arg("subsystem", subsystem)?;
63 let category = c_string_arg("category", category)?;
64 let ptr = bridge_ptr_result("Logger::new", |error_out| unsafe {
65 ffi::apple_log_logger_create(subsystem.as_ptr(), category.as_ptr(), error_out)
69 })?;
70 Ok(Self { ptr })
71 }
72
73 pub fn from_os_log(log: &OSLog) -> Result<Self, LogError> {
79 let ptr = bridge_ptr_result("Logger::from_os_log", |error_out| unsafe {
80 ffi::apple_log_logger_from_os_log(log.as_ptr(), error_out)
83 })?;
84 Ok(Self { ptr })
85 }
86
87 #[must_use]
89 pub fn default() -> Self {
90 Self::bridge_default()
91 }
92
93 #[must_use]
95 pub fn disabled() -> Self {
96 Self {
97 ptr: NonNull::new(unsafe {
98 ffi::apple_log_logger_disabled()
102 })
103 .expect("Swift bridge never returns NULL for Logger.disabled"),
104 }
105 }
106
107 fn write(&self, severity: i32, privacy: Privacy, message: &str) {
108 let message = sanitized_c_string(message);
109 unsafe {
110 ffi::apple_log_logger_log(self.ptr.as_ptr(), severity, privacy.raw(), message.as_ptr());
114 }
115 }
116
117 pub fn log(&self, level: Level, message: &str) {
119 self.write(severity_for_level(level), Privacy::Public, message);
120 }
121
122 pub fn log_with_privacy(&self, level: Level, message: &str, privacy: Privacy) {
124 self.write(severity_for_level(level), privacy, message);
125 }
126
127 pub fn trace(&self, message: &str) {
128 self.write(1, Privacy::Public, message);
129 }
130
131 pub fn debug(&self, message: &str) {
132 self.write(2, Privacy::Public, message);
133 }
134
135 pub fn info(&self, message: &str) {
136 self.write(3, Privacy::Public, message);
137 }
138
139 pub fn notice(&self, message: &str) {
140 self.write(4, Privacy::Public, message);
141 }
142
143 pub fn warning(&self, message: &str) {
144 self.write(5, Privacy::Public, message);
145 }
146
147 pub fn error(&self, message: &str) {
148 self.write(6, Privacy::Public, message);
149 }
150
151 pub fn critical(&self, message: &str) {
152 self.write(7, Privacy::Public, message);
153 }
154
155 pub fn fault(&self, message: &str) {
156 self.write(8, Privacy::Public, message);
157 }
158
159 #[must_use]
161 pub fn is_enabled(&self, level: Level) -> bool {
162 unsafe {
163 ffi::apple_log_logger_is_enabled(self.ptr.as_ptr(), level as u8)
166 }
167 }
168
169 #[must_use]
171 pub fn signpost_id(&self) -> OSSignpostId {
172 OSSignpostId::from_u64(unsafe {
173 ffi::apple_log_logger_signpost_id(self.ptr.as_ptr())
176 })
177 }
178
179 #[must_use]
181 pub fn signpost_id_from_pointer<T>(&self, pointer: *const T) -> OSSignpostId {
182 OSSignpostId::from_u64(unsafe {
183 ffi::apple_log_logger_signpost_id_from_pointer(self.ptr.as_ptr(), pointer.cast())
187 })
188 }
189
190 #[must_use]
192 pub fn signposts_enabled(&self) -> bool {
193 unsafe {
194 ffi::apple_log_logger_signposts_enabled(self.ptr.as_ptr())
197 }
198 }
199
200 pub fn signpost_event(&self, id: OSSignpostId, name: &str, message: &str) {
201 let name = sanitized_c_string(name);
202 let message = sanitized_c_string(message);
203 unsafe {
204 ffi::apple_log_logger_signpost_event(
207 self.ptr.as_ptr(),
208 id.as_u64(),
209 name.as_ptr(),
210 message.as_ptr(),
211 );
212 }
213 }
214
215 pub fn signpost_interval_begin(&self, id: OSSignpostId, name: &str) {
216 let name = sanitized_c_string(name);
217 unsafe {
218 ffi::apple_log_logger_signpost_interval_begin(
221 self.ptr.as_ptr(),
222 id.as_u64(),
223 name.as_ptr(),
224 );
225 }
226 }
227
228 pub fn signpost_animation_interval_begin(&self, id: OSSignpostId, name: &str) {
229 let name = sanitized_c_string(name);
230 unsafe {
231 ffi::apple_log_logger_signpost_animation_interval_begin(
234 self.ptr.as_ptr(),
235 id.as_u64(),
236 name.as_ptr(),
237 );
238 }
239 }
240
241 pub fn signpost_interval_end(&self, id: OSSignpostId, name: &str) {
242 let name = sanitized_c_string(name);
243 unsafe {
244 ffi::apple_log_logger_signpost_interval_end(
247 self.ptr.as_ptr(),
248 id.as_u64(),
249 name.as_ptr(),
250 );
251 }
252 }
253
254 pub(crate) const fn as_ptr(&self) -> *mut c_void {
255 self.ptr.as_ptr()
256 }
257}
258
259impl Default for Logger {
260 fn default() -> Self {
261 Self::bridge_default()
262 }
263}
264
265impl Drop for Logger {
266 fn drop(&mut self) {
267 unsafe {
268 ffi::apple_log_logger_release(self.ptr.as_ptr());
272 }
273 }
274}