diff --git a/Cargo.lock b/Cargo.lock index b0d455ed7..dc9869b6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -919,6 +919,16 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -953,6 +963,12 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1027,6 +1043,8 @@ dependencies = [ "tokio-rustls", "tokio-test", "toml", + "tracing", + "tracing-subscriber", "trust-dns-resolver", "webpki-roots", ] @@ -1390,6 +1408,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -1546,6 +1573,16 @@ dependencies = [ "syn 2.0.26", ] +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" version = "0.1.45" @@ -1721,6 +1758,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +dependencies = [ + "nu-ansi-term", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", + "tracing-serde", ] [[package]] @@ -1824,6 +1900,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index e778d8308..a1c09ab2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,8 @@ tokio-test = "0.4.2" serde_json = "1" itertools = "0.10" clap = { version = "4.3.1", features = ["derive", "env"] } +tracing = "0.1.37" +tracing-subscriber = { version = "0.3.17", features = ["json"]} [target.'cfg(not(target_env = "msvc"))'.dependencies] jemallocator = "0.5.0" diff --git a/src/cmd_args.rs b/src/cmd_args.rs index 159eefe9c..a3ab752bd 100644 --- a/src/cmd_args.rs +++ b/src/cmd_args.rs @@ -1,17 +1,27 @@ -use clap::Parser; -use log::LevelFilter; +use clap::{Parser, ValueEnum}; +use tracing::Level; /// PgCat: Nextgen PostgreSQL Pooler #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] -pub(crate) struct Args { +pub struct Args { #[arg(default_value_t = String::from("pgcat.toml"), env)] pub config_file: String, - #[arg(short, long, default_value_t = LevelFilter::Info, env)] - pub log_level: log::LevelFilter, + #[arg(short, long, default_value_t = tracing::Level::INFO, env)] + pub log_level: Level, + + #[clap(short='F', long, value_enum, default_value_t=LogFormat::Text, env)] + pub log_format: LogFormat, } -pub(crate) fn parse() -> Args { +pub fn parse() -> Args { return Args::parse(); } + +#[derive(ValueEnum, Clone, Debug)] +pub enum LogFormat { + Text, + Structured, + Debug +} diff --git a/src/lib.rs b/src/lib.rs index db6167db0..ed5d8842e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ pub mod dns_cache; pub mod errors; pub mod messages; pub mod mirrors; -pub mod multi_logger; pub mod plugins; pub mod pool; pub mod prometheus; @@ -17,6 +16,7 @@ pub mod server; pub mod sharding; pub mod stats; pub mod tls; +pub mod cmd_args; /// Format chrono::Duration to be more human-friendly. /// diff --git a/src/main.rs b/src/main.rs index 2b3294ee4..9b9bf7085 100644 --- a/src/main.rs +++ b/src/main.rs @@ -67,12 +67,23 @@ use pgcat::messages::configure_socket; use pgcat::pool::{ClientServerMap, ConnectionPool}; use pgcat::prometheus::start_metric_server; use pgcat::stats::{Collector, Reporter, REPORTER}; +use pgcat::cmd_args; -mod cmd_args; +use tracing_subscriber; +use pgcat::cmd_args::LogFormat; fn main() -> Result<(), Box> { let args = cmd_args::parse(); - pgcat::multi_logger::MultiLogger::init(args.log_level).unwrap(); + + match args.log_format { + LogFormat::Structured => tracing_subscriber::fmt().json().with_max_level(args.log_level).init(), + LogFormat::Debug => tracing_subscriber::fmt().pretty().with_max_level(args.log_level).init(), + _ => tracing_subscriber::fmt().with_max_level(args.log_level).init() + }; + + + // pgcat::multi_logger::MultiLogger::init(args.log_level).unwrap(); + info!("Welcome to PgCat! Meow. (Version {})", VERSION); diff --git a/src/multi_logger.rs b/src/multi_logger.rs deleted file mode 100644 index 8c620698a..000000000 --- a/src/multi_logger.rs +++ /dev/null @@ -1,83 +0,0 @@ -use log::{Level, LevelFilter, Log, Metadata, Record, SetLoggerError}; - -// This is a special kind of logger that allows sending logs to different -// targets depending on the log level. -// -// By default, if nothing is set, it acts as a regular env_log logger, -// it sends everything to standard error. -// -// If the Env variable `STDOUT_LOG` is defined, it will be used for -// configuring the standard out logger. -// -// The behavior is: -// - If it is an error, the message is written to standard error. -// - If it is not, and it matches the log level of the standard output logger (`STDOUT_LOG` env var), it will be send to standard output. -// - If the above is not true, it is sent to the stderr logger that will log it or not depending on the value -// of the RUST_LOG env var. -// -// So to summarize, if no `STDOUT_LOG` env var is present, the logger is the default logger. If `STDOUT_LOG` is set, everything -// but errors, that matches the log level set in the `STDOUT_LOG` env var is sent to stdout. You can have also some esoteric configuration -// where you set `RUST_LOG=debug` and `STDOUT_LOG=info`, in here, errors will go to stderr, warns and infos to stdout and debugs to stderr. -// -pub struct MultiLogger { - stderr_logger: env_logger::Logger, - stdout_logger: env_logger::Logger, -} - -impl MultiLogger { - fn new(filter: LevelFilter) -> Self { - let stderr_logger = env_logger::builder() - .filter(None, filter) - .format_timestamp_micros() - .build(); - let stdout_logger = env_logger::Builder::from_env("STDOUT_LOG") - .format_timestamp_micros() - .target(env_logger::Target::Stdout) - .build(); - - Self { - stderr_logger, - stdout_logger, - } - } - - pub fn init(filter: LevelFilter) -> Result<(), SetLoggerError> { - let logger = Self::new(filter); - - log::set_max_level(logger.stderr_logger.filter()); - log::set_boxed_logger(Box::new(logger)) - } -} - -impl Log for MultiLogger { - fn enabled(&self, metadata: &Metadata) -> bool { - self.stderr_logger.enabled(metadata) && self.stdout_logger.enabled(metadata) - } - - fn log(&self, record: &Record) { - if record.level() == Level::Error { - self.stderr_logger.log(record); - } else { - if self.stdout_logger.matches(record) { - self.stdout_logger.log(record); - } else { - self.stderr_logger.log(record); - } - } - } - - fn flush(&self) { - self.stderr_logger.flush(); - self.stdout_logger.flush(); - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_init() { - MultiLogger::init(LevelFilter::Error).unwrap(); - } -}