diff --git a/.schema/pgdog.schema.json b/.schema/pgdog.schema.json index eb9bf4095..8fc1ae709 100644 --- a/.schema/pgdog.schema.json +++ b/.schema/pgdog.schema.json @@ -85,6 +85,7 @@ "pub_sub_channel_size": 0, "query_cache_limit": 1000, "query_log": null, + "query_log_stdout": false, "query_parser": "auto", "query_parser_enabled": false, "query_parser_engine": "pg_query_protobuf", @@ -972,6 +973,11 @@ ], "default": null }, + "query_log_stdout": { + "description": "Log queries to stdout. Format: `query [database: db, user: user]`", + "type": "boolean", + "default": false + }, "query_parser": { "description": "Toggle the query parser to enable/disable query parsing and all of its benefits. By default, the query parser is turned on automatically, so only disable it if you know what you're doing.\n\n_Default:_ `auto`\n\nhttps://docs.pgdog.dev/configuration/pgdog.toml/general/#query_parser", "$ref": "#/$defs/QueryParserLevel", diff --git a/pgdog-config/src/general.rs b/pgdog-config/src/general.rs index 26aef743f..1154ad0cc 100644 --- a/pgdog-config/src/general.rs +++ b/pgdog-config/src/general.rs @@ -269,6 +269,10 @@ pub struct General { #[serde(default)] pub query_log: Option, + /// Log queries to stdout. Format: `query [database: db, user: user]` + #[serde(default = "General::query_log_stdout")] + pub query_log_stdout: bool, + /// Minimum parse duration in milliseconds that triggers a warning log with the query text. /// Queries whose parsing takes longer than this value are logged at WARN level. /// Set to `0` or omit to disable. @@ -800,6 +804,7 @@ impl Default for General { broadcast_address: Self::broadcast_address(), broadcast_port: Self::broadcast_port(), query_log: Self::query_log(), + query_log_stdout: Self::query_log_stdout(), log_min_duration_parse: Self::default_log_min_duration_parse(), log_query_sample_length: Self::log_query_sample_length(), openmetrics_port: Self::openmetrics_port(), @@ -1188,6 +1193,10 @@ impl General { Self::env_option_string("PGDOG_QUERY_LOG").map(PathBuf::from) } + fn query_log_stdout() -> bool { + Self::env_bool_or_default("PGDOG_QUERY_LOG_STDOUT", false) + } + fn default_log_min_duration_parse() -> Option { Self::env_option("PGDOG_LOG_MIN_DURATION_PARSE") } @@ -1587,6 +1596,15 @@ mod tests { assert_eq!(General::query_log(), None); } + #[test] + fn test_query_log_stdout_env() { + env::set_var("PGDOG_QUERY_LOG_STDOUT", "true"); + assert!(General::query_log_stdout()); + + env::remove_var("PGDOG_QUERY_LOG_STDOUT"); + assert!(!General::query_log_stdout()); + } + #[test] fn test_env_numeric_fields() { env::set_var("PGDOG_BROADCAST_PORT", "7432"); diff --git a/pgdog/src/frontend/client/mod.rs b/pgdog/src/frontend/client/mod.rs index 47601c767..fb9a1d8f9 100644 --- a/pgdog/src/frontend/client/mod.rs +++ b/pgdog/src/frontend/client/mod.rs @@ -89,6 +89,8 @@ pub struct Client { sticky: Sticky, /// Client database. database: String, + /// Log queries to stdout. + query_log_stdout: bool, } impl Client { @@ -379,6 +381,7 @@ impl Client { stream_buffer: MessageBuffer::new(config.config.memory.message_buffer), sticky: Sticky::from_params(¶ms), database: database.to_string(), + query_log_stdout: false, })) } @@ -410,6 +413,7 @@ impl Client { sticky: Sticky::from_params(&connect_params), params: connect_params, database: "pgdog".to_string(), + query_log_stdout: false, } } @@ -580,6 +584,7 @@ impl Client { // Configure prepared statements cache. self.prepared_statements.level = config.prepared_statements(); self.timeouts = Timeouts::from_config(&config.config.general); + self.query_log_stdout = config.config.general.query_log_stdout; while !self.client_request.is_complete() { let idle_timeout = self diff --git a/pgdog/src/frontend/client/query_engine/context.rs b/pgdog/src/frontend/client/query_engine/context.rs index b54751a35..8b42ef666 100644 --- a/pgdog/src/frontend/client/query_engine/context.rs +++ b/pgdog/src/frontend/client/query_engine/context.rs @@ -39,6 +39,8 @@ pub struct QueryEngineContext<'a> { pub(super) sticky: Sticky, /// Rewrite result. pub(super) rewrite_result: Option, + /// Log queries to stdout. + pub(super) query_log_stdout: bool, } impl<'a> QueryEngineContext<'a> { @@ -60,6 +62,7 @@ impl<'a> QueryEngineContext<'a> { rollback: false, sticky: client.sticky, rewrite_result: None, + query_log_stdout: client.query_log_stdout, } } @@ -86,6 +89,7 @@ impl<'a> QueryEngineContext<'a> { rollback: false, sticky: Sticky::new(), rewrite_result: None, + query_log_stdout: false, } } diff --git a/pgdog/src/frontend/client/query_engine/mod.rs b/pgdog/src/frontend/client/query_engine/mod.rs index 7bcb447b5..e92071476 100644 --- a/pgdog/src/frontend/client/query_engine/mod.rs +++ b/pgdog/src/frontend/client/query_engine/mod.rs @@ -26,6 +26,7 @@ pub mod multi_step; pub mod notify_buffer; pub mod pub_sub; pub mod query; +mod query_log_stdout; pub mod rewrite; pub mod route_query; pub mod set; @@ -39,6 +40,7 @@ pub mod two_pc; pub mod unknown_command; use self::query::ExplainResponseState; +use self::query_log_stdout::log_query_stdout; pub(crate) use advisory_lock::AdvisoryLocks; pub use context::QueryEngineContext; use notify_buffer::NotifyBuffer; @@ -108,6 +110,8 @@ impl QueryEngine { .received(context.client_request.total_message_len()); self.set_state(State::Active); // Client is active. + log_query_stdout(context); + // Rewrite prepared statements. self.rewrite_extended(context)?; diff --git a/pgdog/src/frontend/client/query_engine/query_log_stdout.rs b/pgdog/src/frontend/client/query_engine/query_log_stdout.rs new file mode 100644 index 000000000..081898c90 --- /dev/null +++ b/pgdog/src/frontend/client/query_engine/query_log_stdout.rs @@ -0,0 +1,21 @@ +use tracing::info; + +use super::QueryEngineContext; +use crate::util::user_database_from_params; + +pub(super) fn log_query_stdout(context: &QueryEngineContext<'_>) { + if !context.query_log_stdout { + return; + } + + if let Ok(Some(query)) = context.client_request.query() { + let (user, database) = user_database_from_params(context.params); + let query_one_line = query.query().replace(['\r', '\n'], " "); + info!( + "{} [database: {}, user: {}]", + query_one_line.trim(), + database, + user + ); + } +}