diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4b5ee81..313403e 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -15027,6 +15027,12 @@ SELECT * FROM pg_ls_dir('.') WITH ORDINALITY AS t(ls,n);
+ pg_current_logfile()
+ text
+ current log file used by the logging collector
+
+
+
pg_notification_queue_usage()
double
fraction of the asynchronous notification queue currently occupied (0-1)
@@ -15264,6 +15270,16 @@ SET search_path TO schema , schema, ..
+ pg_current_logfile
+
+
+
+ pg_current_logfile returns the name of the current log
+ file used by the logging collector, as a text. Log collection
+ must be active.
+
+
+
pg_postmaster_start_time
diff --git a/doc/src/sgml/storage.sgml b/doc/src/sgml/storage.sgml
index 9b2e09e..41aaf5d 100644
--- a/doc/src/sgml/storage.sgml
+++ b/doc/src/sgml/storage.sgml
@@ -166,7 +166,8 @@ last started with
Unix-domain socket directory path (empty on Windows),
first valid listen_address (IP address or *, or empty if
not listening on TCP),
- and shared memory segment ID
+ the shared memory segment ID,
+ and the path to the current log file used by the syslogger
(this file is not present after server shutdown)
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index e7e488a..40fec7a 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -54,7 +54,6 @@
*/
#define READ_BUF_SIZE (2 * PIPE_CHUNK_SIZE)
-
/*
* GUC parameters. Logging_collector cannot be changed after postmaster
* start, but the rest can change at SIGHUP.
@@ -571,6 +570,8 @@ SysLogger_Start(void)
syslogFile = logfile_open(filename, "a", false);
+ AddToDataDirLockFile(LOCK_FILE_LINE_LOG_FILENAME, filename);
+
pfree(filename);
#ifdef EXEC_BACKEND
@@ -1209,6 +1210,9 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
fclose(syslogFile);
syslogFile = fh;
+ /* Store current log filename */
+ AddToDataDirLockFile(LOCK_FILE_LINE_LOG_FILENAME, filename);
+
/* instead of pfree'ing filename, remember it for next time */
if (last_file_name != NULL)
pfree(last_file_name);
@@ -1253,6 +1257,9 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
fclose(csvlogFile);
csvlogFile = fh;
+ /* Store current log filename */
+ AddToDataDirLockFile(LOCK_FILE_LINE_LOG_FILENAME, csvfilename);
+
/* instead of pfree'ing filename, remember it for next time */
if (last_csv_file_name != NULL)
pfree(last_csv_file_name);
@@ -1262,6 +1269,7 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
if (filename)
pfree(filename);
+
if (csvfilename)
pfree(csvfilename);
@@ -1362,3 +1370,4 @@ sigUsr1Handler(SIGNAL_ARGS)
errno = save_errno;
}
+
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 43f36db..2bc2283 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/catalog.h"
@@ -43,7 +44,6 @@
#define atooid(x) ((Oid) strtoul((x), NULL, 10))
-
/*
* Common subroutine for num_nulls() and num_nonnulls().
* Returns TRUE if successful, FALSE if function should return NULL.
@@ -719,3 +719,22 @@ pg_column_is_updatable(PG_FUNCTION_ARGS)
PG_RETURN_BOOL((events & REQ_EVENTS) == REQ_EVENTS);
}
+
+
+/*
+ * Report current log file used by log collector
+ */
+Datum
+pg_current_logfile(PG_FUNCTION_ARGS)
+{
+
+ if (!Logging_collector)
+ {
+ ereport(WARNING,
+ (errmsg("current log can not be reported because log collection is not active")));
+ PG_RETURN_NULL();
+ }
+
+ PG_RETURN_TEXT_P(cstring_to_text(get_current_log_filename()));
+}
+
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 18f5e6f..f38c3fc 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -49,8 +49,6 @@
#include "utils/syscache.h"
-#define DIRECTORY_LOCK_FILE "postmaster.pid"
-
ProcessingMode Mode = InitProcessing;
/* List of lock files to be removed at proc exit */
@@ -1490,3 +1488,188 @@ pg_bindtextdomain(const char *domain)
}
#endif
}
+
+/*
+ * get the lines from postmaster.pid file - return NULL if file can't be opened
+ */
+char **
+read_pidfile(const char *path)
+{
+ int fd;
+ int nlines;
+ char **result;
+ char *buffer;
+ char *linebegin;
+ int i;
+ int n;
+ int len;
+ struct stat statbuf;
+
+ /*
+ * Slurp the file into memory.
+ *
+ * The file can change concurrently, so we read the whole file into memory
+ * with a single read() call. That's not guaranteed to get an atomic
+ * snapshot, but in practice, for a small file, it's close enough for the
+ * current use.
+ */
+ fd = open(path, O_RDONLY | PG_BINARY, 0);
+ if (fd < 0)
+ return NULL;
+ if (fstat(fd, &statbuf) < 0)
+ {
+ close(fd);
+ return NULL;
+ }
+ if (statbuf.st_size == 0)
+ {
+ /* empty file */
+ close(fd);
+ result = (char **) malloc(sizeof(char *));
+ *result = NULL;
+ return result;
+ }
+ buffer = malloc(statbuf.st_size + 1);
+ if (buffer == NULL)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of memory")));
+ return NULL;
+ }
+ len = read(fd, buffer, statbuf.st_size + 1);
+ close(fd);
+ if (len != statbuf.st_size)
+ {
+ /* oops, the file size changed between fstat and read */
+ free(buffer);
+ return NULL;
+ }
+
+ /*
+ * Count newlines. We expect there to be a newline after each full line,
+ * including one at the end of file. If there isn't a newline at the end,
+ * any characters after the last newline will be ignored.
+ */
+ nlines = 0;
+ for (i = 0; i < len; i++)
+ {
+ if (buffer[i] == '\n')
+ nlines++;
+ }
+
+ /* set up the result buffer */
+ result = (char **) malloc((nlines + 1) * sizeof(char *));
+ if (result == NULL)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of memory")));
+ return NULL;
+ }
+
+ /* now split the buffer into lines */
+ linebegin = buffer;
+ n = 0;
+ for (i = 0; i < len; i++)
+ {
+ if (buffer[i] == '\n')
+ {
+ int slen = &buffer[i] - linebegin + 1;
+ char *linebuf = malloc(slen + 1);
+ if (linebuf == NULL)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of memory")));
+ return NULL;
+ }
+
+ memcpy(linebuf, linebegin, slen);
+ linebuf[slen] = '\0';
+ result[n++] = linebuf;
+ linebegin = &buffer[i + 1];
+ }
+ }
+ result[n] = NULL;
+
+ free(buffer);
+
+ return result;
+}
+
+/*
+ * Free memory allocated for optlines through read_pidfile()
+ */
+void
+free_read_pidfile(char **optlines)
+{
+ char *curr_line = NULL;
+ int i = 0;
+
+ if (!optlines)
+ return;
+
+ while ((curr_line = optlines[i++]))
+ free(curr_line);
+
+ free(optlines);
+
+ return;
+}
+
+/*
+ * Find the current log file or NULL when not available.
+ */
+char *
+get_current_log_filename(void)
+{
+ int i;
+ char **optlines;
+ char *current_log;
+
+ /* Try to read the postmaster.pid file */
+ if ((optlines = read_pidfile(DIRECTORY_LOCK_FILE)) != NULL &&
+ optlines[0] != NULL &&
+ optlines[1] != NULL &&
+ optlines[2] != NULL)
+ {
+ /* Only 9.6+ server register the current log file in pid file
+ * and only with stderr redirection and a time-based rotation.
+ * Return null otherwise.
+ */
+ if (optlines[7] == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ /*
+ * Extract current log filename
+ */
+ current_log = palloc(MAXPGPATH);
+ snprintf(current_log, MAXPGPATH, "%s", optlines[LOCK_FILE_LINE_LOG_FILENAME - 1]);
+
+ /* remove trailing newline */
+ if (strchr(current_log, '\n') != NULL)
+ *strchr(current_log, '\n') = '\0';
+
+ /* Fail if couldn't get current log */
+ if (current_log[0] == '\0')
+ {
+ return NULL;
+ }
+ }
+ }
+
+ /*
+ * Free the results of readfile.
+ *
+ * This is safe to call even if optlines is NULL.
+ */
+ free_read_pidfile(optlines);
+
+ /* return current log filename */
+ return current_log;
+}
+
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index cbbb883..5aa95b0 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3120,7 +3120,8 @@ DESCR("true if xlog replay is paused");
DATA(insert OID = 2621 ( pg_reload_conf PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_reload_conf _null_ _null_ _null_ ));
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 = 3794 ( pg_current_logfile PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _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 cc7833e..23ec7f3 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -447,6 +447,9 @@ extern char *local_preload_libraries_string;
#define LOCK_FILE_LINE_SOCKET_DIR 5
#define LOCK_FILE_LINE_LISTEN_ADDR 6
#define LOCK_FILE_LINE_SHMEM_KEY 7
+#define LOCK_FILE_LINE_LOG_FILENAME 8
+
+#define DIRECTORY_LOCK_FILE "postmaster.pid"
extern void CreateDataDirLockFile(bool amPostmaster);
extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster,
@@ -460,6 +463,10 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
+extern char **read_pidfile(const char *path);
+extern void free_read_pidfile(char **optlines);
+extern char *get_current_log_filename(void);
+
/* in access/transam/xlog.c */
extern bool BackupInProgress(void);
extern void CancelBackup(void);
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 115f8af..fd2c4ea 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -509,6 +509,7 @@ extern Datum pg_typeof(PG_FUNCTION_ARGS);
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 pg_current_logfile(PG_FUNCTION_ARGS);
/* oid.c */
extern Datum oidin(PG_FUNCTION_ARGS);