From a4a8c59bb8bb8788548a105c4453f037810563b0 Mon Sep 17 00:00:00 2001 From: Jason Spalti Date: Mon, 2 Dec 2024 11:51:39 -0600 Subject: [PATCH] Refactor logging system to switch between stdout and file logging * Refactor logging to switch between stdout and file logging * Use "clear" instead of "tput reset" for unix * Remove redundant comments --- editor/Cargo.toml | 2 - editor/src/main.rs | 5 ++- engine/Cargo.toml | 5 ++- engine/src/core/mod.rs | 1 - engine/src/core/renderer/ctx.rs | 74 +++++++++++++++++--------------- engine/src/core/renderer/mod.rs | 31 +++++++------ engine/src/core/repl/commands.rs | 10 ++--- engine/src/core/repl/mod.rs | 19 ++++---- engine/src/core/repl/repl.rs | 3 +- engine/src/main.rs | 68 +++++++++++++++-------------- engine/src/utils/logger.rs | 72 +++++++++++++++++++++++++++++++ engine/src/utils/mod.rs | 2 + engine/src/utils/splash.rs | 30 +++++++++++++ xtask/src/editor.rs | 5 ++- xtask/src/engine.rs | 17 ++++---- xtask/src/main.rs | 56 +++++++++++------------- 16 files changed, 252 insertions(+), 148 deletions(-) create mode 100644 engine/src/utils/logger.rs create mode 100644 engine/src/utils/mod.rs create mode 100644 engine/src/utils/splash.rs diff --git a/editor/Cargo.toml b/editor/Cargo.toml index f584ecb..b9c38f2 100644 --- a/editor/Cargo.toml +++ b/editor/Cargo.toml @@ -3,5 +3,3 @@ name = "editor" version = "0.1.0" edition = "2021" -[dependencies] - diff --git a/editor/src/main.rs b/editor/src/main.rs index 6bd4269..dcfd9e3 100644 --- a/editor/src/main.rs +++ b/editor/src/main.rs @@ -1,3 +1,4 @@ fn main() { - println!("editor") -} \ No newline at end of file + todo!() +} + diff --git a/engine/Cargo.toml b/engine/Cargo.toml index d9f748d..8032f37 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -6,10 +6,11 @@ edition = "2021" [dependencies] anyhow = "1.0.93" chrono = "0.4.38" +clap = { version = "4.5.21", features = ["derive"] } colored = "2.1.0" lazy_static = "1.5.0" -#log = "0.4.22" -log2 = "0.1.14" +log = "0.4.22" +once_cell = "1.20.2" parking_lot = "0.12.3" reedline = "0.37.0" regex = "1.11.1" diff --git a/engine/src/core/mod.rs b/engine/src/core/mod.rs index fe2a8cd..5615f54 100644 --- a/engine/src/core/mod.rs +++ b/engine/src/core/mod.rs @@ -11,4 +11,3 @@ pub fn init_renderer() -> Result<()> { let mut app = App::default(); Ok(event_loop.run_app(&mut app)?) } - diff --git a/engine/src/core/renderer/ctx.rs b/engine/src/core/renderer/ctx.rs index 690ed0b..fca1090 100644 --- a/engine/src/core/renderer/ctx.rs +++ b/engine/src/core/renderer/ctx.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use anyhow::Result; -use tokio::task::spawn_blocking; use winit::window::Window; pub struct WgpuCtx<'window> { @@ -46,13 +45,14 @@ impl<'window> WgpuCtx<'window> { surface.configure(&device, &surface_config); Ok(WgpuCtx { - device: device, - queue: queue, - surface: surface, - surface_config: surface_config, - adapter: adapter, + device, + queue, + surface, + surface_config, + adapter, }) } + pub fn new_blocking(window: Arc) -> Result> { tokio::task::block_in_place(|| { tokio::runtime::Runtime::new() @@ -60,41 +60,47 @@ impl<'window> WgpuCtx<'window> { .block_on(async { WgpuCtx::new(window).await }) }) } + pub fn resize(&mut self, new_size: (u32, u32)) { let (width, height) = new_size; self.surface_config.width = width.max(1); self.surface_config.height = height.max(1); self.surface.configure(&self.device, &self.surface_config); } + pub fn draw(&mut self) { let surface_texture = self - .surface - .get_current_texture() - .expect("Failed to get surface texture"); - let view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default()); - let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); - { - let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: None, - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0.1, - g: 0.2, - b: 0.3, - a: 1.0, - }), - store: wgpu::StoreOp::Store, - }, - })], - depth_stencil_attachment: None, - timestamp_writes: None, - occlusion_query_set: None, - }); - } - self.queue.submit(Some(encoder.finish())); - surface_texture.present(); + .surface + .get_current_texture() + .expect("Failed to get surface texture"); + let view = surface_texture + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + { + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.1, + g: 0.2, + b: 0.3, + a: 1.0, + }), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + } + self.queue.submit(Some(encoder.finish())); + surface_texture.present(); } } diff --git a/engine/src/core/renderer/mod.rs b/engine/src/core/renderer/mod.rs index c6fcdab..65486a3 100644 --- a/engine/src/core/renderer/mod.rs +++ b/engine/src/core/renderer/mod.rs @@ -1,12 +1,13 @@ -use std::sync::Arc; - +pub mod ctx; use ctx::WgpuCtx; -use log2::{debug, error, trace}; + +use log::{debug, trace}; +use std::sync::Arc; use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::ActiveEventLoop; -use winit::window::{self, Window, WindowId}; -pub mod ctx; +use winit::window::{Window, WindowId}; + #[derive(Default)] pub struct App<'window> { window: Option>, @@ -17,9 +18,11 @@ impl ApplicationHandler for App<'_> { fn resumed(&mut self, event_loop: &ActiveEventLoop) { if self.window.is_none() { let win_attr = Window::default_attributes().with_title("Zenyx"); - let window = Arc::new(event_loop - .create_window(win_attr) - .expect("create window err.")); + let window = Arc::new( + event_loop + .create_window(win_attr) + .expect("create window err."), + ); self.window = Some(window.clone()); let wgpu_ctx = WgpuCtx::new_blocking(window.clone()).unwrap(); self.ctx = Some(wgpu_ctx) @@ -44,15 +47,15 @@ impl ApplicationHandler for App<'_> { } } WindowEvent::Resized(size) => { - if let (Some(wgpu_ctx),Some(window)) = (&mut self.ctx, &self.window) { + if let (Some(wgpu_ctx), Some(window)) = (&mut self.ctx, &self.window) { wgpu_ctx.resize(size.into()); window.request_redraw(); - let size_str: String = size.height.to_string() + "x" + &size.width.to_string(); - //self.window.as_ref().unwrap().set_title(&format!("you reszed the window to {size_str}")); - debug!("Window resized to {:?}", size_str); + + let size_str: String = size.height.to_string() + "x" + &size.width.to_string(); + debug!("Window resized to {:?}", size_str); + } } - } _ => trace!("Unhandled window event"), } } -} \ No newline at end of file +} diff --git a/engine/src/core/repl/commands.rs b/engine/src/core/repl/commands.rs index c4d2437..d500ca8 100644 --- a/engine/src/core/repl/commands.rs +++ b/engine/src/core/repl/commands.rs @@ -1,30 +1,28 @@ use super::COMMAND_LIST; use std::process::Command; -use log2::{debug, info}; +use log::debug; pub(crate) fn say_hello() { println!("Hello, World!"); } pub(crate) fn echo(args: Vec) { - debug!("{}", args.join(" ")); println!("{}", args.join(" ")) } pub(crate) fn exit() { - debug!("Exiting..."); + println!("Exiting..."); std::process::exit(0) } pub(crate) fn clear() { - info!("Clearing screen..., running command"); + println!("Clearing screen..., running command"); let _result = if cfg!(target_os = "windows") { debug!("target_os is windows"); Command::new("cmd").args(["/c", "cls"]).spawn() } else { debug!("target_os is unix"); - // "clear" or "tput reset" - Command::new("tput").arg("reset").spawn() + Command::new("clear").spawn() }; } diff --git a/engine/src/core/repl/mod.rs b/engine/src/core/repl/mod.rs index 6a0ad4c..19a0cdf 100644 --- a/engine/src/core/repl/mod.rs +++ b/engine/src/core/repl/mod.rs @@ -2,7 +2,7 @@ pub mod commands; pub mod repl; use lazy_static::lazy_static; -use log2::{debug, error, info}; +use log::{debug, info}; use parking_lot::RwLock; use std::{borrow::Borrow, collections::HashMap, sync::Arc}; @@ -26,11 +26,10 @@ pub struct Command { impl Command { pub fn execute(&self, args: Option>) { - //debug!("Executing command: {}", self.name); match &self.function { Callable::Simple(f) => { if let Some(args) = args { - error!( + eprintln!( "Command expected 0 arguments but {} args were given. Ignoring..", args.len() ); @@ -39,7 +38,7 @@ impl Command { } Callable::WithArgs(f) => match args { Some(args) => f(args), - None => error!("Command expected arguments but received 0"), + None => eprintln!("Command expected arguments but received 0"), }, } } @@ -76,7 +75,7 @@ impl CommandList { func: Callable, arg_count: Option, ) { - debug!("Adding command: {}", name); + info!("Adding command: {}", name); let mut commands = self.commands.write(); commands.push(Command { @@ -88,24 +87,22 @@ impl CommandList { } fn add_alias(&self, name: String, alias: String) { - //println!("Input alias: {}", alias); if self.aliases.read().contains_key(&alias) { - error!("Alias: '{}' already exists", alias); + eprintln!("Alias: '{}' already exists", alias); return; } let mut commands = self.commands.write(); if let Some(command) = commands.iter_mut().find(|cmd| cmd.name == name) { - info!("Adding alias: {} for cmd: {}", alias, command.name); + debug!("Adding alias: {} for cmd: {}", alias, command.name); self.aliases .write() .insert(alias.to_string(), name.to_string()); } else { - error!("Command: '{}' was not found", name); + eprintln!("Command: '{}' was not found", name); } } fn execute_command(&self, mut name: String, args: Option>) { - //info!("received input command: {}", name); let commands = self.commands.borrow(); if self.aliases.read().contains_key(&name) { name = self @@ -116,7 +113,7 @@ impl CommandList { .1 .to_string(); - debug!("changed to {}", name); + debug!("changed to {}", &name); } if let Some(command) = commands.read().iter().find(|cmd| cmd.name == name) { match (command.arg_count, args.as_ref()) { diff --git a/engine/src/core/repl/repl.rs b/engine/src/core/repl/repl.rs index 12c5667..673d4ea 100644 --- a/engine/src/core/repl/repl.rs +++ b/engine/src/core/repl/repl.rs @@ -2,7 +2,6 @@ use super::{commands, Callable, COMMAND_LIST}; use chrono::Local; use reedline::{Prompt, Reedline, Signal}; use regex::Regex; -use std::{borrow::Borrow, collections::HashMap, sync::Arc}; fn register_commands() { COMMAND_LIST.add_command( @@ -42,7 +41,7 @@ fn register_commands() { // EXAMPLE // Adding aliases for commands - COMMAND_LIST.add_alias("cls".to_string(), "clear".to_string()); // Likely unintended; consider removing or renaming. + COMMAND_LIST.add_alias("clear".to_string(), "cls".to_string()); } struct ZPrompt { diff --git a/engine/src/main.rs b/engine/src/main.rs index ec45bad..5553944 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -1,46 +1,48 @@ use anyhow::Result; -use colored::Colorize; -use log2::info; +use clap::Parser; +use log::{info, warn, LevelFilter}; pub mod core; +pub mod utils; -pub fn print_splash() { - println!( - r#" - &&&&&&&&&&& - &&&&&&&&&&&&&&&&& - &&&&&&&&&&&&&&&&&&&&& - && &&&&&&&&& - && &&&&&&&&& -&&&&&&&&&&&& &&&&&&&&&&& -&&&&&&&&&&&&& &&&&&&&&&&&& -&&&&&&&&&&&&& &&&&&&&&&&&&& -&&&&&&&&&&&& &&&&&&&&&&&&& -&&&&&&&&&&& &&&&&&&&&&&& - &&&&&&&&& && - &&&&&&&&& && - &&&&&&&&&&&&&&&&&&&&& - &&&&&&&&&&&&&&&&& - &&&&&&&&&&& +use utils::{logger::LOGGER, splash::print_splash}; - Version: {} - "#, - env!("CARGO_PKG_VERSION").yellow().italic().underline() - ); +#[derive(Parser)] +struct Cli { + #[arg(long, short, help = "Enable logging output")] + log: bool, } #[tokio::main] async fn main() -> Result<()> { - let _log2 = log2::open("z.log").tee(true).level("debug").start(); - info!("Initalizing Engine"); - let shell_thread = tokio::task::spawn(async { - info!("Shell thread started"); - core::repl::repl::handle_repl().await; - }); + let cli = Cli::parse(); + + log::set_logger(&*LOGGER).unwrap(); + log::set_max_level(LevelFilter::Debug); print_splash(); - info!("Engine Initalized"); - core::init_renderer()?; - shell_thread.await?; + + if cli.log { + info!("Initializing Engine with logging to stdout enabled"); + warn!("REPL cannot be used with logging enabled due to ReedLine not supporting writing to stdout"); + + core::init_renderer()?; + } else { + LOGGER.write_to_stdout(); + info!("Initializing Engine with logging to stdout disabled"); + warn!("REPL cannot be used with logging enabled due to ReedLine not supporting writing to stdout"); + info!("Writing all logs to file z.log"); + + LOGGER.write_to_file("z.log"); + info!("Logging back to file z.log"); + + let shell_thread = tokio::task::spawn(async { + core::repl::repl::handle_repl().await; + }); + + core::init_renderer()?; + shell_thread.await?; + } + Ok(()) } diff --git a/engine/src/utils/logger.rs b/engine/src/utils/logger.rs new file mode 100644 index 0000000..c542396 --- /dev/null +++ b/engine/src/utils/logger.rs @@ -0,0 +1,72 @@ +use colored::Colorize; +use log::{Level, Log, Metadata, Record}; +use once_cell::sync::Lazy; +use std::fs::OpenOptions; +use std::io::{self, Write}; +use std::sync::{Arc, Mutex}; + +pub static LOGGER: Lazy = Lazy::new(DynamicLogger::new); + +// A logger that dynamically switches between file and stdout +pub struct DynamicLogger { + pub writer: Arc>>, +} + +impl DynamicLogger { + pub fn new() -> Self { + Self { + writer: Arc::new(Mutex::new(Box::new(io::stdout()))), + } + } + + pub fn write_to_file(&self, file_path: &str) { + let file = OpenOptions::new() + .create(true) + .write(true) + .append(true) + .open(file_path) + .expect("Failed to open log file"); + + *self.writer.lock().unwrap() = Box::new(file); + } + + pub fn write_to_stdout(&self) { + *self.writer.lock().unwrap() = Box::new(io::stdout()); + } + + fn colorize_level(level: Level) -> colored::ColoredString { + match level { + Level::Error => "ERROR".red(), + Level::Warn => "WARN".yellow(), + Level::Info => "INFO".green(), + Level::Debug => "DEBUG".blue(), + Level::Trace => "TRACE".cyan(), + } + } +} + +impl Log for DynamicLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= Level::Debug + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + let mut writer = self.writer.lock().unwrap(); + let level = Self::colorize_level(record.level()); // Apply coloring + writeln!( + writer, + "{} [{}] - {}", + chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), + level, + record.args() + ) + .unwrap(); + } + } + + fn flush(&self) { + let mut writer = self.writer.lock().unwrap(); + writer.flush().unwrap(); + } +} diff --git a/engine/src/utils/mod.rs b/engine/src/utils/mod.rs new file mode 100644 index 0000000..a0f8995 --- /dev/null +++ b/engine/src/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod logger; +pub mod splash; diff --git a/engine/src/utils/splash.rs b/engine/src/utils/splash.rs new file mode 100644 index 0000000..5f55560 --- /dev/null +++ b/engine/src/utils/splash.rs @@ -0,0 +1,30 @@ +use colored::Colorize; +use log::info; + +pub fn print_splash() { + info!( + "{}", + format!( + r#" + &&&&&&&&&&& + &&&&&&&&&&&&&&&&& + &&&&&&&&&&&&&&&&&&&&& + && &&&&&&&&& +&&&&&&&&&&&& &&&&&&&&&&& +&&&&&&&&&&&&& &&&&&&&&&&&& +&&&&&&&&&&&&& &&&&&&&&&&&&& +&&&&&&&&&&&& &&&&&&&&&&&&& +&&&&&&&&&&& &&&&&&&&&&&& + &&&&&&&&& && + &&&&&&&&& && + &&&&&&&&&&&&&&&&&&&&& + &&&&&&&&&&&&&&&&& + &&&&&&&&&&& + + Version: {} + "#, + env!("CARGO_PKG_VERSION").color("yellow") + ) + .bright_black() + ); +} diff --git a/xtask/src/editor.rs b/xtask/src/editor.rs index 8cfa650..2fb341f 100644 --- a/xtask/src/editor.rs +++ b/xtask/src/editor.rs @@ -1 +1,4 @@ -pub fn build_editor() {} \ No newline at end of file +pub fn build_editor() { + todo!() +} + diff --git a/xtask/src/engine.rs b/xtask/src/engine.rs index ecdf677..4e901f2 100644 --- a/xtask/src/engine.rs +++ b/xtask/src/engine.rs @@ -1,22 +1,23 @@ use std::process::Stdio; - pub fn build_engine() { - + todo!() } pub fn build_core() { - let threads = format!("-j{}",std::thread::available_parallelism().unwrap().get()); + let threads = format!("-j{}", std::thread::available_parallelism().unwrap().get()); + let mut run = std::process::Command::new("cargo") .arg("run") - .arg(threads) .arg("--bin") .arg("zenyx") - .stdin(Stdio::inherit()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) + .stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) .spawn() .unwrap(); + run.wait().unwrap(); -} \ No newline at end of file +} + diff --git a/xtask/src/main.rs b/xtask/src/main.rs index b146421..e3e07c8 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,12 +1,11 @@ - use clap::{CommandFactory, Parser, Subcommand, ValueEnum}; -pub mod engine; pub mod editor; +pub mod engine; #[derive(Parser)] #[command(version, about, long_about = None,disable_version_flag = true,disable_help_flag = true)] struct Cli { - #[arg(short,long)] + #[arg(short, long)] release: bool, #[command(subcommand)] command: Option, @@ -16,55 +15,48 @@ struct Cli { enum Commands { Run { #[arg()] - task: Task + task: Task, }, Config, - } -#[derive(Clone,ValueEnum)] + +#[derive(Clone, ValueEnum)] enum Task { Engine, // Builds both editor and core Editor, // Builds editor only - Core, // Builds engine core only - Help, + Core, // Builds engine core only + Help, } - - fn main() { let cli = Cli::parse(); - - - if cli.release { println!("Running in release mode") } match &cli.command { - None => { - Cli::command().print_help().map_err(|e| { - println!("Could not run Xtask: {e}"); - - }).unwrap(); + Cli::command() + .print_help() + .map_err(|e| { + println!("Could not run Xtask: {e}"); + }) + .unwrap(); } - Some(Commands::Run { task }) => { - match task { - Task::Engine => engine::build_engine(), - Task::Editor => todo!("Editor is not being actively worked on"), - Task::Core => { - engine::build_core(); - }, - Task::Help => { - println!("The following options are avalible to run"); - todo!() - }, + Some(Commands::Run { task }) => match task { + Task::Engine => engine::build_engine(), + Task::Editor => todo!("Editor is not being actively worked on"), + Task::Core => { + engine::build_core(); } - } + Task::Help => { + println!("The following options are avalible to run"); + todo!() + } + }, Some(Commands::Config) => { todo!() } } - -} \ No newline at end of file +}