Skip to content

Commit 19dc233

Browse files
committed
Add pg_current_logfile() function.
The syslogger will write out the current stderr and csvlog names, if it's running and there are any, to a new file in the data directory called "current_logfiles". We take care to remove this file when it might no longer be valid (but not at shutdown). The function pg_current_logfile() can be used to read the entries in the file. Gilles Darold, reviewed and modified by Karl O. Pinc, Michael Paquier, and me. Further review by Álvaro Herrera and Christoph Berg.
1 parent aea5d29 commit 19dc233

File tree

12 files changed

+288
-4
lines changed

12 files changed

+288
-4
lines changed

doc/src/sgml/config.sgml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4280,6 +4280,11 @@ SELECT * FROM parent WHERE key = 2400;
42804280
<primary>where to log</primary>
42814281
</indexterm>
42824282

4283+
<indexterm>
4284+
<primary>current_logfiles</primary>
4285+
<secondary>and the log_destination configuration parameter</secondary>
4286+
</indexterm>
4287+
42834288
<variablelist>
42844289

42854290
<varlistentry id="guc-log-destination" xreflabel="log_destination">
@@ -4310,6 +4315,27 @@ SELECT * FROM parent WHERE key = 2400;
43104315
<xref linkend="guc-logging-collector"> must be enabled to generate
43114316
CSV-format log output.
43124317
</para>
4318+
<para>
4319+
When either <systemitem>stderr</systemitem> or
4320+
<systemitem>csvlog</systemitem> are included, the file
4321+
<filename>current_logfiles</> is created to record the location
4322+
of the log file(s) currently in use by the logging collector and the
4323+
associated logging destination. This provides a convenient way to
4324+
find the logs currently in use by the instance. Here is an example of
4325+
this file's content:
4326+
<programlisting>
4327+
stderr pg_log/postgresql.log
4328+
csvlog pg_log/postgresql.csv
4329+
</programlisting>
4330+
4331+
<filename>current_logfiles</filename> is recreated when a new log file
4332+
is created as an effect of rotation, and
4333+
when <varname>log_destination</> is reloaded. It is removed when
4334+
neither <systemitem>stderr</systemitem>
4335+
nor <systemitem>csvlog</systemitem> are included
4336+
in <varname>log_destination</>, and when the logging collector is
4337+
disabled.
4338+
</para>
43134339

43144340
<note>
43154341
<para>

doc/src/sgml/func.sgml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15478,6 +15478,13 @@ SELECT * FROM pg_ls_dir('.') WITH ORDINALITY AS t(ls,n);
1547815478
<entry>configuration load time</entry>
1547915479
</row>
1548015480

15481+
<row>
15482+
<entry><literal><function>pg_current_logfile(<optional><type>text</></optional>)</function></literal></entry>
15483+
<entry><type>text</type></entry>
15484+
<entry>Primary log file name, or log in the requested format,
15485+
currently in use by the logging collector</entry>
15486+
</row>
15487+
1548115488
<row>
1548215489
<entry><literal><function>pg_my_temp_schema()</function></literal></entry>
1548315490
<entry><type>oid</type></entry>
@@ -15696,6 +15703,45 @@ SET search_path TO <replaceable>schema</> <optional>, <replaceable>schema</>, ..
1569615703
the time when the postmaster process re-read the configuration files.)
1569715704
</para>
1569815705

