Enhance logging display in dev panel with structured output and improved styling

This commit is contained in:
Greg Burri 2025-04-26 15:56:56 +02:00
parent 2d1aa4bdfd
commit 1bb0f05fc0
4 changed files with 110 additions and 21 deletions

1
.gitignore vendored
View file

@ -16,3 +16,4 @@ conf.ron
node_modules
pkg
package-lock.json
.vscode/settings.json

View file

@ -188,8 +188,52 @@ body {
}
#dev-panel {
.log-line-odd {
background-color: consts.$color-1;
.line {
padding: 3px;
&.odd {
background-color: consts.$color-1;
}
}
.date-time {
font-weight: bold;
}
.level {
padding: 2px;
border-radius: 4px;
&.ERROR {
color: white;
background-color: red;
}
&.WARN {
color: black;
background-color: orange;
}
&.INFO {
color: white;
background-color: blue;
}
&.DEBUG {
color: white;
background-color: green;
}
&.TRACE {
color: black;
background-color: yellow;
}
}
.thread-name,
.thread-id {
font-style: italic;
font-size: 80%;
}
}

View file

@ -1,6 +1,6 @@
use std::{
fs::{self, File},
io::{BufRead, BufReader},
fs::{self, DirEntry, File},
io::{self, BufRead, BufReader},
path::{Path, PathBuf},
sync::Arc,
};
@ -34,7 +34,6 @@ pub struct Log {
directory: PathBuf,
}
// TODO: Remove all 'unwrap'.
impl Log {
pub fn new<P>(directory: P) -> Self
where
@ -76,28 +75,38 @@ impl Log {
}
pub fn file_names(&self) -> std::io::Result<Vec<String>> {
fn dir_entry_to_string(entry: Result<DirEntry, io::Error>) -> String {
entry.map_or_else(
|err| format!("Unable to read entry: {}", err),
|entry| {
entry
.path()
.file_name()
.map_or("Unable to read filename".into(), |filename| {
filename
.to_str()
.map_or("Unable to read filename".into(), |filename| {
filename.to_string()
})
})
},
)
}
Ok(self
.directory
.read_dir()?
.map(|entry| {
entry
.unwrap()
.path()
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_string()
})
.map(dir_entry_to_string)
.sorted()
.rev()
.collect())
}
/// Reads the content of a log file and return it as a vector of lines.
pub fn read_content(&self, filename: &str) -> std::io::Result<Vec<String>> {
let filepath = self.directory.join(filename);
if filepath.is_file() {
let file = File::open(filepath)?;
// tracing::event!(Level::ERROR, "file: {:?}", file);
Ok(BufReader::new(file)
.lines()
.map(|l| l.unwrap_or_default())
@ -106,4 +115,32 @@ impl Log {
Ok(vec![])
}
}
pub fn split_line(line: &str) -> Line {
let mut line_splitted = line.split(' ').filter(|s| !s.is_empty());
Line {
date_time: line_splitted.next().unwrap_or_default(),
level: line_splitted.next().unwrap_or_default(),
thread_name: if TRACING_DISPLAY_THREAD {
line_splitted.next().unwrap_or_default()
} else {
""
},
thread_id: if TRACING_DISPLAY_THREAD {
line_splitted.next().unwrap_or_default()
} else {
""
},
message: line_splitted.join(" "), // TODO: use `remainder()` when in stable Rust.
}
}
}
pub struct Line<'a> {
pub date_time: &'a str,
pub level: &'a str,
pub thread_name: &'a str,
pub thread_id: &'a str,
pub message: String,
}

View file

@ -16,13 +16,20 @@
{% match log.read_content(current_log_file) %}
{% when Ok(lines) %}
{% for l in lines %}
<div class="
{% if loop.index0 % 2 == 0 %}
log-line-even
<div class="line
{%~ if loop.index0 % 2 == 0 %}
even
{% else %}
log-line-odd
odd
{% endif %}
" >{{ l }}</div>
" >
{% let l_info = Log::split_line(l) %}
<span class="date-time">{{ l_info.date_time }}</span>
<span class="level {{~ l_info.level }}">{{ l_info.level }}</span>
<span class="thread-name">{{ l_info.thread_name }}</span>
<span class="thread-id">{{ l_info.thread_id }}</span>
<span class="message">{{ l_info.message | linebreaksbr }}</span>
</div>
{% endfor %}
{% when Err(err) %}
Error reading log: {{ err }}