I currently have the logger outputting to the terminal, using the code below. However, web pages aren't loading until a key has been pressed in the terminal. Is there a way to output the logs to a file. I can't seem to find anything in the official documentation. actix_web middleware documentation
use actix_web::{middleware::Logger, get, post, web, App, HttpResponse, HttpServer, Responder};
use env_logger::Env;
#[get("/")]
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello world!")
}
#[post("/echo")]
async fn echo(req_body: String) -> impl Responder {
HttpResponse::Ok().body(req_body)
}
async fn manual_hello() -> impl Responder {
HttpResponse::Ok().body("Hey there!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(Env::default().default_filter_or("info"));
HttpServer::new(|| {
App::new()
.wrap(Logger::default())
.service(hello)
.service(echo)
.route("/hey", web::get().to(manual_hello))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
I created a mod file called logger.rs and brought it into scope from lib.rs. I used the crates "colored" and "chrono"
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
use colored::{Colorize, control};
use chrono::Local;
// Path to log file
const LOG_PATH: &str = "ServerLogs.log";
/// List of different types of log headers.
pub enum Header {
SUCCESS,
INFO,
WARNING,
ERROR
}
/// Logs a message to the console.
pub fn log(header: Header, message: &str) {
// Type of message to log
let header = match header {
Header::SUCCESS => "SUCCESS".bold().bright_green(),
Header::INFO => "INFO".bold().bright_blue(),
Header::WARNING => "WARNING".bold().bright_yellow(),
Header::ERROR => "ERROR".bold().bright_red()
};
// Print the log to the console
control::set_virtual_terminal(true).unwrap();
println!("[{}] {} {}", Local::now().format("%m-%d-%Y %H:%M:%S").to_string().bold(), header, message);
// Write the log to a file
if Path::new(LOG_PATH).exists() {
let mut log_file = OpenOptions::new().append(true).open(LOG_PATH).unwrap();
writeln!(log_file, "[{}] {} {}", Local::now().format("%m-%d-%Y %H:%M:%S").to_string(), header.clear(), message).unwrap();
} else {
let mut log_file = OpenOptions::new().create_new(true).append(true).open(LOG_PATH).unwrap();
writeln!(log_file, "[{}] {} {}", Local::now().format("%m-%d-%Y %H:%M:%S").to_string(), header.clear(), message).unwrap();
}
}
pub mod logger;
and now you can call the log function from anywhere in your code like so:
#[get("/")]
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello world!")
logger::log(Header::SUCCESS, "Hello world!");
}
#[post("/echo")]
async fn echo(req_body: String) -> impl Responder {
HttpResponse::Ok().body(req_body)
logger::log(Header::INFO, format!("echo: {}", req_body).as_str());
}
async fn manual_hello() -> impl Responder {
HttpResponse::Ok().body("Hey there!")
logger::log(Header::WARNING, "Hey there!");
}
Here is what it will look like in the log file:
[09-27-2022 13:32:56] SUCCESS Hello world!
[09-27-2022 13:41:25] INFO echo: test
[09-27-2022 13:59:48] WARNING Hey there!
Please feel free to edit and modify the code however you'd like to make it work best in your project. I hope this helps.