Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5c6e33f

Browse files
committed
Refactor per-destination file rotation in logging collector
stderr and csvlog have been using duplicated code when it came to the rotation of their file by size, age or if forced by a user request (pg_ctl logrotate or the SQL function pg_rotate_logfile). The main difference between both is that stderr requires its file to always be opened, so as it is possible to have a redirection route if the logging collector is not ready yet to do its work if alternate destinations are enabled. Also, if csvlog gets disabled, we need to close properly its meta-data stored in the logging collector (last file name for current_logfiles and fd currently open for business). Except for those points, the code is the same in terms of error handling and if a file should be created or just continued. This change makes the code simpler overall, and it will help in the introduction of more file-based log destinations. This refactoring is similar to the work done in 5b0b699. Most of the duplication originates from fd801f4. Some of the TAP tests of pg_ctl check the case of a forced log rotation, but this is somewhat limited as there is no coverage for log_rotation_age or log_rotation_size (these may not be worth the extra resources to run either), and no coverage for reload of log_destination with different combinations of stderr and csvlog. I have tested all those cases separately for this refactoring. Author: Michael Paquier Discussion: https://postgr.es/m/CAH7T-aqswBM6JWe4pDehi1uOiufqe06DJWaU5=X7dDLyqUExHg@mail.gmail.com
1 parent 3071bbf commit 5c6e33f

File tree

1 file changed

+113
-116
lines changed

1 file changed

+113
-116
lines changed

src/backend/postmaster/syslogger.c

+113-116
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ static bool rotation_disabled = false;
8787
static FILE *syslogFile = NULL;
8888
static FILE *csvlogFile = NULL;
8989
NON_EXEC_STATIC pg_time_t first_syslogger_file_time = 0;
90-
static char *last_file_name = NULL;
90+
static char *last_sys_file_name = NULL;
9191
static char *last_csv_file_name = NULL;
9292

9393
/*
@@ -145,6 +145,10 @@ static FILE *logfile_open(const char *filename, const char *mode,
145145
static unsigned int __stdcall pipeThread(void *arg);
146146
#endif
147147
static void logfile_rotate(bool time_based_rotation, int size_rotation_for);
148+
static bool logfile_rotate_dest(bool time_based_rotation,
149+
int size_rotation_for, pg_time_t fntime,
150+
int target_dest, char **last_file_name,
151+
FILE **logFile);
148152
static char *logfile_getname(pg_time_t timestamp, const char *suffix);
149153
static void set_next_rotation_time(void);
150154
static void sigUsr1Handler(SIGNAL_ARGS);
@@ -274,7 +278,7 @@ SysLoggerMain(int argc, char *argv[])
274278
* time because passing down just the pg_time_t is a lot cheaper than
275279
* passing a whole file path in the EXEC_BACKEND case.
276280
*/
277-
last_file_name = logfile_getname(first_syslogger_file_time, NULL);
281+
last_sys_file_name = logfile_getname(first_syslogger_file_time, NULL);
278282
if (csvlogFile != NULL)
279283
last_csv_file_name = logfile_getname(first_syslogger_file_time, ".csv");
280284

@@ -1242,145 +1246,138 @@ logfile_open(const char *filename, const char *mode, bool allow_errors)
12421246
}
12431247

