mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
ohos/android: Redirect stdout/stderr to log
sink (#32858)
* ohos: redirect stdout/stderr to logging sink Based on the existing android `redirect_stdout_to_logcat` implementation, but using the safe abstractions from `nix` and dumping to the `log` sink, instead of directly writing the log. Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com> * android: Use new shared implementation for logcat redirection. Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com> * servoshell: Register cfg(production) Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com> * Update ports/servoshell/egl/log.rs Co-authored-by: Martin Robinson <mrobinson@igalia.com> Signed-off-by: Jonathan Schwender <55576758+jschwe@users.noreply.github.com> * Change info! to debug! to match original behavior on android Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com> --------- Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com> Signed-off-by: Jonathan Schwender <55576758+jschwe@users.noreply.github.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
353ceb0ffb
commit
97c84b6127
8 changed files with 127 additions and 93 deletions
96
ports/servoshell/egl/log.rs
Normal file
96
ports/servoshell/egl/log.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Helper Module to redirect stdout/stderr to the logging sink
|
||||
|
||||
use std::os::fd::{AsRawFd, IntoRawFd, RawFd};
|
||||
use std::thread;
|
||||
|
||||
use log::{debug, error, info, warn};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) enum LogRedirectError {
|
||||
CreatePipeFailed(nix::Error),
|
||||
RedirectToPipeFailed(nix::Error),
|
||||
}
|
||||
|
||||
/// Redirect stdout and stderr to the logging system
|
||||
pub(crate) fn redirect_stdout_and_stderr() -> Result<(), LogRedirectError> {
|
||||
fn log_raw_msg(raw_msg: &[u8]) {
|
||||
if let Ok(utf8_msg) = std::str::from_utf8(raw_msg) {
|
||||
debug!("{utf8_msg}");
|
||||
} else {
|
||||
// Note: This could happen if the message is long, and we hit the length
|
||||
// limitation in the middle of a utf-8 codepoint. We could try to handle this
|
||||
// by using `error.valid_up_to()`, but lets see first if we hit this problem
|
||||
// in practice.
|
||||
warn!("Dropping 1 log message due to invalid encoding.");
|
||||
debug!("Raw byte content: {raw_msg:?}")
|
||||
}
|
||||
}
|
||||
|
||||
// The first step is to redirect stdout and stderr to the logs.
|
||||
// We redirect stdout and stderr to a custom descriptor.
|
||||
let (readerfd, writerfd) =
|
||||
nix::unistd::pipe().map_err(|e| LogRedirectError::CreatePipeFailed(e))?;
|
||||
// Leaks the writer fd. We want to log for the whole program lifetime.
|
||||
let raw_writerfd = writerfd.into_raw_fd();
|
||||
let _fd = nix::unistd::dup2(raw_writerfd, RawFd::from(1))
|
||||
.map_err(|e| LogRedirectError::RedirectToPipeFailed(e))?;
|
||||
let _fd = nix::unistd::dup2(raw_writerfd, RawFd::from(2))
|
||||
.map_err(|e| LogRedirectError::RedirectToPipeFailed(e))?;
|
||||
|
||||
// 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'; BUF_LENGTH];
|
||||
|
||||
let mut cursor = 0_usize;
|
||||
|
||||
loop {
|
||||
let result = {
|
||||
let read_into = &mut buf[cursor..];
|
||||
nix::unistd::read(readerfd.as_raw_fd(), read_into)
|
||||
};
|
||||
|
||||
let end = match result {
|
||||
Ok(0) => {
|
||||
info!("Log pipe closed. Terminating log thread");
|
||||
return;
|
||||
},
|
||||
Ok(bytes) => bytes + cursor,
|
||||
Err(nix::errno::Errno::EINTR) => continue,
|
||||
Err(e) => {
|
||||
error!("Failed to read from redirected stdout/stderr pipe due to {e:?}. Closing log thread");
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
// 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') {
|
||||
log_raw_msg(&buf[0..last_newline_pos]);
|
||||
|
||||
if last_newline_pos < buf.len() {
|
||||
let pos_after_newline = last_newline_pos + 1;
|
||||
let len_not_logged_yet = buf[pos_after_newline..].len();
|
||||
buf.copy_within(pos_after_newline..end, 0);
|
||||
cursor = len_not_logged_yet;
|
||||
} else {
|
||||
cursor = 0;
|
||||
}
|
||||
} else if end == BUF_LENGTH {
|
||||
// No newline found but the buffer is full, flush it anyway.
|
||||
log_raw_msg(buf);
|
||||
cursor = 0;
|
||||
} else {
|
||||
cursor = end;
|
||||
}
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue