<primary>where to log</primary>
</indexterm>
+ <indexterm>
+ <primary>current_logfiles</primary>
+ <secondary>and the log_destination configuration parameter</secondary>
+ </indexterm>
+
<variablelist>
<varlistentry id="guc-log-destination" xreflabel="log_destination">
<xref linkend="guc-logging-collector"> must be enabled to generate
CSV-format log output.
</para>
+ <para>
+ When either <systemitem>stderr</systemitem> or
+ <systemitem>csvlog</systemitem> are included, the file
+ <filename>current_logfiles</> is created to record the location
+ of the log file(s) currently in use by the logging collector and the
+ associated logging destination. This provides a convenient way to
+ find the logs currently in use by the instance. Here is an example of
+ this file's content:
+<programlisting>
+stderr pg_log/postgresql.log
+csvlog pg_log/postgresql.csv
+</programlisting>
+
+ <filename>current_logfiles</filename> is recreated when a new log file
+ is created as an effect of rotation, and
+ when <varname>log_destination</> is reloaded. It is removed when
+ neither <systemitem>stderr</systemitem>
+ nor <systemitem>csvlog</systemitem> are included
+ in <varname>log_destination</>, and when the logging collector is
+ disabled.
+ </para>
<note>
<para>
<entry>configuration load time</entry>
</row>
+ <row>
+ <entry><literal><function>pg_current_logfile(<optional><type>text</></optional>)</function></literal></entry>
+ <entry><type>text</type></entry>
+ <entry>Primary log file name, or log in the requested format,
+ currently in use by the logging collector</entry>
+ </row>
+
<row>
<entry><literal><function>pg_my_temp_schema()</function></literal></entry>
<entry><type>oid</type></entry>
the time when the postmaster process re-read the configuration files.)
</para>
+ <indexterm>
+ <primary>pg_current_logfile</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>Logging</primary>
+ <secondary>pg_current_logfile function</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>current_logfiles</primary>
+ <secondary>and the pg_current_logfile function</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>Logging</primary>
+ <secondary>current_logfiles file and the pg_current_logfile
+ function</secondary>
+ </indexterm>
+
+ <para>
+ <function>pg_current_logfile</function> returns, as <type>text</type>,
+ the path of the log file(s) currently in use by the logging collector.
+ The path includes the <xref linkend="guc-log-directory"> directory
+ and the log file name. Log collection must be enabled or the return value
+ is <literal>NULL</literal>. When multiple log files exist, each in a
+ different format, <function>pg_current_logfile</function> called
+ without arguments returns the path of the file having the first format
+ found in the ordered list: <systemitem>stderr</>, <systemitem>csvlog</>.
+ <literal>NULL</literal> is returned when no log file has any of these
+ formats. To request a specific file format supply, as <type>text</type>,
+ either <systemitem>csvlog</> or <systemitem>stderr</> as the value of the
+ optional parameter. The return value is <literal>NULL</literal> when the
+ log format requested is not a configured
+ <xref linkend="guc-log-destination">. The
+ <function>pg_current_logfiles</function> reflects the contents of the
+ <filename>current_logfiles</> file.
+ </para>
+
<indexterm>
<primary>pg_my_temp_schema</primary>
</indexterm>
<entry>Subdirectory containing per-database subdirectories</entry>
</row>
+<row>
+ <entry><filename>current_logfiles</></entry>
+ <entry>File recording the log file(s) currently written to by the logging
+ collector</entry>
+</row>
+
<row>
<entry><filename>global</></entry>
<entry>Subdirectory containing cluster-wide tables, such as
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;
*/
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
*/
static void set_next_rotation_time(void);
static void sigHupHandler(SIGNAL_ARGS);
static void sigUsr1Handler(SIGNAL_ARGS);
+static void update_metainfo_datafile(void);
/*
currentLogRotationAge = Log_RotationAge;
/* set next planned rotation time */
set_next_rotation_time();
+ update_metainfo_datafile();
/* main worker loop */
for (;;)
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)
pfree(last_csv_file_name);
last_csv_file_name = filename;
+
+ update_metainfo_datafile();
}
/*
if (csvfilename)
pfree(csvfilename);
+ update_metainfo_datafile();
+
set_next_rotation_time();
}
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
* --------------------------------
#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"
/* 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
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);
+}
use Config;
use PostgresNode;
use TestLib;
-use Test::More tests => 72;
+use Test::More tests => 73;
program_help_ok('pg_basebackup');
program_version_ok('pg_basebackup');
$node->restart;
# Write some files to test that they are not copied.
-foreach my $filename (qw(backup_label tablespace_map postgresql.auto.conf.tmp))
+foreach my $filename (qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp))
{
open FILE, ">>$pgdata/$filename";
print FILE "DONOTCOPY";
}
# These files should not be copied.
-foreach my $filename (qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map))
+foreach my $filename (qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp))
{
ok(! -f "$tempdir/backup/$filename", "$filename not copied");
}
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201703011
+#define CATALOG_VERSION_NO 201703031
#endif
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");
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 syslogger
+ */
+#define LOG_METAINFO_DATAFILE "current_logfiles"
+#define LOG_METAINFO_DATAFILE_TMP LOG_METAINFO_DATAFILE ".tmp"
+
#endif /* _SYSLOGGER_H */