-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement a percpu line buffer to store the individual log messages.
Each individual log message gets written into the global log buffer from the percpu line buffer. Signed-off-by: Vasant Karasulli <[email protected]>
- Loading branch information
Showing
5 changed files
with
131 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
use crate::cpu::percpu::this_cpu_mut; | ||
use crate::log_buffer::LB; | ||
use crate::utils::immut_after_init::ImmutAfterInitCell; | ||
use core::fmt; | ||
use core::fmt::Write; | ||
|
||
const LINE_BUFFER_SIZE: usize = 256; | ||
pub struct LineBuffer { | ||
buf: [u8; LINE_BUFFER_SIZE], | ||
head: usize, | ||
tail: usize, | ||
} | ||
|
||
impl LineBuffer { | ||
pub const fn new() -> Self { | ||
LineBuffer { | ||
buf: [0; LINE_BUFFER_SIZE], | ||
head: 0, | ||
tail: 0, | ||
} | ||
} | ||
|
||
pub fn write_buffer(&mut self, s: &str) { | ||
for b in s.bytes() { | ||
self.buf[self.head] = b; | ||
self.head = (self.head + 1) % LINE_BUFFER_SIZE; | ||
if b == 0xa { | ||
/* write to global log buffer when '\n' character is encountered */ | ||
if self.tail <= self.head { | ||
let st = core::str::from_utf8(&self.buf[self.tail..self.head]).unwrap(); | ||
unsafe { LB.write_log(st) }; | ||
} else { | ||
let st1 = core::str::from_utf8(&self.buf[self.tail..]).unwrap(); | ||
let st2 = core::str::from_utf8(&self.buf[..self.head]).unwrap(); | ||
unsafe { LB.write_log(st1) }; | ||
unsafe { LB.write_log(st2) }; | ||
} | ||
self.tail = self.head; | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl fmt::Write for LineBuffer { | ||
fn write_str(&mut self, s: &str) -> fmt::Result { | ||
self.write_buffer(s); | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[derive(Clone, Copy)] | ||
struct BufferLogger { | ||
component: &'static str, | ||
} | ||
|
||
impl BufferLogger { | ||
fn new(component: &'static str) -> BufferLogger { | ||
BufferLogger { component } | ||
} | ||
} | ||
|
||
impl log::Log for BufferLogger { | ||
fn enabled(&self, _metadata: &log::Metadata) -> bool { | ||
true | ||
} | ||
|
||
fn log(&self, record: &log::Record) { | ||
let component: &'static str = &self.component; | ||
let line_buf: &mut LineBuffer = this_cpu_mut().get_line_buffer(); | ||
// Log format/detail depends on the level. | ||
match record.metadata().level() { | ||
log::Level::Error | log::Level::Warn => write!( | ||
line_buf, | ||
"[{}] {}: {}\n", | ||
component, | ||
record.metadata().level().as_str(), | ||
record.args() | ||
) | ||
.expect("write error"), | ||
|
||
log::Level::Info => { | ||
write!(line_buf, "[{}] {}\n", component, record.args()).expect("write error") | ||
} | ||
|
||
log::Level::Debug | log::Level::Trace => write!( | ||
line_buf, | ||
"[{}/{}] {} {}\n", | ||
component, | ||
record.metadata().target(), | ||
record.metadata().level().as_str(), | ||
record.args() | ||
) | ||
.expect("write error"), | ||
} | ||
} | ||
|
||
fn flush(&self) {} | ||
} | ||
|
||
static BUFFER_LOGGER: ImmutAfterInitCell<BufferLogger> = ImmutAfterInitCell::uninit(); | ||
|
||
pub fn install_buffer_logger(component: &'static str) -> Result<(), ()> { | ||
BUFFER_LOGGER | ||
.init(&BufferLogger::new(component)) | ||
.expect("already initialized the logger"); | ||
if let Err(_) = log::set_logger(&*BUFFER_LOGGER) { | ||
return Err(()); | ||
} | ||
|
||
// Log levels are to be configured via the log's library feature configuration. | ||
log::set_max_level(log::LevelFilter::Trace); | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters