1515#include <time.h>
1616
1717#include "logger.h"
18+ #include "pgut.h"
1819
1920/* Logger parameters */
2021
@@ -25,7 +26,9 @@ char *error_log_filename = NULL;
2526char * log_directory = NULL ;
2627char log_path [MAXPGPATH ]= "" ;
2728
29+ /* Maximum size of an individual log file in kilobytes */
2830int log_rotation_size = 0 ;
31+ /* Maximum lifetime of an individual log file in minutes */
2932int log_rotation_age = 0 ;
3033
3134/* Implementation for logging.h */
@@ -102,7 +105,9 @@ elog_internal(int elevel, const char *fmt, va_list args)
102105{
103106bool wrote_to_file = false;
104107
105- pthread_mutex_lock (& log_file_mutex );
108+ /* There is no need to lock if this is elog() from upper elog() */
109+ if (!logging_to_file )
110+ pthread_mutex_lock (& log_file_mutex );
106111
107112/*
108113 * Write message to log file.
@@ -161,7 +166,8 @@ elog_internal(int elevel, const char *fmt, va_list args)
161166fflush (stderr );
162167}
163168
164- pthread_mutex_unlock (& log_file_mutex );
169+ if (!logging_to_file )
170+ pthread_mutex_unlock (& log_file_mutex );
165171
166172/* Exit with code if it is an error */
167173if (elevel > WARNING )
@@ -329,56 +335,82 @@ static void
329335open_logfile (FILE * * file ,const char * filename_format )
330336{
331337char * filename ;
338+ char control [MAXPGPATH ];
332339struct stat st ;
333- bool rotation_requested = false;
340+ FILE * control_file ;
341+ time_t cur_time = time (NULL );
342+ bool rotation_requested = false,
343+ logfile_exists = false;
334344
335- filename = logfile_getname (filename_format ,time ( NULL ) );
345+ filename = logfile_getname (filename_format ,cur_time );
336346
337- /* First check for rotation */
338- if (log_rotation_size > 0 || log_rotation_age > 0 )
347+ /* "log_path" was checked in logfile_getname() */
348+ snprintf (control ,MAXPGPATH ,"%s/log_rotation" ,log_path );
349+
350+ if (stat (filename ,& st )== -1 )
339351{
340- if (stat ( filename , & st ) == -1 )
352+ if (errno == ENOENT )
341353{
342- if (errno == ENOENT )
343- {
344- /* There is no file "filename" and rotation does not need */
345- gotologfile_open ;
346- }
347- else
348- elog (ERROR ,"cannot stat log file \"%s\": %s" ,
349- filename ,strerror (errno ));
354+ /* There is no file "filename" and rotation does not need */
355+ gotologfile_open ;
350356}
351- /* Found log file "filename" */
357+ else
358+ elog (ERROR ,"cannot stat log file \"%s\": %s" ,
359+ filename ,strerror (errno ));
360+ }
361+ /* Found log file "filename" */
362+ logfile_exists = true;
352363
364+ /* First check for rotation */
365+ if (log_rotation_size > 0 || log_rotation_age > 0 )
366+ {
353367/* Check for rotation by age */
354368if (log_rotation_age > 0 )
355369{
356- char control [MAXPGPATH ];
357370struct stat control_st ;
358- FILE * control_file ;
359371
360- snprintf (control ,MAXPGPATH ,"%s.rotation" ,filename );
361372if (stat (control ,& control_st )== -1 )
362373{
363- if (errno == ENOENT )
364- {
365- /* There is no control file for rotation */
366- gotologfile_open ;
367- }
368- else
374+ if (errno != ENOENT )
369375elog (ERROR ,"cannot stat rotation file \"%s\": %s" ,
370376control ,strerror (errno ));
371377}
378+ else
379+ {
380+ char buf [1024 ];
372381
373- /* Found control file for rotation */
382+ control_file = fopen (control ,"r" );
383+ if (control_file == NULL )
384+ elog (ERROR ,"cannot open rotation file \"%s\": %s" ,
385+ control ,strerror (errno ));
386+
387+ if (fgets (buf ,lengthof (buf ),control_file ))
388+ {
389+ time_t creation_time ;
390+
391+ if (!parse_int64 (buf , (int64 * )& creation_time ))
392+ elog (ERROR ,"rotation file \"%s\" has wrong "
393+ "creation timestamp \"%s\"" ,
394+ control ,buf );
395+ /* Parsed creation time */
396+
397+ rotation_requested = (cur_time - creation_time )>
398+ /* convert to seconds */
399+ log_rotation_age * 60 ;
400+ }
401+ else
402+ elog (ERROR ,"cannot read creation timestamp from "
403+ "rotation file \"%s\"" ,control );
374404
375- control_file = fopen ( control , "r" );
376- fclose ( control_file );
405+ fclose ( control_file );
406+ }
377407}
378408
379409/* Check for rotation by size */
380410if (!rotation_requested && log_rotation_size > 0 )
381- rotation_requested = (st .st_size >=log_rotation_size * 1024L );
411+ rotation_requested = st .st_size >=
412+ /* convert to bytes */
413+ log_rotation_size * 1024L ;
382414}
383415
384416logfile_open :
@@ -388,6 +420,21 @@ open_logfile(FILE **file, const char *filename_format)
388420* file = logfile_open (filename ,"a" );
389421pfree (filename );
390422
423+ /* Rewrite rotation control file */
424+ if (rotation_requested || !logfile_exists )
425+ {
426+ time_t timestamp = time (NULL );
427+
428+ control_file = fopen (control ,"w" );
429+ if (control_file == NULL )
430+ elog (ERROR ,"cannot open rotation file \"%s\": %s" ,
431+ control ,strerror (errno ));
432+
433+ fprintf (control_file ,"%ld" ,timestamp );
434+
435+ fclose (control_file );
436+ }
437+
391438/*
392439 * Arrange to close opened file at proc_exit.
393440 */