15706+
<indexterm>
15707+
<primary>pg_current_logfile</primary>
15708+
</indexterm>
15709+
15710+
<indexterm>
15711+
<primary>Logging</primary>
15712+
<secondary>pg_current_logfile function</secondary>
15713+
</indexterm>
15714+
15715+
<indexterm>
15716+
<primary>current_logfiles</primary>
15717+
<secondary>and the pg_current_logfile function</secondary>
15718+
</indexterm>
15719+
15720+
<indexterm>
15721+
<primary>Logging</primary>
15722+
<secondary>current_logfiles file and the pg_current_logfile
15723+
function</secondary>
15724+
</indexterm>
15725+
15726+
<para>
15727+
<function>pg_current_logfile</function> returns, as <type>text</type>,
15728+
the path of the log file(s) currently in use by the logging collector.
15729+
The path includes the <xref linkend="guc-log-directory"> directory
15730+
and the log file name. Log collection must be enabled or the return value
15731+
is <literal>NULL</literal>. When multiple log files exist, each in a
15732+
different format, <function>pg_current_logfile</function> called
15733+
without arguments returns the path of the file having the first format
15734+
found in the ordered list: <systemitem>stderr</>, <systemitem>csvlog</>.
15735+
<literal>NULL</literal> is returned when no log file has any of these
15736+
formats. To request a specific file format supply, as <type>text</type>,
15737+
either <systemitem>csvlog</> or <systemitem>stderr</> as the value of the
15738+
optional parameter. The return value is <literal>NULL</literal> when the
15739+
log format requested is not a configured
15740+
<xref linkend="guc-log-destination">. The
15741+
<function>pg_current_logfiles</function> reflects the contents of the
15742+
<filename>current_logfiles</> file.
15743+
</para>
15744+
1569915745
<indexterm>
1570015746
<primary>pg_my_temp_schema</primary>
1570115747
</indexterm>

doc/src/sgml/storage.sgml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ Item
6060
<entry>Subdirectory containing per-database subdirectories</entry>
6161
</row>
6262

63+
<row>
64+
<entry><filename>current_logfiles</></entry>
65+
<entry>File recording the log file(s) currently written to by the logging
66+
collector</entry>
67+
</row>
68+
6369
<row>
6470
<entry><filename>global</></entry>
6571
<entry>Subdirectory containing cluster-wide tables, such as

src/backend/catalog/system_views.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,8 @@ REVOKE EXECUTE ON FUNCTION pg_wal_replay_pause() FROM public;
10911091
REVOKE EXECUTE ON FUNCTION pg_wal_replay_resume() FROM public;
10921092
REVOKE EXECUTE ON FUNCTION pg_rotate_logfile() FROM public;
10931093
REVOKE EXECUTE ON FUNCTION pg_reload_conf() FROM public;
1094+
REVOKE EXECUTE ON FUNCTION pg_current_logfile() FROM public;
1095+
REVOKE EXECUTE ON FUNCTION pg_current_logfile(text) FROM public;
10941096

10951097
REVOKE EXECUTE ON FUNCTION pg_stat_reset() FROM public;
10961098
REVOKE EXECUTE ON FUNCTION pg_stat_reset_shared(text) FROM public;

src/backend/postmaster/postmaster.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,13 @@ PostmasterMain(int argc, char *argv[])
12321232
*/
12331233
RemovePromoteSignalFiles();
12341234

1235+
/* Remove any outdated file holding the current log filenames. */
1236+
if (unlink(LOG_METAINFO_DATAFILE) < 0 && errno != ENOENT)
1237+
ereport(LOG,
1238+
(errcode_for_file_access(),
1239+
errmsg("could not remove file \"%s\": %m",
1240+
LOG_METAINFO_DATAFILE)));
1241+
12351242
/*
12361243
* If enabled, start up syslogger collection subprocess
12371244
*/

src/backend/postmaster/syslogger.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ static char *logfile_getname(pg_time_t timestamp, const char *suffix);
146146
static void set_next_rotation_time(void);
147147
static void sigHupHandler(SIGNAL_ARGS);
148148
static void sigUsr1Handler(SIGNAL_ARGS);
149+
static void update_metainfo_datafile(void);
149150

150151

151152
/*
@@ -282,6 +283,7 @@ SysLoggerMain(int argc, char *argv[])
282283
currentLogRotationAge = Log_RotationAge;
283284
/* set next planned rotation time */
284285
set_next_rotation_time();
286+
update_metainfo_datafile();
285287

286288
/* main worker loop */
287289
for (;;)
@@ -348,6 +350,13 @@ SysLoggerMain(int argc, char *argv[])
348350
rotation_disabled = false;
349351
rotation_requested = true;
350352
}
353+
354+
/*
355+
* Force rewriting last log filename when reloading configuration.
356+
* Even if rotation_requested is false, log_destination may have
357+
* been changed and we don't want to wait the next file rotation.
358+
*/
359+
update_metainfo_datafile();
351360
}
352361

