split log

This commit is contained in:
Nilton Constantino 2026-01-18 04:48:49 +00:00
parent f04c12d78c
commit 203e0835e3
No known key found for this signature in database
5 changed files with 130 additions and 120 deletions

View File

@ -0,0 +1,13 @@
use crate::log::LogLevel;
use crate::log::LogSource;
#[derive(Debug, Clone)]
pub struct LogEvent {
pub seq: u64,
pub ts_ms: u64,
pub frame: u64,
pub level: LogLevel,
pub source: LogSource,
pub tag: u16,
pub msg: String,
}

View File

@ -0,0 +1,8 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogLevel {
Trace,
Debug,
Info,
Warn,
Error,
}

View File

@ -0,0 +1,93 @@
use std::collections::VecDeque;
use crate::log::{LogEvent, LogLevel, LogSource};
pub struct LogService {
events: VecDeque<LogEvent>,
capacity: usize,
next_seq: u64,
}
impl LogService {
pub fn new(capacity: usize) -> Self {
Self {
events: VecDeque::with_capacity(capacity),
capacity,
next_seq: 0,
}
}
pub fn log(&mut self, ts_ms: u64, frame: u64, level: LogLevel, source: LogSource, tag: u16, msg: String) {
if self.events.len() >= self.capacity {
self.events.pop_front();
}
self.events.push_back(LogEvent {
seq: self.next_seq,
ts_ms,
frame,
level,
source,
tag,
msg,
});
self.next_seq += 1;
}
pub fn get_recent(&self, n: usize) -> Vec<LogEvent> {
self.events.iter().rev().take(n).cloned().collect::<Vec<_>>().into_iter().rev().collect()
}
pub fn get_after(&self, seq: u64) -> Vec<LogEvent> {
self.events.iter().filter(|e| e.seq > seq).cloned().collect()
}
pub fn last_seq(&self) -> Option<u64> {
self.events.back().map(|e| e.seq)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ring_buffer_capacity() {
let mut service = LogService::new(3);
service.log(100, 1, LogLevel::Info, LogSource::Pos, 0, "Log 1".to_string());
service.log(110, 1, LogLevel::Info, LogSource::Pos, 0, "Log 2".to_string());
service.log(120, 1, LogLevel::Info, LogSource::Pos, 0, "Log 3".to_string());
assert_eq!(service.events.len(), 3);
assert_eq!(service.events[0].msg, "Log 1");
service.log(130, 1, LogLevel::Info, LogSource::Pos, 0, "Log 4".to_string());
assert_eq!(service.events.len(), 3);
assert_eq!(service.events[0].msg, "Log 2");
assert_eq!(service.events[2].msg, "Log 4");
}
#[test]
fn test_get_recent() {
let mut service = LogService::new(10);
for i in 0..5 {
service.log(i as u64, 1, LogLevel::Info, LogSource::Pos, 0, format!("Log {}", i));
}
let recent = service.get_recent(2);
assert_eq!(recent.len(), 2);
assert_eq!(recent[0].msg, "Log 3");
assert_eq!(recent[1].msg, "Log 4");
}
#[test]
fn test_get_after() {
let mut service = LogService::new(10);
for i in 0..5 {
service.log(i as u64, 1, LogLevel::Info, LogSource::Pos, 0, format!("Log {}", i));
}
let after = service.get_after(2); // seqs são 0, 1, 2, 3, 4. Deve retornar 3 e 4.
assert_eq!(after.len(), 2);
assert_eq!(after[0].msg, "Log 3");
assert_eq!(after[1].msg, "Log 4");
}
}

View File

@ -0,0 +1,8 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogSource {
Pos,
Hub,
Vm,
Fs,
App { app_id: u32 },
}

View File

@ -1,121 +1,9 @@
use std::collections::VecDeque;
mod log_level;
mod log_source;
mod log_event;
mod log_service;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogLevel {
Trace,
Debug,
Info,
Warn,
Error,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogSource {
Pos,
Hub,
Vm,
Fs,
App { app_id: u32 },
}
#[derive(Debug, Clone)]
pub struct LogEvent {
pub seq: u64,
pub ts_ms: u64,
pub frame: u64,
pub level: LogLevel,
pub source: LogSource,
pub tag: u16,
pub msg: String,
}
pub struct LogService {
events: VecDeque<LogEvent>,
capacity: usize,
next_seq: u64,
}
impl LogService {
pub fn new(capacity: usize) -> Self {
Self {
events: VecDeque::with_capacity(capacity),
capacity,
next_seq: 0,
}
}
pub fn log(&mut self, ts_ms: u64, frame: u64, level: LogLevel, source: LogSource, tag: u16, msg: String) {
if self.events.len() >= self.capacity {
self.events.pop_front();
}
self.events.push_back(LogEvent {
seq: self.next_seq,
ts_ms,
frame,
level,
source,
tag,
msg,
});
self.next_seq += 1;
}
pub fn get_recent(&self, n: usize) -> Vec<LogEvent> {
self.events.iter().rev().take(n).cloned().collect::<Vec<_>>().into_iter().rev().collect()
}
pub fn get_after(&self, seq: u64) -> Vec<LogEvent> {
self.events.iter().filter(|e| e.seq > seq).cloned().collect()
}
pub fn last_seq(&self) -> Option<u64> {
self.events.back().map(|e| e.seq)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ring_buffer_capacity() {
let mut service = LogService::new(3);
service.log(100, 1, LogLevel::Info, LogSource::Pos, 0, "Log 1".to_string());
service.log(110, 1, LogLevel::Info, LogSource::Pos, 0, "Log 2".to_string());
service.log(120, 1, LogLevel::Info, LogSource::Pos, 0, "Log 3".to_string());
assert_eq!(service.events.len(), 3);
assert_eq!(service.events[0].msg, "Log 1");
service.log(130, 1, LogLevel::Info, LogSource::Pos, 0, "Log 4".to_string());
assert_eq!(service.events.len(), 3);
assert_eq!(service.events[0].msg, "Log 2");
assert_eq!(service.events[2].msg, "Log 4");
}
#[test]
fn test_get_recent() {
let mut service = LogService::new(10);
for i in 0..5 {
service.log(i as u64, 1, LogLevel::Info, LogSource::Pos, 0, format!("Log {}", i));
}
let recent = service.get_recent(2);
assert_eq!(recent.len(), 2);
assert_eq!(recent[0].msg, "Log 3");
assert_eq!(recent[1].msg, "Log 4");
}
#[test]
fn test_get_after() {
let mut service = LogService::new(10);
for i in 0..5 {
service.log(i as u64, 1, LogLevel::Info, LogSource::Pos, 0, format!("Log {}", i));
}
let after = service.get_after(2); // seqs são 0, 1, 2, 3, 4. Deve retornar 3 e 4.
assert_eq!(after.len(), 2);
assert_eq!(after[0].msg, "Log 3");
assert_eq!(after[1].msg, "Log 4");
}
}
pub use log_level::LogLevel;
pub use log_source::LogSource;
pub use log_event::LogEvent;
pub use log_service::LogService;