diff --git a/bin/src/command/server.rs b/bin/src/command/server.rs index a0d648c14..c2fb32873 100644 --- a/bin/src/command/server.rs +++ b/bin/src/command/server.rs @@ -295,7 +295,7 @@ impl CommandHub { /// - manage timeouts of tasks pub fn run(&mut self) { let mut events = Events::with_capacity(100); - debug!("running the command hub: {:?}", self); + debug!("running the command hub: {:#?}", self); loop { let run_state = self.run_state; @@ -511,7 +511,6 @@ pub enum ServerState { /// - scatter to workers /// - gather worker responses /// - trigger a finishing function when all responses are gathered -#[derive(Debug)] pub struct Server { pub config: Config, /// Sōzu clients that subscribed to events @@ -857,3 +856,23 @@ impl Server { } } } + +impl std::fmt::Debug for Server { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Server") + .field("config", &self.config) + .field("event_subscribers", &self.event_subscribers) + .field("executable_path", &self.executable_path) + .field("in_flight", &self.in_flight) + .field("next_client_id", &self.next_client_id) + .field("next_session_id", &self.next_session_id) + .field("next_task_id", &self.next_task_id) + .field("next_worker_id", &self.next_worker_id) + .field("poll", &self.poll) + .field("queued_tasks", &self.queued_tasks) + .field("run_state", &self.run_state) + .field("unix_listener", &self.unix_listener) + .field("workers", &self.workers) + .finish() + } +} diff --git a/bin/src/worker.rs b/bin/src/worker.rs index a12a5c938..9e1e60bb5 100644 --- a/bin/src/worker.rs +++ b/bin/src/worker.rs @@ -115,8 +115,10 @@ pub fn begin_worker_process( // do not try to log anything before this, or the logger will panic setup_logging( &worker_config.log_target, + worker_config.log_colored, worker_config.log_access_target.as_deref(), Some(access_log_format), + Some(worker_config.log_colored), &worker_config.log_level, &worker_id, ); diff --git a/command/src/access_logs.rs b/command/src/access_logs.rs index b44b73b27..aeaaafa9b 100644 --- a/command/src/access_logs.rs +++ b/command/src/access_logs.rs @@ -3,7 +3,12 @@ use std::{collections::BTreeMap, mem::ManuallyDrop, net::SocketAddr}; use rusty_ulid::Ulid; use time::Duration; -use crate::proto::command::{ProtobufAccessLog, ProtobufEndpoint, TcpEndpoint, Uint128}; +use crate::{ + logging::{LogLevel, Rfc3339Time}, + proto::command::{ + protobuf_endpoint, HttpEndpoint, ProtobufAccessLog, ProtobufEndpoint, TcpEndpoint, Uint128, + }, +}; /// This uses unsafe to creates a "fake" owner of the underlying data. /// Beware that for the compiler it is as legitimate as the original owner. @@ -97,37 +102,52 @@ impl CachedTags { } } +#[derive(Debug)] +pub struct FullTags<'a> { + pub concatenated: Option<&'a str>, + pub user_agent: Option<&'a str>, +} + /// 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: &'a Option<&'a str>, - pub context: &'a LogContext<'a>, - pub session_address: &'a Option, - pub backend_address: &'a Option, + pub error: Option<&'a str>, + pub context: LogContext<'a>, + pub session_address: Option, + pub backend_address: Option, pub protocol: &'a str, - pub endpoint: &'a EndpointRecord<'a>, - pub tags: &'a Option<&'a CachedTags>, - pub client_rtt: &'a Option, - pub server_rtt: &'a Option, - pub user_agent: &'a Option, - pub service_time: &'a Duration, - pub response_time: &'a Duration, - pub bytes_in: &'a usize, - pub bytes_out: &'a usize, + pub endpoint: EndpointRecord<'a>, + pub tags: Option<&'a CachedTags>, + pub client_rtt: Option, + pub server_rtt: Option, + pub user_agent: Option<&'a str>, + pub service_time: Duration, + pub response_time: Duration, + pub bytes_in: usize, + pub bytes_out: usize, + + // added by the logger itself + pub pid: i32, + pub tag: &'a str, + pub level: LogLevel, + pub now: Rfc3339Time, + pub precise_time: i128, } impl RequestRecord<'_> { + pub fn full_tags(&self) -> FullTags { + FullTags { + concatenated: self.tags.as_ref().map(|t| t.concatenated.as_str()), + user_agent: self.user_agent, + } + } + /// Converts the RequestRecord in its protobuf representation. /// Prost needs ownership over all the fields but we don't want to take it from the user /// or clone them, so we use the unsafe DuplicateOwnership. - pub unsafe fn into_protobuf_access_log( - self, - time: i128, - tag: &str, - ) -> ManuallyDrop { + pub unsafe fn into_binary_access_log(self) -> ManuallyDrop { let (low, high) = self.context.request_id.into(); let request_id = Uint128 { low, high }; - let time: Uint128 = time.into(); let endpoint = match self.endpoint { EndpointRecord::Http { @@ -136,33 +156,29 @@ impl RequestRecord<'_> { path, status, reason, - } => crate::proto::command::protobuf_endpoint::Inner::Http( - crate::proto::command::HttpEndpoint { - method: method.duplicate().duplicate(), - authority: authority.duplicate().duplicate(), - path: path.duplicate().duplicate(), - status: status.map(|s| s as u32), - reason: reason.duplicate().duplicate(), - }, - ), - EndpointRecord::Tcp { context } => { - crate::proto::command::protobuf_endpoint::Inner::Tcp(TcpEndpoint { - context: context.duplicate().duplicate(), - }) - } + } => protobuf_endpoint::Inner::Http(HttpEndpoint { + method: method.duplicate(), + authority: authority.duplicate(), + path: path.duplicate(), + status: status.map(|s| s as u32), + reason: reason.duplicate(), + }), + EndpointRecord::Tcp { context } => protobuf_endpoint::Inner::Tcp(TcpEndpoint { + context: context.duplicate(), + }), }; ManuallyDrop::new(ProtobufAccessLog { backend_address: self.backend_address.map(Into::into), backend_id: self.context.backend_id.duplicate(), - bytes_in: *self.bytes_in as u64, - bytes_out: *self.bytes_out as u64, + bytes_in: self.bytes_in as u64, + bytes_out: self.bytes_out as u64, client_rtt: self.client_rtt.map(|t| t.whole_microseconds() as u64), cluster_id: self.context.cluster_id.duplicate(), endpoint: ProtobufEndpoint { inner: Some(endpoint), }, - error: self.error.duplicate().duplicate(), + error: self.error.duplicate(), protocol: self.protocol.duplicate(), request_id, response_time: self.response_time.whole_microseconds() as u64, @@ -174,8 +190,8 @@ impl RequestRecord<'_> { .map(|tags| tags.tags.duplicate()) .unwrap_or_default(), user_agent: self.user_agent.duplicate(), - tag: tag.duplicate(), - time: time.duplicate(), + tag: self.tag.duplicate(), + time: self.precise_time.into(), }) } } diff --git a/command/src/command.proto b/command/src/command.proto index b55263b96..fc8422b2e 100644 --- a/command/src/command.proto +++ b/command/src/command.proto @@ -151,7 +151,7 @@ message HttpsListenerConfig { required uint32 request_timeout = 10 [default = 10]; // wether the listener is actively listening on its socket required bool active = 11 [default = false]; - // TLS versions + // TLS versions repeated TlsVersion versions = 12; repeated string cipher_list = 13; repeated string cipher_suites = 14; @@ -306,7 +306,7 @@ message CertificateAndKey { message QueryCertificatesFilters { // a domain name to filter certificate results optional string domain = 1; - // a hex-encoded fingerprint of the TLS certificate to find + // a hex-encoded fingerprint of the TLS certificate to find optional string fingerprint = 2; } @@ -612,7 +612,7 @@ message RequestCounts { } // matches std::net::SocketAddr in the Rust library -// beware that the ports are expressed with uint32 here, +// beware that the ports are expressed with uint32 here, // but they should NOT exceed uint16 value message SocketAddress { required IpAddress ip = 1; @@ -675,6 +675,7 @@ message ServerConfig { required uint64 max_command_buffer_size = 14 [default = 2000000]; optional ServerMetricsConfig metrics = 15; required ProtobufAccessLogFormat access_log_format = 16; + required bool log_colored = 17; } enum ProtobufAccessLogFormat { diff --git a/command/src/config.rs b/command/src/config.rs index 73967b4b9..82c82639e 100644 --- a/command/src/config.rs +++ b/command/src/config.rs @@ -1091,8 +1091,13 @@ pub struct FileConfig { pub log_level: Option, pub log_target: Option, #[serde(default)] + pub log_colored: bool, + #[serde(default)] pub log_access_target: Option, + #[serde(default)] pub log_access_format: Option, + #[serde(default)] + pub log_access_colored: Option, pub worker_count: Option, pub worker_automatic_restart: Option, pub metrics: Option, @@ -1205,6 +1210,7 @@ impl ConfigBuilder { handle_process_affinity: file_config.handle_process_affinity.unwrap_or(false), log_access_target: file_config.log_access_target.clone(), log_access_format: file_config.log_access_format.clone(), + log_access_colored: file_config.log_access_colored, log_level: file_config .log_level .clone() @@ -1213,6 +1219,7 @@ impl ConfigBuilder { .log_target .clone() .unwrap_or_else(|| String::from("stdout")), + log_colored: file_config.log_colored, max_buffers: file_config.max_buffers.unwrap_or(DEFAULT_MAX_BUFFERS), max_command_buffer_size: file_config .max_command_buffer_size @@ -1434,7 +1441,7 @@ impl ConfigBuilder { /// Sōzu configuration, populated with clusters and listeners. /// /// This struct is used on startup to generate `WorkerRequest`s -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Default, Deserialize)] +#[derive(Clone, PartialEq, Eq, Serialize, Default, Deserialize)] pub struct Config { pub config_path: String, pub command_socket: String, @@ -1449,9 +1456,11 @@ pub struct Config { pub automatic_state_save: bool, pub log_level: String, pub log_target: String, + pub log_colored: bool, #[serde(default)] pub log_access_target: Option, pub log_access_format: Option, + pub log_access_colored: Option, pub worker_count: u16, pub worker_automatic_restart: bool, pub metrics: Option, @@ -1783,7 +1792,7 @@ impl From<&Config> for ServerConfig { max_command_buffer_size: config.max_command_buffer_size, metrics, access_log_format: ProtobufAccessLogFormat::from(&config.log_access_format) as i32, - // log_colored: config.log_colored, + log_colored: config.log_colored, } } } diff --git a/command/src/logging.rs b/command/src/logging.rs index 2eea0acd4..ae119b898 100644 --- a/command/src/logging.rs +++ b/command/src/logging.rs @@ -6,6 +6,7 @@ use std::{ fs::{File, OpenOptions}, io::{stdout, Error as IoError, ErrorKind as IoErrorKind, Stdout, Write}, net::{SocketAddr, TcpStream, ToSocketAddrs, UdpSocket}, + ops::{Deref, DerefMut}, path::Path, str::FromStr, }; @@ -19,7 +20,7 @@ use crate::proto::command::ProtobufAccessLogFormat; pub use crate::access_logs::*; -use crate::{bind_format_args, config::Config}; +use crate::{config::Config, proto::display::AsString}; thread_local! { pub static LOGGER: RefCell = RefCell::new(Logger::new()); @@ -56,22 +57,25 @@ impl From<&Option> for ProtobufAccessLogFormat { } pub struct InnerLogger { - pub directives: Vec, - pub backend: LoggerBackend, + version: u8, + directives: Vec, + backend: LoggerBackend, + pub colored: bool, /// target of the access logs - pub access_backend: Option, + access_backend: Option, /// how to format the access logs - pub access_log_format: AccessLogFormat, - pub buffer: Vec, + access_format: AccessLogFormat, + access_colored: bool, + buffer: LoggerBuffer, } pub struct Logger { - pub inner: InnerLogger, + inner: InnerLogger, /// is displayed in each log, for instance "MAIN" or worker_id - pub tag: String, + tag: String, /// the pid of the current process (main or worker) - pub pid: i32, - pub initialized: bool, + pid: i32, + initialized: bool, } impl std::ops::Deref for Logger { @@ -90,14 +94,17 @@ impl Default for Logger { fn default() -> Self { Self { inner: InnerLogger { + version: 1, // all call site start with a version of 0 directives: vec![LogDirective { name: None, level: LogLevelFilter::Error, }], backend: LoggerBackend::Stdout(stdout()), + colored: false, access_backend: None, - access_log_format: AccessLogFormat::Ascii, - buffer: Vec::with_capacity(4096), + access_format: AccessLogFormat::Ascii, + access_colored: false, + buffer: LoggerBuffer(Vec::with_capacity(4096)), }, tag: "UNINITIALIZED".to_string(), pid: 0, @@ -115,17 +122,29 @@ impl Logger { tag: String, spec: &str, backend: LoggerBackend, + colored: bool, access_backend: Option, - access_log_format: Option, + access_format: Option, + access_colored: Option, ) { let directives = parse_logging_spec(spec); LOGGER.with(|logger| { let mut logger = logger.borrow_mut(); if !logger.initialized { logger.set_directives(directives); + logger.colored = match backend { + LoggerBackend::Stdout(_) => colored, + _ => false, + }; + logger.access_colored = match (&access_backend, &backend) { + (Some(LoggerBackend::Stdout(_)), _) | (None, LoggerBackend::Stdout(_)) => { + access_colored.unwrap_or(colored) + } + _ => false, + }; logger.backend = backend; logger.access_backend = access_backend; - logger.access_log_format = access_log_format.unwrap_or(AccessLogFormat::Ascii); + logger.access_format = access_format.unwrap_or(AccessLogFormat::Ascii); logger.tag = tag; logger.pid = unsafe { libc::getpid() }; logger.initialized = true; @@ -138,19 +157,34 @@ impl Logger { }); } + pub fn set_directives(&mut self, directives: Vec) { + self.version += 1; + if self.version >= LOG_LINE_ENABLED { + self.version = 0; + } + self.directives = directives; + } + pub fn split(&mut self) -> (i32, &str, &mut InnerLogger) { (self.pid, &self.tag, &mut self.inner) } } -trait LoggerBuffer { - fn fmt Result>( - &mut self, - args: Arguments, - flush: F, - ) -> Result<(), IoError>; +struct LoggerBuffer(Vec); + +impl Deref for LoggerBuffer { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for LoggerBuffer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } } -impl LoggerBuffer for Vec { + +impl LoggerBuffer { fn fmt Result>( &mut self, args: Arguments, @@ -163,46 +197,47 @@ impl LoggerBuffer for Vec { } } +fn log_arguments( + args: Arguments, + backend: &mut LoggerBackend, + buffer: &mut LoggerBuffer, +) -> Result<(), IoError> { + match backend { + LoggerBackend::Stdout(stdout) => { + let _ = stdout.write_fmt(args); + Ok(()) + } + LoggerBackend::Tcp(socket) => socket.write_fmt(args), + LoggerBackend::File(file) => file.write_fmt(args), + LoggerBackend::Unix(socket) => buffer.fmt(args, |bytes| socket.send(bytes)), + LoggerBackend::Udp(sock, addr) => buffer.fmt(args, |b| sock.send_to(b, *addr)), + } +} + impl InnerLogger { pub fn log(&mut self, args: Arguments) { - let io_result = match &mut self.backend { - LoggerBackend::Stdout(stdout) => { - let _ = stdout.write_fmt(args); - return; - } - LoggerBackend::Tcp(socket) => socket.write_fmt(args), - LoggerBackend::File(file) => file.write_fmt(args), - LoggerBackend::Unix(socket) => self.buffer.fmt(args, |bytes| socket.send(bytes)), - LoggerBackend::Udp(sock, addr) => self.buffer.fmt(args, |b| sock.send_to(b, *addr)), - }; - - if let Err(e) = io_result { - println!( - "Cannot write access log to {}: {e:?}", - self.backend.as_ref() - ); + if let Err(e) = log_arguments(args, &mut self.backend, &mut self.buffer) { + println!("Could not write log to {}: {e:?}", self.backend.as_ref()); } } - pub fn log_access(&mut self, pid: i32, tag: &str, level_tag: &str, log: RequestRecord) { - let (now, precise_time) = now(); + pub fn log_access(&mut self, log: RequestRecord) { let backend = self.access_backend.as_mut().unwrap_or(&mut self.backend); - let io_result = match self.access_log_format { + let io_result = match self.access_format { AccessLogFormat::Protobuf => { - let protobuf_log = unsafe { log.into_protobuf_access_log(precise_time, tag) }; - // println!("protobuf_log length: {:?}", protobuf_log); - let log_length = protobuf_log.encoded_len(); + let binary_log = unsafe { log.into_binary_access_log() }; + let log_length = binary_log.encoded_len(); let total_length = log_length + encoded_len_varint(log_length as u64); self.buffer.clear(); - if self.buffer.capacity() < total_length { - self.buffer.reserve(total_length - self.buffer.capacity()); + let current_capacity = self.buffer.capacity(); + if current_capacity < total_length { + self.buffer.reserve(total_length - current_capacity); } - if let Err(e) = protobuf_log.encode_length_delimited(&mut self.buffer) { + if let Err(e) = binary_log.encode_length_delimited(&mut self.buffer.0) { Err(IoError::new(IoErrorKind::InvalidData, e)) } else { - // println!("length: {}, {:02X?}", &self.buffer.len(), &self.buffer[..]); let bytes = &self.buffer; match backend { LoggerBackend::Stdout(stdout) => { @@ -217,69 +252,74 @@ impl InnerLogger { .map(|_| ()) } } - AccessLogFormat::Ascii => bind_format_args! { - let args = ("{now} {precise_time} {pid} {tag} {level_tag} {log}"); - // TODO: delete or make it trace - println!("ascii access log length: {}", format!("{}", args).len()); - match backend { - LoggerBackend::Stdout(stdout) => { - let _ = stdout.write_fmt(args); - return Ok(()); - } - LoggerBackend::Tcp(socket) => socket.write_fmt(args), - LoggerBackend::File(file) => file.write_fmt(args), - LoggerBackend::Unix(socket) => self.buffer.fmt(args, |b| socket.send(b)), - LoggerBackend::Udp(sock, addr) => self.buffer.fmt(args, |b| sock.send_to(b, *addr)), + AccessLogFormat::Ascii => crate::prompt_log! { + logger: |args| log_arguments(args, backend, &mut self.buffer), + is_access: true, + condition: self.access_colored, + prompt: [ + log.now, + log.precise_time, + log.pid, + log.level, + log.tag, + ], + standard: { + formats: ["{} {}->{} {}/{}/{}/{} {}->{} [{}] {} {} | {:?}\n"], + args: [ + log.context, + log.session_address.as_string_or("X"), + log.backend_address.as_string_or("X"), + LogDuration(Some(log.response_time)), + LogDuration(Some(log.service_time)), + LogDuration(log.client_rtt), + LogDuration(log.server_rtt), + log.bytes_in, + log.bytes_out, + log.full_tags(), + log.protocol, + log.endpoint, + log.error, + ] + }, + colored: { + formats: ["\x1b[;1m{}\x1b[m {}->{} {}/{}/{}/{} {}->{} \x1b[2m[{}] \x1b[;1m{} {}\x1b[m | {:?}\n"], + args: @, } }, }; if let Err(e) = io_result { - println!("Cannot write access log to {}: {:?}", backend.as_ref(), e); - } - } - - pub fn compat_log(&mut self, args: Arguments) { - let io_result = match &mut self.backend { - LoggerBackend::Stdout(stdout) => { - let _ = stdout.write_fmt(args); - return; - } - LoggerBackend::Tcp(socket) => socket.write_fmt(args), - LoggerBackend::File(file) => file.write_fmt(args), - LoggerBackend::Unix(socket) => self.buffer.fmt(args, |b| socket.send(b)), - LoggerBackend::Udp(sock, addr) => self.buffer.fmt(args, |b| sock.send_to(b, *addr)), - }; - - if let Err(e) = io_result { - println!( - "Cannot write access log to {}: {e:?}", - self.backend.as_ref() - ); + println!("Could not write access log to {}: {e:?}", backend.as_ref()); } } - pub fn set_directives(&mut self, directives: Vec) { - self.directives = directives; - } - pub fn enabled(&self, meta: Metadata) -> bool { // Search for the longest match, the vector is assumed to be pre-sorted. for directive in self.directives.iter().rev() { - match directive.name { - Some(ref name) if !meta.target.starts_with(name) => {} - Some(..) | None => return meta.level <= directive.level, + match &directive.name { + Some(name) if !meta.target.starts_with(name) => {} + Some(_) | None => return meta.level <= directive.level, } } false } + pub fn cached_enabled(&self, call_site_state: &mut LogLineCachedState, meta: Metadata) -> bool { + if call_site_state.version() == self.version { + call_site_state.enabled() + } else { + let enabled = self.enabled(meta); + call_site_state.set(self.version, enabled); + enabled + } + } + fn compat_enabled(&self, meta: &log::Metadata) -> bool { // Search for the longest match, the vector is assumed to be pre-sorted. for directive in self.directives.iter().rev() { - match directive.name { - Some(ref name) if !meta.target().starts_with(name) => {} - Some(..) | None => return Into::::into(meta.level()) <= directive.level, + match &directive.name { + Some(name) if !meta.target().starts_with(name) => {} + Some(_) | None => return LogLevel::from(meta.level()) <= directive.level, } } false @@ -295,7 +335,7 @@ pub enum LoggerBackend { } #[repr(usize)] -#[derive(Copy, Eq, Debug)] +#[derive(Clone, Copy, Eq, Debug)] pub enum LogLevel { /// The "error" level. /// @@ -321,13 +361,6 @@ pub enum LogLevel { static LOG_LEVEL_NAMES: [&str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"]; -impl Clone for LogLevel { - #[inline] - fn clone(&self) -> LogLevel { - *self - } -} - impl PartialEq for LogLevel { #[inline] fn eq(&self, other: &LogLevel) -> bool { @@ -389,7 +422,7 @@ impl LogLevel { } #[repr(usize)] -#[derive(Copy, Eq, Debug)] +#[derive(Clone, Copy, Eq, Debug)] pub enum LogLevelFilter { Off, Error, @@ -399,13 +432,6 @@ pub enum LogLevelFilter { Trace, } -impl Clone for LogLevelFilter { - #[inline] - fn clone(&self) -> LogLevelFilter { - *self - } -} - impl PartialEq for LogLevelFilter { #[inline] fn eq(&self, other: &LogLevelFilter) -> bool { @@ -550,12 +576,19 @@ pub fn parse_logging_spec(spec: &str) -> Vec { dirs } +/// start the logger with all logs and access logs on stdout +pub fn setup_default_logging(log_colored: bool, log_level: &str, tag: &str) { + setup_logging("stdout", log_colored, None, None, None, log_level, tag) +} + /// start the logger from config (takes RUST_LOG into account) pub fn setup_logging_with_config(config: &Config, tag: &str) { setup_logging( &config.log_target, + config.log_colored, config.log_access_target.as_deref(), config.log_access_format.clone(), + config.log_access_colored, &config.log_level, tag, ) @@ -567,31 +600,25 @@ pub fn setup_logging_with_config(config: &Config, tag: &str) { /// - taking RUST_LOG into account pub fn setup_logging( log_target: &str, + log_colored: bool, log_access_target: Option<&str>, log_access_format: Option, + log_access_colored: Option, log_level: &str, tag: &str, ) { let backend = target_to_backend(log_target); let access_backend = log_access_target.map(target_to_backend); - if let Ok(env_log_level) = env::var("RUST_LOG") { - Logger::init( - tag.to_string(), - &env_log_level, - backend, - access_backend, - log_access_format, - ); - } else { - Logger::init( - tag.to_string(), - log_level, - backend, - access_backend, - log_access_format, - ); - } + Logger::init( + tag.to_string(), + env::var("RUST_LOG").as_deref().unwrap_or(log_level), + backend, + log_colored, + access_backend, + log_access_format, + log_access_colored, + ); } pub fn target_to_backend(target: &str) -> LoggerBackend { @@ -653,83 +680,173 @@ pub fn target_to_backend(target: &str) -> LoggerBackend { #[macro_export] macro_rules! bind_format_args { (let $args: ident = ($($f:tt)+); $($t:tt)*) => { - (|$args| { $($t)* })(format_args!($($f)+)) + (|$args| { $($t)* })($($f)+) }; } -/// write a log with the custom logger (used in other macros, do not use directly) #[macro_export] -macro_rules! log { - ($lvl:expr, $format:expr, $level_tag:expr $(, $args:expr)*) => { - log!(@ module_path!(), $lvl, $format, $level_tag, [] $(, $args)*) +macro_rules! prompt_log { + { + logger: $logger:expr, + is_access: $access:expr, + condition: $cond:expr, + prompt: [$($p:tt)*], + standard: {$($std:tt)*}$(,)? + } => { + $crate::prompt_log!{ + logger: $logger, + is_access: $access, + condition: $cond, + prompt: [$($p)*], + standard: {$($std)*}, + colored: {$($std)*}, + } + }; + { + logger: $logger:expr, + is_access: $access:expr, + condition: $cond:expr, + prompt: [$($p:tt)*], + standard: { + formats: [$($std_fmt:tt)*], + args: [$($std_args:expr),*$(,)?]$(,)? + }, + colored: { + formats: [$($col_fmt:tt)*], + args: @$(,)? + }$(,)? + } => { + $crate::prompt_log!{ + logger: $logger, + is_access: $access, + condition: $cond, + prompt: [$($p)*], + standard: { + formats: [$($std_fmt)*], + args: [$($std_args),*], + }, + colored: { + formats: [$($col_fmt)*], + args: [$($std_args),*], + }, + } + }; + { + logger: $logger:expr, + is_access: $access:expr, + condition: $cond:expr, + prompt: [$now:expr, $precise_time:expr, $pid:expr, $lvl:expr, $tag:expr$(,)?], + standard: { + formats: [$($std_fmt:tt)*], + args: [$($std_args:expr),*$(,)?]$(,)? + }, + colored: { + formats: [$($col_fmt:tt)*], + args: [$($col_args:expr),*$(,)?]$(,)? + }$(,)? + } => { + if $cond { + $crate::prompt_log!(@bind [$logger, concat!("{} \x1b[2m{} \x1b[;2;1m{} {} \x1b[0;1m{}\x1b[m\t", $($col_fmt)*)] [$now, $precise_time, $pid, $lvl.as_str($access, true), $tag] $($col_args),*) + } else { + $crate::prompt_log!(@bind [$logger, concat!("{} {} {} {} {}\t", $($std_fmt)*)] [$now, $precise_time, $pid, $lvl.as_str($access, false), $tag] $($std_args),*) + } }; - (@ $target:expr, $lvl:expr, $format:expr, $level_tag:expr, - [$($ref_args:ident),*], $first_arg:expr $(, $other_args:expr)*) => {{ - let reg_arg = &$first_arg; - log!(@ $target, $lvl, $format, $level_tag, [$($ref_args,)* reg_arg] $(, $other_args)*); + (@bind [$logger:expr, $fmt:expr] [$($bindings:expr),*] $arg:expr $(, $args:expr)*) => {{ + let binding = &$arg; + $crate::prompt_log!(@bind [$logger, $fmt] [$($bindings),* , binding] $($args),*) }}; - (@ $target:expr, $lvl:expr, $format:expr, $level_tag:expr, [$($final_args:ident),*]) => {{ + (@bind [$logger:expr, $fmt:expr] [$($bindings:expr),*]) => { + $logger(format_args!($fmt, $($bindings),*)) + }; +} + +#[derive(Clone, Copy, Debug)] +pub struct LogLineCachedState(u8); +const LOG_LINE_ENABLED: u8 = 1 << 7; + +impl LogLineCachedState { + pub const fn new() -> Self { + Self(0) + } + #[inline(always)] + pub fn version(&self) -> u8 { + self.0 & !LOG_LINE_ENABLED + } + #[inline(always)] + pub fn enabled(&self) -> bool { + self.0 & LOG_LINE_ENABLED != 0 + } + #[inline(always)] + pub fn set(&mut self, version: u8, enabled: bool) { + self.0 = version; + if enabled { + self.0 |= LOG_LINE_ENABLED + } + } +} + +#[macro_export] +macro_rules! log { + ($lvl:expr, $format:expr $(, $args:expr)*) => {{ + static mut LOG_LINE_CACHED_STATE: $crate::logging::LogLineCachedState = $crate::logging::LogLineCachedState::new(); $crate::logging::LOGGER.with(|logger| { let mut logger = logger.borrow_mut(); - if !logger.enabled($crate::logging::Metadata { - level: $lvl, - target: module_path!(), - }) { return; } + if !logger.cached_enabled( + unsafe { &mut LOG_LINE_CACHED_STATE }, + $crate::logging::Metadata { level: $lvl, target: module_path!() } + ) { return; } let (pid, tag, inner) = logger.split(); let (now, precise_time) = $crate::logging::now(); - inner.log( - format_args!( - concat!("{} {} {} {} {}\t", $format, '\n'), - now, precise_time, pid, tag, - $level_tag $(, $final_args)*) - ); + + $crate::prompt_log!{ + logger: |args| inner.log(args), + is_access: false, + condition: inner.colored, + prompt: [now, precise_time, pid, $lvl, tag], + standard: { + formats: [$format, '\n'], + args: [$($args),*] + } + }; }) }}; - } -/// log a failure concerning an HTTP or TCP request #[macro_export] macro_rules! log_access { - ($lvl:expr, $level_tag:expr, $request_record:expr) => {{ + ($lvl:expr, $($request_record_fields:tt)*) => {{ + static mut LOG_LINE_CACHED_STATE: $crate::logging::LogLineCachedState = $crate::logging::LogLineCachedState::new(); $crate::logging::LOGGER.with(|logger| { let mut logger = logger.borrow_mut(); - if !logger.enabled($crate::logging::Metadata { - level: $lvl, - target: module_path!(), - }) { - return; - } + if !logger.cached_enabled( + unsafe { &mut LOG_LINE_CACHED_STATE }, + $crate::logging::Metadata { level: $lvl, target: module_path!() } + ) { return; } let (pid, tag, inner) = logger.split(); - inner.log_access(pid, tag, $level_tag, $request_record); + let (now, precise_time) = $crate::logging::now(); + + inner.log_access( + structured_access_log!([$crate::logging::RequestRecord] + pid, tag, now, precise_time, level: $lvl, $($request_record_fields)* + )); }) }}; } -#[macro_export] -macro_rules! unwrap_or { - ({} {$($default:tt)*}) => { - $($default)* - }; - ({$($value:tt)*} {$($default:tt)*}) => { - $($value)* - } -} - #[macro_export] macro_rules! structured_access_log { - ($($k:ident $(: $v:expr)?),* $(,)?) => { - $crate::logging::RequestRecord {$( - $k: &unwrap_or!({$($v)?} {$k}), + ([$($struct_name:tt)+] $($fields:tt)*) => {{ + $($struct_name)+ {$( + $fields )*} - }; + }}; } /// log a failure concerning an HTTP or TCP request #[macro_export] macro_rules! error_access { ($($request_record_fields:tt)*) => { - log_access!($crate::logging::LogLevel::Error, "ERROR", structured_access_log!($($request_record_fields)*)); + log_access!($crate::logging::LogLevel::Error, $($request_record_fields)*); }; } @@ -737,7 +854,7 @@ macro_rules! error_access { #[macro_export] macro_rules! info_access { ($($request_record_fields:tt)*) => { - log_access!($crate::logging::LogLevel::Info, "INFO", structured_access_log!($($request_record_fields)*)); + log_access!($crate::logging::LogLevel::Info, $($request_record_fields)*); }; } @@ -745,7 +862,7 @@ macro_rules! info_access { #[macro_export] macro_rules! error { ($format:expr $(, $args:expr)* $(,)?) => { - log!($crate::logging::LogLevel::Error, $format, "ERROR" $(, $args)*) + log!($crate::logging::LogLevel::Error, $format $(, $args)*) }; } @@ -753,7 +870,7 @@ macro_rules! error { #[macro_export] macro_rules! warn { ($format:expr $(, $args:expr)* $(,)?) => { - log!($crate::logging::LogLevel::Warn, $format, "WARN" $(, $args)*); + log!($crate::logging::LogLevel::Warn, $format $(, $args)*) }; } @@ -761,35 +878,37 @@ macro_rules! warn { #[macro_export] macro_rules! info { ($format:expr $(, $args:expr)* $(,)?) => { - log!($crate::logging::LogLevel::Info, $format, "INFO" $(, $args)*); + log!($crate::logging::LogLevel::Info, $format $(, $args)*) }; } /// log a debug with Sōzu’s custom log stack #[macro_export] macro_rules! debug { - ($format:expr $(, $args:expr)* $(,)?) => { + ($format:expr $(, $args:expr)* $(,)?) => {{ #[cfg(any(debug_assertions, feature = "logs-debug", feature = "logs-trace"))] - log!($crate::logging::LogLevel::Debug, concat!("{}\t", $format), - "DEBUG", module_path!() $(, $args)*); - }; + log!($crate::logging::LogLevel::Debug, concat!("{}\t", $format), module_path!() $(, $args)*); + #[cfg(not(any(debug_assertions, feature = "logs-trace")))] + {$( let _ = $args; )*} + }}; } /// log a trace with Sōzu’s custom log stack #[macro_export] macro_rules! trace { - ($format:expr $(, $args:expr)* $(,)?) => ( + ($format:expr $(, $args:expr)* $(,)?) => {{ #[cfg(any(debug_assertions, feature = "logs-trace"))] - log!($crate::logging::LogLevel::Trace, concat!("{}\t", $format), - "TRACE", module_path!() $(, $args)*); - ); + log!($crate::logging::LogLevel::Trace, concat!("{}\t", $format), module_path!() $(, $args)*); + #[cfg(not(any(debug_assertions, feature = "logs-trace")))] + {$( let _ = $args; )*} + }}; } /// write a log with a "FIXME" prefix on an info level #[macro_export] macro_rules! fixme { ($(, $args:expr)* $(,)?) => { - log!($crate::logging::LogLevel::Info, "FIXME: {}:{} in {}: {}", "INFO", file!(), line!(), module_path!() $(, $args)*); + log!($crate::logging::LogLevel::Info, "FIXME: {}:{} in {}: {}", file!(), line!(), module_path!() $(, $args)*) }; } @@ -813,22 +932,25 @@ impl log::Log for CompatLogger { } fn log(&self, record: &log::Record) { - LOGGER.with(|l| { - let mut l = l.borrow_mut(); - if !l.compat_enabled(record.metadata()) { + LOGGER.with(|logger| { + let mut logger = logger.borrow_mut(); + if !logger.compat_enabled(record.metadata()) { return; } - let (pid, tag, inner) = l.split(); + let (pid, tag, inner) = logger.split(); let (now, precise_time) = now(); - inner.compat_log(format_args!( - concat!("{} {} {} {} {}\t{}\n"), - now, - precise_time, - pid, - tag, - record.level(), - record.args() - )); + crate::prompt_log! { + logger: |args| inner.log(args), + is_access: false, + condition: inner.colored, + prompt: [ + now, precise_time, pid, LogLevel::from(record.level()), tag + ], + standard: { + formats: ["{}\n"], + args: [record.args()] + } + }; }) } @@ -843,6 +965,8 @@ macro_rules! setup_test_logger { module_path!().to_string(), "error", $crate::logging::LoggerBackend::Stdout(::std::io::stdout()), + false, + None, None, None, ); @@ -850,24 +974,7 @@ macro_rules! setup_test_logger { } pub struct Rfc3339Time { - inner: ::time::OffsetDateTime, -} - -impl std::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() - ) - } + pub inner: ::time::OffsetDateTime, } pub fn now() -> (Rfc3339Time, i128) { diff --git a/command/src/proto/display.rs b/command/src/proto/display.rs index 1b869074a..a96a99dfa 100644 --- a/command/src/proto/display.rs +++ b/command/src/proto/display.rs @@ -1,6 +1,6 @@ use std::{ collections::{BTreeMap, HashMap, HashSet}, - fmt::{self, Display, Formatter}, + fmt::{self, Debug, Display, Formatter}, net::SocketAddr, }; @@ -9,22 +9,23 @@ use time::format_description; use x509_parser::time::ASN1Time; use crate::{ - access_logs::{prepare_user_agent, EndpointRecord, LogContext, LogDuration, RequestRecord}, - logging::LoggerBackend, + access_logs::{prepare_user_agent, EndpointRecord, FullTags, LogContext, LogDuration}, + config::Config, + logging::{LogLevel, LoggerBackend, Rfc3339Time}, proto::{ command::{ - filtered_metrics, request::RequestType, response_content::ContentType, - AggregatedMetrics, AvailableMetrics, CertificateAndKey, CertificateSummary, - CertificatesWithFingerprints, ClusterMetrics, FilteredMetrics, - ListOfCertificatesByAddress, ListedFrontends, ListenersList, QueryCertificatesFilters, - RequestCounts, Response, ResponseContent, ResponseStatus, RunState, TlsVersion, - WorkerInfos, WorkerMetrics, WorkerResponses, + filtered_metrics, protobuf_endpoint, request::RequestType, + response_content::ContentType, AggregatedMetrics, AvailableMetrics, CertificateAndKey, + CertificateSummary, CertificatesWithFingerprints, ClusterMetrics, FilteredMetrics, + ListOfCertificatesByAddress, ListedFrontends, ListenersList, ProtobufEndpoint, + QueryCertificatesFilters, RequestCounts, Response, ResponseContent, ResponseStatus, + RunState, SocketAddress, TlsVersion, WorkerInfos, WorkerMetrics, WorkerResponses, }, DisplayError, }, }; -use super::command::{protobuf_endpoint, ProtobufEndpoint, HttpEndpoint, SocketAddress, TcpEndpoint}; +use super::command::{HttpEndpoint, TcpEndpoint}; impl Display for CertificateAndKey { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { @@ -949,6 +950,42 @@ fn create_cluster_table(headers: Vec<&str>, data: &BTreeMap) -> 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() + } +} + impl Display for SocketAddress { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", SocketAddr::from(self.clone())) @@ -1018,6 +1055,63 @@ impl AsRef for LoggerBackend { } } +impl LogLevel { + pub const fn as_str_access(&self) -> &'static str { + match self { + LogLevel::Error => "\x1b[;35;1mERROR-ACCESS", + LogLevel::Info => "\x1b[;35;1mINFO-ACCESS ", + _ => "\x1b[;35m???", + } + // match self { + // LogLevel::Error => "ERROR", + // LogLevel::Warn => "WARN", + // LogLevel::Info => "INFO", + // LogLevel::Debug => "DEBUG", + // LogLevel::Trace => "TRACE", + // } + } + 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 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 Display for LogDuration { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.0 { @@ -1049,7 +1143,7 @@ impl 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("-") @@ -1081,42 +1175,15 @@ impl Display for EndpointRecord<'_> { } } -impl Display for RequestRecord<'_> { +impl<'a> Display for FullTags<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let (tags, ua_separator, user_agent) = match (self.tags, &self.user_agent) { - (None, None) => ("-", "", String::new()), - (Some(tags), None) => (tags.concatenated.as_str(), "", String::new()), - (None, Some(ua)) => ("", "user-agent=", prepare_user_agent(ua)), - (Some(tags), Some(ua)) => ( - tags.concatenated.as_str(), - ", user-agent=", - prepare_user_agent(ua), - ), - }; - - write!( - f, - "{} \t{} -> {} \t{}/{}/{}/{} \t{} -> {} \t {}{}{} {} {}", - self.context, - self.session_address.as_string_or("X"), - self.backend_address.as_string_or("X"), - LogDuration(Some(*self.response_time)), - LogDuration(Some(*self.service_time)), - LogDuration(*self.client_rtt), - LogDuration(*self.server_rtt), - self.bytes_in, - self.bytes_out, - tags, - ua_separator, - user_agent, - self.protocol, - self.endpoint - )?; - - if let Some(message) = &self.error { - writeln!(f, " | {}", message) - } else { - writeln!(f) + 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)), } } } diff --git a/doc/benchmark.md b/doc/benchmark.md index fa21ad56f..9eed9ff97 100644 --- a/doc/benchmark.md +++ b/doc/benchmark.md @@ -14,7 +14,7 @@ worker only seems ideal: worker_count = 1 ``` -The HTTP and HTTPS listeners should be identical. +The HTTP and HTTPS listeners should be identical. Chose a TLS version and a cipher list for the HTTPS listener, and stick to it. ```toml diff --git a/e2e/src/mock/client.rs b/e2e/src/mock/client.rs index 2a1adae60..da0e1f242 100644 --- a/e2e/src/mock/client.rs +++ b/e2e/src/mock/client.rs @@ -36,8 +36,8 @@ impl Client { } } - /// Establish a TCP connection with its address, - /// register the yielded TCP stream, apply timeouts + /// Establish a TCP connection with its address, + /// register the yielded TCP stream, apply timeouts pub fn connect(&mut self) { let stream = TcpStream::connect(self.address).expect("could not connect"); stream diff --git a/e2e/src/mock/sync_backend.rs b/e2e/src/mock/sync_backend.rs index 14712bb7f..2208ab5dd 100644 --- a/e2e/src/mock/sync_backend.rs +++ b/e2e/src/mock/sync_backend.rs @@ -42,7 +42,7 @@ impl Backend { } } - /// Binds itself to its address, stores the yielded TCP listener + /// Binds itself to its address, stores the yielded TCP listener pub fn connect(&mut self) { let listener = TcpListener::bind(self.address).expect("could not bind"); let timeout = Duration::from_millis(100); diff --git a/e2e/src/sozu/worker.rs b/e2e/src/sozu/worker.rs index d613f14d5..b3bc6605b 100644 --- a/e2e/src/sozu/worker.rs +++ b/e2e/src/sozu/worker.rs @@ -13,7 +13,7 @@ use sozu::server::Server; use sozu_command::{ channel::Channel, config::{ConfigBuilder, FileConfig}, - logging::setup_logging, + logging::setup_default_logging, proto::command::{ request::RequestType, AddBackend, Cluster, HardStop, LoadBalancingParams, PathRule, Request, RequestHttpFrontend, RequestTcpFrontend, ReturnListenSockets, RulePosition, @@ -133,7 +133,7 @@ impl Worker { println!("Setting up logging"); let server_job = thread::spawn(move || { - setup_logging("stdout", None, None, "error", &thread_name); + setup_default_logging(false, "error", &thread_name); let mut server = Server::try_new_from_config( cmd_worker_to_main, thread_scm_worker_to_main, diff --git a/e2e/src/tests/tests.rs b/e2e/src/tests/tests.rs index 2b73528d2..eab178521 100644 --- a/e2e/src/tests/tests.rs +++ b/e2e/src/tests/tests.rs @@ -7,7 +7,7 @@ use std::{ use sozu_command_lib::{ config::{FileConfig, ListenerBuilder}, info, log, - logging::setup_logging, + logging::setup_default_logging, proto::command::{ request::RequestType, ActivateListener, AddCertificate, CertificateAndKey, ListenerType, RemoveBackend, RequestHttpFrontend, SocketAddress, @@ -631,7 +631,7 @@ pub fn try_hard_or_soft_stop(soft: bool) -> State { } fn try_http_behaviors() -> State { - setup_logging("stdout", None, None, "debug", "BEHAVE-OUT"); + setup_default_logging(false, "debug", "BEHAVE-OUT"); info!("starting up"); @@ -1069,7 +1069,7 @@ pub fn try_blue_geen() -> State { } pub fn try_keep_alive() -> State { - setup_logging("stdout", None, None, "debug", "KA-OUT"); + setup_default_logging(false, "debug", "KA-OUT"); let front_address = create_local_address(); diff --git a/lib/assets/certificate-dominum.csr b/lib/assets/certificate-dominum.csr new file mode 100644 index 000000000..368d1b92f --- /dev/null +++ b/lib/assets/certificate-dominum.csr @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEzDCCArQCAQAwXjELMAkGA1UEBhMCRlIxETAPBgNVBAgMCEhlaWxpZ2VzMQ8w +DQYDVQQHDAZOYW50ZXMxFTATBgNVBAoMDENsZXZlci1DbG91ZDEUMBIGA1UEAwwL +ZG9taW51bS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDEXCAq +ud46VcSFp+2hs6zoXCjCYUewmggq/0t7Hu5G3niCTyDu07UJambvN528/SudJF6A +mguECPS/vt4jN8ced8hln+Lg54HczNwUk+3a+kbj1A4xfmKNwRIb3p+r07DmhbsY +FcqTaKeC/mRTobxH+HC01Zvc0K48Hf+W84kuBNp2PSH3BxiuxjoFbxGAKCHkDTvW +IJfq/mYiFV/8bwNNCBesKPwTxcEd1TCS34ChTRtBxs/cYJmMb0/LRcy8/lb8EvUB +GztD6qfpoXhM3FbHBz9UD3Pi1AFLfKbaN0mPfMFYoQQvgTU8rmplVLOYPI3Sc7LC +W77tnUqAz9ojhRAvYohJA0P4oto4YiunwDfhSgh/HlxqrLH5jAWYN9yiNzOpTuAE +ivpVt/pF8l6nzR/nlVWPrJ0HR42QVnpWhtSUbsOrmUgr5gXTswN+VD5Osju7/gEv +NoW4hLNm3ozxH8O8U0nUMuJs5CRqhZCGWpvQq5PSm+ROsxe5Wb29nDh3RR3dUuun +nh0kLzDuPKvpnmEwt5fcUzoLEJWuh7q3bKwkkke+qE6c56+n9VQ5P+Kdr7a5Isn4 +YDdGSLwjVqKW89CFeXUA3RL2Spf9LBtcYrzMBSK/h3CKMx8jORR9VVoxrve99YBU +Fum3QfvQ+Uc2zMX2VVB90BUJNQqR3xUjMcmv4QIDAQABoCkwJwYJKoZIhvcNAQkO +MRowGDAWBgNVHREEDzANggtkb21pbnVtLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEA +TbfwbQD9zP7fS9vpkBr3oK+CRWcyEar0vkxd/bK92+sIEZmaMnivxLet7A7VX0Mq +8rzqi+Ynvc5HP+O51XZ9TnXKpjmOgDPpIObKyirt3g/fHoE9J3vVfLiOzJ7nzw6H +94jPZrZOXKY9ERjDYldGRpDqGPyxmkJY7WvhR5p2dFZGcsR7V05Et+WqZMI0xLbW +wQ1FVh5/qCAZZM+y90TLO3OxRPsqihDSfugLxhWhibQHM9ozoatzP+bH2IskT4S3 +tV6zq9ZrvTWpLzEWK8QWWyPeu6VlnT1vVUqml536RGtGWjEVOFYULc4tVuh7Ymjl +1Z8Csz44G9/GXWkz/KTapHiCJhh0JmkkxDUGdxpaLLKvaJP0vNxxYmmX2lkbcNpF +hxB8b9biqZms7sWzHUZ84OWGPsgSwv7eoOte5PfP8PNGYXfWR2YHg3z0r60JjFe2 +7/nOozg/nNwzj4QX6Y0aDRT7cE014o8XEOLYIykuZ+2THH2juCwXqlZyGbY2anjn +Hr/tj/GcQPq30ozytzkZwGUUcghgaoszXAN7udF2zlLPADA79xzKhjmJgt/dm4JA +QOQ1caSskALLUrdvxLFN6NhrzM7b58jwl0i0XQ7tbH15uGHXct/E1VzLWISwksVd +URMs4x1xCZ3YVJGfqt3ZJpaahaEZVzcu01qewjs6+kc= +-----END CERTIFICATE REQUEST----- diff --git a/lib/assets/certificate-dominum.pem b/lib/assets/certificate-dominum.pem new file mode 100644 index 000000000..bcd4ccbc8 --- /dev/null +++ b/lib/assets/certificate-dominum.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIULMhT/P5RZKIbSQsKusAFPKmE+I8wDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCRlIxETAPBgNVBAgMCEhlaWxpZ2VzMQ8wDQYDVQQHDAZO +YW50ZXMxFTATBgNVBAoMDENsZXZlci1DbG91ZDEUMBIGA1UEAwwLZG9taW51bS5j +b20wHhcNMjQwMjEzMTUyODIwWhcNMjYwMjEyMTUyODIwWjBeMQswCQYDVQQGEwJG +UjERMA8GA1UECAwISGVpbGlnZXMxDzANBgNVBAcMBk5hbnRlczEVMBMGA1UECgwM +Q2xldmVyLUNsb3VkMRQwEgYDVQQDDAtkb21pbnVtLmNvbTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAMRcICq53jpVxIWn7aGzrOhcKMJhR7CaCCr/S3se +7kbeeIJPIO7TtQlqZu83nbz9K50kXoCaC4QI9L++3iM3xx53yGWf4uDngdzM3BST +7dr6RuPUDjF+Yo3BEhven6vTsOaFuxgVypNop4L+ZFOhvEf4cLTVm9zQrjwd/5bz +iS4E2nY9IfcHGK7GOgVvEYAoIeQNO9Ygl+r+ZiIVX/xvA00IF6wo/BPFwR3VMJLf +gKFNG0HGz9xgmYxvT8tFzLz+VvwS9QEbO0Pqp+mheEzcVscHP1QPc+LUAUt8pto3 +SY98wVihBC+BNTyuamVUs5g8jdJzssJbvu2dSoDP2iOFEC9iiEkDQ/ii2jhiK6fA +N+FKCH8eXGqssfmMBZg33KI3M6lO4ASK+lW3+kXyXqfNH+eVVY+snQdHjZBWelaG +1JRuw6uZSCvmBdOzA35UPk6yO7v+AS82hbiEs2bejPEfw7xTSdQy4mzkJGqFkIZa +m9Crk9Kb5E6zF7lZvb2cOHdFHd1S66eeHSQvMO48q+meYTC3l9xTOgsQla6Hurds +rCSSR76oTpznr6f1VDk/4p2vtrkiyfhgN0ZIvCNWopbz0IV5dQDdEvZKl/0sG1xi +vMwFIr+HcIozHyM5FH1VWjGu9731gFQW6bdB+9D5RzbMxfZVUH3QFQk1CpHfFSMx +ya/hAgMBAAGjOTA3MBYGA1UdEQQPMA2CC2RvbWludW0uY29tMB0GA1UdDgQWBBSC +LZzCFrfpEi3e4cX25wi9Z6osbDANBgkqhkiG9w0BAQsFAAOCAgEAe2DKKvolPqY0 +Ptswq8CgRzoJX2ITZnR2keNilse573q9rzi1sVamd6hX+b+A1qbJL9UVC+EtFkx1 +QZh1BuTuXMNoma2wHPFYP9uZ9UQmg7BDlBPoTvG8UkHdMc5I4YsM2loUcr9pm/WN +ziiiD0AqZ2tapo/AX9ez4Zrkm9y2R2ZE5SvArLY2pBooluA3gMlE2IfbxskhZ2kk +SpT6xrmkvG1Qi9NxQQnUREKf10DNtw+gaFog+Mfap5fxAlfhBu24/AAed2zVdaZx +cEdqgdONr8QeYw7a5Vlo+PJGo1Vf/iMd1kXy4VZ7gS3bwcYDxXGogBaIQWxrzWNt +Mx+zOXjLEzgfKMID59ReU3d0w5wYqz1lLdAmPFhqXNdOeJRu7TwNJ1M73HjxXirg +LI8ZZGaoY9ClJQik7bozvMUEBhOu2uZ6iUVnME9xy0vEXLfRb4LxXmI809lDeWjj +0+FWQN37rC4mIXmxl0yTFv1W1rlQ0QJCtAIJkOj2B7jssjTfpzPZFjAr2oJuja1E ++hMJCn+uwqCPTdrO2DyzztKl1PG1jVA8kedS0yNTtycFyRdPUoa622YyWmz3QOVy +QnRGdETy5KRXbW1UUstC26Eoz+FCVy5r9AA7oZEfny5xRuhYYReEk/bzba9U5aFo +TWVXb6P4rHpcTaCSqL0PWViO55c+p2g= +-----END CERTIFICATE----- diff --git a/lib/assets/certificate-dominum2.csr b/lib/assets/certificate-dominum2.csr new file mode 100644 index 000000000..06c25fdca --- /dev/null +++ b/lib/assets/certificate-dominum2.csr @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIE2zCCAsMCAQAwXDELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTEPMA0G +A1UEBwwGTmFudGVzMRUwEwYDVQQKDAxDbGV2ZXItQ2xvdWQxFDASBgNVBAMMC2Rv +bWludW0uY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxFwgKrne +OlXEhaftobOs6FwowmFHsJoIKv9Lex7uRt54gk8g7tO1CWpm7zedvP0rnSRegJoL +hAj0v77eIzfHHnfIZZ/i4OeB3MzcFJPt2vpG49QOMX5ijcESG96fq9Ow5oW7GBXK +k2ingv5kU6G8R/hwtNWb3NCuPB3/lvOJLgTadj0h9wcYrsY6BW8RgCgh5A071iCX +6v5mIhVf/G8DTQgXrCj8E8XBHdUwkt+AoU0bQcbP3GCZjG9Py0XMvP5W/BL1ARs7 +Q+qn6aF4TNxWxwc/VA9z4tQBS3ym2jdJj3zBWKEEL4E1PK5qZVSzmDyN0nOywlu+ +7Z1KgM/aI4UQL2KISQND+KLaOGIrp8A34UoIfx5caqyx+YwFmDfcojczqU7gBIr6 +Vbf6RfJep80f55VVj6ydB0eNkFZ6VobUlG7Dq5lIK+YF07MDflQ+TrI7u/4BLzaF +uISzZt6M8R/DvFNJ1DLibOQkaoWQhlqb0KuT0pvkTrMXuVm9vZw4d0Ud3VLrp54d +JC8w7jyr6Z5hMLeX3FM6CxCVroe6t2ysJJJHvqhOnOevp/VUOT/ina+2uSLJ+GA3 +Rki8I1ailvPQhXl1AN0S9kqX/SwbXGK8zAUiv4dwijMfIzkUfVVaMa73vfWAVBbp +t0H70PlHNszF9lVQfdAVCTUKkd8VIzHJr+ECAwEAAaA6MDgGCSqGSIb3DQEJDjEr +MCkwJwYDVR0RBCAwHoILZG9taW51bS5jb22CD3d3dy5kb21pbnVtLmNvbTANBgkq +hkiG9w0BAQsFAAOCAgEAadwTKf3FZ2F7idKQj1xU/2B09mCLQd3ZjbcPfESVg8bb +plyP13777y0j8/QGxIQFheVr5M3RxwQ7b77QYLHZxN5CdXUOKD4fCLC9xd7BEM0Q +RjYivsDB1G6rbf+czrkYiJBpZ28VePl6QkiD1x+sVWY9OgZMB+oKuRTiMktot3kc +PFerzhP7Dyr8EO9DiZHOW3LaN9O9HM9B+4YGyAuIKSCupNXq6318pQSi01RkSe1E +So/GXmrD9bhTfj6n62Lb3kQhahipWbUZW9D61kCOE+6WVxJGEvaE8USZRwrW5gYn +JvA9D22nybFEtK4hnOYriCK0ARVLZj89vJGw78ueZFSGeO6CXcRtxZJfUkSxp6o4 +/q10XhWRX4av4Lg8Dvk/EwXI3K97BDI8NXcjJpLAURs82DP01LT2ojeItvi/634E +uEvKzxUdXePSEaJmWWSzI1FzOoyPTlgAllFBV4b73y3t3pTKV+cqCihzXR1xbzA8 +tmZw6UuveICrfddjXPLW8Rfn12W1a3e/xlcjEpx8voEzrOsRNfqO7e1JIvesYE9h ++LJ4ht4Z6AAYX/Hdys5hCRatz3UTsea68ZKGmN1mHYhPqgMuPIauprirVuCwHZgv +8CIEs0+LEso8npTeo1kGqEroihUD7fUAouEs9w6HD11z4s3plSV9zR+HyhaBtoo= +-----END CERTIFICATE REQUEST----- diff --git a/lib/assets/certificate-dominum2.pem b/lib/assets/certificate-dominum2.pem new file mode 100644 index 000000000..66f33a177 --- /dev/null +++ b/lib/assets/certificate-dominum2.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIUVsVc5NHYJGg1F/o1em6KbFts7KcwDQYJKoZIhvcNAQEL +BQAwXDELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTEPMA0GA1UEBwwGTmFu +dGVzMRUwEwYDVQQKDAxDbGV2ZXItQ2xvdWQxFDASBgNVBAMMC2RvbWludW0uY29t +MB4XDTI0MDIxMzE1MjkyM1oXDTI2MDIxMjE1MjkyM1owXDELMAkGA1UEBhMCRlIx +DzANBgNVBAgMBkZyYW5jZTEPMA0GA1UEBwwGTmFudGVzMRUwEwYDVQQKDAxDbGV2 +ZXItQ2xvdWQxFDASBgNVBAMMC2RvbWludW0uY29tMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEAxFwgKrneOlXEhaftobOs6FwowmFHsJoIKv9Lex7uRt54 +gk8g7tO1CWpm7zedvP0rnSRegJoLhAj0v77eIzfHHnfIZZ/i4OeB3MzcFJPt2vpG +49QOMX5ijcESG96fq9Ow5oW7GBXKk2ingv5kU6G8R/hwtNWb3NCuPB3/lvOJLgTa +dj0h9wcYrsY6BW8RgCgh5A071iCX6v5mIhVf/G8DTQgXrCj8E8XBHdUwkt+AoU0b +QcbP3GCZjG9Py0XMvP5W/BL1ARs7Q+qn6aF4TNxWxwc/VA9z4tQBS3ym2jdJj3zB +WKEEL4E1PK5qZVSzmDyN0nOywlu+7Z1KgM/aI4UQL2KISQND+KLaOGIrp8A34UoI +fx5caqyx+YwFmDfcojczqU7gBIr6Vbf6RfJep80f55VVj6ydB0eNkFZ6VobUlG7D +q5lIK+YF07MDflQ+TrI7u/4BLzaFuISzZt6M8R/DvFNJ1DLibOQkaoWQhlqb0KuT +0pvkTrMXuVm9vZw4d0Ud3VLrp54dJC8w7jyr6Z5hMLeX3FM6CxCVroe6t2ysJJJH +vqhOnOevp/VUOT/ina+2uSLJ+GA3Rki8I1ailvPQhXl1AN0S9kqX/SwbXGK8zAUi +v4dwijMfIzkUfVVaMa73vfWAVBbpt0H70PlHNszF9lVQfdAVCTUKkd8VIzHJr+EC +AwEAAaNKMEgwJwYDVR0RBCAwHoILZG9taW51bS5jb22CD3d3dy5kb21pbnVtLmNv +bTAdBgNVHQ4EFgQUgi2cwha36RIt3uHF9ucIvWeqLGwwDQYJKoZIhvcNAQELBQAD +ggIBAEbtoqWD7xyE/+8MtA6cAbO/pDbvSipleCjmXvjSw6+5QKxzFO2iX/Ipx/9w +k11F2UF10FehWE3NRXt0xVN/NwWcmVb4LHg7DDL0gvLjgryLkqv8ncD8DwYMxZEj +x5zKTZX6aEjVbAJ4z0y3UpgzMoaFOlpNAImx6FbbfTr6WL7GDln5VG81rOSSzzL+ +9ded8e5OQxW/Q7Mgdhcm/9wa/HOEzB/2GpzFw9TlJtgWGT9SRLeXSdnrwicbWF36 +KcUZWYbidtyCxzj4YR1oXGevYW5HsgtvwxO5mqPt/pHKlIwhctJ9yKKTMMida/iT +kzJ0EyxnLUcZA7wiLZVJvjNIj+kVO4pi2e5lwyKkgl9KAilIQKwbugPvksYSlG4e +lXZf5q6CfVOawpTo6Af3uJYblJNTDbdBQB+Krt6JUHFhCPaOqJB28gxbt67wLI5j +UQ+EqEfgQ1PFuR6kDa5avj9wd/BSYBbCoiSK7wjGkTJkzUBSmR7lUENAj4KLOlc0 +RkpbGTA3+o5B08svTF1qMVVcr/XKqAKLpl8OoQsIDoiLobhZT901oiN/IVmqMLLV +3T2MAMX193fT/C07+rFBT8Z/PmHJ1FXadkesgAlSOlCzxHIXVMF2zz9+b7639O3k +6Ng7gkIBTHnI1AWXsMBWISp3wiWUhF3cwg5IFYcgl8NLqHBz +-----END CERTIFICATE----- diff --git a/lib/assets/dominum.conf b/lib/assets/dominum.conf new file mode 100644 index 000000000..1280ad3e1 --- /dev/null +++ b/lib/assets/dominum.conf @@ -0,0 +1,23 @@ +# based on https://gist.github.com/croxton/ebfb5f3ac143cd86542788f972434c96 +[ req ] +default_bits = 4096 +distinguished_name = req_distinguished_name +req_extensions = req_ext + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = FR +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Heiliges +localityName = Locality Name (eg, city) +localityName_default = Nantes +organizationName = Organization Name (eg, company) +organizationName_default = Clever-Cloud +commonName = Common Name (eg, server fqdn) +commonName_default = dominum.com + +[ req_ext ] +subjectAltName = @alt_names + +[ alt_names ] +DNS.1 = dominum.com diff --git a/lib/assets/dominum2.conf b/lib/assets/dominum2.conf new file mode 100644 index 000000000..dfbb7f069 --- /dev/null +++ b/lib/assets/dominum2.conf @@ -0,0 +1,25 @@ +# based on https://gist.github.com/croxton/ebfb5f3ac143cd86542788f972434c96 +[ req ] +default_bits = 4096 +distinguished_name = req_distinguished_name +req_extensions = req_ext + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = FR +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = France +localityName = Locality Name (eg, city) +localityName_default = Nantes +organizationName = Organization Name (eg, company) +organizationName_default = Clever-Cloud +commonName = Common Name (eg, server fqdn) +commonName_default = dominum.com + +[ req_ext ] +subjectAltName = @alt_names + +[ alt_names ] +DNS.1 = dominum.com +DNS.2 = www.dominum.com + diff --git a/lib/examples/http.rs b/lib/examples/http.rs index 7fd7d145e..78b92759e 100644 --- a/lib/examples/http.rs +++ b/lib/examples/http.rs @@ -11,7 +11,7 @@ use sozu_command_lib::{ channel::Channel, config::ListenerBuilder, info, - logging::setup_logging, + logging::setup_default_logging, proto::command::{ request::RequestType, AddBackend, Cluster, LoadBalancingAlgorithms, LoadBalancingParams, PathRule, RequestHttpFrontend, RulePosition, SocketAddress, WorkerRequest, WorkerResponse, @@ -19,7 +19,7 @@ use sozu_command_lib::{ }; fn main() -> anyhow::Result<()> { - setup_logging("stdout", None, None, "info", "EXAMPLE"); + setup_default_logging(true, "info", "EXAMPLE"); info!("starting up"); diff --git a/lib/examples/https.rs b/lib/examples/https.rs index e09cbb0aa..4fdc72a74 100644 --- a/lib/examples/https.rs +++ b/lib/examples/https.rs @@ -12,7 +12,7 @@ use anyhow::Context; use sozu_command_lib::{ channel::Channel, config::ListenerBuilder, - logging::setup_logging, + logging::setup_default_logging, proto::command::{ request::RequestType, AddBackend, AddCertificate, CertificateAndKey, LoadBalancingParams, PathRule, RequestHttpFrontend, SocketAddress, WorkerRequest, @@ -20,7 +20,7 @@ use sozu_command_lib::{ }; fn main() -> anyhow::Result<()> { - setup_logging("stdout", None, None, "info", "EXAMPLE"); + setup_default_logging(true, "info", "EXAMPLE"); info!("MAIN\tstarting up"); diff --git a/lib/examples/tcp.rs b/lib/examples/tcp.rs index 1793f3ecb..7109c8919 100644 --- a/lib/examples/tcp.rs +++ b/lib/examples/tcp.rs @@ -9,7 +9,7 @@ use std::thread; use anyhow::Context; use sozu_command_lib::{ channel::Channel, - logging::setup_logging, + logging::setup_default_logging, proto::command::{ request::RequestType, AddBackend, LoadBalancingParams, RequestTcpFrontend, SocketAddress, TcpListenerConfig, WorkerRequest, @@ -17,7 +17,7 @@ use sozu_command_lib::{ }; fn main() -> anyhow::Result<()> { - setup_logging("stdout", None, None, "info", "EXAMPLE"); + setup_default_logging(true, "info", "EXAMPLE"); info!("starting up"); @@ -32,7 +32,7 @@ fn main() -> anyhow::Result<()> { address: SocketAddress::new_v4(127, 0, 0, 1, 8080), ..Default::default() }; - setup_logging("stdout", None, None, "debug", "TCP"); + setup_default_logging(true, "debug", "TCP"); sozu_lib::tcp::testing::start_tcp_worker(listener, max_buffers, buffer_size, channel); }); diff --git a/lib/src/lib.rs b/lib/src/lib.rs index dab2cc9d0..60daea04f 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -115,7 +115,7 @@ //! //! We can now define a frontend. A frontend is a way to recognize a request and match //! it to a `cluster_id`, depending on the hostname and the beginning of the URL path. -//! The `address` field must match the one of the HTTP listener we defined before: +//! The `address` field must match the one of the HTTP listener we defined before: //! //! ``` //! use std::collections::BTreeMap; @@ -230,7 +230,7 @@ //! }; //! //! fn main() -> anyhow::Result<()> { -//! setup_logging("stdout", None, None, "info", "EXAMPLE"); +//! setup_logging("stdout", true, None, None, None, "info", "EXAMPLE"); //! //! info!("starting up"); //! @@ -643,7 +643,7 @@ pub enum ListenerError { RemoveFrontend(RouterError), } -/// Returned by the HTTP, HTTPS and TCP proxies +/// Returned by the HTTP, HTTPS and TCP proxies #[derive(thiserror::Error, Debug)] pub enum ProxyError { #[error("error while soft stopping {proxy_protocol} proxy: {error}")] diff --git a/lib/src/protocol/kawa_h1/mod.rs b/lib/src/protocol/kawa_h1/mod.rs index 6e94fc9bf..d5dd7cd90 100644 --- a/lib/src/protocol/kawa_h1/mod.rs +++ b/lib/src/protocol/kawa_h1/mod.rs @@ -843,7 +843,7 @@ impl Http Result { + fn new(config: TcpListenerConfig, token: Token) -> Result { Ok(TcpListener { cluster_id: None, listener: None, @@ -1192,7 +1189,10 @@ impl TcpProxy { let mut owned = listener.borrow_mut(); - let taken_listener = owned.listener.take().ok_or(ProxyError::UnactivatedListener)?; + let taken_listener = owned + .listener + .take() + .ok_or(ProxyError::UnactivatedListener)?; Ok((owned.token, taken_listener)) } diff --git a/lib/src/timer.rs b/lib/src/timer.rs index 4ad248404..a34a63108 100644 --- a/lib/src/timer.rs +++ b/lib/src/timer.rs @@ -338,7 +338,7 @@ impl Timer { .map(|state| self.set_timeout(delay_from_now, state)) } - // TODO: return Result with context + // TODO: return Result with context /// Cancel a timeout. /// /// If the timeout has not yet occurred, the return value holds the