diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 2e64cc4..d577bac 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -15443,6 +15443,19 @@ SELECT * FROM pg_ls_dir('.') WITH ORDINALITY AS t(ls,n);
+ pg_current_logfile()
+ text
+ primary log file name in use by the logging collector
+
+
+
+ pg_current_logfile(text>)
+ text
+ log file name, of log in the requested format, in use by the
+ logging collector
+
+
+
pg_my_temp_schema()
oid
OID of session's temporary schema, or 0 if none
@@ -15660,6 +15673,29 @@ SET search_path TO schema> , schema>, ..
the time when the postmaster process re-read the configuration files.)
+
+ pg_current_logile
+
+
+
+ pg_current_logfile returns, as text,
+ the path of either the csv or stderr log file currently in use by the
+ logging collector. This is a path including the
+ directory and the log file name.
+ Log collection must be active or the return value
+ is NULL. When multiple logfiles exist, each in a
+ different format, pg_current_logfile called
+ without arguments returns the path of the file having the first format
+ found in the ordered
+ list: stderr>, csvlog>.
+ NULL is returned when no log file has any of these
+ formats. To request a specific file format supply,
+ as text, either csvlog>
+ or stderr> as the value of the optional parameter. The
+ return value is NULL when the log format requested
+ is not a configured .
+
+
pg_my_temp_schema
diff --git a/doc/src/sgml/storage.sgml b/doc/src/sgml/storage.sgml
index fddb69b..5bea196 100644
--- a/doc/src/sgml/storage.sgml
+++ b/doc/src/sgml/storage.sgml
@@ -61,6 +61,18 @@ Item
+ current_logfiles>
+ A file recording the current log file(s) used by the syslogger and
+ its log format, stderr> or csvlog>. Each line
+ of the file is a space separated list of two elements: the log format and
+ the full path to the log file including the value
+ of . The log format must be present
+ in to be listed in the file. This file
+ is present only when is
+ activated.
+
+
+
global>
Subdirectory containing cluster-wide tables, such as
pg_database>
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index fd62d66..83afc34 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 logfile_writename(char *filename, char *csvfilename);
/*
@@ -348,6 +349,13 @@ SysLoggerMain(int argc, char *argv[])
rotation_disabled = false;
rotation_requested = true;
}
+
+ /*
+ * Force rewriting last log filename when reloading configuration,
+ * log_destination and logging_collector may have been changed. Do
+ * it right now to not wait for the next file rotation.
+ */
+ logfile_writename(last_file_name, last_csv_file_name);
}
if (Log_RotationAge > 0 && !rotation_disabled)
@@ -513,8 +521,13 @@ SysLogger_Start(void)
pid_t sysloggerPid;
char *filename;
- if (!Logging_collector)
+ if (!Logging_collector) {
+ /* Logging collector is not enabled. We don't know where messages are
+ * logged. Remove outdated file holding the current log filenames.
+ */
+ unlink(CURRENT_LOG_FILENAME);
return 0;
+ }
/*
* If first time through, create the pipe which will receive stderr
@@ -574,6 +587,8 @@ SysLogger_Start(void)
syslogFile = logfile_open(filename, "a", false);
+ logfile_writename(filename, NULL);
+
pfree(filename);
#ifdef EXEC_BACKEND
@@ -1098,6 +1113,8 @@ open_csvlogfile(void)
pfree(last_csv_file_name);
last_csv_file_name = filename;
+
+ logfile_writename(last_file_name, last_csv_file_name);
}
/*
@@ -1209,6 +1226,8 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
return;
}
+ logfile_writename(filename, csvfilename);
+
fclose(syslogFile);
syslogFile = fh;
@@ -1220,7 +1239,6 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
}
/* Same as above, but for csv file. */
-
if (csvlogFile != NULL &&
(time_based_rotation || (size_rotation_for & LOG_DESTINATION_CSVLOG)))
{
@@ -1253,6 +1271,8 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
return;
}
+ logfile_writename(last_file_name, csvfilename);
+
fclose(csvlogFile);
csvlogFile = fh;
@@ -1365,3 +1385,60 @@ sigUsr1Handler(SIGNAL_ARGS)
errno = save_errno;
}
+
+/*
+ * 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 renamed into the final destination for atomicity.
+ */
+static void
+logfile_writename(char *filename, char *csvfilename)
+{
+ FILE *fh;
+ char tempfn[MAXPGPATH];
+ char logpathfilename[MAXPGPATH];
+
+ snprintf(tempfn, sizeof(tempfn), "%s",
+ CURRENT_LOG_FILENAME);
+ strcat(tempfn, ".tmp");
+ snprintf(logpathfilename, sizeof(logpathfilename), "%s",
+ CURRENT_LOG_FILENAME);
+ if ((fh = logfile_open(tempfn, "w", true) ) == NULL)
+ {
+ return;
+ }
+ if (filename && (Log_destination & LOG_DESTINATION_STDERR)) {
+ if (fprintf(fh, "stderr %s\n", filename) < 0)
+ {
+ ereport(LOG,
+ (errcode_for_file_access(),
+ errmsg("could not write log file \"%s\": %m",
+ tempfn)));
+ fclose(fh);
+ return;
+ }
+ }
+
+ if (csvfilename && (Log_destination & LOG_DESTINATION_CSVLOG)) {
+ if (fprintf(fh, "csvlog %s\n", csvfilename) < 0)
+ {
+ ereport(LOG,
+ (errcode_for_file_access(),
+ errmsg("could not write log file \"%s\": %m",
+ tempfn)));
+ fclose(fh);
+ return;
+ }
+ }
+ fclose(fh);
+
+ if (rename(tempfn, logpathfilename) != 0)
+ {
+ ereport(LOG,
+ (errcode_for_file_access(),
+ errmsg("could not rename file \"%s\": %m",
+ tempfn)));
+ return;
+ }
+}
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 0da051a..06acdb2 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include "access/sysattr.h"
#include "catalog/pg_authid.h"
@@ -892,3 +893,122 @@ parse_ident(PG_FUNCTION_ARGS)
PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
}
+
+/*
+ * Report current log file used by log collector
+ */
+Datum
+pg_current_logfile(PG_FUNCTION_ARGS)
+{
+ FILE *fd;
+ char lbuffer[MAXPGPATH];
+ text *fmt;
+ char *logfmt;
+ struct stat stat_buf;
+ char *log_format;
+ char *log_filename;
+
+ /* The log format parameter is optional */
+ if (PG_NARGS() == 1) {
+ fmt = PG_ARGISNULL(0) ? NULL : PG_GETARG_TEXT_PP(0);
+ if (fmt != NULL) {
+ logfmt = text_to_cstring(fmt);
+ if ( (strcmp(logfmt, "stderr") != 0) &&
+ (strcmp(logfmt, "csvlog") != 0) ) {
+ ereport(ERROR,
+ (errmsg("log format %s not supported, possible values are stderr or csvlog", logfmt)));
+ PG_RETURN_NULL();
+ }
+ }
+ } else {
+ logfmt = NULL;
+ }
+
+ if (!Logging_collector)
+ PG_RETURN_NULL();
+
+ /* Check if current log file is present */
+ if (stat(CURRENT_LOG_FILENAME, &stat_buf) != 0)
+ PG_RETURN_NULL();
+
+ fd = AllocateFile(CURRENT_LOG_FILENAME, "r");
+ if (fd == NULL)
+ {
+ if (errno != ENOENT)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not read file \"%s\": %m",
+ CURRENT_LOG_FILENAME)));
+ PG_RETURN_NULL();
+ }
+
+ /*
+ * Read the file to gather current log filename(s) registered
+ * by the syslogger.
+ */
+ while (fgets(lbuffer, sizeof(lbuffer), fd) != NULL) {
+
+ /* Check for a read error. */
+ if (ferror(fd)) {
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not read file \"%s\": %m", CURRENT_LOG_FILENAME)));
+ FreeFile(fd);
+ break;
+ }
+
+ /* remove trailing newline */
+ if (strchr(lbuffer, '\n') != NULL)
+ *strchr(lbuffer, '\n') = '\0';
+
+ /* extract log format and log file path from the line */
+ log_format = strtok(lbuffer, " ");
+ if (log_format)
+ {
+ log_filename = strtok(NULL, " ");
+ if (!log_filename) {
+ ereport(ERROR,
+ (errmsg("unexpected line format in file %s", CURRENT_LOG_FILENAME)));
+ break;
+ }
+ }
+ else
+ {
+ ereport(ERROR,
+ (errmsg("unexpected line format in file %s", CURRENT_LOG_FILENAME)));
+ break;
+ }
+
+ /*
+ * When no log format is provided as argument always reports
+ * the first registered log file in CURRENT_LOG_FILENAME.
+ */
+ if (logfmt == NULL)
+ break;
+
+ /* report the entry corresponding to the requested format */
+ if (strcmp(logfmt, log_format) == 0)
+ break;
+ }
+ /* Close the current log filename file. */
+ if (FreeFile(fd))
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not close file \"%s\": %m", CURRENT_LOG_FILENAME)));
+
+
+ if (log_filename[0] == '\0')
+ PG_RETURN_NULL();
+
+ /* Return null when csvlog is requested but we have a stderr log */
+ if ( (logfmt != NULL) && (strcmp(logfmt, "csvlog") == 0)
+ && !(Log_destination & LOG_DESTINATION_CSVLOG) )
+ PG_RETURN_NULL();
+
+ /* Return null when stderr is requested but we have a csv log */
+ if ( (logfmt != NULL) && (strcmp(logfmt, "stderr") == 0)
+ && !(Log_destination & LOG_DESTINATION_STDERR) )
+ PG_RETURN_NULL();
+
+ PG_RETURN_TEXT_P(cstring_to_text(log_filename));
+}
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 17ec71d..78e23a6 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3179,6 +3179,8 @@ DATA(insert OID = 2621 ( pg_reload_conf PGNSP PGUID 12 1 0 0 0 f f f f t f v s
DESCR("reload configuration files");
DATA(insert OID = 2622 ( pg_rotate_logfile PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_rotate_logfile _null_ _null_ _null_ ));
DESCR("rotate log file");
+DATA(insert OID = 3800 ( pg_current_logfile PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 25 "25" _null_ _null_ _null_ _null_ _null_ pg_current_logfile _null_ _null_ _null_ ));
+DESCR("current logging collector file location");
DATA(insert OID = 2623 ( pg_stat_file PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2249 "25" "{25,20,1184,1184,1184,1184,16}" "{i,o,o,o,o,o,o}" "{filename,size,access,modification,change,creation,isdir}" _null_ _null_ pg_stat_file_1arg _null_ _null_ _null_ ));
DESCR("get information about file");
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 78545da..2faefdd 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -466,4 +466,12 @@ extern bool has_rolreplication(Oid roleid);
extern bool BackupInProgress(void);
extern void CancelBackup(void);
+/* in backend/utils/adt/misc.c and backend/postmaster/syslogger.c */
+/*
+ * Name of file where current log messages are written when log collector is
+ * enabled. Useful to find the name of the current log file when a time-based
+ * rotation is defined.
+ */
+#define CURRENT_LOG_FILENAME "current_logfiles"
+
#endif /* MISCADMIN_H */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 90f5132..df9a1e1 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -522,6 +522,7 @@ extern Datum pg_collation_for(PG_FUNCTION_ARGS);
extern Datum pg_relation_is_updatable(PG_FUNCTION_ARGS);
extern Datum pg_column_is_updatable(PG_FUNCTION_ARGS);
extern Datum parse_ident(PG_FUNCTION_ARGS);
+extern Datum pg_current_logfile(PG_FUNCTION_ARGS);
/* oid.c */
extern Datum oidin(PG_FUNCTION_ARGS);