From 55036fd6c2014786159f8d86a9fbce89c18a259e Mon Sep 17 00:00:00 2001 From: Bo Peng Date: Mon, 5 Aug 2024 15:34:33 +0900 Subject: [PATCH] Feature: Add new PCP command to trigger log rotation Currently the only way to trigger log rotation in logging collector process is to send SIGUSR1 signal directly to logging collector process. However, I think it would be nice to have a better way to do it with an external tool (e.g. logrotate) without requiring knowledge of the logging collector's PID. This commit adds a new PCP command "pcp_log_rotate" for triggering log rotation. --- doc.ja/src/sgml/ref/allfiles.sgml | 1 + doc.ja/src/sgml/ref/pcp_log_rotate.sgml | 74 +++++++++++++++++++ doc.ja/src/sgml/reference.sgml | 1 + doc/src/sgml/ref/allfiles.sgml | 3 +- doc/src/sgml/ref/pcp_log_rotate.sgml | 73 ++++++++++++++++++ doc/src/sgml/reference.sgml | 1 + src/include/pcp/libpcp_ext.h | 1 + src/include/pool.h | 3 +- src/include/watchdog/wd_ipc_defines.h | 1 + src/libs/pcp/pcp.c | 32 ++++++++ src/main/pgpool_logger.c | 2 +- src/main/pgpool_main.c | 31 ++++++++ src/pcp_con/pcp_worker.c | 33 +++++++++ .../regression/tests/038.pcp_commands/test.sh | 63 ++++++++++++++++ src/tools/pcp/.gitignore | 1 + src/tools/pcp/Makefile.am | 8 +- src/tools/pcp/pcp_frontend_client.c | 10 ++- src/watchdog/watchdog.c | 11 +++ 18 files changed, 342 insertions(+), 7 deletions(-) create mode 100644 doc.ja/src/sgml/ref/pcp_log_rotate.sgml create mode 100644 doc/src/sgml/ref/pcp_log_rotate.sgml create mode 100755 src/test/regression/tests/038.pcp_commands/test.sh diff --git a/doc.ja/src/sgml/ref/allfiles.sgml b/doc.ja/src/sgml/ref/allfiles.sgml index 1af1c380d..69fbe1efe 100644 --- a/doc.ja/src/sgml/ref/allfiles.sgml +++ b/doc.ja/src/sgml/ref/allfiles.sgml @@ -18,6 +18,7 @@ Complete list of usable sgml source files in this directory. + diff --git a/doc.ja/src/sgml/ref/pcp_log_rotate.sgml b/doc.ja/src/sgml/ref/pcp_log_rotate.sgml new file mode 100644 index 000000000..f49c922bd --- /dev/null +++ b/doc.ja/src/sgml/ref/pcp_log_rotate.sgml @@ -0,0 +1,74 @@ + + + + + pcp_log_rotate + + + + pcp_log_rotate + 1 + PCP Command + + + + pcp_log_rotate + + Pgpool-IIのログファイルをローテーションします + + + + + pcp_log_rotate + options + + + + + 説明 + + pcp_log_rotate + Pgpool-IIのログファイルをローテーションします。 + + + + + オプション + + + + + + + + + コマンドの与える影響範囲を指定します。 + + +    サポートされているコマンドスコープは以下です。 + デフォルトは"local"です。 + + c, cluster : クラスタを構成するすべてのPgpool-IIのログファイルをローテーションします。 + l, local : ローカルPgpool-IIのログファイルをローテーションします。 + + + + + + + + + + を参照してください。 + + + + + + + + + diff --git a/doc.ja/src/sgml/reference.sgml b/doc.ja/src/sgml/reference.sgml index 33c48db6c..05e4d87b5 100644 --- a/doc.ja/src/sgml/reference.sgml +++ b/doc.ja/src/sgml/reference.sgml @@ -161,6 +161,7 @@ &pcpStopPgpool; &pcpReloadConfig; &pcpRecoveryNode; + &pcpLogRotate; diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml index aa55db096..69fbe1efe 100644 --- a/doc/src/sgml/ref/allfiles.sgml +++ b/doc/src/sgml/ref/allfiles.sgml @@ -17,7 +17,8 @@ Complete list of usable sgml source files in this directory. - + + diff --git a/doc/src/sgml/ref/pcp_log_rotate.sgml b/doc/src/sgml/ref/pcp_log_rotate.sgml new file mode 100644 index 000000000..be1ecbe7b --- /dev/null +++ b/doc/src/sgml/ref/pcp_log_rotate.sgml @@ -0,0 +1,73 @@ + + + + + pcp_log_rotate + + + + pcp_log_rotate + 1 + PCP Command + + + + pcp_log_rotate + + rotates the Pgpool-II's log file + + + + + pcp_log_rotate + options + + + + + Description + + pcp_log_rotate + rotates the Pgpool-II's log file. + + + + + Options + + + + + + + + + Specifies the breadth of a command's impact. + + + The supported command scopes are as follows (The default is "local"): + + c, cluster : rotates the Pgpool-II's log files of all Pgpool-II nodes part of the cluster + l, local : rotates the Pgpool-II's log file of local Pgpool-II node only + + + + + + + + + + See . + + + + + + + + + diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml index 51f2d893d..30be90bc5 100644 --- a/doc/src/sgml/reference.sgml +++ b/doc/src/sgml/reference.sgml @@ -110,6 +110,7 @@ &pcpStopPgpool; &pcpReloadConfig; &pcpRecoveryNode; + &pcpLogRotate; diff --git a/src/include/pcp/libpcp_ext.h b/src/include/pcp/libpcp_ext.h index 3c9d1d6bb..32dfcb003 100644 --- a/src/include/pcp/libpcp_ext.h +++ b/src/include/pcp/libpcp_ext.h @@ -381,6 +381,7 @@ extern PCPResultInfo * pcp_health_check_stats(PCPConnInfo * pcpCon, int nid); extern PCPResultInfo * pcp_process_count(PCPConnInfo * pcpConn); extern PCPResultInfo * pcp_process_info(PCPConnInfo * pcpConn, int pid); extern PCPResultInfo * pcp_reload_config(PCPConnInfo * pcpConn,char command_scope); +extern PCPResultInfo * pcp_log_rotate(PCPConnInfo * pcpConn,char command_scope); extern PCPResultInfo * pcp_detach_node(PCPConnInfo * pcpConn, int nid); extern PCPResultInfo * pcp_detach_node_gracefully(PCPConnInfo * pcpConn, int nid); diff --git a/src/include/pool.h b/src/include/pool.h index 21513f1d3..8fa429fa7 100644 --- a/src/include/pool.h +++ b/src/include/pool.h @@ -619,7 +619,7 @@ extern void initialize_shared_memory_main_segment(size_t size); extern void * pool_shared_memory_segment_get_chunk(size_t size); -/* pool_main.c*/ +/* pgpool_main.c*/ extern BackendInfo * pool_get_node_info(int node_number); extern int pool_get_node_count(void); extern int *pool_get_process_list(int *array_size); @@ -636,6 +636,7 @@ extern void pool_set_backend_status_changed_time(int backend_id); extern int get_next_main_node(void); extern bool pool_acquire_follow_primary_lock(bool block, bool remote_reques); extern void pool_release_follow_primary_lock(bool remote_reques); +extern void pool_signal_logrotate(void); /* strlcpy.c */ #ifndef HAVE_STRLCPY diff --git a/src/include/watchdog/wd_ipc_defines.h b/src/include/watchdog/wd_ipc_defines.h index 16ff5a415..654f48715 100644 --- a/src/include/watchdog/wd_ipc_defines.h +++ b/src/include/watchdog/wd_ipc_defines.h @@ -75,6 +75,7 @@ typedef enum WDValueDataType #define WD_COMMAND_REELECT_LEADER "REELECT_LEADER" #define WD_COMMAND_SHUTDOWN_CLUSTER "SHUTDOWN_CLUSTER" #define WD_COMMAND_RELOAD_CONFIG_CLUSTER "RELOAD_CONFIG_CLUSTER" +#define WD_COMMAND_LOGROTATE_CLUSTER "LOGROTATE_CLUSTER" #define WD_COMMAND_LOCK_ON_STANDBY "APPLY_LOCK_ON_STANDBY" diff --git a/src/libs/pcp/pcp.c b/src/libs/pcp/pcp.c index 0a2b74a88..8b4b569d4 100644 --- a/src/libs/pcp/pcp.c +++ b/src/libs/pcp/pcp.c @@ -476,6 +476,13 @@ static PCPResultInfo * process_pcp_response(PCPConnInfo * pcpConn, char sentMsg) process_command_complete_response(pcpConn, buf, rsize); break; + case 'v': /* pcp_log_rotate */ + if (sentMsg != 'V') + setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE); + else + process_command_complete_response(pcpConn, buf, rsize); + break; + case 'w': if (sentMsg != 'W') setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE); @@ -926,6 +933,31 @@ pcp_reload_config(PCPConnInfo * pcpConn,char command_scope) return process_pcp_response(pcpConn, 'Z'); } +PCPResultInfo * +pcp_log_rotate(PCPConnInfo * pcpConn,char command_scope) +{ + int wsize; +/* + * pcp packet format for pcp_log_rotate + * v[size][command_scope] + */ + if (PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK) + { + pcp_internal_error(pcpConn, "invalid PCP connection"); + return NULL; + } + + pcp_write(pcpConn->pcpConn, "V", 1); + wsize = htonl(sizeof(int) + sizeof(char)); + pcp_write(pcpConn->pcpConn, &wsize, sizeof(int)); + pcp_write(pcpConn->pcpConn, &command_scope, sizeof(char)); + if (PCPFlush(pcpConn) < 0) + return NULL; + if (pcpConn->Pfdebug) + fprintf(pcpConn->Pfdebug, "DEBUG: send: tos=\"Z\", len=%d\n", ntohl(wsize)); + + return process_pcp_response(pcpConn, 'V'); +} /* * Process health check response from PCP server. diff --git a/src/main/pgpool_logger.c b/src/main/pgpool_logger.c index 68621b30a..206086732 100644 --- a/src/main/pgpool_logger.c +++ b/src/main/pgpool_logger.c @@ -345,7 +345,7 @@ SysLoggerMain(int argc, char *argv[]) { /* * Force rotation when both values are zero. It means the request - * was sent by pg_rotate_logfile() or "pg_ctl logrotate". + * was sent by pcp_log_rotate. */ if (!time_based_rotation && size_rotation_for == 0) size_rotation_for = LOG_DESTINATION_STDERR | LOG_DESTINATION_CSVLOG; diff --git a/src/main/pgpool_main.c b/src/main/pgpool_main.c index 020863727..20b89b150 100644 --- a/src/main/pgpool_main.c +++ b/src/main/pgpool_main.c @@ -4097,6 +4097,37 @@ pool_release_follow_primary_lock(bool remote_request) } +/* + * Sending log rotation signal to logger process. + */ +void +pool_signal_logrotate(void) +{ + if (!pool_config->logging_collector) + { + ereport(ERROR, + (errmsg("process log rotation request failed"), + errdetail("logging_collector is disabled"))); + } + + if (pgpool_logger_pid != 0) + { + ereport(DEBUG1, + (errmsg("sending SIGUSR1 to logger process with PID:%d to rotate log file", pgpool_logger_pid))); + + if (kill(pgpool_logger_pid, SIGUSR1) != 0) + ereport(ERROR, + (errmsg("process log rotation request failed"), + errdetail("failed to send SIGUSR1 to logger process with PID:%d", pgpool_logger_pid))); + } + else + { + ereport(ERROR, + (errmsg("process log rotation request failed"), + errdetail("logger process PID:%d is not valid", pgpool_logger_pid))); + } +} + /* * ------------------------------------------------------------------------- * Subroutines for failover() begin diff --git a/src/pcp_con/pcp_worker.c b/src/pcp_con/pcp_worker.c index 482941215..02f76eecb 100644 --- a/src/pcp_con/pcp_worker.c +++ b/src/pcp_con/pcp_worker.c @@ -84,6 +84,7 @@ static void inform_watchdog_info(PCP_CONNECTION * frontend, char *buf); static void inform_node_info(PCP_CONNECTION * frontend, char *buf); static void inform_node_count(PCP_CONNECTION * frontend); static void process_reload_config(PCP_CONNECTION * frontend,char scope); +static void process_log_rotate(PCP_CONNECTION * frontend,char scope); static void inform_health_check_stats(PCP_CONNECTION *frontend, char *buf); static void process_detach_node(PCP_CONNECTION * frontend, char *buf, char tos); static void process_attach_node(PCP_CONNECTION * frontend, char *buf); @@ -329,6 +330,11 @@ pcp_process_command(char tos, char *buf, int buf_len) process_reload_config(pcp_frontend, buf[0]); break; + case 'V': /* log rotate */ + set_ps_display("PCP: processing log rotation request", false); + process_log_rotate(pcp_frontend, buf[0]); + break; + case 'J': /* promote node */ case 'j': /* promote node gracefully */ set_ps_display("PCP: processing promote node request", false); @@ -1074,6 +1080,7 @@ inform_node_count(PCP_CONNECTION * frontend) (errmsg("PCP: informing node count"), errdetail("%d node(s) found", node_count))); } + static void process_reload_config(PCP_CONNECTION * frontend, char scope) { @@ -1105,6 +1112,32 @@ process_reload_config(PCP_CONNECTION * frontend, char scope) do_pcp_flush(frontend); } +static void +process_log_rotate(PCP_CONNECTION * frontend, char scope) +{ + char code[] = "CommandComplete"; + int wsize; + + if (scope == 'c' && pool_config->use_watchdog) + { + ereport(LOG, + (errmsg("PCP: sending command to watchdog to logrotate cluster"))); + + if (wd_execute_cluster_command(WD_COMMAND_LOGROTATE_CLUSTER, NULL) != COMMAND_OK) + ereport(ERROR, + (errmsg("PCP: error while processing log rotation request for cluster"), + errdetail("failed to propagate log rotation command through watchdog"))); + } + + pool_signal_logrotate(); + + pcp_write(frontend, "v", 1); + wsize = htonl(sizeof(code) + sizeof(int)); + pcp_write(frontend, &wsize, sizeof(int)); + pcp_write(frontend, code, sizeof(code)); + do_pcp_flush(frontend); +} + static void process_detach_node(PCP_CONNECTION * frontend, char *buf, char tos) { diff --git a/src/test/regression/tests/038.pcp_commands/test.sh b/src/test/regression/tests/038.pcp_commands/test.sh new file mode 100755 index 000000000..5b6e7b18c --- /dev/null +++ b/src/test/regression/tests/038.pcp_commands/test.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------- +# Test script for pcp commands. +# +source $TESTLIBS +TESTDIR=testdir +PSQL=$PGBIN/psql + +rm -fr $TESTDIR +mkdir $TESTDIR +cd $TESTDIR + +# create test environment. +echo -n "creating test environment..." +$PGPOOL_SETUP -m s -n 2 || exit 1 +echo "done." + +source ./bashrc.ports +export PGPORT=$PGPOOL_PORT + +echo "=== test1: pcp_log_rotate" + +BASEDIR=`pwd` +echo "logging_collector = on" >> etc/pgpool.conf +echo "log_directory = '$BASEDIR/log'" >> etc/pgpool.conf +echo "log_filename = 'pgpool.log'" >> etc/pgpool.conf + +./startall +wait_for_pgpool_startup + +mv log/pgpool.log log/pgpool.log.1 + +sleep 1 +$PSQL -h localhost -c "SELECT 1" test > /dev/null 2>&1 + +grep "SELECT 1" log/pgpool.log.1 > /dev/null 2>&1 +if [ $? != 0 ];then + r1=fail + echo "test1 failed before running pcp_log_rotate." +else + $PGPOOL_INSTALL_DIR/bin/pcp_log_rotate -h localhost -w -p $PCP_PORT + $PSQL -h localhost -c "SELECT 1" test > /dev/null 2>&1 + + sleep 1 + grep "SELECT 1" log/pgpool.log > /dev/null 2>&1 + if [ $? = 0 ];then + r1=ok + echo "test1 ok" + else + echo "test1 failed." + fi +fi + +./shutdownall + +if [ $r1 = ok ]; then + echo "all test succeeded" + exit 0 +else + echo "some tests failed" + echo "test1: $r1" + exit 1 +fi diff --git a/src/tools/pcp/.gitignore b/src/tools/pcp/.gitignore index ec13595f3..ff2c7cce4 100644 --- a/src/tools/pcp/.gitignore +++ b/src/tools/pcp/.gitignore @@ -1,6 +1,7 @@ pcp_attach_node pcp_detach_node pcp_health_check_stats +pcp_log_rotate pcp_node_count pcp_node_info pcp_pool_status diff --git a/src/tools/pcp/Makefile.am b/src/tools/pcp/Makefile.am index a0942f489..53152f34c 100644 --- a/src/tools/pcp/Makefile.am +++ b/src/tools/pcp/Makefile.am @@ -12,8 +12,9 @@ bin_PROGRAMS = pcp_stop_pgpool \ pcp_recovery_node \ pcp_promote_node \ pcp_pool_status \ - pcp_watchdog_info\ - pcp_reload_config + pcp_watchdog_info \ + pcp_reload_config \ + pcp_log_rotate client_sources = pcp_frontend_client.c ../fe_memutils.c ../../utils/sprompt.c ../../utils/pool_path.c @@ -43,4 +44,5 @@ pcp_watchdog_info_SOURCES = $(client_sources) pcp_watchdog_info_LDADD = $(libs_dir)/pcp/libpcp.la pcp_reload_config_SOURCES = $(client_sources) pcp_reload_config_LDADD = $(libs_dir)/pcp/libpcp.la - +pcp_log_rotate_SOURCES = $(client_sources) +pcp_log_rotate_LDADD = $(libs_dir)/pcp/libpcp.la diff --git a/src/tools/pcp/pcp_frontend_client.c b/src/tools/pcp/pcp_frontend_client.c index 576bd8ce1..930e2a811 100644 --- a/src/tools/pcp/pcp_frontend_client.c +++ b/src/tools/pcp/pcp_frontend_client.c @@ -69,6 +69,7 @@ typedef enum PCP_STOP_PGPOOL, PCP_WATCHDOG_INFO, PCP_RELOAD_CONFIG, + PCP_LOG_ROTATE, UNKNOWN, } PCP_UTILITIES; @@ -95,6 +96,7 @@ struct AppTypes AllAppTypes[] = {"pcp_stop_pgpool", PCP_STOP_PGPOOL, "m:h:p:U:s:wWvda", "terminate pgpool-II"}, {"pcp_watchdog_info", PCP_WATCHDOG_INFO, "n:h:p:U:wWvd", "display a pgpool-II watchdog's information"}, {"pcp_reload_config",PCP_RELOAD_CONFIG,"h:p:U:s:wWvd", "reload a pgpool-II config file"}, + {"pcp_log_rotate",PCP_LOG_ROTATE,"h:p:U:s:wWvd", "rotate the Pgpool-II's log file"}, {NULL, UNKNOWN, NULL, NULL}, }; struct AppTypes *current_app_type; @@ -451,6 +453,11 @@ main(int argc, char **argv) pcpResInfo = pcp_reload_config(pcpConn,command_scope); } + else if (current_app_type->app_type == PCP_LOG_ROTATE) + { + pcpResInfo = pcp_log_rotate(pcpConn,command_scope); + } + else { /* should never happen */ @@ -861,7 +868,8 @@ static inline bool app_support_cluster_mode(void) { return (current_app_type->app_type == PCP_STOP_PGPOOL || - current_app_type->app_type == PCP_RELOAD_CONFIG); + current_app_type->app_type == PCP_RELOAD_CONFIG || + current_app_type->app_type == PCP_LOG_ROTATE); } static void diff --git a/src/watchdog/watchdog.c b/src/watchdog/watchdog.c index 561d9a60f..41b53d26d 100644 --- a/src/watchdog/watchdog.c +++ b/src/watchdog/watchdog.c @@ -2111,6 +2111,11 @@ process_IPC_execute_cluster_command(WDCommandData * ipcCommand) ereport(LOG, (errmsg("Watchdog has received reload config cluster command from IPC channel"))); } + else if (strcasecmp(WD_COMMAND_LOGROTATE_CLUSTER, clusterCommand) == 0) + { + ereport(LOG, + (errmsg("Watchdog has received log rotation cluster command from IPC channel"))); + } else if (strcasecmp(WD_COMMAND_LOCK_ON_STANDBY, clusterCommand) == 0) { ereport(LOG, @@ -4115,6 +4120,12 @@ wd_execute_cluster_command_processor(WatchdogNode * wdNode, WDPacketData * pkt) (errmsg("processing reload config command from remote node \"%s\"", wdNode->nodeName))); pool_signal_parent(SIGHUP); } + else if (strcasecmp(WD_COMMAND_LOGROTATE_CLUSTER, clusterCommand) == 0) + { + ereport(LOG, + (errmsg("processing log rotation command from remote node \"%s\"", wdNode->nodeName))); + pool_signal_logrotate(); + } else if (strcasecmp(WD_COMMAND_LOCK_ON_STANDBY, clusterCommand) == 0) { int lock_type = -1; -- 2.39.5