1use std::{borrow::Cow, ffi::CStr, fmt, ptr};
4
5use glib::{ffi::gpointer, prelude::*, translate::*};
6use libc::c_char;
7#[cfg(feature = "log")]
8use log;
9use once_cell::sync::Lazy;
10
11use crate::{ffi, DebugLevel};
12
13pub use crate::auto::functions::debug_add_ring_buffer_logger as add_ring_buffer_logger;
15pub use crate::auto::functions::debug_get_default_threshold as get_default_threshold;
16pub use crate::auto::functions::debug_get_stack_trace as get_stack_trace;
17pub use crate::auto::functions::debug_is_active as is_active;
18pub use crate::auto::functions::debug_is_colored as is_colored;
19pub use crate::auto::functions::debug_print_stack_trace as print_stack_trace;
20pub use crate::auto::functions::debug_remove_ring_buffer_logger as remove_ring_buffer_logger;
21pub use crate::auto::functions::debug_ring_buffer_logger_get_logs as ring_buffer_logger_get_logs;
22pub use crate::auto::functions::debug_set_active as set_active;
23pub use crate::auto::functions::debug_set_colored as set_colored;
24pub use crate::auto::functions::debug_set_default_threshold as set_default_threshold;
25pub use crate::auto::functions::debug_set_threshold_for_name as set_threshold_for_name;
26pub use crate::auto::functions::debug_set_threshold_from_string as set_threshold_from_string;
27pub use crate::auto::functions::debug_unset_threshold_for_name as unset_threshold_for_name;
28
29#[derive(PartialEq, Eq)]
30#[doc(alias = "GstDebugMessage")]
31pub struct DebugMessage(ptr::NonNull<ffi::GstDebugMessage>);
32
33impl fmt::Debug for DebugMessage {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 f.debug_tuple("DebugMessage").field(&self.get()).finish()
36 }
37}
38
39impl DebugMessage {
40 #[doc(alias = "gst_debug_message_get")]
41 #[inline]
42 pub fn get(&self) -> Option<Cow<glib::GStr>> {
43 unsafe {
44 let message = ffi::gst_debug_message_get(self.0.as_ptr());
45
46 if message.is_null() {
47 None
48 } else {
49 Some(glib::GStr::from_ptr_lossy(message))
50 }
51 }
52 }
53
54 #[cfg(feature = "v1_22")]
55 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
56 #[doc(alias = "gst_debug_message_get_id")]
57 #[inline]
58 pub fn id(&self) -> Option<&glib::GStr> {
59 unsafe {
60 let id = ffi::gst_debug_message_get_id(self.0.as_ptr());
61
62 if id.is_null() {
63 None
64 } else {
65 Some(glib::GStr::from_ptr(id))
66 }
67 }
68 }
69
70 #[inline]
71 pub fn as_ptr(&self) -> *mut ffi::GstDebugMessage {
72 self.0.as_ptr()
73 }
74}
75
76#[derive(PartialEq, Eq, Clone, Copy, Hash)]
77#[doc(alias = "GstDebugCategory")]
78#[repr(transparent)]
79pub struct DebugCategory(Option<ptr::NonNull<ffi::GstDebugCategory>>);
80
81impl DebugCategory {
82 #[doc(alias = "gst_debug_category_new")]
83 #[doc(alias = "GST_DEBUG_CATEGORY")]
84 #[doc(alias = "GST_DEBUG_CATEGORY_INIT")]
85 pub fn new(
86 name: &str,
87 color: crate::DebugColorFlags,
88 description: Option<&str>,
89 ) -> DebugCategory {
90 skip_assert_initialized!();
91 extern "C" {
92 fn _gst_debug_category_new(
93 name: *const c_char,
94 color: ffi::GstDebugColorFlags,
95 description: *const c_char,
96 ) -> *mut ffi::GstDebugCategory;
97 }
98
99 unsafe {
101 let ptr = name.run_with_gstr(|name| {
102 description.run_with_gstr(|description| {
103 _gst_debug_category_new(
104 name.to_glib_none().0,
105 color.into_glib(),
106 description.to_glib_none().0,
107 )
108 })
109 });
110
111 DebugCategory(ptr::NonNull::new(ptr))
113 }
114 }
115
116 #[doc(alias = "gst_debug_get_category")]
117 #[inline]
118 pub fn get(name: &str) -> Option<DebugCategory> {
119 skip_assert_initialized!();
120 unsafe {
121 extern "C" {
122 fn _gst_debug_get_category(name: *const c_char) -> *mut ffi::GstDebugCategory;
123 }
124
125 let cat = name.run_with_gstr(|name| _gst_debug_get_category(name.to_glib_none().0));
126
127 if cat.is_null() {
128 None
129 } else {
130 Some(DebugCategory(Some(ptr::NonNull::new_unchecked(cat))))
131 }
132 }
133 }
134
135 #[doc(alias = "get_threshold")]
136 #[doc(alias = "gst_debug_category_get_threshold")]
137 #[inline]
138 pub fn threshold(self) -> crate::DebugLevel {
139 match self.0 {
140 Some(cat) => unsafe { from_glib(cat.as_ref().threshold) },
141 None => crate::DebugLevel::None,
142 }
143 }
144
145 #[doc(alias = "gst_debug_category_set_threshold")]
146 #[inline]
147 pub fn set_threshold(self, threshold: crate::DebugLevel) {
148 if let Some(cat) = self.0 {
149 unsafe { ffi::gst_debug_category_set_threshold(cat.as_ptr(), threshold.into_glib()) }
150 }
151 }
152
153 #[doc(alias = "gst_debug_category_reset_threshold")]
154 #[inline]
155 pub fn reset_threshold(self) {
156 if let Some(cat) = self.0 {
157 unsafe { ffi::gst_debug_category_reset_threshold(cat.as_ptr()) }
158 }
159 }
160
161 #[inline]
162 pub fn above_threshold(self, level: crate::DebugLevel) -> bool {
163 match self.0 {
164 Some(cat) => unsafe { cat.as_ref().threshold >= level.into_glib() },
165 None => false,
166 }
167 }
168
169 #[doc(alias = "get_color")]
170 #[doc(alias = "gst_debug_category_get_color")]
171 #[inline]
172 pub fn color(self) -> crate::DebugColorFlags {
173 match self.0 {
174 Some(cat) => unsafe { from_glib(cat.as_ref().color) },
175 None => crate::DebugColorFlags::empty(),
176 }
177 }
178
179 #[doc(alias = "get_name")]
180 #[doc(alias = "gst_debug_category_get_name")]
181 #[inline]
182 pub fn name<'a>(self) -> &'a str {
183 match self.0 {
184 Some(cat) => unsafe { CStr::from_ptr(cat.as_ref().name).to_str().unwrap() },
185 None => "",
186 }
187 }
188
189 #[doc(alias = "get_description")]
190 #[doc(alias = "gst_debug_category_get_description")]
191 #[inline]
192 pub fn description<'a>(self) -> Option<&'a str> {
193 let cat = self.0?;
194
195 unsafe {
196 let ptr = cat.as_ref().description;
197
198 if ptr.is_null() {
199 None
200 } else {
201 Some(CStr::from_ptr(ptr).to_str().unwrap())
202 }
203 }
204 }
205
206 #[inline]
207 #[doc(alias = "gst_debug_log")]
208 #[doc(alias = "gst_debug_log_literal")]
209 pub fn log(
210 self,
211 obj: Option<&impl IsA<glib::Object>>,
212 level: crate::DebugLevel,
213 file: &glib::GStr,
214 function: &str,
215 line: u32,
216 args: fmt::Arguments,
217 ) {
218 if !self.above_threshold(level) {
219 return;
220 }
221
222 self.log_unfiltered_internal(
223 obj.map(|obj| obj.as_ref()),
224 level,
225 file,
226 function,
227 line,
228 args,
229 )
230 }
231
232 #[inline]
233 #[doc(alias = "gst_debug_log_literal")]
234 pub fn log_literal(
235 self,
236 obj: Option<&impl IsA<glib::Object>>,
237 level: crate::DebugLevel,
238 file: &glib::GStr,
239 function: &str,
240 line: u32,
241 msg: &glib::GStr,
242 ) {
243 if !self.above_threshold(level) {
244 return;
245 }
246
247 self.log_literal_unfiltered_internal(
248 obj.map(|obj| obj.as_ref()),
249 level,
250 file,
251 function,
252 line,
253 msg,
254 )
255 }
256
257 #[inline]
260 #[doc(alias = "gst_debug_log")]
261 pub fn log_unfiltered(
262 self,
263 obj: Option<&impl IsA<glib::Object>>,
264 level: crate::DebugLevel,
265 file: &glib::GStr,
266 function: &str,
267 line: u32,
268 args: fmt::Arguments,
269 ) {
270 self.log_unfiltered_internal(
271 obj.map(|obj| obj.as_ref()),
272 level,
273 file,
274 function,
275 line,
276 args,
277 )
278 }
279
280 #[inline]
283 #[doc(alias = "gst_debug_log_literal")]
284 pub fn log_literal_unfiltered(
285 self,
286 obj: Option<&impl IsA<glib::Object>>,
287 level: crate::DebugLevel,
288 file: &glib::GStr,
289 function: &str,
290 line: u32,
291 msg: &glib::GStr,
292 ) {
293 self.log_literal_unfiltered_internal(
294 obj.map(|obj| obj.as_ref()),
295 level,
296 file,
297 function,
298 line,
299 msg,
300 )
301 }
302
303 #[inline(never)]
304 fn log_unfiltered_internal(
305 self,
306 obj: Option<&glib::Object>,
307 level: crate::DebugLevel,
308 file: &glib::GStr,
309 function: &str,
310 line: u32,
311 args: fmt::Arguments,
312 ) {
313 let mut w = smallvec::SmallVec::<[u8; 256]>::new();
314
315 if std::io::Write::write_fmt(&mut w, args).is_err() {
317 return;
318 }
319 w.push(0);
320
321 self.log_literal_unfiltered_internal(obj, level, file, function, line, unsafe {
322 glib::GStr::from_utf8_with_nul_unchecked(&w)
323 });
324 }
325
326 #[inline(never)]
327 fn log_literal_unfiltered_internal(
328 self,
329 obj: Option<&glib::Object>,
330 level: crate::DebugLevel,
331 file: &glib::GStr,
332 function: &str,
333 line: u32,
334 msg: &glib::GStr,
335 ) {
336 let cat = match self.0 {
337 Some(cat) => cat,
338 None => return,
339 };
340
341 let obj_ptr = match obj {
342 Some(obj) => obj.as_ptr(),
343 None => ptr::null_mut(),
344 };
345
346 function.run_with_gstr(|function| {
347 #[cfg(feature = "v1_20")]
348 unsafe {
349 ffi::gst_debug_log_literal(
350 cat.as_ptr(),
351 level.into_glib(),
352 file.as_ptr(),
353 function.as_ptr(),
354 line as i32,
355 obj_ptr,
356 msg.as_ptr(),
357 );
358 }
359 #[cfg(not(feature = "v1_20"))]
360 unsafe {
361 ffi::gst_debug_log(
362 cat.as_ptr(),
363 level.into_glib(),
364 file.as_ptr(),
365 function.as_ptr(),
366 line as i32,
367 obj_ptr,
368 b"%s\0".as_ptr() as *const _,
369 msg.as_ptr(),
370 );
371 }
372 });
373 }
374
375 #[cfg(feature = "v1_22")]
376 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
377 #[inline]
378 #[doc(alias = "gst_debug_log_id")]
379 pub fn log_id(
380 self,
381 id: impl AsRef<glib::GStr>,
382 level: crate::DebugLevel,
383 file: &glib::GStr,
384 function: &str,
385 line: u32,
386 args: fmt::Arguments,
387 ) {
388 if !self.above_threshold(level) {
389 return;
390 }
391
392 self.log_id_unfiltered_internal(id.as_ref(), level, file, function, line, args);
393 }
394
395 #[cfg(feature = "v1_22")]
396 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
397 #[inline]
398 #[doc(alias = "gst_debug_log_id_literal")]
399 pub fn log_id_literal(
400 self,
401 id: impl AsRef<glib::GStr>,
402 level: crate::DebugLevel,
403 file: &glib::GStr,
404 function: &str,
405 line: u32,
406 msg: &glib::GStr,
407 ) {
408 if !self.above_threshold(level) {
409 return;
410 }
411
412 self.log_id_literal_unfiltered_internal(id.as_ref(), level, file, function, line, msg);
413 }
414
415 #[cfg(feature = "v1_22")]
416 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
417 #[inline]
420 #[doc(alias = "gst_debug_log_id")]
421 pub fn log_id_unfiltered(
422 self,
423 id: impl AsRef<glib::GStr>,
424 level: crate::DebugLevel,
425 file: &glib::GStr,
426 function: &str,
427 line: u32,
428 args: fmt::Arguments,
429 ) {
430 self.log_id_unfiltered_internal(id.as_ref(), level, file, function, line, args)
431 }
432
433 #[cfg(feature = "v1_22")]
434 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
435 #[inline]
438 #[doc(alias = "gst_debug_log_id_literal")]
439 pub fn log_id_literal_unfiltered(
440 self,
441 id: impl AsRef<glib::GStr>,
442 level: crate::DebugLevel,
443 file: &glib::GStr,
444 function: &str,
445 line: u32,
446 msg: &glib::GStr,
447 ) {
448 self.log_id_literal_unfiltered_internal(id.as_ref(), level, file, function, line, msg)
449 }
450
451 #[cfg(feature = "v1_22")]
452 #[inline(never)]
453 fn log_id_unfiltered_internal(
454 self,
455 id: &glib::GStr,
456 level: crate::DebugLevel,
457 file: &glib::GStr,
458 function: &str,
459 line: u32,
460 args: fmt::Arguments,
461 ) {
462 let mut w = smallvec::SmallVec::<[u8; 256]>::new();
463
464 if std::io::Write::write_fmt(&mut w, args).is_err() {
466 return;
467 }
468 w.push(0);
469
470 self.log_id_literal_unfiltered_internal(id, level, file, function, line, unsafe {
471 glib::GStr::from_utf8_with_nul_unchecked(&w)
472 });
473 }
474
475 #[cfg(feature = "v1_22")]
476 #[inline(never)]
477 fn log_id_literal_unfiltered_internal(
478 self,
479 id: &glib::GStr,
480 level: crate::DebugLevel,
481 file: &glib::GStr,
482 function: &str,
483 line: u32,
484 msg: &glib::GStr,
485 ) {
486 let cat = match self.0 {
487 Some(cat) => cat,
488 None => return,
489 };
490
491 function.run_with_gstr(|function| unsafe {
492 ffi::gst_debug_log_id_literal(
493 cat.as_ptr(),
494 level.into_glib(),
495 file.as_ptr(),
496 function.as_ptr(),
497 line as i32,
498 id.as_ptr(),
499 msg.as_ptr(),
500 );
501 });
502 }
503
504 #[doc(alias = "get_all_categories")]
505 #[doc(alias = "gst_debug_get_all_categories")]
506 #[inline]
507 pub fn all_categories() -> glib::SList<DebugCategory> {
508 unsafe { glib::SList::from_glib_container(ffi::gst_debug_get_all_categories()) }
509 }
510
511 #[cfg(feature = "v1_18")]
512 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
513 #[doc(alias = "gst_debug_log_get_line")]
514 #[inline]
515 pub fn get_line(
516 &self,
517 level: crate::DebugLevel,
518 file: &glib::GStr,
519 function: &glib::GStr,
520 line: u32,
521 object: Option<&LoggedObject>,
522 message: &DebugMessage,
523 ) -> Option<glib::GString> {
524 let cat = self.0?;
525
526 unsafe {
527 from_glib_full(ffi::gst_debug_log_get_line(
528 cat.as_ptr(),
529 level.into_glib(),
530 file.as_ptr(),
531 function.as_ptr(),
532 line as i32,
533 object.map(|o| o.as_ptr()).unwrap_or(ptr::null_mut()),
534 message.0.as_ptr(),
535 ))
536 }
537 }
538
539 #[inline]
540 pub fn as_ptr(&self) -> *mut ffi::GstDebugCategory {
541 self.0.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
542 }
543}
544
545unsafe impl Sync for DebugCategory {}
546unsafe impl Send for DebugCategory {}
547
548impl fmt::Debug for DebugCategory {
549 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
550 f.debug_tuple("DebugCategory").field(&self.name()).finish()
551 }
552}
553
554impl GlibPtrDefault for DebugCategory {
555 type GlibType = *mut ffi::GstDebugCategory;
556}
557
558unsafe impl TransparentPtrType for DebugCategory {}
559
560impl FromGlibPtrNone<*mut ffi::GstDebugCategory> for DebugCategory {
561 #[inline]
562 unsafe fn from_glib_none(ptr: *mut ffi::GstDebugCategory) -> Self {
563 debug_assert!(!ptr.is_null());
564 DebugCategory(Some(ptr::NonNull::new_unchecked(ptr)))
565 }
566}
567
568impl FromGlibPtrFull<*mut ffi::GstDebugCategory> for DebugCategory {
569 #[inline]
570 unsafe fn from_glib_full(ptr: *mut ffi::GstDebugCategory) -> Self {
571 debug_assert!(!ptr.is_null());
572 DebugCategory(Some(ptr::NonNull::new_unchecked(ptr)))
573 }
574}
575
576pub static CAT_RUST: Lazy<DebugCategory> = Lazy::new(|| {
577 DebugCategory::new(
578 "GST_RUST",
579 crate::DebugColorFlags::UNDERLINE,
580 Some("GStreamer's Rust binding core"),
581 )
582});
583
584macro_rules! declare_debug_category_from_name(
585 ($cat:ident, $cat_name:expr) => (
586 pub static $cat: Lazy<DebugCategory> = Lazy::new(|| DebugCategory::get($cat_name)
587 .expect(&format!("Unable to find `DebugCategory` with name {}", $cat_name)));
588 );
589);
590
591declare_debug_category_from_name!(CAT_DEFAULT, "default");
592declare_debug_category_from_name!(CAT_GST_INIT, "GST_INIT");
593declare_debug_category_from_name!(CAT_MEMORY, "GST_MEMORY");
594declare_debug_category_from_name!(CAT_PARENTAGE, "GST_PARENTAGE");
595declare_debug_category_from_name!(CAT_STATES, "GST_STATES");
596declare_debug_category_from_name!(CAT_SCHEDULING, "GST_SCHEDULING");
597declare_debug_category_from_name!(CAT_BUFFER, "GST_BUFFER");
598declare_debug_category_from_name!(CAT_BUFFER_LIST, "GST_BUFFER_LIST");
599declare_debug_category_from_name!(CAT_BUS, "GST_BUS");
600declare_debug_category_from_name!(CAT_CAPS, "GST_CAPS");
601declare_debug_category_from_name!(CAT_CLOCK, "GST_CLOCK");
602declare_debug_category_from_name!(CAT_ELEMENT_PADS, "GST_ELEMENT_PADS");
603declare_debug_category_from_name!(CAT_PADS, "GST_PADS");
604declare_debug_category_from_name!(CAT_PERFORMANCE, "GST_PERFORMANCE");
605declare_debug_category_from_name!(CAT_PIPELINE, "GST_PIPELINE");
606declare_debug_category_from_name!(CAT_PLUGIN_LOADING, "GST_PLUGIN_LOADING");
607declare_debug_category_from_name!(CAT_PLUGIN_INFO, "GST_PLUGIN_INFO");
608declare_debug_category_from_name!(CAT_PROPERTIES, "GST_PROPERTIES");
609declare_debug_category_from_name!(CAT_NEGOTIATION, "GST_NEGOTIATION");
610declare_debug_category_from_name!(CAT_REFCOUNTING, "GST_REFCOUNTING");
611declare_debug_category_from_name!(CAT_ERROR_SYSTEM, "GST_ERROR_SYSTEM");
612declare_debug_category_from_name!(CAT_EVENT, "GST_EVENT");
613declare_debug_category_from_name!(CAT_MESSAGE, "GST_MESSAGE");
614declare_debug_category_from_name!(CAT_PARAMS, "GST_PARAMS");
615declare_debug_category_from_name!(CAT_CALL_TRACE, "GST_CALL_TRACE");
616declare_debug_category_from_name!(CAT_SIGNAL, "GST_SIGNAL");
617declare_debug_category_from_name!(CAT_PROBE, "GST_PROBE");
618declare_debug_category_from_name!(CAT_REGISTRY, "GST_REGISTRY");
619declare_debug_category_from_name!(CAT_QOS, "GST_QOS");
620declare_debug_category_from_name!(CAT_META, "GST_META");
621declare_debug_category_from_name!(CAT_LOCKING, "GST_LOCKING");
622declare_debug_category_from_name!(CAT_CONTEXT, "GST_CONTEXT");
623
624#[macro_export]
625macro_rules! error(
626 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
627 $crate::log_with_level!($cat, $crate::DebugLevel::Error, obj = $obj, $($args)*)
628 }};
629 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
630 $crate::log_with_level!($cat, $crate::DebugLevel::Error, imp = $imp, $($args)*)
631 }};
632 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
633 $crate::log_with_level!($cat, $crate::DebugLevel::Error, id = $id, $($args)*)
634 }};
635
636 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
637 {
638 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
639 macro_rules! error(
640 () => {}
641 );
642 error!();
643 }
644 $crate::log_with_level!($cat, $crate::DebugLevel::Error, obj = $obj, $($args)*)
645 }};
646 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
647 {
648 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
649 macro_rules! error(
650 () => {}
651 );
652 error!();
653 }
654 $crate::log_with_level!($cat, $crate::DebugLevel::Error, imp = $imp, $($args)*)
655 }};
656 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
657 {
658 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
659 macro_rules! error(
660 () => {}
661 );
662 error!();
663 }
664 $crate::log_with_level!($cat, $crate::DebugLevel::Error, id = $id, $($args)*)
665 }};
666 ($cat:expr, $($args:tt)*) => { {
667 $crate::log_with_level!($cat, $crate::DebugLevel::Error, $($args)*)
668 }};
669);
670
671#[macro_export]
672macro_rules! warning(
673 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
674 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, obj = $obj, $($args)*)
675 }};
676 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
677 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, imp = $imp, $($args)*)
678 }};
679 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
680 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, id = $id, $($args)*)
681 }};
682
683 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
684 {
685 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
686 macro_rules! warning(
687 () => {}
688 );
689 warning!();
690 }
691 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, obj = $obj, $($args)*)
692 }};
693 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
694 {
695 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
696 macro_rules! warning(
697 () => {}
698 );
699 warning!();
700 }
701 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, imp = $imp, $($args)*)
702 }};
703 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
704 {
705 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
706 macro_rules! warning(
707 () => {}
708 );
709 warning!();
710 }
711 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, id = $id, $($args)*)
712 }};
713 ($cat:expr, $($args:tt)*) => { {
714 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, $($args)*)
715 }};
716);
717
718#[macro_export]
719macro_rules! fixme(
720 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
721 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, obj = $obj, $($args)*)
722 }};
723 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
724 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, imp = $imp, $($args)*)
725 }};
726 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
727 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, id = $id, $($args)*)
728 }};
729
730 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
731 {
732 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
733 macro_rules! fixme(
734 () => {}
735 );
736 fixme!();
737 }
738 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, obj = $obj, $($args)*)
739 }};
740 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
741 {
742 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
743 macro_rules! fixme(
744 () => {}
745 );
746 fixme!();
747 }
748 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, imp = $imp, $($args)*)
749 }};
750 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
751 {
752 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
753 macro_rules! fixme(
754 () => {}
755 );
756 fixme!();
757 }
758 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, id = $id, $($args)*)
759 }};
760 ($cat:expr, $($args:tt)*) => { {
761 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, $($args)*)
762 }};
763);
764
765#[macro_export]
766macro_rules! info(
767 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
768 $crate::log_with_level!($cat, $crate::DebugLevel::Info, obj = $obj, $($args)*)
769 }};
770 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
771 $crate::log_with_level!($cat, $crate::DebugLevel::Info, imp = $imp, $($args)*)
772 }};
773 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
774 $crate::log_with_level!($cat, $crate::DebugLevel::Info, id = $id, $($args)*)
775 }};
776
777 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
778 {
779 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
780 macro_rules! info(
781 () => {}
782 );
783 info!();
784 }
785 $crate::log_with_level!($cat, $crate::DebugLevel::Info, obj = $obj, $($args)*)
786 }};
787 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
788 {
789 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
790 macro_rules! info(
791 () => {}
792 );
793 info!();
794 }
795 $crate::log_with_level!($cat, $crate::DebugLevel::Info, imp = $imp, $($args)*)
796 }};
797 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
798 {
799 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
800 macro_rules! info(
801 () => {}
802 );
803 info!();
804 }
805 $crate::log_with_level!($cat, $crate::DebugLevel::Info, id = $id, $($args)*)
806 }};
807 ($cat:expr, $($args:tt)*) => { {
808 $crate::log_with_level!($cat, $crate::DebugLevel::Info, $($args)*)
809 }};
810);
811
812#[macro_export]
813macro_rules! debug(
814 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
815 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, obj = $obj, $($args)*)
816 }};
817 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
818 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, imp = $imp, $($args)*)
819 }};
820 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
821 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, id = $id, $($args)*)
822 }};
823
824 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
825 {
826 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
827 macro_rules! debug(
828 () => {}
829 );
830 debug!();
831 }
832 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, obj = $obj, $($args)*)
833 }};
834 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
835 {
836 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
837 macro_rules! debug(
838 () => {}
839 );
840 debug!();
841 }
842 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, imp = $imp, $($args)*)
843 }};
844 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
845 {
846 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
847 macro_rules! debug(
848 () => {}
849 );
850 debug!();
851 }
852 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, id = $id, $($args)*)
853 }};
854 ($cat:expr, $($args:tt)*) => { {
855 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, $($args)*)
856 }};
857);
858
859#[macro_export]
860macro_rules! log(
861 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
862 $crate::log_with_level!($cat, $crate::DebugLevel::Log, obj = $obj, $($args)*)
863 }};
864 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
865 $crate::log_with_level!($cat, $crate::DebugLevel::Log, imp = $imp, $($args)*)
866 }};
867 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
868 $crate::log_with_level!($cat, $crate::DebugLevel::Log, id = $id, $($args)*)
869 }};
870
871 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
872 {
873 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
874 macro_rules! log(
875 () => {}
876 );
877 log!();
878 }
879 $crate::log_with_level!($cat, $crate::DebugLevel::Log, obj = $obj, $($args)*)
880 }};
881 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
882 {
883 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
884 macro_rules! log(
885 () => {}
886 );
887 log!();
888 }
889 $crate::log_with_level!($cat, $crate::DebugLevel::Log, imp = $imp, $($args)*)
890 }};
891 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
892 {
893 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
894 macro_rules! log(
895 () => {}
896 );
897 log!();
898 }
899 $crate::log_with_level!($cat, $crate::DebugLevel::Log, id = $id, $($args)*)
900 }};
901 ($cat:expr, $($args:tt)*) => { {
902 $crate::log_with_level!($cat, $crate::DebugLevel::Log, $($args)*)
903 }};
904);
905
906#[macro_export]
907macro_rules! trace(
908 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
909 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, obj = $obj, $($args)*)
910 }};
911 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
912 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, imp = $imp, $($args)*)
913 }};
914 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
915 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, id = $id, $($args)*)
916 }};
917
918 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
919 {
920 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
921 macro_rules! trace(
922 () => {}
923 );
924 trace!();
925 }
926 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, obj = $obj, $($args)*)
927 }};
928 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
929 {
930 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
931 macro_rules! trace(
932 () => {}
933 );
934 trace!();
935 }
936 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, imp = $imp, $($args)*)
937 }};
938 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
939 {
940 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: `"]
941 macro_rules! trace(
942 () => {}
943 );
944 trace!();
945 }
946 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, id = $id, $($args)*)
947 }};
948 ($cat:expr, $($args:tt)*) => { {
949 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, $($args)*)
950 }};
951);
952
953#[macro_export]
954macro_rules! memdump(
955 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
956 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, obj = $obj, $($args)*)
957 }};
958 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
959 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, imp = $imp, $($args)*)
960 }};
961 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
962 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, id = $id, $($args)*)
963 }};
964
965 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
966 {
967 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
968 macro_rules! memdump(
969 () => {}
970 );
971 memdump!();
972 }
973 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, obj = $obj, $($args)*)
974 }};
975 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
976 {
977 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
978 macro_rules! memdump(
979 () => {}
980 );
981 memdump!();
982 }
983 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, imp = $imp, $($args)*)
984 }};
985 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
986 {
987 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
988 macro_rules! memdump(
989 () => {}
990 );
991 memdump!();
992 }
993 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, id = $id, $($args)*)
994 }};
995 ($cat:expr, $($args:tt)*) => { {
996 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, $($args)*)
997 }};
998);
999
1000#[macro_export]
1001macro_rules! log_with_level(
1002 ($cat:expr, $level:expr, obj = $obj:expr, $msg:literal) => { {
1003 let cat = $cat.clone();
1004
1005 #[allow(unused_unsafe)]
1008 #[allow(clippy::redundant_closure_call)]
1009 if cat.above_threshold($level) {
1010 use $crate::glib::prelude::Cast;
1011
1012 let obj = &$obj;
1016 let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() };
1017 let function_name = $crate::glib::function_name!();
1018
1019 (|args: std::fmt::Arguments| {
1023 if args.as_str().is_some() {
1024 $crate::DebugCategory::log_literal_unfiltered(
1025 cat,
1026 Some(obj),
1027 $level,
1028 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1029 function_name,
1030 line!(),
1031 $crate::glib::gstr!($msg),
1032 )
1033 } else {
1034 $crate::DebugCategory::log_unfiltered(
1035 cat,
1036 Some(obj),
1037 $level,
1038 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1039 function_name,
1040 line!(),
1041 args,
1042 )
1043 }
1044 })(format_args!($msg))
1045 }
1046 }};
1047 ($cat:expr, $level:expr, obj = $obj:expr, $($args:tt)*) => { {
1048 let cat = $cat.clone();
1049
1050 #[allow(unused_unsafe)]
1053 if cat.above_threshold($level) {
1054 use $crate::glib::prelude::Cast;
1055
1056 let obj = &$obj;
1060 let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() };
1061 $crate::DebugCategory::log_unfiltered(
1062 cat,
1063 Some(obj),
1064 $level,
1065 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1066 $crate::glib::function_name!(),
1067 line!(),
1068 format_args!($($args)*),
1069 )
1070 }
1071 }};
1072 ($cat:expr, $level:expr, imp = $imp:expr, $msg:literal) => { {
1073 let cat = $cat.clone();
1074
1075 #[allow(unused_unsafe)]
1078 #[allow(clippy::redundant_closure_call)]
1079 if cat.above_threshold($level) {
1080 use $crate::glib::prelude::Cast;
1081
1082 let obj = $imp.obj();
1086 let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() };
1087 let function_name = $crate::glib::function_name!();
1088
1089 (|args: std::fmt::Arguments| {
1093 if args.as_str().is_some() {
1094 $crate::DebugCategory::log_literal_unfiltered(
1095 cat,
1096 Some(obj),
1097 $level,
1098 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1099 function_name,
1100 line!(),
1101 $crate::glib::gstr!($msg),
1102 )
1103 } else {
1104 $crate::DebugCategory::log_unfiltered(
1105 cat,
1106 Some(obj),
1107 $level,
1108 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1109 function_name,
1110 line!(),
1111 args,
1112 )
1113 }
1114 })(format_args!($msg))
1115 }
1116 }};
1117 ($cat:expr, $level:expr, imp = $imp:expr, $($args:tt)*) => { {
1118 let cat = $cat.clone();
1119
1120 #[allow(unused_unsafe)]
1123 if cat.above_threshold($level) {
1124 use $crate::glib::prelude::Cast;
1125
1126 let obj = $imp.obj();
1130 let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() };
1131 $crate::DebugCategory::log_unfiltered(
1132 cat,
1133 Some(obj),
1134 $level,
1135 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1136 $crate::glib::function_name!(),
1137 line!(),
1138 format_args!($($args)*),
1139 )
1140 }
1141 }};
1142 ($cat:expr, $level:expr, id = $id:literal, $msg:literal) => { {
1143 let cat = $cat.clone();
1144
1145 #[allow(unused_unsafe)]
1148 #[allow(clippy::redundant_closure_call)]
1149 if cat.above_threshold($level) {
1150 let function_name = $crate::glib::function_name!();
1154
1155 (|args: std::fmt::Arguments| {
1159 if args.as_str().is_some() {
1160 $crate::DebugCategory::log_id_literal_unfiltered(
1161 cat,
1162 $crate::glib::gstr!($id),
1163 $level,
1164 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1165 function_name,
1166 line!(),
1167 $crate::glib::gstr!($msg),
1168 )
1169 } else {
1170 $crate::DebugCategory::log_id_unfiltered(
1171 cat,
1172 $crate::glib::gstr!($id),
1173 $level,
1174 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1175 function_name,
1176 line!(),
1177 args,
1178 )
1179 }
1180 })(format_args!($msg))
1181 }
1182 }};
1183 ($cat:expr, $level:expr, id = $id:literal, $($args:tt)*) => { {
1184 let cat = $cat.clone();
1185
1186 #[allow(unused_unsafe)]
1189 if cat.above_threshold($level) {
1190 $crate::DebugCategory::log_id_unfiltered(
1194 cat,
1195 $crate::glib::gstr!($id),
1196 $level,
1197 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1198 $crate::glib::function_name!(),
1199 line!(),
1200 format_args!($($args)*),
1201 )
1202 }
1203 }};
1204 ($cat:expr, $level:expr, id = $id:expr, $msg:literal) => { {
1205 let cat = $cat.clone();
1206
1207 #[allow(unused_unsafe)]
1210 #[allow(clippy::redundant_closure_call)]
1211 if cat.above_threshold($level) {
1212 let function_name = $crate::glib::function_name!();
1216
1217 (|args: std::fmt::Arguments| {
1221 if args.as_str().is_some() {
1222 $crate::DebugCategory::log_id_literal_unfiltered(
1223 cat,
1224 $id,
1225 $level,
1226 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1227 function_name,
1228 line!(),
1229 $crate::glib::gstr!($msg),
1230 )
1231 } else {
1232 $crate::DebugCategory::log_id_unfiltered(
1233 cat,
1234 $id,
1235 $level,
1236 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1237 function_name,
1238 line!(),
1239 args,
1240 )
1241 }
1242 })(format_args!($msg))
1243 }
1244 }};
1245 ($cat:expr, $level:expr, id = $id:expr, $($args:tt)*) => { {
1246 let cat = $cat.clone();
1247
1248 #[allow(unused_unsafe)]
1251 if cat.above_threshold($level) {
1252 $crate::DebugCategory::log_id_unfiltered(
1256 cat,
1257 $id,
1258 $level,
1259 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1260 $crate::glib::function_name!(),
1261 line!(),
1262 format_args!($($args)*),
1263 )
1264 }
1265 }};
1266 ($cat:expr, $level:expr, $msg:literal) => { {
1267 let cat = $cat.clone();
1268
1269 #[allow(unused_unsafe)]
1272 #[allow(clippy::redundant_closure_call)]
1273 if cat.above_threshold($level) {
1274 let function_name = $crate::glib::function_name!();
1278
1279 (|args: std::fmt::Arguments| {
1283 if args.as_str().is_some() {
1284 $crate::DebugCategory::log_literal_unfiltered(
1285 cat,
1286 None as Option<&$crate::glib::Object>,
1287 $level,
1288 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1289 function_name,
1290 line!(),
1291 $crate::glib::gstr!($msg),
1292 )
1293 } else {
1294 $crate::DebugCategory::log_unfiltered(
1295 cat,
1296 None as Option<&$crate::glib::Object>,
1297 $level,
1298 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1299 function_name,
1300 line!(),
1301 args,
1302 )
1303 }
1304 })(format_args!($msg))
1305 }
1306 }};
1307 ($cat:expr, $level:expr, $($args:tt)*) => { {
1308 let cat = $cat.clone();
1309
1310 #[allow(unused_unsafe)]
1313 if cat.above_threshold($level) {
1314 $crate::DebugCategory::log_unfiltered(
1318 cat,
1319 None as Option<&$crate::glib::Object>,
1320 $level,
1321 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1322 $crate::glib::function_name!(),
1323 line!(),
1324 format_args!($($args)*),
1325 )
1326 }
1327 }};
1328);
1329
1330#[cfg(feature = "log")]
1331#[cfg_attr(docsrs, doc(cfg(feature = "log")))]
1332#[derive(Debug)]
1333pub struct DebugCategoryLogger(DebugCategory);
1334
1335#[cfg(feature = "log")]
1336#[cfg_attr(docsrs, doc(cfg(feature = "log")))]
1337impl DebugCategoryLogger {
1338 pub fn new(cat: DebugCategory) -> Self {
1339 skip_assert_initialized!();
1340 Self(cat)
1341 }
1342
1343 fn to_level(level: log::Level) -> crate::DebugLevel {
1344 skip_assert_initialized!();
1345 match level {
1346 log::Level::Error => DebugLevel::Error,
1347 log::Level::Warn => DebugLevel::Warning,
1348 log::Level::Info => DebugLevel::Info,
1349 log::Level::Debug => DebugLevel::Debug,
1350 log::Level::Trace => DebugLevel::Trace,
1351 }
1352 }
1353}
1354
1355#[cfg(feature = "log")]
1356#[cfg_attr(docsrs, doc(cfg(feature = "log")))]
1357impl log::Log for DebugCategoryLogger {
1358 fn enabled(&self, metadata: &log::Metadata) -> bool {
1359 self.0.above_threshold(Self::to_level(metadata.level()))
1360 }
1361
1362 fn log(&self, record: &log::Record) {
1363 if !self.enabled(record.metadata()) {
1364 return;
1365 }
1366 record.file().unwrap_or("").run_with_gstr(|file| {
1367 self.0.log(
1368 None::<&glib::Object>,
1369 Self::to_level(record.level()),
1370 file,
1371 record.module_path().unwrap_or(""),
1372 record.line().unwrap_or(0),
1373 *record.args(),
1374 );
1375 });
1376 }
1377
1378 fn flush(&self) {}
1379}
1380
1381unsafe extern "C" fn log_handler<T>(
1382 category: *mut ffi::GstDebugCategory,
1383 level: ffi::GstDebugLevel,
1384 file: *const c_char,
1385 function: *const c_char,
1386 line: i32,
1387 object: *mut glib::gobject_ffi::GObject,
1388 message: *mut ffi::GstDebugMessage,
1389 user_data: gpointer,
1390) where
1391 T: Fn(
1392 DebugCategory,
1393 DebugLevel,
1394 &glib::GStr,
1395 &glib::GStr,
1396 u32,
1397 Option<&LoggedObject>,
1398 &DebugMessage,
1399 ) + Send
1400 + Sync
1401 + 'static,
1402{
1403 if category.is_null() {
1404 return;
1405 }
1406 let category = DebugCategory(Some(ptr::NonNull::new_unchecked(category)));
1407 let level = from_glib(level);
1408 let file = glib::GStr::from_ptr(file);
1409 let function = glib::GStr::from_ptr(function);
1410 let line = line as u32;
1411 let object = ptr::NonNull::new(object).map(LoggedObject);
1412 let message = DebugMessage(ptr::NonNull::new_unchecked(message));
1413 let handler = &*(user_data as *mut T);
1414 (handler)(
1415 category,
1416 level,
1417 file,
1418 function,
1419 line,
1420 object.as_ref(),
1421 &message,
1422 );
1423}
1424
1425unsafe extern "C" fn log_handler_data_free<T>(data: gpointer) {
1426 let data = Box::from_raw(data as *mut T);
1427 drop(data);
1428}
1429
1430#[derive(Debug)]
1431pub struct DebugLogFunction(ptr::NonNull<std::os::raw::c_void>);
1432
1433unsafe impl Send for DebugLogFunction {}
1437unsafe impl Sync for DebugLogFunction {}
1438
1439#[derive(Debug)]
1440#[doc(alias = "GObject")]
1441pub struct LoggedObject(ptr::NonNull<glib::gobject_ffi::GObject>);
1442
1443impl LoggedObject {
1444 #[inline]
1445 pub fn as_ptr(&self) -> *mut glib::gobject_ffi::GObject {
1446 self.0.as_ptr()
1447 }
1448}
1449
1450impl fmt::Display for LoggedObject {
1451 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1452 unsafe {
1453 let ptr = self.0.as_ptr();
1454 let g_type_instance = &mut (*ptr).g_type_instance;
1455 if glib::gobject_ffi::g_type_check_instance_is_fundamentally_a(
1456 g_type_instance,
1457 glib::gobject_ffi::g_object_get_type(),
1458 ) != glib::ffi::GFALSE
1459 {
1460 let type_ = (*g_type_instance.g_class).g_type;
1461
1462 if glib::gobject_ffi::g_type_is_a(type_, ffi::gst_pad_get_type())
1463 != glib::ffi::GFALSE
1464 {
1465 let name_ptr = (*(ptr as *mut ffi::GstObject)).name;
1466 let name = if name_ptr.is_null() {
1467 "<null>"
1468 } else {
1469 CStr::from_ptr(name_ptr)
1470 .to_str()
1471 .unwrap_or("<invalid name>")
1472 };
1473
1474 let parent_ptr = (*(ptr as *mut ffi::GstObject)).parent;
1475 let parent_name = if parent_ptr.is_null() {
1476 "<null>"
1477 } else {
1478 let name_ptr = (*(parent_ptr)).name;
1479 if name_ptr.is_null() {
1480 "<null>"
1481 } else {
1482 CStr::from_ptr(name_ptr)
1483 .to_str()
1484 .unwrap_or("<invalid name>")
1485 }
1486 };
1487
1488 write!(f, "{parent_name}:{name}")
1489 } else if glib::gobject_ffi::g_type_is_a(type_, ffi::gst_object_get_type())
1490 != glib::ffi::GFALSE
1491 {
1492 let name_ptr = (*(ptr as *mut ffi::GstObject)).name;
1493 let name = if name_ptr.is_null() {
1494 "<null>"
1495 } else {
1496 CStr::from_ptr(name_ptr)
1497 .to_str()
1498 .unwrap_or("<invalid name>")
1499 };
1500 write!(f, "{name}")
1501 } else {
1502 let type_name = CStr::from_ptr(glib::gobject_ffi::g_type_name(type_));
1503 write!(
1504 f,
1505 "{}:{:?}",
1506 type_name.to_str().unwrap_or("<invalid type>"),
1507 ptr
1508 )
1509 }
1510 } else {
1511 write!(f, "{ptr:?}")
1512 }
1513 }
1514 }
1515}
1516
1517#[doc(alias = "gst_debug_add_log_function")]
1518pub fn add_log_function<T>(function: T) -> DebugLogFunction
1519where
1520 T: Fn(
1521 DebugCategory,
1522 DebugLevel,
1523 &glib::GStr,
1524 &glib::GStr,
1525 u32,
1526 Option<&LoggedObject>,
1527 &DebugMessage,
1528 ) + Send
1529 + Sync
1530 + 'static,
1531{
1532 skip_assert_initialized!();
1533 unsafe {
1534 let user_data = Box::new(function);
1535 let user_data_ptr = Box::into_raw(user_data) as gpointer;
1536 ffi::gst_debug_add_log_function(
1537 Some(log_handler::<T>),
1538 user_data_ptr,
1539 Some(log_handler_data_free::<T>),
1540 );
1541 DebugLogFunction(ptr::NonNull::new_unchecked(user_data_ptr))
1542 }
1543}
1544
1545pub fn remove_default_log_function() {
1546 skip_assert_initialized!();
1547 unsafe {
1548 ffi::gst_debug_remove_log_function(None);
1549 }
1550}
1551
1552#[doc(alias = "gst_debug_remove_log_function_by_data")]
1553pub fn remove_log_function(log_fn: DebugLogFunction) {
1554 skip_assert_initialized!();
1555 unsafe {
1556 ffi::gst_debug_remove_log_function_by_data(log_fn.0.as_ptr());
1557 }
1558}
1559
1560#[cfg(test)]
1561mod tests {
1562 use std::sync::{mpsc, Arc, Mutex};
1563
1564 use super::*;
1565
1566 #[test]
1567 #[doc(alias = "get_existing")]
1568 fn existing() {
1569 crate::init().unwrap();
1570
1571 let perf_cat = DebugCategory::get("GST_PERFORMANCE")
1572 .expect("Unable to find `DebugCategory` with name \"GST_PERFORMANCE\"");
1573 assert_eq!(perf_cat.name(), CAT_PERFORMANCE.name());
1574 }
1575
1576 #[test]
1577 fn all() {
1578 crate::init().unwrap();
1579
1580 assert!(DebugCategory::all_categories()
1581 .iter()
1582 .any(|c| c.name() == "GST_PERFORMANCE"));
1583 }
1584
1585 #[test]
1586 fn new_and_log() {
1587 crate::init().unwrap();
1588
1589 let cat = DebugCategory::new(
1590 "test-cat",
1591 crate::DebugColorFlags::empty(),
1592 Some("some debug category"),
1593 );
1594
1595 error!(cat, "meh");
1596 warning!(cat, "meh");
1597 fixme!(cat, "meh");
1598 info!(cat, "meh");
1599 debug!(cat, "meh");
1600 log!(cat, "meh");
1601 trace!(cat, "meh");
1602 memdump!(cat, "meh");
1603
1604 let obj = crate::Bin::with_name("meh");
1605
1606 error!(cat, obj = &obj, "meh");
1607 warning!(cat, obj = &obj, "meh");
1608 fixme!(cat, obj = &obj, "meh");
1609 info!(cat, obj = &obj, "meh");
1610 debug!(cat, obj = &obj, "meh");
1611 log!(cat, obj = &obj, "meh");
1612 trace!(cat, obj = &obj, "meh");
1613 memdump!(cat, obj = &obj, "meh");
1614
1615 error!(cat, obj = obj, "meh");
1616 warning!(cat, obj = obj, "meh");
1617 fixme!(cat, obj = obj, "meh");
1618 info!(cat, obj = obj, "meh");
1619 debug!(cat, obj = obj, "meh");
1620 log!(cat, obj = obj, "meh");
1621 trace!(cat, obj = obj, "meh");
1622 memdump!(cat, obj = obj, "meh");
1623 }
1624
1625 #[cfg(feature = "log")]
1626 static LOGGER: Lazy<DebugCategoryLogger> = Lazy::new(|| {
1627 DebugCategoryLogger::new(DebugCategory::new(
1628 "Log_trait",
1629 crate::DebugColorFlags::empty(),
1630 Some("Using the Log trait"),
1631 ))
1632 });
1633
1634 #[test]
1635 #[cfg(feature = "log")]
1636 fn log_trait() {
1637 crate::init().unwrap();
1638
1639 log::set_logger(&(*LOGGER)).expect("Failed to set logger");
1640 log::set_max_level(log::LevelFilter::Trace);
1641 log::error!("meh");
1642 log::warn!("fish");
1643
1644 let (sender, receiver) = mpsc::channel();
1645 let sender = Arc::new(Mutex::new(sender));
1646 let handler = move |category: DebugCategory,
1647 level: DebugLevel,
1648 _file: &glib::GStr,
1649 _function: &glib::GStr,
1650 _line: u32,
1651 _object: Option<&LoggedObject>,
1652 message: &DebugMessage| {
1653 let cat = DebugCategory::get("Log_trait").unwrap();
1654
1655 if category != cat {
1656 return;
1659 }
1660
1661 assert_eq!(level, DebugLevel::Error);
1662 assert_eq!(message.get().unwrap().as_ref(), "meh");
1663 let _ = sender.lock().unwrap().send(());
1664 };
1665
1666 remove_default_log_function();
1667 add_log_function(handler);
1668
1669 let cat = LOGGER.0;
1670
1671 cat.set_threshold(crate::DebugLevel::Warning);
1672 log::error!("meh");
1673 receiver.recv().unwrap();
1674
1675 cat.set_threshold(crate::DebugLevel::Error);
1676 log::error!("meh");
1677 receiver.recv().unwrap();
1678
1679 cat.set_threshold(crate::DebugLevel::None);
1680 log::error!("fish");
1681 log::warn!("meh");
1682 }
1683
1684 #[test]
1685 fn log_handler() {
1686 crate::init().unwrap();
1687
1688 let cat = DebugCategory::new(
1689 "test-cat-log",
1690 crate::DebugColorFlags::empty(),
1691 Some("some debug category"),
1692 );
1693 cat.set_threshold(DebugLevel::Info);
1694 let obj = crate::Bin::with_name("meh");
1695
1696 let (sender, receiver) = mpsc::channel();
1697
1698 let sender = Arc::new(Mutex::new(sender));
1699
1700 let handler = move |category: DebugCategory,
1701 level: DebugLevel,
1702 _file: &glib::GStr,
1703 _function: &glib::GStr,
1704 _line: u32,
1705 _object: Option<&LoggedObject>,
1706 message: &DebugMessage| {
1707 let cat = DebugCategory::get("test-cat-log").unwrap();
1708
1709 if category != cat {
1710 return;
1713 }
1714
1715 assert_eq!(level, DebugLevel::Info);
1716 assert_eq!(message.get().unwrap().as_ref(), "meh");
1717 let _ = sender.lock().unwrap().send(());
1718 };
1719
1720 remove_default_log_function();
1721 let log_fn = add_log_function(handler);
1722 info!(cat, obj = &obj, "meh");
1723
1724 receiver.recv().unwrap();
1725
1726 remove_log_function(log_fn);
1727
1728 info!(cat, obj = &obj, "meh2");
1729 assert!(receiver.recv().is_err());
1730 }
1731
1732 #[test]
1733 fn no_argument_evaluation() {
1734 crate::init().unwrap();
1735
1736 let cat = DebugCategory::new(
1737 "no_argument_evaluation",
1738 crate::DebugColorFlags::empty(),
1739 Some("No Argument Evaluation debug category"),
1740 );
1741
1742 let mut arg_evaluated = false;
1743 trace!(cat, "{}", {
1744 arg_evaluated = true;
1745 "trace log"
1746 });
1747
1748 assert!(!arg_evaluated);
1749 }
1750
1751 #[cfg(feature = "v1_22")]
1752 #[test]
1753 fn id_logging() {
1754 crate::init().unwrap();
1755
1756 let cat = DebugCategory::new(
1757 "log_with_id_test_category",
1758 crate::DebugColorFlags::empty(),
1759 Some("Blablabla"),
1760 );
1761
1762 cat.set_threshold(crate::DebugLevel::Trace);
1763
1764 trace!(cat, id = "123", "test");
1765 trace!(cat, id = glib::GString::from("123"), "test");
1766 trace!(cat, id = &glib::GString::from("123"), "test");
1767
1768 let log_id = glib::GString::from("456");
1770 trace!(cat, id = &log_id, "{log_id:?}");
1771 }
1772}