@@ -125,6 +125,20 @@ enum Commands {
125125 #[ arg( trailing_var_arg = true , allow_hyphen_values = true ) ]
126126 args : Vec < String > ,
127127 } ,
128+ /// Show PostgreSQL logs
129+ Logs {
130+ /// Instance name
131+ #[ arg( long, default_value = DEFAULT_INSTANCE_NAME ) ]
132+ name : String ,
133+
134+ /// Number of lines to show (default: all)
135+ #[ arg( short = 'n' , long) ]
136+ lines : Option < usize > ,
137+
138+ /// Follow log output (like tail -f)
139+ #[ arg( short, long) ]
140+ follow : bool ,
141+ } ,
128142 /// Install a PostgreSQL extension (e.g., pgvector)
129143 InstallExtension {
130144 /// Instance name
@@ -865,6 +879,87 @@ fn psql(name: String, args: Vec<String>) -> Result<(), CliError> {
865879 Ok ( ( ) )
866880}
867881
882+ fn logs ( name : String , lines : Option < usize > , follow : bool ) -> Result < ( ) , CliError > {
883+ let instance_dir = get_instance_dir ( & name) ?;
884+ let log_dir = instance_dir. join ( "data" ) . join ( "log" ) ;
885+
886+ if !log_dir. exists ( ) {
887+ return Err ( CliError :: Other ( format ! (
888+ "Log directory not found for instance '{}'. Has PostgreSQL been started?" ,
889+ name
890+ ) ) ) ;
891+ }
892+
893+ // Find the most recent log file
894+ let mut log_files: Vec < _ > = fs:: read_dir ( & log_dir) ?
895+ . filter_map ( |e| e. ok ( ) )
896+ . filter ( |e| e. path ( ) . is_file ( ) )
897+ . collect ( ) ;
898+
899+ if log_files. is_empty ( ) {
900+ return Err ( CliError :: Other ( format ! (
901+ "No log files found for instance '{}'" ,
902+ name
903+ ) ) ) ;
904+ }
905+
906+ // Sort by modification time, most recent first
907+ log_files. sort_by_key ( |e| std:: cmp:: Reverse (
908+ e. metadata ( ) . and_then ( |m| m. modified ( ) ) . ok ( )
909+ ) ) ;
910+
911+ let log_file = & log_files[ 0 ] . path ( ) ;
912+
913+ if follow {
914+ // Follow mode - use tail -f equivalent
915+ println ! ( "Following logs for instance '{}' (Ctrl+C to exit):" , name) ;
916+ println ! ( "Log file: {}" , log_file. display( ) ) ;
917+ println ! ( ) ;
918+
919+ let mut file = fs:: File :: open ( log_file) ?;
920+ let mut pos = file. metadata ( ) ?. len ( ) ;
921+
922+ // Print existing content first
923+ use std:: io:: { BufRead , BufReader , Seek , SeekFrom } ;
924+ file. seek ( SeekFrom :: Start ( 0 ) ) ?;
925+ let reader = BufReader :: new ( & file) ;
926+ for line in reader. lines ( ) {
927+ println ! ( "{}" , line?) ;
928+ }
929+
930+ // Now follow new content
931+ loop {
932+ file. seek ( SeekFrom :: Start ( pos) ) ?;
933+ let reader = BufReader :: new ( & file) ;
934+ for line in reader. lines ( ) {
935+ println ! ( "{}" , line?) ;
936+ }
937+ pos = file. metadata ( ) ?. len ( ) ;
938+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
939+ }
940+ } else {
941+ // Show logs (optionally limited to N lines)
942+ use std:: io:: { BufRead , BufReader } ;
943+ let file = fs:: File :: open ( log_file) ?;
944+ let reader = BufReader :: new ( file) ;
945+ let all_lines: Vec < _ > = reader. lines ( ) . collect :: < Result < _ , _ > > ( ) ?;
946+
947+ let lines_to_show = if let Some ( n) = lines {
948+ & all_lines[ all_lines. len ( ) . saturating_sub ( n) ..]
949+ } else {
950+ & all_lines[ ..]
951+ } ;
952+
953+ println ! ( "Logs for instance '{}' ({})" , name, log_file. display( ) ) ;
954+ println ! ( ) ;
955+ for line in lines_to_show {
956+ println ! ( "{}" , line) ;
957+ }
958+ }
959+
960+ Ok ( ( ) )
961+ }
962+
868963fn find_installed_version ( installation_dir : & PathBuf ) -> Result < String , CliError > {
869964 if let Ok ( entries) = fs:: read_dir ( installation_dir) {
870965 for entry in entries. flatten ( ) {
@@ -1070,6 +1165,7 @@ fn main() {
10701165 Commands :: Info { name, output } => info ( name, output) ,
10711166 Commands :: List { output } => list ( output) ,
10721167 Commands :: Psql { name, args } => psql ( name, args) ,
1168+ Commands :: Logs { name, lines, follow } => logs ( name, lines, follow) ,
10731169 Commands :: InstallExtension { name, extension } => install_extension ( name, extension) ,
10741170 Commands :: ListExtensions => list_extensions ( ) ,
10751171 } ;
0 commit comments