On 04/16/2018 05:54 AM, Kyotaro HORIGUCHI wrote:
We can provide a new command "pg_ctl logrotate" to hide the
details. (It cannot be executed by root, though.)
I like this approach.
I looked at the patch and changed some things:
- cleaned up the error messages
- moved checkLogrotateSignal to postmaster.c, since it has no reason to
be in xlog.c
- added some documentation I had from my older patch
Other than that, it looks good to me. The updated patch is attached.
--
Alexander Kuzmenkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index 4a68ec3..c0bf632 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -960,6 +960,22 @@ pg_ctl start | rotatelogs /var/log/pgsql_log 86400
</para>
<para>
+ An external log rotation tool, such as <application>logrotate</application>, can also
+ be used to collect log files produced by the built-in logging collector. In this
+ configuration, the location and names of the log files are determined by logging
+ collector, and <application>logrotate</application> periodically archives these files.
+ There must be some way for <application>logrotate</application> to inform the application
+ that the log file it is using is going to be archived, and that it must direct further
+ output to a new file. This is commonly done with a <literal>postrotate</literal> script
+ that sends a <literal>SIGHUP</literal> signal to the application, which then reopens the
+ log file. In <productname>PostgreSQL</productname>, this is achieved using a
+ <literal>logrotate</literal> command of <application>pg_ctl</application>. When the
+ server receives this command, it switches to the new log files according to its
+ configuration (see <xref linkend="runtime-config-logging-where"/>). If it is configured
+ to use a static file name, it will just reopen the file.
+ </para>
+
+ <para>
On many systems, however, <application>syslog</application> is not very reliable,
particularly with large log messages; it might truncate or drop messages
just when you need them the most. Also, on <productname>Linux</productname>,
diff --git a/doc/src/sgml/ref/pg_ctl-ref.sgml b/doc/src/sgml/ref/pg_ctl-ref.sgml
index 0816bc1..acd1d91 100644
--- a/doc/src/sgml/ref/pg_ctl-ref.sgml
+++ b/doc/src/sgml/ref/pg_ctl-ref.sgml
@@ -102,6 +102,12 @@ PostgreSQL documentation
<arg choice="plain"><option>kill</option></arg>
<arg choice="plain"><replaceable>signal_name</replaceable></arg>
<arg choice="plain"><replaceable>process_id</replaceable></arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>pg_ctl</command>
+ <arg choice="plain"><option>logrotate</option></arg>
+ <arg choice="opt"><option>-D</option> <replaceable>datadir</replaceable></arg>
</cmdsynopsis>
<para>On Microsoft Windows, also:</para>
@@ -234,6 +240,12 @@ PostgreSQL documentation
</para>
<para>
+ <option>logrotate</option> mode commands the server to rotate its log file.
+ For the discussion of how to use this with external log rotation tools, see
+ <xref linkend="logfile-maintenance"/>.
+ </para>
+
+ <para>
<option>register</option> mode registers the <productname>PostgreSQL</productname>
server as a system service on <productname>Microsoft Windows</productname>.
The <option>-S</option> option allows selection of service start type,
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index d948369..4549f2e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -385,6 +385,9 @@ static bool LoadedSSL = false;
static DNSServiceRef bonjour_sdref = NULL;
#endif
+/* Log rotation signal file path, relative to $PGDATA */
+#define LOGROTATE_SIGNAL_FILE "logrotate"
+
/*
* postmaster.c - function prototypes
*/
@@ -398,6 +401,7 @@ static void reset_shared(int port);
static void SIGHUP_handler(SIGNAL_ARGS);
static void pmdie(SIGNAL_ARGS);
static void reaper(SIGNAL_ARGS);
+static bool checkLogrotateSignal(void);
static void sigusr1_handler(SIGNAL_ARGS);
static void startup_die(SIGNAL_ARGS);
static void dummy_handler(SIGNAL_ARGS);
@@ -4995,6 +4999,24 @@ ExitPostmaster(int status)
}
/*
+ * Check to see if a log rotation request has arrived. Should be
+ * called by postmaster after receiving SIGUSR1.
+ */
+static bool
+checkLogrotateSignal(void)
+{
+ struct stat stat_buf;
+
+ if (stat(LOGROTATE_SIGNAL_FILE, &stat_buf) == 0)
+ {
+ unlink(LOGROTATE_SIGNAL_FILE);
+ return true;
+ }
+
+ return false;
+}
+
+/*
* sigusr1_handler - handle signal conditions from child processes
*/
static void
@@ -5092,7 +5114,8 @@ sigusr1_handler(SIGNAL_ARGS)
signal_child(PgArchPID, SIGUSR1);
}
- if (CheckPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE) &&
+ if ((checkLogrotateSignal() ||
+ CheckPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE)) &&
SysLoggerPID != 0)
{
/* Tell syslogger to rotate logfile */
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 143021d..5abafb2 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -59,6 +59,7 @@ typedef enum
STOP_COMMAND,
RESTART_COMMAND,
RELOAD_COMMAND,
+ LOGROTATE_COMMAND,
STATUS_COMMAND,
PROMOTE_COMMAND,
KILL_COMMAND,
@@ -100,6 +101,7 @@ static char version_file[MAXPGPATH];
static char pid_file[MAXPGPATH];
static char backup_file[MAXPGPATH];
static char promote_file[MAXPGPATH];
+static char logrotate_file[MAXPGPATH];
#ifdef WIN32
static DWORD pgctl_start_type = SERVICE_AUTO_START;
@@ -125,6 +127,7 @@ static void do_restart(void);
static void do_reload(void);
static void do_status(void);
static void do_promote(void);
+static void do_logrotate(void);
static void do_kill(pgpid_t pid);
static void print_msg(const char *msg);
static void adjust_data_dir(void);
@@ -1171,6 +1174,62 @@ do_promote(void)
print_msg(_("server promoting\n"));
}
+/*
+ * log rotate
+ */
+
+static void
+do_logrotate(void)
+{
+ FILE *logrotatefile;
+ pgpid_t pid;
+
+ pid = get_pgpid(false);
+
+ if (pid == 0) /* no pid file */
+ {
+ write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
+ write_stderr(_("Is server running?\n"));
+ exit(1);
+ }
+ else if (pid < 0) /* standalone backend, not postmaster */
+ {
+ pid = -pid;
+ write_stderr(_("%s: cannot rotate log file; "
+ "single-user server is running (PID: %ld)\n"),
+ progname, pid);
+ exit(1);
+ }
+
+ snprintf(logrotate_file, MAXPGPATH, "%s/logrotate", pg_data);
+
+ if ((logrotatefile = fopen(logrotate_file, "w")) == NULL)
+ {
+ write_stderr(_("%s: could not create log rotation signal file \"%s\": %s\n"),
+ progname, logrotate_file, strerror(errno));
+ exit(1);
+ }
+ if (fclose(logrotatefile))
+ {
+ write_stderr(_("%s: could not write log rotation signal file \"%s\": %s\n"),
+ progname, logrotate_file, strerror(errno));
+ exit(1);
+ }
+
+ sig = SIGUSR1;
+ if (kill((pid_t) pid, sig) != 0)
+ {
+ write_stderr(_("%s: could not send log rotation signal (PID: %ld): %s\n"),
+ progname, pid, strerror(errno));
+ if (unlink(logrotate_file) != 0)
+ write_stderr(_("%s: could not remove log rotation signal file \"%s\": %s\n"),
+ progname, logrotate_file, strerror(errno));
+ exit(1);
+ }
+
+ print_msg(_("commanded to rotate log file\n"));
+}
+
/*
* utility routines
@@ -2332,6 +2391,8 @@ main(int argc, char **argv)
ctl_command = RESTART_COMMAND;
else if (strcmp(argv[optind], "reload") == 0)
ctl_command = RELOAD_COMMAND;
+ else if (strcmp(argv[optind], "logrotate") == 0)
+ ctl_command = LOGROTATE_COMMAND;
else if (strcmp(argv[optind], "status") == 0)
ctl_command = STATUS_COMMAND;
else if (strcmp(argv[optind], "promote") == 0)
@@ -2442,6 +2503,9 @@ main(int argc, char **argv)
case PROMOTE_COMMAND:
do_promote();
break;
+ case LOGROTATE_COMMAND:
+ do_logrotate();
+ break;
case KILL_COMMAND:
do_kill(killproc);
break;
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 421ba6d..31d1fb4 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -280,6 +280,7 @@ extern void GetNextXidAndEpoch(TransactionId *xid, uint32 *epoch);
extern void RemovePromoteSignalFiles(void);
extern bool CheckPromoteSignal(void);
+extern bool CheckLogrotateSignal(void);
extern void WakeupRecovery(void);
extern void SetWalWriterSleeping(bool sleeping);