1use super::*;
3use env_logger::filter::{Builder as FilterBuilder, Filter};
4use log::{Level, Metadata, Record};
5use std::io::Write;
6
7pub struct RetroLogger {
8 callback: retro_log_callback,
9 filter: Filter,
10}
11
12impl RetroLogger {
13 pub fn new(callback: retro_log_callback) -> Self {
14 let mut builder = FilterBuilder::new();
15 let mut set_default_level = true;
16
17 if let Ok(s) = std::env::var("RUST_LOG") {
18 builder.parse(&s);
19
20 if !s.trim().is_empty() {
23 set_default_level = false;
24 }
25 }
26
27 if set_default_level {
30 builder.filter(None, log::LevelFilter::Trace);
31 }
32
33 let filter = builder.build();
34
35 Self { callback, filter }
36 }
37
38 fn get_retro_log_level(level: Level) -> retro_log_level {
39 match level {
40 Level::Error => retro_log_level::RETRO_LOG_ERROR,
41 Level::Warn => retro_log_level::RETRO_LOG_WARN,
42 Level::Info => retro_log_level::RETRO_LOG_INFO,
43 Level::Debug => retro_log_level::RETRO_LOG_DEBUG,
44 Level::Trace => retro_log_level::RETRO_LOG_DEBUG,
45 }
46 }
47}
48
49impl log::Log for RetroLogger {
50 fn enabled(&self, metadata: &Metadata) -> bool {
51 self.filter.enabled(metadata)
52 }
53
54 fn log(&self, record: &Record) {
55 if !self.filter.matches(record) {
56 return;
57 }
58
59 let target = if !record.target().is_empty() {
60 record.target()
61 } else {
62 record.module_path().unwrap_or_default()
63 };
64
65 if let Some(cb) = self.callback.log {
66 let mut args: Vec<u8> = Vec::new();
67
68 if writeln!(args, "{}\0", record.args()).is_ok() {
69 let level = Self::get_retro_log_level(record.level());
70 let target = CString::new(target).unwrap();
71
72 unsafe {
73 let args = CString::from_vec_unchecked(args);
74
75 (cb)(
77 level,
78 "[%s] %s\n\0".as_ptr() as *const c_char,
79 target.as_ptr() as *const c_char,
80 args.as_ptr() as *const c_char,
81 )
82 }
83 }
84 } else {
85 let level = match record.level() {
86 Level::Debug => "DEBUG",
87 Level::Info => "INFO",
88 Level::Warn => "WARN",
89 Level::Error => "ERROR",
90 Level::Trace => "TRACE",
91 };
92
93 let stderr = std::io::stderr();
94 let mut stderr_lock = stderr.lock();
95
96 let _ = writeln!(
97 stderr_lock,
98 "[libretro {}] [{}] {}",
99 level,
100 target,
101 record.args()
102 );
103 }
104 }
105
106 fn flush(&self) {
107 }
109}