353362
if (Log_RotationAge > 0 && !rotation_disabled)
@@ -1098,6 +1107,8 @@ open_csvlogfile(void)
10981107
pfree(last_csv_file_name);
10991108

11001109
last_csv_file_name = filename;
1110+
1111+
update_metainfo_datafile();
11011112
}
11021113

11031114
/*
@@ -1268,6 +1279,8 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
12681279
if (csvfilename)
12691280
pfree(csvfilename);
12701281

1282+
update_metainfo_datafile();
1283+
12711284
set_next_rotation_time();
12721285
}
12731286

@@ -1337,6 +1350,72 @@ set_next_rotation_time(void)
13371350
next_rotation_time = now;
13381351
}
13391352

1353+
/*
1354+
* Store the name of the file(s) where the log collector, when enabled, writes
1355+
* log messages. Useful for finding the name(s) of the current log file(s)
1356+
* when there is time-based logfile rotation. Filenames are stored in a
1357+
* temporary file and which is renamed into the final destination for
1358+
* atomicity.
1359+
*/
1360+
static void
1361+
update_metainfo_datafile(void)
1362+
{
1363+
FILE *fh;
1364+
1365+
if (!(Log_destination & LOG_DESTINATION_STDERR) &&
1366+
!(Log_destination & LOG_DESTINATION_CSVLOG))
1367+
{
1368+
if (unlink(LOG_METAINFO_DATAFILE) < 0 && errno != ENOENT)
1369+
ereport(LOG,
1370+
(errcode_for_file_access(),
1371+
errmsg("could not remove file \"%s\": %m",
1372+
LOG_METAINFO_DATAFILE)));
1373+
return;
1374+
}
1375+
1376+
if ((fh = logfile_open(LOG_METAINFO_DATAFILE_TMP, "w", true)) == NULL)
1377+
{
1378+
ereport(LOG,
1379+
(errcode_for_file_access(),
1380+
errmsg("could not open file \"%s\": %m",
1381+
LOG_METAINFO_DATAFILE_TMP)));
1382+
return;
1383+
}
1384+
1385+
if (last_file_name && (Log_destination & LOG_DESTINATION_STDERR))
1386+
{
1387+
if (fprintf(fh, "stderr %s\n", last_file_name) < 0)
1388+
{
1389+
ereport(LOG,
1390+
(errcode_for_file_access(),
1391+
errmsg("could not write file \"%s\": %m",
1392+
LOG_METAINFO_DATAFILE_TMP)));
1393+
fclose(fh);
1394+
return;
1395+
}
1396+
}
1397+
1398+
if (last_csv_file_name && (Log_destination & LOG_DESTINATION_CSVLOG))
1399+
{
1400+
if (fprintf(fh, "csvlog %s\n", last_csv_file_name) < 0)
1401+
{
1402+
ereport(LOG,
1403+
(errcode_for_file_access(),
1404+
errmsg("could not write file \"%s\": %m",
1405+
LOG_METAINFO_DATAFILE_TMP)));
1406+
fclose(fh);
1407+
return;
1408+
}
1409+
}
1410+
fclose(fh);
1411+
1412+
if (rename(LOG_METAINFO_DATAFILE_TMP, LOG_METAINFO_DATAFILE) != 0)
1413+
ereport(LOG,
1414+
(errcode_for_file_access(),
1415+
errmsg("could not rename file \"%s\" to \"%s\": %m",
1416+
LOG_METAINFO_DATAFILE_TMP, LOG_METAINFO_DATAFILE)));
1417+
}
1418+
13401419
/* --------------------------------
13411420
* signal handler routines
13421421
* --------------------------------

src/backend/replication/basebackup.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "nodes/pg_list.h"
2727
#include "pgtar.h"
2828
#include "pgstat.h"
29+
#include "postmaster/syslogger.h"
2930
#include "replication/basebackup.h"
3031
#include "replication/walsender.h"
3132
#include "replication/walsender_private.h"
@@ -147,6 +148,9 @@ static const char *excludeFiles[] =
147148
/* Skip auto conf temporary file. */
148149
PG_AUTOCONF_FILENAME ".tmp",
149150

