Skip to content

Commit

Permalink
Move all logging primitives in their own module
Browse files Browse the repository at this point in the history
Signed-off-by: Eloi DEMOLIS <[email protected]>
  • Loading branch information
Wonshtrum authored and Keksoj committed Feb 9, 2024
1 parent 6024d51 commit 2b5ed4c
Show file tree
Hide file tree
Showing 11 changed files with 259 additions and 253 deletions.
38 changes: 37 additions & 1 deletion command/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
//! 3. if a variable has not been set in the TOML file, it will be set to a default defined here
use std::{
collections::{BTreeMap, HashMap, HashSet},
env,
env, fmt,
fs::{create_dir_all, metadata, File},
io::{ErrorKind, Read},
net::SocketAddr,
Expand Down Expand Up @@ -1753,6 +1753,42 @@ impl Config {
}
}

impl fmt::Debug for Config {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Config")
.field("config_path", &self.config_path)
.field("command_socket", &self.command_socket)
.field("command_buffer_size", &self.command_buffer_size)
.field("max_command_buffer_size", &self.max_command_buffer_size)
.field("max_connections", &self.max_connections)
.field("min_buffers", &self.min_buffers)
.field("max_buffers", &self.max_buffers)
.field("buffer_size", &self.buffer_size)
.field("saved_state", &self.saved_state)
.field("automatic_state_save", &self.automatic_state_save)
.field("log_level", &self.log_level)
.field("log_target", &self.log_target)
.field("log_access_target", &self.log_access_target)
.field("log_access_format", &self.log_access_format)
.field("worker_count", &self.worker_count)
.field("worker_automatic_restart", &self.worker_automatic_restart)
.field("metrics", &self.metrics)
.field("disable_cluster_metrics", &self.disable_cluster_metrics)
.field("handle_process_affinity", &self.handle_process_affinity)
.field("ctl_command_timeout", &self.ctl_command_timeout)
.field("pid_file_path", &self.pid_file_path)
.field("activate_listeners", &self.activate_listeners)
.field("front_timeout", &self.front_timeout)
.field("back_timeout", &self.back_timeout)
.field("connect_timeout", &self.connect_timeout)
.field("zombie_check_interval", &self.zombie_check_interval)
.field("accept_queue_timeout", &self.accept_queue_timeout)
.field("request_timeout", &self.request_timeout)
.field("worker_timeout", &self.worker_timeout)
.finish()
}
}

fn display_toml_error(file: &str, error: &toml::de::Error) {
println!("error parsing the configuration file '{file}': {error}");
if let Some(Range { start, end }) = error.span() {
Expand Down
27 changes: 26 additions & 1 deletion command/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ extern crate serde;
#[macro_use]
/// custom made logging macros
pub mod logging;
pub mod access_logs;
/// Custom buffer used for parsing within the Sōzu codebase.
pub mod buffer;
/// TLS certificates
Expand Down Expand Up @@ -88,3 +87,29 @@ pub enum ObjectKind {
TcpListener,
TcpFrontend,
}

pub trait AsString {
fn as_string_or(&self, default: &'static str) -> String;
}

impl<T: ToString> AsString for Option<T> {
fn as_string_or(&self, default: &'static str) -> String {
match self {
None => default.to_string(),
Some(t) => t.to_string(),
}
}
}

pub trait AsStr {
fn as_str_or(&self, default: &'static str) -> &str;
}

impl<T: AsRef<str>> AsStr for Option<T> {
fn as_str_or(&self, default: &'static str) -> &str {
match self {
None => default,
Some(s) => s.as_ref(),
}
}
}
16 changes: 3 additions & 13 deletions command/src/access_logs.rs → command/src/logging/access_logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,7 @@ impl<T> DuplicateOwnership for &[T] {
}
}

pub fn prepare_user_agent(user_agent: &str) -> String {
let mut user_agent = user_agent.replace(' ', "_");
let mut ua_bytes = std::mem::take(&mut user_agent).into_bytes();
if let Some(last) = ua_bytes.last_mut() {
if *last == b',' {
*last = b'!'
}
}
unsafe { String::from_utf8_unchecked(ua_bytes) }
}

pub struct LogMessage<'a>(pub Option<&'a str>);
pub struct LogDuration(pub Option<Duration>);

#[derive(Debug)]
Expand Down Expand Up @@ -111,7 +101,7 @@ pub struct FullTags<'a> {
/// Intermediate representation of an access log agnostic of the final format.
/// Every field is a reference to avoid capturing ownership (as a logger should).
pub struct RequestRecord<'a> {
pub error: Option<&'a str>,
pub message: Option<&'a str>,
pub context: LogContext<'a>,
pub session_address: Option<SocketAddr>,
pub backend_address: Option<SocketAddr>,
Expand Down Expand Up @@ -178,7 +168,7 @@ impl RequestRecord<'_> {
endpoint: ProtobufEndpoint {
inner: Some(endpoint),
},
error: self.error.duplicate(),
error: self.message.duplicate(),
protocol: self.protocol.duplicate(),
request_id,
response_time: self.response_time.whole_microseconds() as u64,
Expand Down
160 changes: 160 additions & 0 deletions command/src/logging/display.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
use std::fmt;

use crate::{
logging::{
EndpointRecord, FullTags, LogContext, LogDuration, LogLevel, LogMessage, LoggerBackend,
Rfc3339Time,
},
AsStr, AsString,
};

impl LogLevel {
pub const fn as_str(&self, access: bool, colored: bool) -> &'static str {
match (self, access, colored) {
(LogLevel::Error, false, false) => "ERROR",
(LogLevel::Warn, false, false) => "WARN ",
(LogLevel::Info, false, false) => "INFO ",
(LogLevel::Debug, false, false) => "DEBUG",
(LogLevel::Trace, false, false) => "TRACE",

(LogLevel::Error, false, true) => "\x1b[;31;1mERROR",
(LogLevel::Warn, false, true) => "\x1b[;33;1mWARN ",
(LogLevel::Info, false, true) => "\x1b[;32;1mINFO ",
(LogLevel::Debug, false, true) => "\x1b[;34mDEBUG",
(LogLevel::Trace, false, true) => "\x1b[;90mTRACE",

(LogLevel::Error, true, false) => "ERROR-ACCESS",
(LogLevel::Info, true, false) => "INFO-ACCESS ",
(_, true, false) => "???",

(LogLevel::Error, true, true) => "\x1b[;35;1mERROR-ACCESS",
(LogLevel::Info, true, true) => "\x1b[;35;1mINFO-ACCESS ",
(_, true, true) => "\x1b[;35;1m???",
}
}
}

impl AsRef<str> for LoggerBackend {
fn as_ref(&self) -> &str {
match self {
LoggerBackend::Stdout(_) => "stdout",
LoggerBackend::Unix(_) => "UNIX socket",
LoggerBackend::Udp(_, _) => "UDP socket",
LoggerBackend::Tcp(_) => "TCP socket",
LoggerBackend::File(_) => "file",
}
}
}

impl fmt::Display for Rfc3339Time {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let t = self.inner;
write!(
f,
"{}-{:02}-{:02}T{:02}:{:02}:{:02}.{:06}Z",
t.year(),
t.month() as u8,
t.day(),
t.hour(),
t.minute(),
t.second(),
t.microsecond()
)
}
}

