diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/system_views.sql | 2 | ||||
-rw-r--r-- | src/backend/postmaster/postmaster.c | 7 | ||||
-rw-r--r-- | src/backend/postmaster/syslogger.c | 79 | ||||
-rw-r--r-- | src/backend/replication/basebackup.c | 4 | ||||
-rw-r--r-- | src/backend/utils/adt/misc.c | 103 |
5 files changed, 195 insertions, 0 deletions
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 38be9cf1a0c..ada542c530b 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1091,6 +1091,8 @@ REVOKE EXECUTE ON FUNCTION pg_wal_replay_pause() FROM public; REVOKE EXECUTE ON FUNCTION pg_wal_replay_resume() FROM public; REVOKE EXECUTE ON FUNCTION pg_rotate_logfile() FROM public; REVOKE EXECUTE ON FUNCTION pg_reload_conf() FROM public; +REVOKE EXECUTE ON FUNCTION pg_current_logfile() FROM public; +REVOKE EXECUTE ON FUNCTION pg_current_logfile(text) FROM public; REVOKE EXECUTE ON FUNCTION pg_stat_reset() FROM public; REVOKE EXECUTE ON FUNCTION pg_stat_reset_shared(text) FROM public; diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 2cf17ac42e0..68313424ee2 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -1232,6 +1232,13 @@ PostmasterMain(int argc, char *argv[]) */ RemovePromoteSignalFiles(); + /* Remove any outdated file holding the current log filenames. */ + if (unlink(LOG_METAINFO_DATAFILE) < 0 && errno != ENOENT) + ereport(LOG, + (errcode_for_file_access(), + errmsg("could not remove file \"%s\": %m", + LOG_METAINFO_DATAFILE))); + /* * If enabled, start up syslogger collection subprocess */ diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index 13a03014ebb..aaefdaebad9 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -146,6 +146,7 @@ static char *logfile_getname(pg_time_t timestamp, const char *suffix); static void set_next_rotation_time(void); static void sigHupHandler(SIGNAL_ARGS); static void sigUsr1Handler(SIGNAL_ARGS); +static void update_metainfo_datafile(void); /* @@ -282,6 +283,7 @@ SysLoggerMain(int argc, char *argv[]) currentLogRotationAge = Log_RotationAge; /* set next planned rotation time */ set_next_rotation_time(); + update_metainfo_datafile(); /* main worker loop */ for (;;) @@ -348,6 +350,13 @@ SysLoggerMain(int argc, char *argv[]) rotation_disabled = false; rotation_requested = true; } + + /* + * Force rewriting last log filename when reloading configuration. + * Even if rotation_requested is false, log_destination may have + * been changed and we don't want to wait the next file rotation. + */ + update_metainfo_datafile(); } if (Log_RotationAge > 0 && !rotation_disabled) @@ -1098,6 +1107,8 @@ open_csvlogfile(void) pfree(last_csv_file_name); last_csv_file_name = filename; + + update_metainfo_datafile(); } /* @@ -1268,6 +1279,8 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for) if (csvfilename) pfree(csvfilename); + update_metainfo_datafile(); + set_next_rotation_time(); } @@ -1337,6 +1350,72 @@ set_next_rotation_time(void) next_rotation_time = now; } +/* + * Store the name of the file(s) where the log collector, when enabled, writes + * log messages. Useful for finding the name(s) of the current log file(s) + * when there is time-based logfile rotation. Filenames are stored in a + * temporary file and which is renamed into the final destination for + * atomicity. + */ +static void +update_metainfo_datafile(void) +{ + FILE *fh; + + if (!(Log_destination & LOG_DESTINATION_STDERR) && + !(Log_destination & LOG_DESTINATION_CSVLOG)) + { + if (unlink(LOG_METAINFO_DATAFILE) < 0 && errno != ENOENT) + ereport(LOG, + (errcode_for_file_access(), + errmsg("could not remove file \"%s\": %m", + LOG_METAINFO_DATAFILE))); + return; + } + + if ((fh = logfile_open(LOG_METAINFO_DATAFILE_TMP, "w", true)) == NULL) + { + ereport(LOG, + (errcode_for_file_access(), + errmsg("could not open file \"%s\": %m", + LOG_METAINFO_DATAFILE_TMP))); + return; + } + + if (last_file_name && (Log_destination & LOG_DESTINATION_STDERR)) + { + if (fprintf(fh, "stderr %s\n", last_file_name) < 0) + { + ereport(LOG, + (errcode_for_file_access(), + errmsg("could not write file \"%s\": %m", + LOG_METAINFO_DATAFILE_TMP))); + fclose(fh); + return; + } + } + + if (last_csv_file_name && (Log_destination & LOG_DESTINATION_CSVLOG)) + { + if (fprintf(fh, "csvlog %s\n", last_csv_file_name) < 0) + { + ereport(LOG, + (errcode_for_file_access(), + errmsg("could not write file \"%s\": %m", + LOG_METAINFO_DATAFILE_TMP))); + fclose(fh); + return; + } + } + fclose(fh); + + if (rename(LOG_METAINFO_DATAFILE_TMP, LOG_METAINFO_DATAFILE) != 0) + ereport(LOG, + (errcode_for_file_access(), + errmsg("could not rename file \"%s\" to \"%s\": %m", + LOG_METAINFO_DATAFILE_TMP, LOG_METAINFO_DATAFILE))); +} + /* -------------------------------- * signal handler routines * -------------------------------- diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index 7414048f4eb..e3a7ad5e9ab 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -26,6 +26,7 @@ #include "nodes/pg_list.h" #include "pgtar.h" #include "pgstat.h" +#include "postmaster/syslogger.h" #include "replication/basebackup.h" #include "replication/walsender.h" #include "replication/walsender_private.h" @@ -147,6 +148,9 @@ static const char *excludeFiles[] = /* Skip auto conf temporary file. */ PG_AUTOCONF_FILENAME ".tmp", + /* Skip current log file temporary file */ + LOG_METAINFO_DATAFILE_TMP, + /* * If there's a backup_label or tablespace_map file, it belongs to a * backup started by the user with pg_start_backup(). It is *not* correct diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 8f7c1f81fd4..ff6a25d2b60 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -885,3 +885,106 @@ parse_ident(PG_FUNCTION_ARGS) PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext)); } + +/* + * pg_current_logfile + * + * Report current log file used by log collector by scanning current_logfiles. + */ +Datum +pg_current_logfile(PG_FUNCTION_ARGS) +{ + FILE *fd; + char lbuffer[MAXPGPATH]; + char *logfmt; + char *log_filepath; + char *log_format = lbuffer; + char *nlpos; + + /* The log format parameter is optional */ + if (PG_NARGS() == 0 || PG_ARGISNULL(0)) + logfmt = NULL; + else + { + logfmt = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + if (strcmp(logfmt, "stderr") != 0 && strcmp(logfmt, "csvlog") != 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("log format \"%s\" is not supported", logfmt), + errhint("The supported log formats are \"stderr\" and \"csvlog\"."))); + } + + fd = AllocateFile(LOG_METAINFO_DATAFILE, "r"); + if (fd == NULL) + { + if (errno != ENOENT) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not read file \"%s\": %m", + LOG_METAINFO_DATAFILE))); + PG_RETURN_NULL(); + } + + /* + * Read the file to gather current log filename(s) registered by the + * syslogger. + */ + while (fgets(lbuffer, sizeof(lbuffer), fd) != NULL) + { + /* + * Extract log format and log file path from the line; lbuffer == + * log_format, they share storage. + */ + log_filepath = strchr(lbuffer, ' '); + if (log_filepath == NULL) + { + /* + * No space found, file content is corrupted. Return NULL to the + * caller and inform him on the situation. + */ + elog(ERROR, + "missing space character in \"%s\"", LOG_METAINFO_DATAFILE); + break; + } + + *log_filepath = '\0'; + log_filepath++; + nlpos = strchr(log_filepath, '\n'); + if (nlpos == NULL) + { + /* + * No newlinei found, file content is corrupted. Return NULL to + * the caller and inform him on the situation. + */ + elog(ERROR, + "missing newline character in \"%s\"", LOG_METAINFO_DATAFILE); + break; + } + *nlpos = '\0'; + + if (logfmt == NULL || strcmp(logfmt, log_format) == 0) + { + FreeFile(fd); + PG_RETURN_TEXT_P(cstring_to_text(log_filepath)); + } + } + + /* Close the current log filename file. */ + FreeFile(fd); + + PG_RETURN_NULL(); +} + +/* + * Report current log file used by log collector (1 argument version) + * + * note: this wrapper is necessary to pass the sanity check in opr_sanity, + * which checks that all built-in functions that share the implementing C + * function take the same number of arguments + */ +Datum +pg_current_logfile_1arg(PG_FUNCTION_ARGS) +{ + return pg_current_logfile(fcinfo); +} |