Browse Source

New logging system

- Switched current ANSI frontend to trait,
 - Added barebones frontend, without fancy things
main
ThePerkinrex 4 years ago
parent
commit
e96b7e3220
No known key found for this signature in database GPG Key ID: FD81DE6D75E20917
  1. 8
      server/schema/server-properties.json
  2. 5
      server/src/games/run.rs
  3. 39
      server/src/logger.rs
  4. 57
      server/src/logger/ansi.rs
  5. 62
      server/src/logger/ansi/color_message.rs
  6. 74
      server/src/logger/barebones.rs
  7. 10
      server/src/server_properties.rs

8
server/schema/server-properties.json

@ -7,6 +7,10 @@
"default": "0.0.0.0:50052",
"type": "string"
},
"logger": {
"default": "barebones",
"type": "string"
},
"name": {
"default": "Spah's sappin' mah sentreh",
"type": "string"
@ -14,10 +18,6 @@
"schema": {
"default": "https://theperkinrex.duckdns.org/CardsSimulator/cards-simulator/raw/branch/main/server/schema/server-properties.json",
"type": "string"
},
"use_colors": {
"default": true,
"type": "boolean"
}
}
}

5
server/src/games/run.rs

@ -141,7 +141,10 @@ impl RunningGame {
let mut arr = match self.functions.turn_end(data, self.current_player) {
Err(x) => match x.as_ref() {
EvalAltResult::Return(x, _) => Ok(x.clone_cast()),
_ =>{log::debug!("ERR: {}", x);Err(x)},
_ => {
log::debug!("ERR: {}", x);
Err(x)
}
},
x => x,
}?;

39
server/src/logger.rs

@ -1,9 +1,17 @@
use std::sync::mpsc;
mod ansi;
mod barebones;
use fern::Dispatch;
use crate::{allocator::{self, Allocator}, command::command_handler, server_properties::ServerProperties};
use crate::{
allocator::{self, Allocator},
command::command_handler,
server_properties::ServerProperties,
};
use self::{ansi::ANSIFrontend, barebones::BarebonesFrontend};
pub type Stdout = mpsc::Sender<String>;
pub type Stdin<T> = mpsc::Receiver<T>;
@ -11,7 +19,7 @@ pub type Stdin<T> = mpsc::Receiver<T>;
pub struct Close {
close: mpsc::Sender<()>,
handle: tokio::task::JoinHandle<()>,
close_handler: Box<dyn Fn()>
close_handler: Box<dyn Fn()>,
}
impl Close {
@ -25,7 +33,7 @@ impl Close {
trait LoggingFrontend {
fn setup(
properties: &crate::server_properties::ServerProperties,
logger_filter: Dispatch
logger_filter: Dispatch,
) -> anyhow::Result<(Close, Stdin<String>)> {
Self::setup_with_handler(properties, command_handler, logger_filter)
}
@ -33,12 +41,8 @@ trait LoggingFrontend {
fn setup_with_handler<F: Fn(String) -> String + Send + 'static>(
properties: &crate::server_properties::ServerProperties,
handler: F,
logger_filter: Dispatch
logger_filter: Dispatch,
) -> anyhow::Result<(Close, Stdin<String>)>;
fn cleanup(&self);
fn name() -> &'static str;
}
pub fn setup(properties: &ServerProperties) -> anyhow::Result<(Close, Stdin<String>)> {
@ -51,13 +55,20 @@ pub fn setup(properties: &ServerProperties) -> anyhow::Result<(Close, Stdin<Stri
);
let d = fern::Dispatch::new()
.level(log::LevelFilter::Debug)
.level_for("h2", log::LevelFilter::Info)
.level_for("tokio::codec", log::LevelFilter::Info)
.level_for("sqlx::query", log::LevelFilter::Info)
.chain(file);
.level(log::LevelFilter::Debug)
.level_for("h2", log::LevelFilter::Info)
.level_for("tokio::codec", log::LevelFilter::Info)
.level_for("sqlx::query", log::LevelFilter::Info)
.chain(file);
// TODO select logging frontend
ansi::ANSIFrontend::setup(properties, d)
match properties.logger.as_str() {
"barebones" => BarebonesFrontend::setup(properties, d),
"ANSI" => ANSIFrontend::setup(properties, d),
x => {
println!("Unrecognized logging frontend {}, please select a valid one (barebones, ANSI) from the ones featured on your build, whose list could be smaller than the one shown", x);
Err(anyhow::anyhow!("Unrecognized logging frontend"))
}
}
}
fn simple_formatter(d: fern::Dispatch) -> fern::Dispatch {

57
server/src/logger/ansi.rs

@ -12,25 +12,23 @@ use crossterm::{
terminal::{Clear, ClearType},
};
use fern::Dispatch;
use fern::colors::{Color, ColoredLevelConfig};
use fern::Dispatch;
mod color_message;
use color_message::print_line;
use crate::allocator::{self, Allocator};
use crate::logger::simple_formatter;
pub(super) struct ANSIFrontend;
impl LoggingFrontend for ANSIFrontend {
fn setup_with_handler<F: Fn(String) -> String + Send + 'static>(
properties: &crate::server_properties::ServerProperties,
_: &crate::server_properties::ServerProperties,
handler: F,
logger_filter: Dispatch
logger_filter: Dispatch,
) -> anyhow::Result<(Close, Stdin<String>)> {
let (stdout, stdin, close, join_handle) =
TerminalHandler::new(handler, properties.use_colors);
let (stdout, stdin, close, join_handle) = TerminalHandler::new(handler);
// let simple_formatter = |out: fern::FormatCallback, message: _, record: &log::Record| {
// out.finish(format_args!(
@ -41,36 +39,22 @@ impl LoggingFrontend for ANSIFrontend {
// message,
// ))
// };
let stdout_logger = if properties.use_colors {
colored_formatter(fern::Dispatch::new())
} else {
simple_formatter(fern::Dispatch::new())
}
.chain(stdout);
let stdout_logger = colored_formatter(fern::Dispatch::new()).chain(stdout);
logger_filter
.chain(stdout_logger)
.apply()?;
logger_filter.chain(stdout_logger).apply()?;
log::info!("Saving output to output.log");
// std::process::exit(1);
Ok((
Close {
close,
handle: join_handle,
close_handler: Box::new(|| queue!(std::io::stdout(), crossterm::event::DisableMouseCapture).unwrap())
close_handler: Box::new(|| {
queue!(std::io::stdout(), crossterm::event::DisableMouseCapture).unwrap()
}),
},
stdin,
))
}
fn cleanup(&self) {
cleanup()
}
fn name() -> &'static str {
"ANSI"
}
}
fn cleanup() {
@ -128,7 +112,6 @@ where
handler: F,
lines: LimitedVec<String>,
command: String,
use_colors: bool,
}
impl<T, F> TerminalHandler<T, F>
@ -139,7 +122,6 @@ where
#[allow(clippy::new_ret_no_self)]
fn new(
handler: F,
use_colors: bool,
) -> (
Stdout,
Stdin<T>,
@ -160,7 +142,6 @@ where
handler,
lines: LimitedVec::new(crossterm::terminal::size().unwrap().1 as usize - 1),
command: String::new(),
use_colors,
};
loop {
if s.iterate() {
@ -256,8 +237,8 @@ where
queue!(stdout, Clear(ClearType::All), MoveTo(0, 0)).unwrap();
let mut i = 0;
let size = crossterm::terminal::size().unwrap();
for v in self.lines.iter(self.use_colors) {
print_line(&v, self.use_colors, &mut stdout);
for v in self.lines.iter() {
print_line(&v, &mut stdout);
queue!(stdout, MoveToNextLine(1)).unwrap();
i += 1;
if i >= size.1 as usize - 1 {
@ -319,7 +300,7 @@ impl<T> LimitedVec<T> {
// assert!(self.inner.len() <= self.size)
}
fn iter<'a>(&'a self, use_colors: bool) -> Box<dyn Iterator<Item = String> + 'a>
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = String> + 'a>
where
T: std::fmt::Display,
{
@ -341,15 +322,11 @@ impl<T> LimitedVec<T> {
let map = iter.enumerate().map(move |(i, x)| {
format!(
"{}{}",
if use_colors {
format!(
"\x1B[{}m{:>5}\x1B[0m ",
fern::colors::Color::BrightBlack.to_fg_str(),
start + i
)
} else {
String::new()
},
format!(
"\x1B[{}m{:>5}\x1B[0m ",
fern::colors::Color::BrightBlack.to_fg_str(),
start + i
),
x
)
});

62
server/src/logger/ansi/color_message.rs

@ -9,42 +9,38 @@ lazy_static! {
pub static ref ANSI_REGEX: Regex = Regex::new(ANSI_RE).unwrap();
}
pub fn print_line(message: &str, use_colors: bool, stdout: &mut std::io::Stdout) {
if use_colors {
let mut s = String::new();
let mut highlight = false;
let mut i = 0;
let mut current = "\x1B[0m".to_string();
for c in message.chars() {
if c == '`' {
// queue!(stdout, Print(format!("{}`", highlight))).unwrap();
if highlight {
let styled = format!(
"\x1B[{}m{}{}",
fern::colors::Color::Blue.to_fg_str(),
s,
current
);
queue!(stdout, Print(styled)).unwrap();
} else {
queue!(stdout, Print(s)).unwrap();
}
s = String::new();
pub fn print_line(message: &str, stdout: &mut std::io::Stdout) {
let mut s = String::new();
let mut highlight = false;
let mut i = 0;
let mut current = "\x1B[0m".to_string();
for c in message.chars() {
if c == '`' {
// queue!(stdout, Print(format!("{}`", highlight))).unwrap();
if highlight {
let styled = format!(
"\x1B[{}m{}{}",
fern::colors::Color::Blue.to_fg_str(),
s,
current
);
queue!(stdout, Print(styled)).unwrap();
} else {
queue!(stdout, Print(s)).unwrap();
}
s = String::new();
highlight = !highlight;
continue;
} else if !highlight {
if let Some(m) = ANSI_REGEX.find_at(message, i) {
if i == m.start() {
current = m.as_str().to_string();
}
highlight = !highlight;
continue;
} else if !highlight {
if let Some(m) = ANSI_REGEX.find_at(message, i) {
if i == m.start() {
current = m.as_str().to_string();
}
}
i += 1;
s.push(c);
}
queue!(stdout, Print(&s)).unwrap();
} else {
queue!(stdout, Print(message)).unwrap();
i += 1;
s.push(c);
}
queue!(stdout, Print(&s)).unwrap();
}

74
server/src/logger/barebones.rs

@ -0,0 +1,74 @@
use std::{io::stdout, sync::mpsc, time::Duration};
use fern::Dispatch;
use tokio::{
io::{AsyncBufReadExt, BufReader},
select, spawn,
task::spawn_blocking,
};
use crate::logger::simple_formatter;
use super::{Close, LoggingFrontend, Stdin};
pub(super) struct BarebonesFrontend;
impl LoggingFrontend for BarebonesFrontend {
fn setup_with_handler<F: Fn(String) -> String + Send + 'static>(
_: &crate::server_properties::ServerProperties,
handler: F,
logger_filter: fern::Dispatch,
) -> anyhow::Result<(Close, Stdin<String>)> {
let l = simple_formatter(Dispatch::new()).chain(stdout());
logger_filter.chain(l).apply()?;
log::info!("Saving output to output.log");
let (stdin_send, stdin) = mpsc::channel();
let (close, close_recv) = mpsc::channel();
let (close_send_async, mut close_recv_async) = tokio::sync::mpsc::unbounded_channel();
spawn_blocking(move || {
while let Err(mpsc::TryRecvError::Empty) = close_recv.try_recv() {}
close_send_async
.send(())
.expect("Error resending close signal");
});
let handle = spawn(async move {
select! {_ = close_recv_async.recv() => cleanup(),
_ = async move {
let mut lines = BufReader::new(tokio::io::stdin()).lines();
while let Some(line) = lines.next_line().await.expect("Error reading line") {
log::info!(target: "command", " >> {}", line);
stdin_send.send(handler(line)).expect("Error sending input line");
}
} => (),
_ = tokio::signal::ctrl_c() => {println!(); cleanup(); std::process::exit(0)},
}
});
std::panic::set_hook(Box::new(|info| {
let thread = std::thread::current();
let name = thread.name().unwrap_or("<unnamed>");
log::error!("thread '{}' {}", name, info);
log::info!("Exiting in 5 seconds");
std::thread::sleep(Duration::from_secs(5));
std::process::exit(0)
}));
Ok((
Close {
close,
handle,
close_handler: Box::new(|| {}),
},
stdin,
))
}
}
fn cleanup() {
log::info!(target: "cleanup", "Exiting server");
println!("Exiting server, output has been saved to output.log");
}

10
server/src/server_properties.rs

@ -9,8 +9,8 @@ pub struct ServerProperties {
pub name: String,
#[serde(default = "default_addr")]
pub addr: SocketAddr,
#[serde(default = "default_colors")]
pub use_colors: bool,
#[serde(default = "default_logger")]
pub logger: String,
#[serde(alias = "$schema", default = "default_schema")]
schema: String,
}
@ -33,14 +33,14 @@ impl Default for ServerProperties {
Self {
name: default_name(),
addr: default_addr(),
use_colors: default_colors(),
logger: default_logger(),
schema: default_schema(),
}
}
}
const fn default_colors() -> bool {
true
fn default_logger() -> String {
"barebones".into()
}
fn default_addr() -> SocketAddr {

Loading…
Cancel
Save