Hi,

Here is a patch that is supposed to solve the remaining problem to
find the current log file used by the log collector after a rotation.
There is lot of external command to try to find this information but
it seems useful to have an internal function to retrieve the name
of the current log file from the log collector.

There is a corresponding item in the TODO list at "Administration"
section. The original thread can be reach at the following link
http://archives.postgresql.org/pgsql-general/2008-11/msg00418.php
The goal is to provide a way to query the log collector subprocess
to determine the name of the currently active log file.

This patch implements the pg_current_logfile() function that can be
used as follow. The function returns NULL when logging_collector
is not active and outputs a warning.

postgres=# \pset null *
postgres=# SELECT pg_current_logfile();
WARNING:  current log can not be reported because log collection is not
active
 pg_current_logfile
--------------------
 *
(1 line)

So a better query should be:

postgres=# SELECT CASE WHEN current_setting('logging_collector')='on'
        THEN pg_current_logfile()
        ELSE current_setting('log_destination')
    END;
 current_setting
-----------------
 syslog
(1 line)

Same query with log collection active and, for example,
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'

postgres=# SELECT CASE WHEN current_setting('logging_collector')='on'
                THEN pg_current_logfile()
                ELSE current_setting('log_destination')
        END;
             current_setting            
-----------------------------------------
 pg_log/postgresql-2016-03-09_152827.log
(1 line)

Then after a log rotation:

postgres=# SELECT pg_rotate_logfile();
 pg_rotate_logfile
-------------------
 t
(1 line)

postgres=# select pg_current_logfile();
           pg_current_logfile           
-----------------------------------------
 pg_log/postgresql-2016-03-09_152908.log
(1 line)

I choose to allow the log collector to write his current log file name
into the lock file 'postmaster.pid'. This allow simple access to this
information through system commands, for example:

postgres@W230ST:~$ tail -n1 /usr/local/pgql-devel/data/postmaster.pid
pg_log/postgresql-2016-03-09_152908.log

Log filename is written at the 8th line position when log collection
is active and all other information have been written to lock file.

The function pg_current_logfile() use in SQL mode read the lock file
to report the information.

I don't know if there's any limitation on using postmaster.pid file to
do that but it seems to me a bit weird to log this information to an
other file. My first attempt was to use a dedicated file and save it
to global/pg_current_logfile or pg_stat_tmp/pg_current_logfile but I
think it is better to use the postmaster.pid file for that. I also
though about a communication protocol or notification with the log
collector subprocess to query and retrieve the name of the currently
active log file. But obviously, it would be too much work for just this
simple function and I can't see any other feature that need such a
work.

Any though? Should I add this patch to the commit fest? If the use
of the postmater.pid file is a problem I can easily modify the patch
to use an alternate file.

Best regards,

-- 
Gilles Darold
Consultant PostgreSQL
http://dalibo.com - http://dalibo.org

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);
       </row>
 
       <row>
+       <entry><literal><function>pg_current_logfile()</function></literal></entry>
+       <entry><type>text</type></entry>
+       <entry>current log file used by the logging collector</entry>
+      </row>
+
+      <row>
        <entry><literal><function>pg_notification_queue_usage()</function></literal></entry>
        <entry><type>double</type></entry>
        <entry>fraction of the asynchronous notification queue currently occupied (0-1)</entry>
@@ -15264,6 +15270,16 @@ SET search_path TO <replaceable>schema</> <optional>, <replaceable>schema</>, ..
    </para>
 
    <indexterm>
+    <primary>pg_current_logfile</primary>
+   </indexterm>
+
+   <para>
+    <function>pg_current_logfile</function> returns the name of the current log
+    file used by the logging collector, as a <type>text</type>. Log collection
+    must be active.
+   </para>
+
+   <indexterm>
     <primary>pg_postmaster_start_time</primary>
    </indexterm>
 
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</entry>
   Unix-domain socket directory path (empty on Windows),
   first valid listen_address (IP address or <literal>*</>, 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)</entry>
 </row>
 
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 <dirent.h>
 #include <math.h>
 #include <unistd.h>
+#include <sys/stat.h>
 
 #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);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to