From cf182c65d2add37042f88515508e96439982ee44 Mon Sep 17 00:00:00 2001 From: Gyan Sreejith Date: Tue, 23 Dec 2025 18:07:10 -0500 Subject: [PATCH] Add a new argument -l to pg_createsubscriber. Enabling the option will create three new log files - 1. logdir/pg_createsubscriber_server.log - captures messages related to starting and stopping the standby server. 2. logdir/pg_createsubscriber_resetwal.log - captures the output of pg_resetwal. 3. logdir/pg_createsubscriber_internal.log - captures internal diagnostic output from pg_createsubscriber. --- doc/src/sgml/ref/pg_createsubscriber.sgml | 27 ++++++++ src/bin/pg_basebackup/pg_createsubscriber.c | 63 +++++++++++++++++-- .../t/040_pg_createsubscriber.pl | 36 ++++++++++- 3 files changed, 121 insertions(+), 5 deletions(-) diff --git a/doc/src/sgml/ref/pg_createsubscriber.sgml b/doc/src/sgml/ref/pg_createsubscriber.sgml index bb9cc72576c..5e24a297566 100644 --- a/doc/src/sgml/ref/pg_createsubscriber.sgml +++ b/doc/src/sgml/ref/pg_createsubscriber.sgml @@ -136,6 +136,33 @@ PostgreSQL documentation + + + + + + The target directory in which the following three log files will be created: + + + + pg_createsubscriber_server.log which captures logs related to stopping and starting the standby server, + + + + + pg_createsubscriber_resetwal.log which captures the output of pg_resetwal, and + + + + + pg_createsubscriber_internal.log which captures internal diagnostic output (validations, checks, etc.) + + + + + + + diff --git a/src/bin/pg_basebackup/pg_createsubscriber.c b/src/bin/pg_basebackup/pg_createsubscriber.c index f59c293d875..e8d7b0730e9 100644 --- a/src/bin/pg_basebackup/pg_createsubscriber.c +++ b/src/bin/pg_basebackup/pg_createsubscriber.c @@ -36,6 +36,7 @@ struct CreateSubscriberOptions { char *config_file; /* configuration file */ + char *log_dir; /* log directory */ char *pub_conninfo_str; /* publisher connection string */ char *socket_dir; /* directory for Unix-domain socket, if any */ char *sub_port; /* subscriber port number */ @@ -150,6 +151,8 @@ static pg_prng_state prng_state; static char *pg_ctl_path = NULL; static char *pg_resetwal_path = NULL; +static char *internal_log_file = NULL; + /* standby / subscriber data directory */ static char *subscriber_dir = NULL; @@ -251,6 +254,7 @@ usage(void) " databases and databases that don't allow connections\n")); printf(_(" -d, --database=DBNAME database in which to create a subscription\n")); printf(_(" -D, --pgdata=DATADIR location for the subscriber data directory\n")); + printf(_(" -l, --logdir=LOGDIR location for the new log directory\n")); printf(_(" -n, --dry-run dry run, just show what would be done\n")); printf(_(" -p, --subscriber-port=PORT subscriber port number (default %s)\n"), DEFAULT_SUB_PORT); printf(_(" -P, --publisher-server=CONNSTR publisher connection string\n")); @@ -670,6 +674,7 @@ modify_subscriber_sysid(const struct CreateSubscriberOptions *opt) bool crc_ok; struct timeval tv; + char *out_file; char *cmd_str; pg_log_info("modifying system identifier of subscriber"); @@ -703,8 +708,14 @@ modify_subscriber_sysid(const struct CreateSubscriberOptions *opt) else pg_log_info("running pg_resetwal on the subscriber"); + + if (opt->log_dir != NULL) + out_file = psprintf("%s/pg_createsubscriber_resetwal.log", opt->log_dir); + else + out_file = DEVNULL; + cmd_str = psprintf("\"%s\" -D \"%s\" > \"%s\"", pg_resetwal_path, - subscriber_dir, DEVNULL); + subscriber_dir, out_file); pg_log_debug("pg_resetwal command is: %s", cmd_str); @@ -893,8 +904,18 @@ check_publisher(const struct LogicalRepInfo *dbinfo) int cur_walsenders; int max_prepared_transactions; char *max_slot_wal_keep_size; + FILE *fp; + + if (internal_log_file != NULL) + { + if ((fp = fopen(internal_log_file, "a")) == NULL) + pg_fatal("could not write to log file \"%s\": %m", internal_log_file); - pg_log_info("checking settings on publisher"); + fprintf(fp, "checking settings on publisher\n"); + fclose(fp); + } + else + pg_log_info("checking settings on publisher"); conn = connect_database(dbinfo[0].pubconninfo, true); @@ -1028,8 +1049,18 @@ check_subscriber(const struct LogicalRepInfo *dbinfo) int max_lrworkers; int max_reporigins; int max_wprocs; + FILE *fp; + + if (internal_log_file != NULL) + { + if ((fp = fopen(internal_log_file, "a")) == NULL) + pg_fatal("could not write to log file \"%s\": %m", internal_log_file); - pg_log_info("checking settings on subscriber"); + fprintf(fp, "checking settings on subscriber\n"); + fclose(fp); + } + else + pg_log_info("checking settings on subscriber"); conn = connect_database(dbinfo[0].subconninfo, true); @@ -1548,6 +1579,11 @@ start_standby_server(const struct CreateSubscriberOptions *opt, bool restricted_ if (restrict_logical_worker) appendPQExpBufferStr(pg_ctl_cmd, " -o \"-c max_logical_replication_workers=0\""); + if (opt->log_dir != NULL) + { + appendPQExpBuffer(pg_ctl_cmd, " -l %s/pg_createsubscriber_server.log", opt->log_dir); + } + pg_log_debug("pg_ctl command is: %s", pg_ctl_cmd->data); rc = system(pg_ctl_cmd->data); pg_ctl_status(pg_ctl_cmd->data, rc); @@ -2071,6 +2107,7 @@ main(int argc, char **argv) {"all", no_argument, NULL, 'a'}, {"database", required_argument, NULL, 'd'}, {"pgdata", required_argument, NULL, 'D'}, + {"logdir", required_argument, NULL, 'l'}, {"dry-run", no_argument, NULL, 'n'}, {"subscriber-port", required_argument, NULL, 'p'}, {"publisher-server", required_argument, NULL, 'P'}, @@ -2129,6 +2166,7 @@ main(int argc, char **argv) /* Default settings */ subscriber_dir = NULL; opt.config_file = NULL; + opt.log_dir = NULL; opt.pub_conninfo_str = NULL; opt.socket_dir = NULL; opt.sub_port = DEFAULT_SUB_PORT; @@ -2157,7 +2195,7 @@ main(int argc, char **argv) get_restricted_token(); - while ((c = getopt_long(argc, argv, "ad:D:np:P:s:t:TU:v", + while ((c = getopt_long(argc, argv, "ad:D:l:np:P:s:t:TU:v", long_options, &option_index)) != -1) { switch (c) @@ -2178,6 +2216,23 @@ main(int argc, char **argv) subscriber_dir = pg_strdup(optarg); canonicalize_path(subscriber_dir); break; + case 'l': + opt.log_dir = pg_strdup(optarg); + canonicalize_path(opt.log_dir); + + if (stat(opt.log_dir, &statbuf) != 0) + { + if (errno == ENOENT) + { + mkdir(opt.log_dir, S_IRWXU); + pg_log_info("log directory created"); + } + else + pg_fatal("could not access directory \"%s\": %m", opt.log_dir); + } + + internal_log_file = psprintf("%s/pg_createsubscriber_internal.log", opt.log_dir); + break; case 'n': dry_run = true; break; diff --git a/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl b/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl index 3d6086dc489..1712adc0439 100644 --- a/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl +++ b/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl @@ -13,7 +13,8 @@ program_help_ok('pg_createsubscriber'); program_version_ok('pg_createsubscriber'); program_options_handling_ok('pg_createsubscriber'); -my $datadir = PostgreSQL::Test::Utils::tempdir; +my $datadir = PostgreSQL::Test::Utils::tempdir + "/datadir"; +my $logdir = PostgreSQL::Test::Utils::tempdir + "/logdir"; # Generate a database with a name made of a range of ASCII characters. # Extracted from 002_pg_upgrade.pl. @@ -537,10 +538,43 @@ my $sysid_s = $node_s->safe_psql('postgres', 'SELECT system_identifier FROM pg_control_system()'); isnt($sysid_p, $sysid_s, 'system identifier was changed'); +$node_p->backup('backup_3'); + +# Set up node R as a logical replica node +my $node_r = PostgreSQL::Test::Cluster->new('node_r'); +$node_r->init_from_backup($node_p, 'backup_3', has_streaming => 1); +$node_r->append_conf( + 'postgresql.conf', qq[ +primary_conninfo = '$pconnstr dbname=postgres' +hot_standby_feedback = on +]); +$node_r->set_standby_mode(); + +# Test that --logdir works for pg_createsubscriber +command_ok( + [ + 'pg_createsubscriber', + '--verbose', + '--pgdata' => $node_r->data_dir, + '--publisher-server' => $pconnstr, + '--database' => 'postgres', + '--logdir' => $logdir, + ], + 'check for log file creation for pg_createSubscriber'); + +# Check that all log files were created +ok( -f "$logdir/pg_createsubscriber_server.log", + 'pg_createsubscriber_server.log file was created'); +ok(-f "$logdir/pg_createsubscriber_resetwal.log", + 'pg_resetwal.log file was created'); +ok( -f "$logdir/pg_createsubscriber_internal.log", + 'pg_createsubsriber.log file was created'); + # clean up $node_p->teardown_node; $node_s->teardown_node; $node_t->teardown_node; $node_f->teardown_node; +$node_r->teardown_node; done_testing(); -- 2.43.0