151+
/* Skip current log file temporary file */
152+
LOG_METAINFO_DATAFILE_TMP,
153+
150154
/*
151155
* If there's a backup_label or tablespace_map file, it belongs to a
152156
* backup started by the user with pg_start_backup(). It is *not* correct

src/backend/utils/adt/misc.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,3 +885,106 @@ parse_ident(PG_FUNCTION_ARGS)
885885

886886
PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
887887
}
888+
889+
/*
890+
* pg_current_logfile
891+
*
892+
* Report current log file used by log collector by scanning current_logfiles.
893+
*/
894+
Datum
895+
pg_current_logfile(PG_FUNCTION_ARGS)
896+
{
897+
FILE *fd;
898+
char lbuffer[MAXPGPATH];
899+
char *logfmt;
900+
char *log_filepath;
901+
char *log_format = lbuffer;
902+
char *nlpos;
903+
904+
/* The log format parameter is optional */
905+
if (PG_NARGS() == 0 || PG_ARGISNULL(0))
906+
logfmt = NULL;
907+
else
908+
{
909+
logfmt = text_to_cstring(PG_GETARG_TEXT_PP(0));
910+
911+
if (strcmp(logfmt, "stderr") != 0 && strcmp(logfmt, "csvlog") != 0)
912+
ereport(ERROR,
913+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
914+
errmsg("log format \"%s\" is not supported", logfmt),
915+
errhint("The supported log formats are \"stderr\" and \"csvlog\".")));
916+
}
917+
918+
fd = AllocateFile(LOG_METAINFO_DATAFILE, "r");
919+
if (fd == NULL)
920+
{
921+
if (errno != ENOENT)
922+
ereport(ERROR,
923+
(errcode_for_file_access(),
924+
errmsg("could not read file \"%s\": %m",
925+
LOG_METAINFO_DATAFILE)));
926+
PG_RETURN_NULL();
927+
}
928+
929+
/*
930+
* Read the file to gather current log filename(s) registered by the
931+
* syslogger.
932+
*/
933+
while (fgets(lbuffer, sizeof(lbuffer), fd) != NULL)
934+
{
935+
/*
936+
* Extract log format and log file path from the line; lbuffer ==
937+
* log_format, they share storage.
938+
*/
939+
log_filepath = strchr(lbuffer, ' ');
940+
if (log_filepath == NULL)
941+
{
942+
/*
943+
* No space found, file content is corrupted. Return NULL to the
944+
* caller and inform him on the situation.
945+
*/
946+
elog(ERROR,
947+
"missing space character in \"%s\"", LOG_METAINFO_DATAFILE);
948+
break;
949+
}
950+
951+
*log_filepath = '\0';
952+
log_filepath++;
953+
nlpos = strchr(log_filepath, '\n');
954+
if (nlpos == NULL)
955+
{
956+
/*
957+
* No newlinei found, file content is corrupted. Return NULL to
958+
* the caller and inform him on the situation.
959+
*/
960+
elog(ERROR,
961+
"missing newline character in \"%s\"", LOG_METAINFO_DATAFILE);
962+
break;
963+
}
964+
*nlpos = '\0';
965+
966+
if (logfmt == NULL || strcmp(logfmt, log_format) == 0)
967+
{
968+
FreeFile(fd);
969+
PG_RETURN_TEXT_P(cstring_to_text(log_filepath));
970+
}
971+
}
972+
973+
/* Close the current log filename file. */
974+
FreeFile(fd);
975+
976+
PG_RETURN_NULL();
977+
}
978+
979+
/*
980+
* Report current log file used by log collector (1 argument version)
981+
*
982+
* note: this wrapper is necessary to pass the sanity check in opr_sanity,
983+
* which checks that all built-in functions that share the implementing C
984+
* function take the same number of arguments
985+
*/
986+
Datum
987+
pg_current_logfile_1arg(PG_FUNCTION_ARGS)
988+
{
989+
return pg_current_logfile(fcinfo);
990+
}

0 commit comments

Comments
 (0)