runtime/logger: use blocking wait.

Fixes #84 using the first solution.

If the performance is considered too slow,
we can do the second option later.
This commit is contained in:
pca006132 2020-08-05 16:20:20 +08:00
parent 72427dbebb
commit c1402552c1
2 changed files with 26 additions and 16 deletions

View File

@ -38,7 +38,8 @@ impl<'a> Drop for LogBufferRef<'a> {
pub struct BufferLogger { pub struct BufferLogger {
buffer: Mutex<LogBuffer<&'static mut [u8]>>, buffer: Mutex<LogBuffer<&'static mut [u8]>>,
uart_filter: Cell<LevelFilter> uart_filter: Cell<LevelFilter>,
buffer_filter: Cell<LevelFilter>,
} }
static mut LOGGER: Option<BufferLogger> = None; static mut LOGGER: Option<BufferLogger> = None;
@ -48,6 +49,7 @@ impl BufferLogger {
BufferLogger { BufferLogger {
buffer: Mutex::new(LogBuffer::new(buffer)), buffer: Mutex::new(LogBuffer::new(buffer)),
uart_filter: Cell::new(LevelFilter::Info), uart_filter: Cell::new(LevelFilter::Info),
buffer_filter: Cell::new(LevelFilter::Trace),
} }
} }
@ -76,6 +78,15 @@ impl BufferLogger {
pub fn set_uart_log_level(&self, max_level: LevelFilter) { pub fn set_uart_log_level(&self, max_level: LevelFilter) {
self.uart_filter.set(max_level) self.uart_filter.set(max_level)
} }
pub fn buffer_log_level(&self) -> LevelFilter {
self.buffer_filter.get()
}
/// this should be reserverd for mgmt module
pub fn set_buffer_log_level(&self, max_level: LevelFilter) {
self.buffer_filter.set(max_level)
}
} }
// required for impl Log // required for impl Log
@ -94,7 +105,8 @@ impl Log for BufferLogger {
let seconds = timestamp / 1_000_000; let seconds = timestamp / 1_000_000;
let micros = timestamp % 1_000_000; let micros = timestamp % 1_000_000;
if let Some(mut buffer) = self.buffer.try_lock() { if record.level() <= self.buffer_log_level() {
let mut buffer = self.buffer.lock();
writeln!(buffer, "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros, writeln!(buffer, "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros,
record.level(), record.target(), record.args()).unwrap(); record.level(), record.target(), record.args()).unwrap();
} }

View File

@ -98,9 +98,9 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>) ->
let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?; let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?;
match msg { match msg {
Request::GetLog => { Request::GetLog => {
let mut buffer = get_logger_buffer().await; let buffer = get_logger_buffer().await.extract().as_bytes().to_vec();
write_i8(stream, Reply::LogContent as i8).await?; write_i8(stream, Reply::LogContent as i8).await?;
write_chunk(stream, buffer.extract().as_bytes()).await?; write_chunk(stream, &buffer).await?;
} }
Request::ClearLog => { Request::ClearLog => {
let mut buffer = get_logger_buffer().await; let mut buffer = get_logger_buffer().await;
@ -115,24 +115,22 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>) ->
}; };
loop { loop {
let mut buffer = get_logger_buffer_pred(|b| !b.is_empty()).await; let mut buffer = get_logger_buffer_pred(|b| !b.is_empty()).await;
let bytes = buffer.extract().as_bytes();
if id != *pull_id.borrow() { if id != *pull_id.borrow() {
// another connection attempts to pull the log... // another connection attempts to pull the log...
// abort this connection... // abort this connection...
break; break;
} }
write_chunk(stream, bytes).await?; let bytes = buffer.extract().as_bytes().to_vec();
if log::max_level() == LevelFilter::Trace {
// Hold exclusive access over the logger until we get positive
// acknowledgement; otherwise we get an infinite loop of network
// trace messages being transmitted and causing more network
// trace messages to be emitted.
//
// Any messages unrelated to this management socket that arrive
// while it is flushed are lost, but such is life.
stream.flush().await?;
}
buffer.clear(); buffer.clear();
core::mem::drop(buffer);
write_chunk(stream, &bytes).await?;
if log::max_level() == LevelFilter::Trace {
// temporarily discard all trace level log
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
logger.set_buffer_log_level(LevelFilter::Debug);
stream.flush().await?;
logger.set_buffer_log_level(LevelFilter::Trace);
}
} }
}, },
Request::SetLogFilter => { Request::SetLogFilter => {