mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Redirect stdout to ML logging.
This commit is contained in:
parent
daabda7fe1
commit
d0e9acf1eb
3 changed files with 82 additions and 0 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2437,6 +2437,7 @@ dependencies = [
|
|||
name = "libmlservo"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libservo 0.0.1",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -15,6 +15,7 @@ bench = false
|
|||
[dependencies]
|
||||
libservo = { path = "../../components/servo", features = ["no_static_freetype"] }
|
||||
simpleservo = { path = "../libsimpleservo/api", features = ["no_static_freetype"] }
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
servo-egl = "0.2"
|
||||
smallvec = "0.6"
|
||||
|
|
|
@ -7,6 +7,7 @@ use egl::egl::EGLDisplay;
|
|||
use egl::egl::EGLSurface;
|
||||
use egl::egl::MakeCurrent;
|
||||
use egl::egl::SwapBuffers;
|
||||
use libc::{dup2, pipe, read};
|
||||
use log::info;
|
||||
use log::warn;
|
||||
use servo::euclid::TypedScale;
|
||||
|
@ -25,6 +26,7 @@ use std::ffi::CStr;
|
|||
use std::ffi::CString;
|
||||
use std::io::Write;
|
||||
use std::os::raw::c_char;
|
||||
use std::os::raw::c_int;
|
||||
use std::os::raw::c_void;
|
||||
use std::rc::Rc;
|
||||
use std::thread;
|
||||
|
@ -67,6 +69,7 @@ pub enum MLKeyType {
|
|||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MLLogger(extern "C" fn(MLLogLevel, *const c_char));
|
||||
|
||||
#[repr(transparent)]
|
||||
|
@ -109,6 +112,7 @@ pub unsafe extern "C" fn init_servo(
|
|||
height: u32,
|
||||
hidpi: f32,
|
||||
) -> *mut ServoInstance {
|
||||
redirect_stdout_to_log(logger);
|
||||
let _ = log::set_boxed_logger(Box::new(logger));
|
||||
log::set_max_level(LOG_LEVEL);
|
||||
|
||||
|
@ -382,3 +386,79 @@ impl log::Log for MLLogger {
|
|||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
fn redirect_stdout_to_log(logger: MLLogger) {
|
||||
// The first step is to redirect stdout and stderr to the logs.
|
||||
// We redirect stdout and stderr to a custom descriptor.
|
||||
let mut pfd: [c_int; 2] = [0, 0];
|
||||
unsafe {
|
||||
pipe(pfd.as_mut_ptr());
|
||||
dup2(pfd[1], 1);
|
||||
dup2(pfd[1], 2);
|
||||
}
|
||||
|
||||
let descriptor = pfd[0];
|
||||
|
||||
// Then we spawn a thread whose only job is to read from the other side of the
|
||||
// pipe and redirect to the logs.
|
||||
let _detached = thread::spawn(move || {
|
||||
const BUF_LENGTH: usize = 512;
|
||||
let mut buf = vec![b'\0' as c_char; BUF_LENGTH];
|
||||
|
||||
// Always keep at least one null terminator
|
||||
const BUF_AVAILABLE: usize = BUF_LENGTH - 1;
|
||||
let buf = &mut buf[..BUF_AVAILABLE];
|
||||
|
||||
let mut cursor = 0_usize;
|
||||
|
||||
loop {
|
||||
let result = {
|
||||
let read_into = &mut buf[cursor..];
|
||||
unsafe {
|
||||
read(
|
||||
descriptor,
|
||||
read_into.as_mut_ptr() as *mut _,
|
||||
read_into.len(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let end = if result == 0 {
|
||||
return;
|
||||
} else if result < 0 {
|
||||
(logger.0)(
|
||||
MLLogLevel::Error,
|
||||
b"error in log thread; closing\0".as_ptr() as *const _,
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
result as usize + cursor
|
||||
};
|
||||
|
||||
// Only modify the portion of the buffer that contains real data.
|
||||
let buf = &mut buf[0..end];
|
||||
|
||||
if let Some(last_newline_pos) = buf.iter().rposition(|&c| c == b'\n' as c_char) {
|
||||
buf[last_newline_pos] = b'\0' as c_char;
|
||||
(logger.0)(MLLogLevel::Info, buf.as_ptr());
|
||||
if last_newline_pos < buf.len() - 1 {
|
||||
let pos_after_newline = last_newline_pos + 1;
|
||||
let len_not_logged_yet = buf[pos_after_newline..].len();
|
||||
for j in 0..len_not_logged_yet as usize {
|
||||
buf[j] = buf[pos_after_newline + j];
|
||||
}
|
||||
cursor = len_not_logged_yet;
|
||||
} else {
|
||||
cursor = 0;
|
||||
}
|
||||
} else if end == BUF_AVAILABLE {
|
||||
// No newline found but the buffer is full, flush it anyway.
|
||||
// `buf.as_ptr()` is null-terminated by BUF_LENGTH being 1 less than BUF_AVAILABLE.
|
||||
(logger.0)(MLLogLevel::Info, buf.as_ptr());
|
||||
cursor = 0;
|
||||
} else {
|
||||
cursor = end;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue