diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 30dd54c..393195f 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -4211,6 +4211,17 @@ SELECT * FROM parent WHERE key = 2400;
server log
+
+ When logs are written to the file system, the file includes the type,
+ the location and the name of the logs currently in use. This provides a
+ convenient way to find the logs currently in used by the instance.
+
+$ cat $PGDATA/current_logfiles
+stderr pg_log/postgresql-2017-01-13_085812.log
+
+
+
Where To Log
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 10e3186..693669b 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -15441,6 +15441,13 @@ SELECT * FROM pg_ls_dir('.') WITH ORDINALITY AS t(ls,n);
+ pg_current_logfile(text>)
+ text
+ Primary log file name, or log in the requested format,
+ currently in use by the logging collector
+
+
+
pg_my_temp_schema()
oid
OID of session's temporary schema, or 0 if none
@@ -15658,6 +15665,39 @@ SET search_path TO schema> , schema>, ..
the time when the postmaster process re-read the configuration files.)
+
+ pg_current_logile
+
+
+
+ Logging
+ pg_current_logfile function
+
+
+
+ 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 log files 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_current_logfiles reflects the content of the
+ file. All caveats
+ regards current_logfiles content are applicable
+ to pg_current_logfiles' return value.
+
+
pg_my_temp_schema
diff --git a/doc/src/sgml/storage.sgml b/doc/src/sgml/storage.sgml
index 5c52824..3ce2a7e 100644
--- a/doc/src/sgml/storage.sgml
+++ b/doc/src/sgml/storage.sgml
@@ -60,6 +60,38 @@ Item
Subdirectory containing per-database subdirectories
+
+
+
+ current_logfiles
+
+
+ Logging
+ current_logfiles file
+
+ current_logfiles>
+
+
+
+ A file recording the log file(s) currently written to by the syslogger
+ and the file's log formats, 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
+ current_logfiles.
+
+
+
+ The current_logfiles file
+ is present only when is
+ activated and when at least one of stderr> or
+ csvlog> value is present in
+ .
+
+
+
+
global>
Subdirectory containing cluster-wide tables, such as
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 31aade1..1d7f68b 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1055,6 +1055,7 @@ REVOKE EXECUTE ON FUNCTION pg_xlog_replay_pause() FROM public;
REVOKE EXECUTE ON FUNCTION pg_xlog_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_stat_reset() FROM public;
REVOKE EXECUTE ON FUNCTION pg_stat_reset_shared(text) FROM public;
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 13a0301..80f4204 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -146,7 +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);
/*
* Main entry point for syslogger process
@@ -348,6 +348,12 @@ 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)
@@ -511,10 +517,15 @@ int
SysLogger_Start(void)
{
pid_t sysloggerPid;
- char *filename;
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(LOG_METAINFO_DATAFILE);
return 0;
+ }
/*
* If first time through, create the pipe which will receive stderr
@@ -570,11 +581,15 @@ SysLogger_Start(void)
* a time-based rotation.
*/
first_syslogger_file_time = time(NULL);
- filename = logfile_getname(first_syslogger_file_time, NULL);
- syslogFile = logfile_open(filename, "a", false);
+ if (last_file_name != NULL)
+ pfree(last_file_name);
+
+ last_file_name = logfile_getname(first_syslogger_file_time, NULL);
+
+ syslogFile = logfile_open(last_file_name, "a", false);
- pfree(filename);
+ update_metainfo_datafile();
#ifdef EXEC_BACKEND
switch ((sysloggerPid = syslogger_forkexec()))
@@ -1098,6 +1113,8 @@ open_csvlogfile(void)
pfree(last_csv_file_name);
last_csv_file_name = filename;
+
+ update_metainfo_datafile();
}
/*
@@ -1268,6 +1285,8 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
if (csvfilename)
pfree(csvfilename);
+ update_metainfo_datafile();
+
set_next_rotation_time();
}
@@ -1365,3 +1384,61 @@ 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
+update_metainfo_datafile()
+{
+ FILE *fh;
+
+ if (!(Log_destination & LOG_DESTINATION_STDERR)
+ && !(Log_destination & LOG_DESTINATION_CSVLOG))
+ {
+ unlink(LOG_METAINFO_DATAFILE);
+ return;
+ }
+
+ if ((fh = logfile_open(LOG_METAINFO_DATAFILE_TMP, "w", true)) == NULL)
+ 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 stderr log file path \"%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 csvlog log file path \"%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\": %m",
+ LOG_METAINFO_DATAFILE_TMP)));
+ return;
+ }
+}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 09ecc15..4152d30 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -37,6 +37,7 @@
#include "utils/elog.h"
#include "utils/ps_status.h"
#include "utils/timestamp.h"
+#include "postmaster/syslogger.h"
typedef struct
@@ -148,6 +149,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 66d09bc..60ab512 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -892,3 +892,99 @@ 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];
+ char *logfmt;
+ char *log_filepath;
+ char *log_format = lbuffer;
+
+ /* 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\".")));
+ PG_RETURN_NULL();
+ }
+ }
+
+ 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)
+ {
+ /* Check for a read error. */
+ if (ferror(fd))
+ {
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not read file \"%s\": %m",
+ LOG_METAINFO_DATAFILE)));
+ }
+
+ /*
+ * extract log format and log file path from the line
+ * lbuffer == log_format, they share storage
+ */
+ if (log_filepath = strchr(lbuffer, ' '))
+ *log_filepath = '\0';
+ else
+ {
+ /* Unknown format, no space. Return NULL to caller. */
+ lbuffer[0] = '\0';
+ break;
+ }
+ log_filepath++;
+ log_filepath[strcspn(log_filepath, "\n")] = '\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);
+}
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 37e022d..eb56e8d 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3183,6 +3183,10 @@ 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 0 0 25 "" _null_ _null_ _null_ _null_ _null_ pg_current_logfile _null_ _null_ _null_ ));
+DESCR("current logging collector file location");
+DATA(insert OID = 3801 ( 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_1arg _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/postmaster/syslogger.h b/src/include/postmaster/syslogger.h
index c187a5f..ebe3247 100644
--- a/src/include/postmaster/syslogger.h
+++ b/src/include/postmaster/syslogger.h
@@ -87,4 +87,11 @@ extern void write_syslogger_file(const char *buffer, int count, int dest);
extern void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn();
#endif
+/*
+ * Name of files saving meta-data information about the log
+ * files currently in use by the system logging process
+ */
+#define LOG_METAINFO_DATAFILE "current_logfiles"
+#define LOG_METAINFO_DATAFILE_TMP LOG_METAINFO_DATAFILE ".tmp"
+
#endif /* _SYSLOGGER_H */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index e1bb344..e2532e6 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -522,6 +522,8 @@ 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);
+extern Datum pg_current_logfile_1arg(PG_FUNCTION_ARGS);
/* oid.c */
extern Datum oidin(PG_FUNCTION_ARGS);