starnix_logging/
logging.rs1use starnix_task_command::TaskCommand;
6use starnix_uapi::errors::Errno;
7use starnix_uapi::{pid_t, tid_t};
8use std::cell::RefCell;
9use std::fmt;
10
11#[doc(hidden)]
14pub use log as __log;
15
16pub use log::kv::{ToValue, Value};
17pub use log::{Level, Record, logger};
18
19enum TaskDebugInfo {
21 Kernel,
23 User { pid: pid_t, tid: tid_t, command: TaskCommand, leader_command: TaskCommand },
26 Unknown,
29}
30
31impl TaskDebugInfo {
32 pub fn leader_command(&self) -> TaskCommand {
33 match self {
34 Self::Kernel => TaskCommand::new(b"kthreadd"),
35 Self::User { leader_command, .. } => leader_command.clone(),
36 Self::Unknown => TaskCommand::new(b"<unknown>"),
37 }
38 }
39}
40
41thread_local! {
42 static CURRENT_TASK_INFO: RefCell<TaskDebugInfo> = const { RefCell::new(TaskDebugInfo::Kernel) } ;
46}
47
48impl fmt::Display for TaskDebugInfo {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 Self::Kernel => write!(f, "kthread"),
52 Self::User { pid, tid, command, .. } => write!(f, "{pid}:{tid}[{command}]"),
53 Self::Unknown => write!(f, "unknown"),
54 }
55 }
56}
57
58#[doc(hidden)]
61#[derive(Clone, Copy, Debug)]
62pub struct CurrentTaskInfo;
63
64impl fmt::Display for CurrentTaskInfo {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 with_current_task_info(|task| fmt::Display::fmt(task, f))
67 }
68}
69
70#[inline]
71pub const fn trace_debug_logs_enabled() -> bool {
72 cfg!(debug_assertions) || cfg!(feature = "trace_and_debug_logs_in_release")
75}
76
77#[macro_export]
78macro_rules! log_trace {
79 ($($key:tt $(:$capture:tt)? $(= $value:expr)?),+; $($arg:tt)+) => {
80 if $crate::trace_debug_logs_enabled() {
81 $crate::__log::trace!(
82 tag:% = $crate::CurrentTaskInfo,
83 $($key $(:$capture)* $(= $value)*),+;
84 $($arg)*
85 );
86 }
87 };
88 ($($arg:tt)*) => {
89 if $crate::trace_debug_logs_enabled() {
90 $crate::__log::trace!(tag:% = $crate::CurrentTaskInfo; $($arg)*)
91 }
92 };
93}
94
95#[macro_export]
96macro_rules! log_syscall {
97 ($current_task:expr, $($arg:tt)*) => {
98 if $crate::trace_debug_logs_enabled() {
99 $crate::log!(
100 $current_task.task.thread_group.syscall_log_level(),
101 $($arg)*
102 )
103 }
104 };
105}
106
107#[macro_export]
108macro_rules! log_debug {
109 ($($key:tt $(:$capture:tt)? $(= $value:expr)?),+; $($arg:tt)+) => {
110 if $crate::trace_debug_logs_enabled() {
111 $crate::__log::debug!(
112 tag:% = $crate::CurrentTaskInfo,
113 $($key $(:$capture)* $(= $value)*),+;
114 $($arg)*
115 );
116 }
117 };
118 ($($arg:tt)*) => {
119 if $crate::trace_debug_logs_enabled() {
120 $crate::__log::debug!(tag:% = $crate::CurrentTaskInfo; $($arg)*)
121 }
122 };
123}
124
125#[macro_export]
126macro_rules! log_info {
127 ($($arg:tt)*) => {
128 $crate::log!($crate::__log::Level::Info, $($arg)*)
129 };
130}
131
132#[macro_export]
133macro_rules! log_warn {
134 ($($arg:tt)*) => {
135 $crate::log!($crate::__log::Level::Warn, $($arg)*)
136 };
137}
138
139#[macro_export]
140macro_rules! log_error {
141 ($($arg:tt)*) => {
142 $crate::log!($crate::__log::Level::Error, $($arg)*)
143 };
144}
145
146#[macro_export]
147macro_rules! log {
148 ($lvl:expr, $($key:tt $(:$capture:tt)? $(= $value:expr)?),+; $($arg:tt)+) => {
149 $crate::__log::log!(
150 $lvl,
151 tag:% = $crate::CurrentTaskInfo,
152 $($key $(:$capture)* $(= $value)*),+;
153 $($arg)*
154 )
155 };
156 ($lvl:expr, $($arg:tt)+) => {
157 $crate::__log::log!($lvl, tag:% = $crate::CurrentTaskInfo; $($arg)*)
158 };
159}
160
161#[track_caller]
164pub fn impossible_error(status: zx::Status) -> Errno {
165 panic!("encountered impossible error: {status}");
166}
167
168pub fn set_zx_name(obj: &impl zx::AsHandleRef, name: impl AsRef<[u8]>) {
169 match obj.as_handle_ref().set_name(&zx::Name::from_bytes_lossy(name.as_ref())) {
170 Ok(()) | Err(zx::Status::BAD_STATE) => {}
173 Err(status) => {
174 impossible_error(status);
175 }
176 }
177}
178
179pub fn with_zx_name<O: zx::AsHandleRef>(obj: O, name: impl AsRef<[u8]>) -> O {
180 set_zx_name(&obj, name);
181 obj
182}
183
184pub fn set_current_task_info(
188 command: TaskCommand,
189 leader_command: TaskCommand,
190 pid: pid_t,
191 tid: tid_t,
192) {
193 CURRENT_TASK_INFO.with(|task_info| {
194 *task_info.borrow_mut() = TaskDebugInfo::User { pid, tid, command, leader_command };
195 });
196}
197
198#[doc(hidden)]
205pub fn with_current_task_info<T>(mut f: impl FnMut(&dyn fmt::Display) -> T) -> T {
206 match CURRENT_TASK_INFO.try_with(|task_info| f(&task_info.borrow())) {
207 Ok(value) => value,
208 Err(_) => f(&TaskDebugInfo::Unknown),
209 }
210}
211
212pub(crate) fn get_current_leader_command() -> flyweights::FlyByteStr {
213 match CURRENT_TASK_INFO.try_with(|task_info| task_info.borrow().leader_command()) {
214 Ok(value) => value.into(),
215 Err(_) => flyweights::FlyByteStr::new(b"<unknown>"),
216 }
217}
218
219#[derive(Debug, Clone, PartialEq, Eq, Hash)]
221pub struct SyscallLogFilter {
222 match_string: String,
223}
224
225impl SyscallLogFilter {
226 pub fn new(match_string: String) -> Self {
227 Self { match_string }
228 }
229
230 pub fn matches(&self, command: &TaskCommand) -> bool {
231 let matcher = self.match_string.as_bytes();
232 command.as_bytes().windows(matcher.len()).any(|w| w == matcher)
233 }
234}
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239
240 unsafe extern "C" {
241 fn zx_thread_self() -> zx::sys::zx_handle_t;
242 }
243
244 #[test]
245 fn test_set_zx_name_on_terminated_thread() {
246 let mut terminated_thread = None;
247 std::thread::scope(|s| {
248 s.spawn(|| {
249 terminated_thread = Some(
250 #[allow(clippy::undocumented_unsafe_blocks)]
251 unsafe {
252 let thread = zx::Unowned::<zx::Thread>::from_raw_handle(zx_thread_self());
253 thread.duplicate_handle(zx::Rights::SAME_RIGHTS)
254 }
255 .unwrap(),
256 );
257 });
258 });
259 let terminated_thread = terminated_thread.expect("failed to obtain thread handle");
260 let _ = terminated_thread
261 .wait_one(zx::Signals::THREAD_TERMINATED, zx::MonotonicInstant::INFINITE);
262
263 set_zx_name(&terminated_thread, b"dead-thread-name");
269 }
270
271 #[test]
272 #[should_panic(expected = "encountered impossible error: BAD_HANDLE")]
273 #[allow(clippy::undocumented_unsafe_blocks)]
274 fn test_set_zx_name_invalid_handle_panics() {
275 let invalid =
276 unsafe { zx::Unowned::<zx::Thread>::from_raw_handle(zx::sys::ZX_HANDLE_INVALID) };
277 set_zx_name(&invalid, b"any-name");
278 }
279}