-
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
4 changed files
with
150 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
// | ||
// Copyright (c) 2022-2023 SUSE LLC | ||
// | ||
// Author: Vasant Karasulli <[email protected]> | ||
|
||
use crate::cpu::percpu::this_cpu_mut; | ||
use crate::log_buffer::LB; | ||
use crate::string::FixedString; | ||
use crate::utils::immut_after_init::ImmutAfterInitCell; | ||
use core::fmt; | ||
use core::fmt::Write; | ||
|
||
const LINE_BUFFER_SIZE: usize = 256; | ||
|
||
#[derive(Debug)] | ||
pub struct LineBuffer { | ||
buf: FixedString<LINE_BUFFER_SIZE>, | ||
} | ||
|
||
impl LineBuffer { | ||
pub const fn new() -> Self { | ||
LineBuffer { | ||
buf: FixedString::new(), | ||
} | ||
} | ||
|
||
pub fn write_buffer(&mut self, s: &str) { | ||
for c in s.chars() { | ||
self.buf.push(c); | ||
if c == '\n' || self.buf.length() == LINE_BUFFER_SIZE { | ||
// when buffer is full or '\n' character is encountered | ||
let mut buf_str: [u8; LINE_BUFFER_SIZE * 4] = [0; LINE_BUFFER_SIZE * 4]; | ||
let mut count: usize = 0; | ||
let mut tmp: [u8; 4] = [0; 4]; | ||
for ch in self.buf { | ||
ch.encode_utf8(&mut tmp); | ||
buf_str[count] = tmp[0]; | ||
count += 1; | ||
for item in tmp.iter().skip(1) { | ||
/* ignore the trailing zeros in the utf8 array */ | ||
if *item != 0 { | ||
buf_str[count] = *item; | ||
count += 1; | ||
} | ||
} | ||
} | ||
unsafe { LB.lock().write_log(&buf_str[..count]) }; | ||
self.buf.reset(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
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 comp: &'static str = self.component; | ||
let line_buf: &mut LineBuffer = this_cpu_mut().get_line_buffer(); | ||
// Log format/detail depends on the level. | ||
let rec_args = record.args(); | ||
let lvl = record.metadata().level().as_str(); | ||
let target = record.metadata().target(); | ||
match record.metadata().level() { | ||
log::Level::Error | log::Level::Warn => { | ||
line_buf | ||
.write_fmt(format_args!("[{}] {}: {}\n", comp, lvl, rec_args)) | ||
.unwrap(); | ||
} | ||
|
||
log::Level::Info => { | ||
line_buf | ||
.write_fmt(format_args!("[{}] {}\n", comp, rec_args)) | ||
.unwrap(); | ||
} | ||
|
||
log::Level::Debug | log::Level::Trace => { | ||
line_buf | ||
.write_fmt(format_args!("[{}/{}] {} {}\n", comp, target, lvl, rec_args)) | ||
.unwrap(); | ||
} | ||
} | ||
} | ||
|
||
fn flush(&self) {} | ||
} | ||
|
||
static BUFFER_LOGGER: ImmutAfterInitCell<BufferLogger> = ImmutAfterInitCell::uninit(); | ||
|
||
pub fn install_buffer_logger(component: &'static str) { | ||
BUFFER_LOGGER | ||
.init(&BufferLogger::new(component)) | ||
.expect("already initialized the logger"); | ||
let _ = log::set_logger(&*BUFFER_LOGGER); | ||
|
||
// Log levels are to be configured via the log's library feature configuration. | ||
log::set_max_level(log::LevelFilter::Trace); | ||
} |
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