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);