mirror of
https://github.com/postgresml/pgcat.git
synced 2026-03-26 18:36:28 +00:00
Add debug logging (#39)
* Add debug for easier debugging * fmt * a couple more messages
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
/// We are pretending to the server in this scenario,
|
/// We are pretending to the server in this scenario,
|
||||||
/// and this module implements that.
|
/// and this module implements that.
|
||||||
use bytes::{Buf, BufMut, BytesMut};
|
use bytes::{Buf, BufMut, BytesMut};
|
||||||
use log::error;
|
use log::{debug, error};
|
||||||
use tokio::io::{AsyncReadExt, BufReader};
|
use tokio::io::{AsyncReadExt, BufReader};
|
||||||
use tokio::net::{
|
use tokio::net::{
|
||||||
tcp::{OwnedReadHalf, OwnedWriteHalf},
|
tcp::{OwnedReadHalf, OwnedWriteHalf},
|
||||||
@@ -70,6 +70,8 @@ impl Client {
|
|||||||
let transaction_mode = config.general.pool_mode.starts_with("t");
|
let transaction_mode = config.general.pool_mode.starts_with("t");
|
||||||
drop(config);
|
drop(config);
|
||||||
loop {
|
loop {
|
||||||
|
debug!("Waiting for StartupMessage");
|
||||||
|
|
||||||
// Could be StartupMessage or SSLRequest
|
// Could be StartupMessage or SSLRequest
|
||||||
// which makes this variable length.
|
// which makes this variable length.
|
||||||
let len = match stream.read_i32().await {
|
let len = match stream.read_i32().await {
|
||||||
@@ -91,6 +93,8 @@ impl Client {
|
|||||||
match code {
|
match code {
|
||||||
// Client wants SSL. We don't support it at the moment.
|
// Client wants SSL. We don't support it at the moment.
|
||||||
SSL_REQUEST_CODE => {
|
SSL_REQUEST_CODE => {
|
||||||
|
debug!("Rejecting SSLRequest");
|
||||||
|
|
||||||
let mut no = BytesMut::with_capacity(1);
|
let mut no = BytesMut::with_capacity(1);
|
||||||
no.put_u8(b'N');
|
no.put_u8(b'N');
|
||||||
|
|
||||||
@@ -99,6 +103,8 @@ impl Client {
|
|||||||
|
|
||||||
// Regular startup message.
|
// Regular startup message.
|
||||||
PROTOCOL_VERSION_NUMBER => {
|
PROTOCOL_VERSION_NUMBER => {
|
||||||
|
debug!("Got StartupMessage");
|
||||||
|
|
||||||
// TODO: perform actual auth.
|
// TODO: perform actual auth.
|
||||||
let parameters = parse_startup(bytes.clone())?;
|
let parameters = parse_startup(bytes.clone())?;
|
||||||
|
|
||||||
@@ -110,6 +116,7 @@ impl Client {
|
|||||||
write_all(&mut stream, server_info).await?;
|
write_all(&mut stream, server_info).await?;
|
||||||
backend_key_data(&mut stream, process_id, secret_key).await?;
|
backend_key_data(&mut stream, process_id, secret_key).await?;
|
||||||
ready_for_query(&mut stream).await?;
|
ready_for_query(&mut stream).await?;
|
||||||
|
debug!("Startup OK");
|
||||||
|
|
||||||
// Split the read and write streams
|
// Split the read and write streams
|
||||||
// so we can control buffering.
|
// so we can control buffering.
|
||||||
@@ -161,6 +168,8 @@ impl Client {
|
|||||||
pub async fn handle(&mut self, mut pool: ConnectionPool) -> Result<(), Error> {
|
pub async fn handle(&mut self, mut pool: ConnectionPool) -> Result<(), Error> {
|
||||||
// The client wants to cancel a query it has issued previously.
|
// The client wants to cancel a query it has issued previously.
|
||||||
if self.cancel_mode {
|
if self.cancel_mode {
|
||||||
|
debug!("Sending CancelRequest");
|
||||||
|
|
||||||
let (process_id, secret_key, address, port) = {
|
let (process_id, secret_key, address, port) = {
|
||||||
let guard = self.client_server_map.lock().unwrap();
|
let guard = self.client_server_map.lock().unwrap();
|
||||||
|
|
||||||
@@ -193,6 +202,8 @@ impl Client {
|
|||||||
// We expect the client to either start a transaction with regular queries
|
// We expect the client to either start a transaction with regular queries
|
||||||
// or issue commands for our sharding and server selection protocols.
|
// or issue commands for our sharding and server selection protocols.
|
||||||
loop {
|
loop {
|
||||||
|
debug!("Client idle, waiting for message");
|
||||||
|
|
||||||
// Client idle, waiting for messages.
|
// Client idle, waiting for messages.
|
||||||
self.stats.client_idle(self.process_id);
|
self.stats.client_idle(self.process_id);
|
||||||
|
|
||||||
@@ -203,6 +214,12 @@ impl Client {
|
|||||||
// SET SHARDING KEY TO 'bigint';
|
// SET SHARDING KEY TO 'bigint';
|
||||||
let mut message = read_message(&mut self.read).await?;
|
let mut message = read_message(&mut self.read).await?;
|
||||||
|
|
||||||
|
// Avoid taking a server if the client just wants to disconnect.
|
||||||
|
if message[0] as char == 'X' {
|
||||||
|
debug!("Client disconnecting");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
// Handle all custom protocol commands here.
|
// Handle all custom protocol commands here.
|
||||||
match query_router.try_execute_command(message.clone()) {
|
match query_router.try_execute_command(message.clone()) {
|
||||||
// Normal query
|
// Normal query
|
||||||
@@ -250,9 +267,14 @@ impl Client {
|
|||||||
// Waiting for server connection.
|
// Waiting for server connection.
|
||||||
self.stats.client_waiting(self.process_id);
|
self.stats.client_waiting(self.process_id);
|
||||||
|
|
||||||
|
debug!("Waiting for connection from pool");
|
||||||
|
|
||||||
// Grab a server from the pool: the client issued a regular query.
|
// Grab a server from the pool: the client issued a regular query.
|
||||||
let connection = match pool.get(query_router.shard(), query_router.role()).await {
|
let connection = match pool.get(query_router.shard(), query_router.role()).await {
|
||||||
Ok(conn) => conn,
|
Ok(conn) => {
|
||||||
|
debug!("Got connection from pool");
|
||||||
|
conn
|
||||||
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Could not get connection from pool: {:?}", err);
|
error!("Could not get connection from pool: {:?}", err);
|
||||||
error_response(&mut self.write, "could not get connection from the pool")
|
error_response(&mut self.write, "could not get connection from the pool")
|
||||||
@@ -272,11 +294,19 @@ impl Client {
|
|||||||
self.stats.client_active(self.process_id);
|
self.stats.client_active(self.process_id);
|
||||||
self.stats.server_active(server.process_id());
|
self.stats.server_active(server.process_id());
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"Client {:?} talking to server {:?}",
|
||||||
|
self.write.peer_addr().unwrap(),
|
||||||
|
server.address()
|
||||||
|
);
|
||||||
|
|
||||||
// Transaction loop. Multiple queries can be issued by the client here.
|
// Transaction loop. Multiple queries can be issued by the client here.
|
||||||
// The connection belongs to the client until the transaction is over,
|
// The connection belongs to the client until the transaction is over,
|
||||||
// or until the client disconnects if we are in session mode.
|
// or until the client disconnects if we are in session mode.
|
||||||
loop {
|
loop {
|
||||||
let mut message = if message.len() == 0 {
|
let mut message = if message.len() == 0 {
|
||||||
|
debug!("Waiting for message inside transaction or in session mode");
|
||||||
|
|
||||||
match read_message(&mut self.read).await {
|
match read_message(&mut self.read).await {
|
||||||
Ok(message) => message,
|
Ok(message) => message,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -303,9 +333,13 @@ impl Client {
|
|||||||
let code = message.get_u8() as char;
|
let code = message.get_u8() as char;
|
||||||
let _len = message.get_i32() as usize;
|
let _len = message.get_i32() as usize;
|
||||||
|
|
||||||
|
debug!("Message: {}", code);
|
||||||
|
|
||||||
match code {
|
match code {
|
||||||
// ReadyForQuery
|
// ReadyForQuery
|
||||||
'Q' => {
|
'Q' => {
|
||||||
|
debug!("Sending query to server");
|
||||||
|
|
||||||
// TODO: implement retries here for read-only transactions.
|
// TODO: implement retries here for read-only transactions.
|
||||||
server.send(original).await?;
|
server.send(original).await?;
|
||||||
|
|
||||||
@@ -387,6 +421,8 @@ impl Client {
|
|||||||
// Sync
|
// Sync
|
||||||
// Frontend (client) is asking for the query result now.
|
// Frontend (client) is asking for the query result now.
|
||||||
'S' => {
|
'S' => {
|
||||||
|
debug!("Sending query to server");
|
||||||
|
|
||||||
self.buffer.put(&original[..]);
|
self.buffer.put(&original[..]);
|
||||||
|
|
||||||
// TODO: retries for read-only transactions.
|
// TODO: retries for read-only transactions.
|
||||||
@@ -471,6 +507,7 @@ impl Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The server is no longer bound to us, we can't cancel it's queries anymore.
|
// The server is no longer bound to us, we can't cancel it's queries anymore.
|
||||||
|
debug!("Releasing server back into the pool");
|
||||||
self.release();
|
self.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,7 +194,12 @@ impl QueryRouter {
|
|||||||
let len = buf.get_i32() as usize;
|
let len = buf.get_i32() as usize;
|
||||||
|
|
||||||
let query = match code {
|
let query = match code {
|
||||||
'Q' => String::from_utf8_lossy(&buf[..len - 5]).to_string(),
|
'Q' => {
|
||||||
|
let query = String::from_utf8_lossy(&buf[..len - 5]).to_string();
|
||||||
|
debug!("Query: '{}'", query);
|
||||||
|
query
|
||||||
|
}
|
||||||
|
|
||||||
'P' => {
|
'P' => {
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
let mut end;
|
let mut end;
|
||||||
@@ -213,6 +218,8 @@ impl QueryRouter {
|
|||||||
|
|
||||||
let query = String::from_utf8_lossy(&buf[start..end]).to_string();
|
let query = String::from_utf8_lossy(&buf[start..end]).to_string();
|
||||||
|
|
||||||
|
debug!("Prepared statement: '{}'", query);
|
||||||
|
|
||||||
query.replace("$", "") // Remove placeholders turning them into "values"
|
query.replace("$", "") // Remove placeholders turning them into "values"
|
||||||
}
|
}
|
||||||
_ => return false,
|
_ => return false,
|
||||||
@@ -221,7 +228,7 @@ impl QueryRouter {
|
|||||||
let ast = match Parser::parse_sql(&PostgreSqlDialect {}, &query) {
|
let ast = match Parser::parse_sql(&PostgreSqlDialect {}, &query) {
|
||||||
Ok(ast) => ast,
|
Ok(ast) => ast,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("{:?}, query: {}", err, query);
|
debug!("{}", err.to_string());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use bytes::{Buf, BufMut, BytesMut};
|
use bytes::{Buf, BufMut, BytesMut};
|
||||||
///! Implementation of the PostgreSQL server (database) protocol.
|
///! Implementation of the PostgreSQL server (database) protocol.
|
||||||
///! Here we are pretending to the a Postgres client.
|
///! Here we are pretending to the a Postgres client.
|
||||||
use log::{error, info};
|
use log::{debug, error, info};
|
||||||
use tokio::io::{AsyncReadExt, BufReader};
|
use tokio::io::{AsyncReadExt, BufReader};
|
||||||
use tokio::net::{
|
use tokio::net::{
|
||||||
tcp::{OwnedReadHalf, OwnedWriteHalf},
|
tcp::{OwnedReadHalf, OwnedWriteHalf},
|
||||||
@@ -75,6 +75,8 @@ impl Server {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("Sending StartupMessage");
|
||||||
|
|
||||||
// Send the startup packet telling the server we're a normal Postgres client.
|
// Send the startup packet telling the server we're a normal Postgres client.
|
||||||
startup(&mut stream, &user.name, database).await?;
|
startup(&mut stream, &user.name, database).await?;
|
||||||
|
|
||||||
@@ -95,6 +97,8 @@ impl Server {
|
|||||||
Err(_) => return Err(Error::SocketError),
|
Err(_) => return Err(Error::SocketError),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("Message: {}", code);
|
||||||
|
|
||||||
match code {
|
match code {
|
||||||
// Authentication
|
// Authentication
|
||||||
'R' => {
|
'R' => {
|
||||||
@@ -104,6 +108,8 @@ impl Server {
|
|||||||
Err(_) => return Err(Error::SocketError),
|
Err(_) => return Err(Error::SocketError),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("Auth: {}", auth_code);
|
||||||
|
|
||||||
match auth_code {
|
match auth_code {
|
||||||
MD5_ENCRYPTED_PASSWORD => {
|
MD5_ENCRYPTED_PASSWORD => {
|
||||||
// The salt is 4 bytes.
|
// The salt is 4 bytes.
|
||||||
@@ -135,6 +141,8 @@ impl Server {
|
|||||||
Err(_) => return Err(Error::SocketError),
|
Err(_) => return Err(Error::SocketError),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("Error: {}", error_code);
|
||||||
|
|
||||||
match error_code {
|
match error_code {
|
||||||
// No error message is present in the message.
|
// No error message is present in the message.
|
||||||
MESSAGE_TERMINATOR => (),
|
MESSAGE_TERMINATOR => (),
|
||||||
@@ -247,6 +255,8 @@ impl Server {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("Sending CancelRequest");
|
||||||
|
|
||||||
let mut bytes = BytesMut::with_capacity(16);
|
let mut bytes = BytesMut::with_capacity(16);
|
||||||
bytes.put_i32(16);
|
bytes.put_i32(16);
|
||||||
bytes.put_i32(CANCEL_REQUEST_CODE);
|
bytes.put_i32(CANCEL_REQUEST_CODE);
|
||||||
@@ -290,6 +300,8 @@ impl Server {
|
|||||||
let code = message.get_u8() as char;
|
let code = message.get_u8() as char;
|
||||||
let _len = message.get_i32();
|
let _len = message.get_i32();
|
||||||
|
|
||||||
|
debug!("Message: {}", code);
|
||||||
|
|
||||||
match code {
|
match code {
|
||||||
// ReadyForQuery
|
// ReadyForQuery
|
||||||
'Z' => {
|
'Z' => {
|
||||||
|
|||||||
Reference in New Issue
Block a user