impl fmt::Display for LogMessage<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Some(message) => write!(f, " | {message}"),
None => Ok(()),
}
}
}

impl fmt::Display for LogDuration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
None => write!(f, "-"),
Some(duration) => {
let secs = duration.whole_seconds();
if secs >= 10 {
return write!(f, "{secs}s");
}

let ms = duration.whole_milliseconds();
if ms < 10 {
let us = duration.whole_microseconds();
if us >= 10 {
return write!(f, "{us}μs");
}

let ns = duration.whole_nanoseconds();
return write!(f, "{ns}ns");
}

write!(f, "{ms}ms")
}
}
}
}

impl fmt::Display for LogContext<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"[{} {} {}]",
self.request_id,
self.cluster_id.unwrap_or("-"),
self.backend_id.unwrap_or("-")
)
}
}

impl fmt::Display for EndpointRecord<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Http {
method,
authority,
path,
status,
..
} => write!(
f,
"{} {} {} -> {}",
authority.as_str_or("-"),
method.as_str_or("-"),
path.as_str_or("-"),
status.as_string_or("-"),
),
Self::Tcp { context } => {
write!(f, "{}", context.as_str_or("-"))
}
}
}
}

impl<'a> fmt::Display for FullTags<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match (self.concatenated, self.user_agent) {
(None, None) => write!(f, "-"),
(Some(tags), None) => write!(f, "{tags}"),
(Some(tags), Some(ua)) if !tags.is_empty() => {
write!(f, "{tags}, user-agent={}", prepare_user_agent(ua))
}
(_, Some(ua)) => write!(f, "user-agent={}", prepare_user_agent(ua)),
}
}
}

fn prepare_user_agent(user_agent: &str) -> String {
let mut user_agent = user_agent.replace(' ', "_");
let mut ua_bytes = std::mem::take(&mut user_agent).into_bytes();
if let Some(last) = ua_bytes.last_mut() {
if *last == b',' {
*last = b'!'
}
}
unsafe { String::from_utf8_unchecked(ua_bytes) }
}
17 changes: 9 additions & 8 deletions command/src/logging.rs → command/src/logging/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ use mio::net::UnixDatagram;
use prost::{encoding::encoded_len_varint, Message};
use rand::{distributions::Alphanumeric, thread_rng, Rng};

use crate::proto::command::ProtobufAccessLogFormat;

pub use crate::access_logs::*;

use crate::{config::Config, proto::display::AsString};
use crate::{
config::Config,
logging::{LogDuration, LogMessage, RequestRecord},
proto::command::ProtobufAccessLogFormat,
AsString,
};

thread_local! {
pub static LOGGER: RefCell<Logger> = RefCell::new(Logger::new());
Expand Down Expand Up @@ -264,7 +265,7 @@ impl InnerLogger {
log.tag,
],
standard: {
formats: ["{} {}->{} {}/{}/{}/{} {}->{} [{}] {} {} | {:?}\n"],
formats: ["{} {}->{} {}/{}/{}/{} {}->{} [{}] {} {}{}\n"],
args: [
log.context,
log.session_address.as_string_or("X"),
Expand All @@ -278,11 +279,11 @@ impl InnerLogger {
log.full_tags(),
log.protocol,
log.endpoint,
log.error,
LogMessage(log.message),
]
},
colored: {
formats: ["\x1b[;1m{}\x1b[m {}->{} {}/{}/{}/{} {}->{} \x1b[2m[{}] \x1b[;1m{} {}\x1b[m | {:?}\n"],
formats: ["\x1b[;1m{}\x1b[m {}->{} {}/{}/{}/{} {}->{} \x1b[2m[{}] \x1b[;1m{} {}\x1b[m{}\n"],
args: @,
}
},
Expand Down
7 changes: 7 additions & 0 deletions command/src/logging/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub mod access_logs;
pub mod display;
#[macro_use]
pub mod logs;

pub use crate::logging::access_logs::*;
pub use crate::logging::logs::*;
Loading

0 comments on commit 2b5ed4c

Please sign in to comment.