12441248
/*
1245-
* perform logfile rotation
1249+
* Do logfile rotation for a single destination, as specified by target_dest.
1250+
* The information stored in *last_file_name and *logFile is updated on a
1251+
* successful file rotation.
1252+
*
1253+
* Returns false if the rotation has been stopped, or true to move on to
1254+
* the processing of other formats.
12461255
*/
1247-
static void
1248-
logfile_rotate(bool time_based_rotation, int size_rotation_for)
1256+
static bool
1257+
logfile_rotate_dest(bool time_based_rotation, int size_rotation_for,
1258+
pg_time_t fntime, int target_dest,
1259+
char **last_file_name, FILE **logFile)
12491260
{
1261+
char *logFileExt;
12501262
char *filename;
1251-
char *csvfilename = NULL;
1252-
pg_time_t fntime;
12531263
FILE *fh;
12541264

1255-
rotation_requested = false;
1265+
/*
1266+
* If the target destination was just turned off, close the previous file
1267+
* and unregister its data. This cannot happen for stderr as syslogFile
1268+
* is assumed to be always opened even if stderr is disabled in
1269+
* log_destination.
1270+
*/
1271+
if ((Log_destination & target_dest) == 0 &&
1272+
target_dest != LOG_DESTINATION_STDERR)
1273+
{
1274+
if (*logFile != NULL)
1275+
fclose(*logFile);
1276+
*logFile = NULL;
1277+
if (*last_file_name != NULL)
1278+
pfree(*last_file_name);
1279+
*last_file_name = NULL;
1280+
return true;
1281+
}
12561282

12571283
/*
1258-
* When doing a time-based rotation, invent the new logfile name based on
1259-
* the planned rotation time, not current time, to avoid "slippage" in the
1260-
* file name when we don't do the rotation immediately.
1284+
* Leave if it is not time for a rotation or if the target destination has
1285+
* no need to do a rotation based on the size of its file.
12611286
*/
1262-
if (time_based_rotation)
1263-
fntime = next_rotation_time;
1287+
if (!time_based_rotation && (size_rotation_for & target_dest) == 0)
1288+
return true;
1289+
1290+
/* file extension depends on the destination type */
1291+
if (target_dest == LOG_DESTINATION_STDERR)
1292+
logFileExt = NULL;
1293+
else if (target_dest == LOG_DESTINATION_CSVLOG)
1294+
logFileExt = ".csv";
12641295
else
1265-
fntime = time(NULL);
1266-
filename = logfile_getname(fntime, NULL);
1267-
if (Log_destination & LOG_DESTINATION_CSVLOG)
1268-
csvfilename = logfile_getname(fntime, ".csv");
1296+
{
1297+
/* cannot happen */
1298+
Assert(false);
1299+
}
1300+
1301+
/* build the new file name */
1302+
filename = logfile_getname(fntime, logFileExt);
12691303

12701304
/*
12711305
* Decide whether to overwrite or append. We can overwrite if (a)
12721306
* Log_truncate_on_rotation is set, (b) the rotation was triggered by
12731307
* elapsed time and not something else, and (c) the computed file name is
12741308
* different from what we were previously logging into.
1275-
*
1276-
* Note: last_file_name should never be NULL here, but if it is, append.
12771309
*/
1278-
if (time_based_rotation || (size_rotation_for & LOG_DESTINATION_STDERR))
1279-
{
1280-
if (Log_truncate_on_rotation && time_based_rotation &&
1281-
last_file_name != NULL &&
1282-
strcmp(filename, last_file_name) != 0)
1283-
fh = logfile_open(filename, "w", true);
1284-
else
1285-
fh = logfile_open(filename, "a", true);
1310+
if (Log_truncate_on_rotation && time_based_rotation &&
1311+
*last_file_name != NULL &&
1312+
strcmp(filename, *last_file_name) != 0)
1313+
fh = logfile_open(filename, "w", true);
1314+
else
1315+
fh = logfile_open(filename, "a", true);
12861316

1287-
if (!fh)
1317+
if (!fh)
1318+
{
1319+
/*
1320+
* ENFILE/EMFILE are not too surprising on a busy system; just keep
1321+
* using the old file till we manage to get a new one. Otherwise,
1322+
* assume something's wrong with Log_directory and stop trying to
1323+
* create files.
1324+
*/
1325+
if (errno != ENFILE && errno != EMFILE)
12881326
{
1289-
/*
1290-
* ENFILE/EMFILE are not too surprising on a busy system; just
1291-
* keep using the old file till we manage to get a new one.
1292-
* Otherwise, assume something's wrong with Log_directory and stop
1293-
* trying to create files.
1294-
*/
1295-
if (errno != ENFILE && errno != EMFILE)
1296-
{
1297-
ereport(LOG,
1298-
(errmsg("disabling automatic rotation (use SIGHUP to re-enable)")));
1299-
rotation_disabled = true;
1300-
}
1301-
1302-
if (filename)
1303-
pfree(filename);
1304-
if (csvfilename)
1305-
pfree(csvfilename);
1306-
return;
1327+
ereport(LOG,
1328+
(errmsg("disabling automatic rotation (use SIGHUP to re-enable)")));
1329+
rotation_disabled = true;
13071330
}
13081331

1309-
fclose(syslogFile);
1310-
syslogFile = fh;
1311-
1312-
/* instead of pfree'ing filename, remember it for next time */
1313-
if (last_file_name != NULL)
1314-
pfree(last_file_name);
1315-
last_file_name = filename;
1316-
filename = NULL;
1332+
if (filename)
1333+
pfree(filename);
1334+
return false;
13171335
}
13181336

1319-
/*
1320-
* Same as above, but for csv file. Note that if LOG_DESTINATION_CSVLOG
1321-
* was just turned on, we might have to open csvlogFile here though it was
1322-
* not open before. In such a case we'll append not overwrite (since
1323-
* last_csv_file_name will be NULL); that is consistent with the normal
1324-
* rules since it's not a time-based rotation.
1325-
*/
1326-
if ((Log_destination & LOG_DESTINATION_CSVLOG) &&
1327-
(csvlogFile == NULL ||
1328-
time_based_rotation || (size_rotation_for & LOG_DESTINATION_CSVLOG)))
1329-
{
1330-
if (Log_truncate_on_rotation && time_based_rotation &&
1331-
last_csv_file_name != NULL &&
1332-
strcmp(csvfilename, last_csv_file_name) != 0)
1333-
fh = logfile_open(csvfilename, "w", true);
1334-
else
1335-
fh = logfile_open(csvfilename, "a", true);
1337+
/* fill in the new information */
1338+
if (*logFile != NULL)
1339+
fclose(*logFile);
1340+
*logFile = fh;
13361341

1337-
if (!fh)
1338-
{
1339-
/*
1340-
* ENFILE/EMFILE are not too surprising on a busy system; just
1341-
* keep using the old file till we manage to get a new one.
1342-
* Otherwise, assume something's wrong with Log_directory and stop
1343-
* trying to create files.
1344-
*/
1345-
if (errno != ENFILE && errno != EMFILE)
1346-
{
1347-
ereport(LOG,
1348-
(errmsg("disabling automatic rotation (use SIGHUP to re-enable)")));
1349-
rotation_disabled = true;
1350-
}
1342+
/* instead of pfree'ing filename, remember it for next time */
1343+
if (*last_file_name != NULL)
1344+
pfree(*last_file_name);
1345+
*last_file_name = filename;
13511346

1352-
if (filename)
1353-
pfree(filename);
1354-
if (csvfilename)
1355-
pfree(csvfilename);
1356-
return;
1357-
}
1347+
return true;
1348+
}
1349+
1350+
/*
1351+
* perform logfile rotation
1352+
*/
1353+
static void
1354+
logfile_rotate(bool time_based_rotation, int size_rotation_for)
1355+
{
1356+
pg_time_t fntime;
13581357

1359-
if (csvlogFile != NULL)
1360-
fclose(csvlogFile);
1361-
csvlogFile = fh;
1358+
rotation_requested = false;
13621359

1363-
/* instead of pfree'ing filename, remember it for next time */
1364-
if (last_csv_file_name != NULL)
1365-
pfree(last_csv_file_name);
1366-
last_csv_file_name = csvfilename;
1367-
csvfilename = NULL;
1368-
}
1369-
else if (!(Log_destination & LOG_DESTINATION_CSVLOG) &&
1370-
csvlogFile != NULL)
1371-
{
1372-
/* CSVLOG was just turned off, so close the old file */
1373-
fclose(csvlogFile);
1374-
csvlogFile = NULL;
1375-
if (last_csv_file_name != NULL)
1376-
pfree(last_csv_file_name);
1377-
last_csv_file_name = NULL;
1378-
}
1360+
/*
1361+
* When doing a time-based rotation, invent the new logfile name based on
1362+
* the planned rotation time, not current time, to avoid "slippage" in the
1363+
* file name when we don't do the rotation immediately.
1364+
*/
1365+
if (time_based_rotation)
1366+
fntime = next_rotation_time;
1367+
else
1368+
fntime = time(NULL);
13791369

1380-
if (filename)
1381-
pfree(filename);
1382-
if (csvfilename)
1383-
pfree(csvfilename);
1370+
/* file rotation for stderr */
1371+
if (!logfile_rotate_dest(time_based_rotation, size_rotation_for, fntime,
1372+
LOG_DESTINATION_STDERR, &last_sys_file_name,
1373+
&syslogFile))
1374+
return;
1375+
1376+
/* file rotation for csvlog */
1377+
if (!logfile_rotate_dest(time_based_rotation, size_rotation_for, fntime,
1378+
LOG_DESTINATION_CSVLOG, &last_csv_file_name,
1379+
&csvlogFile))
1380+
return;
13841381

13851382
update_metainfo_datafile();
13861383

@@ -1501,9 +1498,9 @@ update_metainfo_datafile(void)
15011498
return;
15021499
}
15031500

1504-
if (last_file_name && (Log_destination & LOG_DESTINATION_STDERR))
1501+
if (last_sys_file_name && (Log_destination & LOG_DESTINATION_STDERR))
15051502
{
1506-
if (fprintf(fh, "stderr %s\n", last_file_name) < 0)
1503+
if (fprintf(fh, "stderr %s\n", last_sys_file_name) < 0)
15071504
{
15081505
ereport(LOG,
15091506
(errcode_for_file_access(),

0 commit comments

Comments
 (0)