reorganize debug events

This commit is contained in:
yggverse 2025-06-28 21:11:18 +03:00
parent 57dfe79568
commit 212ffeab79
10 changed files with 75 additions and 117 deletions

View file

@ -41,12 +41,8 @@ nexy -p /path/to/public_dir
[default: 127.0.0.1:1900 [::1]:1900]
-d, --debug <DEBUG>
Debug level
* `e` - error * `i` - info
[default: ei]
-d, --debug
Print debug information
-p, --public <PUBLIC>
Absolute path to the public files directory

View file

@ -20,12 +20,9 @@ pub struct Config {
])]
pub bind: Vec<String>,
/// Debug level
///
/// * `e` - error
/// * `i` - info
#[arg(short, long, default_value_t = String::from("ei"))]
pub debug: String,
/// Print debug information
#[arg(short, long, default_value_t = false)]
pub debug: bool,
/// Absolute path to the public files directory
#[arg(short, long)]

View file

@ -5,10 +5,10 @@ mod session;
fn main() -> anyhow::Result<()> {
use clap::Parser;
let a = config::Config::parse();
let s = std::sync::Arc::new(session::Session::init(&a)?);
for b in a.bind {
s.debug.info(&format!("start server on `{b}`..."));
let c = config::Config::parse();
let s = std::sync::Arc::new(session::Session::init(&c)?);
for b in c.bind {
println!("start server on `{b}`...");
match std::net::TcpListener::bind(&b) {
Ok(r) => {
std::thread::spawn({
@ -16,9 +16,7 @@ fn main() -> anyhow::Result<()> {
move || server::start(r, &s)
});
}
Err(e) => s
.debug
.error(&format!("failed to start server on `{b}`: `{e}`")),
Err(e) => eprintln!("failed to start server on `{b}`: `{e}`"),
}
}
std::thread::park();

View file

@ -1,9 +1,9 @@
/// Internal types
/// Internal server response types
pub enum Response<'a> {
/// Includes reference to the original request
AccessDenied(&'a str),
/// Includes server-side error description
InternalServerError(String),
/// Includes query + server-side error description
InternalServerError(&'a str, String),
/// Includes reference to the original request
NotFound(&'a str),
/// Includes bytes array

View file

@ -12,15 +12,11 @@ pub fn start(server: TcpListener, session: &Arc<Session>) {
let session = session.clone();
move || match Connection::init(&session, stream) {
Ok(connection) => connection.handle(),
Err(e) => session
.debug
.error(&format!("failed to init connection: `{e}`")),
Err(e) => eprintln!("failed to init connection: `{e}`"),
}
});
}
Err(e) => session
.debug
.error(&format!("failed to accept incoming connection: `{e}`")),
Err(e) => eprintln!("failed to accept incoming connection: `{e}`"),
}
}
}

View file

@ -35,10 +35,12 @@ impl Connection {
let mut t = 0; // total bytes
match self.request() {
Ok(q) => {
self.session.debug.info(&format!(
if self.session.is_debug {
println!(
"[{}] < [{}] request `{q}`...",
self.address.server, self.address.client
));
)
}
if let Some(ref i) = self.session.request {
i.add(&self.address.client, &q)
}
@ -51,10 +53,13 @@ impl Connection {
.clf(&self.address.client, Some(&q), 0, t);
}
Err(e) => {
t += self.response(Response::InternalServerError(format!(
t += self.response(Response::InternalServerError(
"",
format!(
"[{}] < [{}] failed to handle incoming request: `{e}`",
self.address.server, self.address.client
)));
),
));
self.session
.access_log
.clf(&self.address.client, None, 1, t);
@ -87,50 +92,61 @@ impl Connection {
)
}
}
Response::InternalServerError(e) => {
self.session.debug.error(&e);
Response::InternalServerError(q, e) => {
eprintln!(
"[{}] > [{}] `{q}`: internal server error: `{e}`",
self.address.server, self.address.client
);
self.session.template.internal_server_error()
}
Response::AccessDenied(q) => {
self.session.debug.error(&format!(
eprintln!(
"[{}] < [{}] access to `{q}` denied.",
self.address.server, self.address.client
));
);
self.session.template.access_denied()
}
Response::NotFound(q) => {
self.session.debug.error(&format!(
eprintln!(
"[{}] < [{}] requested resource `{q}` not found.",
self.address.server, self.address.client
));
);
self.session.template.not_found()
}
};
match self.stream.write_all(bytes) {
Ok(()) => self.session.debug.info(&format!(
Ok(()) => {
if self.session.is_debug {
println!(
"[{}] > [{}] sent {} bytes response.",
self.address.server,
self.address.client,
bytes.len()
)),
Err(e) => self.session.debug.error(&format!(
)
}
}
Err(e) => eprintln!(
"[{}] ! [{}] failed to response: `{e}`",
self.address.server, self.address.client,
)),
),
};
bytes.len()
}
fn shutdown(self) {
match self.stream.shutdown(std::net::Shutdown::Both) {
Ok(()) => self.session.debug.info(&format!(
Ok(()) => {
if self.session.is_debug {
println!(
"[{}] - [{}] connection closed by server.",
self.address.server, self.address.client,
)),
Err(e) => self.session.debug.error(&format!(
)
}
}
Err(e) => eprintln!(
"[{}] > [{}] failed to close connection: `{e}`",
self.address.server, self.address.client,
)),
),
}
}
}

View file

@ -1,18 +1,17 @@
mod access_log;
mod debug;
mod public;
mod request;
mod template;
use {access_log::AccessLog, debug::Debug, public::Public, request::Request, template::Template};
use {access_log::AccessLog, public::Public, request::Request, template::Template};
/// Shared, multi-thread features for the current server session
pub struct Session {
pub access_log: AccessLog,
pub debug: Debug,
pub public: Public,
pub request: Option<Request>,
pub template: Template,
pub is_debug: bool,
}
impl Session {
@ -20,7 +19,6 @@ impl Session {
let template = Template::init(config)?;
Ok(Self {
access_log: AccessLog::init(config)?,
debug: Debug::init(config)?,
public: Public::init(config)?,
request: if template.welcome.contains("{hosts}")
|| template.welcome.contains("{hits}")
@ -32,6 +30,7 @@ impl Session {
None // do not int request collector if its features not in use
},
template,
is_debug: config.debug,
})
}
}

View file

@ -1,30 +0,0 @@
mod level;
use level::Level;
pub struct Debug(Vec<Level>);
impl Debug {
pub fn init(config: &crate::config::Config) -> anyhow::Result<Self> {
let mut l = Vec::with_capacity(config.debug.len());
for s in config.debug.to_lowercase().chars() {
l.push(Level::parse(s)?);
}
Ok(Self(l))
}
pub fn error(&self, message: &str) {
if self.0.contains(&Level::Error) {
eprintln!("[{}] [error] {message}", now());
}
}
pub fn info(&self, message: &str) {
if self.0.contains(&Level::Info) {
println!("[{}] [info] {message}", now());
}
}
}
fn now() -> String {
chrono::Local::now().to_rfc3339()
}

View file

@ -1,17 +0,0 @@
use anyhow::{Result, bail};
#[derive(PartialEq)]
pub enum Level {
Error,
Info,
}
impl Level {
pub fn parse(value: char) -> Result<Self> {
match value {
'e' => Ok(Self::Error),
'i' => Ok(Self::Info),
_ => bail!("unsupported debug level `{value}`!"),
}
}
}

View file

@ -61,7 +61,7 @@ impl Public {
Ok(t) => match (t.is_dir(), t.is_file()) {
(true, _) => callback(match self.list(&p) {
Ok(list) => Response::Directory(query, list, p == self.public_dir),
Err(e) => Response::InternalServerError(e.to_string()),
Err(e) => Response::InternalServerError(query, e.to_string()),
}),
(_, true) => match fs::File::open(p) {
Ok(mut f) => loop {
@ -70,21 +70,24 @@ impl Public {
Ok(0) => break,
Ok(n) => callback(Response::File(&b[..n])),
Err(e) => {
return callback(Response::InternalServerError(format!(
"failed to read response chunk for `{query}`: `{e}`"
)));
return callback(Response::InternalServerError(
query,
format!("failed to read response chunk: `{e}`"),
));
}
}
},
Err(e) => callback(Response::InternalServerError(format!(
"failed to read response for query`{query}`: `{e}`"
))),
Err(e) => callback(Response::InternalServerError(
query,
format!("failed to read response: `{e}`"),
)),
},
_ => panic!(), // unexpected
},
Err(e) => callback(Response::InternalServerError(format!(
"failed to read storage for `{query}`: `{e}`"
))),
Err(e) => callback(Response::InternalServerError(
query,
format!("failed to read storage: `{e}`"),
)),
}
}