Le 16/02/2017 à 16:13, Robert Haas a écrit : > On Wed, Feb 15, 2017 at 4:03 PM, Alvaro Herrera > <alvhe...@2ndquadrant.com> wrote: >> So what is going on here is that SysLogger_Start() wants to unlink the >> current-logfile file if the collector is not enabled. This should >> probably be split out into a separate new function, for two reasons: >> first, it doesn't seem good idea to have SysLogger_Start do something >> other than start the logger; and second, so that we don't have a syscall >> on each ServerLoop iteration. That new function should be called from >> some other place -- perhaps reaper() and just before entering >> ServerLoop, so that the file is deleted if the syslogger goes away or is >> not started. > I think it's sufficient to just remove the file once on postmaster > startup before trying to launch the syslogger for the first time. > logging_collector is PGC_POSTMASTER, so if it's not turned on when the > cluster first starts, it can't be activated later. If it dies, that > doesn't seem like a reason to remove the file. We're going to restart > the syslogger, and when we do, it can update the file. >
I've attached a new full v30 patch that include last patch from Karl. Now the current_logfile file is removed only at postmaster startup, just before launching the syslogger for the first time. -- Gilles Darold Consultant PostgreSQL http://dalibo.com - http://dalibo.org
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 95afc2c..a668456 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -4280,6 +4280,11 @@ SELECT * FROM parent WHERE key = 2400; <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"> @@ -4310,6 +4315,27 @@ SELECT * FROM parent WHERE key = 2400; <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> diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index d7738b1..cfa6349 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -15468,6 +15468,13 @@ SELECT * FROM pg_ls_dir('.') WITH ORDINALITY AS t(ls,n); </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> <entry>OID of session's temporary schema, or 0 if none</entry> @@ -15686,6 +15693,45 @@ SET search_path TO <replaceable>schema</> <optional>, <replaceable>schema</>, .. </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> diff --git a/doc/src/sgml/storage.sgml b/doc/src/sgml/storage.sgml index 127b759..262adea 100644 --- a/doc/src/sgml/storage.sgml +++ b/doc/src/sgml/storage.sgml @@ -36,6 +36,10 @@ these required items, the cluster configuration files <varname>PGDATA</>, although it is possible to place them elsewhere. </para> +<indexterm> + <primary>current_logfiles</primary> +</indexterm> + <table tocentry="1" id="pgdata-contents-table"> <title>Contents of <varname>PGDATA</></title> <tgroup cols="2"> @@ -61,6 +65,12 @@ Item </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 <structname>pg_database</></entry> diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 38be9cf..21a5f18 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1091,6 +1091,7 @@ REVOKE EXECUTE ON FUNCTION pg_wal_replay_pause() FROM public; 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_stat_reset() FROM public; REVOKE EXECUTE ON FUNCTION pg_stat_reset_shared(text) FROM public; diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 271c492..80f4661 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -1232,6 +1232,9 @@ PostmasterMain(int argc, char *argv[]) */ RemovePromoteSignalFiles(); + /* Remove outdated file holding the current log filenames. */ + unlink(LOG_METAINFO_DATAFILE); + /* * If enabled, start up syslogger collection subprocess */ diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index 13a0301..77059a4 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 update_metainfo_datafile(void); /* @@ -348,6 +349,13 @@ 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 +519,6 @@ int SysLogger_Start(void) { pid_t sysloggerPid; - char *filename; - - if (!Logging_collector) - return 0; /* * If first time through, create the pipe which will receive stderr @@ -570,11 +574,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); - pfree(filename); + last_file_name = logfile_getname(first_syslogger_file_time, NULL); + + syslogFile = logfile_open(last_file_name, "a", false); + + update_metainfo_datafile(); #ifdef EXEC_BACKEND switch ((sysloggerPid = syslogger_forkexec())) @@ -1098,6 +1106,8 @@ open_csvlogfile(void) pfree(last_csv_file_name); last_csv_file_name = filename; + + update_metainfo_datafile(); } /* @@ -1268,6 +1278,8 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for) if (csvfilename) pfree(csvfilename); + update_metainfo_datafile(); + set_next_rotation_time(); } @@ -1337,6 +1349,62 @@ set_next_rotation_time(void) 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)) + { + 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\" to \"%s\": %m", + LOG_METAINFO_DATAFILE_TMP, LOG_METAINFO_DATAFILE))); +} + /* -------------------------------- * signal handler routines * -------------------------------- diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index 09ecc15..24d5d9f 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -27,6 +27,7 @@ #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" @@ -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..89c6d0d 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -892,3 +892,106 @@ parse_ident(PG_FUNCTION_ARGS) 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); +} diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl index 29f519d..aafb138 100644 --- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl +++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl @@ -4,7 +4,7 @@ use Cwd; 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'); @@ -56,7 +56,7 @@ close CONF; $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"; @@ -83,7 +83,7 @@ foreach my $dirname (qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots } # 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"); } diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index bb7053a..717fc8d 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3191,6 +3191,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 */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers