43
43
#include "storage/ipc.h"
44
44
#include "storage/latch.h"
45
45
#include "storage/pg_shmem.h"
46
+ #include "tcop/tcopprot.h"
46
47
#include "utils/guc.h"
47
48
#include "utils/ps_status.h"
48
49
#include "utils/timestamp.h"
@@ -134,7 +135,6 @@ static void syslogger_parseArgs(int argc, char *argv[]);
134
135
NON_EXEC_STATIC void SysLoggerMain (int argc , char * argv []) __attribute__((noreturn ));
135
136
static void process_pipe_input (char * logbuffer , int * bytes_in_logbuffer );
136
137
static void flush_pipe_input (char * logbuffer , int * bytes_in_logbuffer );
137
- static void open_csvlogfile (void );
138
138
static FILE * logfile_open (const char * filename , const char * mode ,
139
139
bool allow_errors );
140
140
@@ -291,11 +291,13 @@ SysLoggerMain(int argc, char *argv[])
291
291
#endif /* WIN32 */
292
292
293
293
/*
294
- * Remember active logfile's name. We recompute this from the reference
294
+ * Remember active logfiles' name(s) . We recompute 'em from the reference
295
295
* time because passing down just the pg_time_t is a lot cheaper than
296
296
* passing a whole file path in the EXEC_BACKEND case.
297
297
*/
298
298
last_file_name = logfile_getname (first_syslogger_file_time , NULL );
299
+ if (csvlogFile != NULL )
300
+ last_csv_file_name = logfile_getname (first_syslogger_file_time , ".csv" );
299
301
300
302
/* remember active logfile parameters */
301
303
currentLogDir = pstrdup (Log_directory );
@@ -304,6 +306,13 @@ SysLoggerMain(int argc, char *argv[])
304
306
/* set next planned rotation time */
305
307
set_next_rotation_time ();
306
308
309
+ /*
310
+ * Reset whereToSendOutput, as the postmaster will do (but hasn't yet, at
311
+ * the point where we forked). This prevents duplicate output of messages
312
+ * from syslogger itself.
313
+ */
314
+ whereToSendOutput = DestNone ;
315
+
307
316
/* main worker loop */
308
317
for (;;)
309
318
{
@@ -350,6 +359,14 @@ SysLoggerMain(int argc, char *argv[])
350
359
rotation_requested = true;
351
360
}
352
361
362
+ /*
363
+ * Force a rotation if CSVLOG output was just turned on or off and
364
+ * we need to open or close csvlogFile accordingly.
365
+ */
366
+ if (((Log_destination & LOG_DESTINATION_CSVLOG ) != 0 ) !=
367
+ (csvlogFile != NULL ))
368
+ rotation_requested = true;
369
+
353
370
/*
354
371
* If rotation time parameter changed, reset next rotation time,
355
372
* but don't immediately force a rotation.
@@ -589,12 +606,27 @@ SysLogger_Start(void)
589
606
* a time-based rotation.
590
607
*/
591
608
first_syslogger_file_time = time (NULL );
609
+
592
610
filename = logfile_getname (first_syslogger_file_time , NULL );
593
611
594
612
syslogFile = logfile_open (filename , "a" , false);
595
613
596
614
pfree (filename );
597
615
616
+ /*
617
+ * Likewise for the initial CSV log file, if that's enabled. (Note that
618
+ * we open syslogFile even when only CSV output is nominally enabled,
619
+ * since some code paths will write to syslogFile anyway.)
620
+ */
621
+ if (Log_destination & LOG_DESTINATION_CSVLOG )
622
+ {
623
+ filename = logfile_getname (first_syslogger_file_time , ".csv" );
624
+
625
+ csvlogFile = logfile_open (filename , "a" , false);
626
+
627
+ pfree (filename );
628
+ }
629
+
598
630
#ifdef EXEC_BACKEND
599
631
switch ((sysloggerPid = syslogger_forkexec ()))
600
632
#else
@@ -685,9 +717,14 @@ SysLogger_Start(void)
685
717
redirection_done = true;
686
718
}
687
719
688
- /* postmaster will never write the file; close it */
720
+ /* postmaster will never write the file(s) ; close 'em */
689
721
fclose (syslogFile );
690
722
syslogFile = NULL ;
723
+ if (csvlogFile != NULL )
724
+ {
725
+ fclose (csvlogFile );
726
+ csvlogFile = NULL ;
727
+ }
691
728
return (int ) sysloggerPid ;
692
729
}
693
730
@@ -709,6 +746,7 @@ syslogger_forkexec(void)
709
746
char * av [10 ];
710
747
int ac = 0 ;
711
748
char filenobuf [32 ];
749
+ char csvfilenobuf [32 ];
712
750
713
751
av [ac ++ ] = "postgres" ;
714
752
av [ac ++ ] = "--forklog" ;
@@ -730,6 +768,21 @@ syslogger_forkexec(void)
730
768
#endif /* WIN32 */
731
769
av [ac ++ ] = filenobuf ;
732
770
771
+ #ifndef WIN32
772
+ if (csvlogFile != NULL )
773
+ snprintf (csvfilenobuf , sizeof (csvfilenobuf ), "%d" ,
774
+ fileno (csvlogFile ));
775
+ else
776
+ strcpy (csvfilenobuf , "-1" );
777
+ #else /* WIN32 */
778
+ if (csvlogFile != NULL )
779
+ snprintf (csvfilenobuf , sizeof (csvfilenobuf ), "%ld" ,
780
+ (long ) _get_osfhandle (_fileno (csvlogFile )));
781
+ else
782
+ strcpy (csvfilenobuf , "0" );
783
+ #endif /* WIN32 */
784
+ av [ac ++ ] = csvfilenobuf ;
785
+
733
786
av [ac ] = NULL ;
734
787
Assert (ac < lengthof (av ));
735
788
@@ -746,16 +799,29 @@ syslogger_parseArgs(int argc, char *argv[])
746
799
{
747
800
int fd ;
748
801
749
- Assert (argc == 4 );
802
+ Assert (argc == 5 );
750
803
argv += 3 ;
751
804
805
+ /*
806
+ * Re-open the error output files that were opened by SysLogger_Start().
807
+ *
808
+ * We expect this will always succeed, which is too optimistic, but if it
809
+ * fails there's not a lot we can do to report the problem anyway. As
810
+ * coded, we'll just crash on a null pointer dereference after failure...
811
+ */
752
812
#ifndef WIN32
753
813
fd = atoi (* argv ++ );
754
814
if (fd != -1 )
755
815
{
756
816
syslogFile = fdopen (fd , "a" );
757
817
setvbuf (syslogFile , NULL , PG_IOLBF , 0 );
758
818
}
819
+ fd = atoi (* argv ++ );
820
+ if (fd != -1 )
821
+ {
822
+ csvlogFile = fdopen (fd , "a" );
823
+ setvbuf (csvlogFile , NULL , PG_IOLBF , 0 );
824
+ }
759
825
#else /* WIN32 */
760
826
fd = atoi (* argv ++ );
761
827
if (fd != 0 )
@@ -767,6 +833,16 @@ syslogger_parseArgs(int argc, char *argv[])
767
833
setvbuf (syslogFile , NULL , PG_IOLBF , 0 );
768
834
}
769
835
}
836
+ fd = atoi (* argv ++ );
837
+ if (fd != 0 )
838
+ {
839
+ fd = _open_osfhandle (fd , _O_APPEND | _O_TEXT );
840
+ if (fd > 0 )
841
+ {
842
+ csvlogFile = fdopen (fd , "a" );
843
+ setvbuf (csvlogFile , NULL , PG_IOLBF , 0 );
844
+ }
845
+ }
770
846
#endif /* WIN32 */
771
847
}
772
848
#endif /* EXEC_BACKEND */
@@ -1008,13 +1084,29 @@ write_syslogger_file(const char *buffer, int count, int destination)
1008
1084
int rc ;
1009
1085
FILE * logfile ;
1010
1086
1011
- if (destination == LOG_DESTINATION_CSVLOG && csvlogFile == NULL )
1012
- open_csvlogfile ();
1087
+ /*
1088
+ * If we're told to write to csvlogFile, but it's not open, dump the data
1089
+ * to syslogFile (which is always open) instead. This can happen if CSV
1090
+ * output is enabled after postmaster start and we've been unable to open
1091
+ * csvlogFile. There are also race conditions during a parameter change
1092
+ * whereby backends might send us CSV output before we open csvlogFile or
1093
+ * after we close it. Writing CSV-formatted output to the regular log
1094
+ * file isn't great, but it beats dropping log output on the floor.
1095
+ *
1096
+ * Think not to improve this by trying to open csvlogFile on-the-fly. Any
1097
+ * failure in that would lead to recursion.
1098
+ */
1099
+ logfile = (destination == LOG_DESTINATION_CSVLOG &&
1100
+ csvlogFile != NULL ) ? csvlogFile : syslogFile ;
1013
1101
1014
- logfile = destination == LOG_DESTINATION_CSVLOG ? csvlogFile : syslogFile ;
1015
1102
rc = fwrite (buffer , 1 , count , logfile );
1016
1103
1017
- /* can't use ereport here because of possible recursion */
1104
+ /*
1105
+ * Try to report any failure. We mustn't use ereport because it would
1106
+ * just recurse right back here, but write_stderr is OK: it will write
1107
+ * either to the postmaster's original stderr, or to /dev/null, but never
1108
+ * to our input pipe which would result in a different sort of looping.
1109
+ */
1018
1110
if (rc != count )
1019
1111
write_stderr ("could not write to log file: %s\n" , strerror (errno ));
1020
1112
}
@@ -1097,29 +1189,6 @@ pipeThread(void *arg)
1097
1189
}
1098
1190
#endif /* WIN32 */
1099
1191
1100
- /*
1101
- * Open the csv log file - we do this opportunistically, because
1102
- * we don't know if CSV logging will be wanted.
1103
- *
1104
- * This is only used the first time we open the csv log in a given syslogger
1105
- * process, not during rotations. As with opening the main log file, we
1106
- * always append in this situation.
1107
- */
1108
- static void
1109
- open_csvlogfile (void )
1110
- {
1111
- char * filename ;
1112
-
1113
- filename = logfile_getname (time (NULL ), ".csv" );
1114
-
1115
- csvlogFile = logfile_open (filename , "a" , false);
1116
-
1117
- if (last_csv_file_name != NULL ) /* probably shouldn't happen */
1118
- pfree (last_csv_file_name );
1119
-
1120
- last_csv_file_name = filename ;
1121
- }
1122
-
1123
1192
/*
1124
1193
* Open a new logfile with proper permissions and buffering options.
1125
1194
*
@@ -1187,7 +1256,7 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1187
1256
else
1188
1257
fntime = time (NULL );
1189
1258
filename = logfile_getname (fntime , NULL );
1190
- if (csvlogFile != NULL )
1259
+ if (Log_destination & LOG_DESTINATION_CSVLOG )
1191
1260
csvfilename = logfile_getname (fntime , ".csv" );
1192
1261
1193
1262
/*
@@ -1239,10 +1308,16 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1239
1308
filename = NULL ;
1240
1309
}
1241
1310
1242
- /* Same as above, but for csv file. */
1243
-
1244
- if (csvlogFile != NULL &&
1245
- (time_based_rotation || (size_rotation_for & LOG_DESTINATION_CSVLOG )))
1311
+ /*
1312
+ * Same as above, but for csv file. Note that if LOG_DESTINATION_CSVLOG
1313
+ * was just turned on, we might have to open csvlogFile here though it was
1314
+ * not open before. In such a case we'll append not overwrite (since
1315
+ * last_csv_file_name will be NULL); that is consistent with the normal
1316
+ * rules since it's not a time-based rotation.
1317
+ */
1318
+ if ((Log_destination & LOG_DESTINATION_CSVLOG ) &&
1319
+ (csvlogFile == NULL ||
1320
+ time_based_rotation || (size_rotation_for & LOG_DESTINATION_CSVLOG )))
1246
1321
{
1247
1322
if (Log_truncate_on_rotation && time_based_rotation &&
1248
1323
last_csv_file_name != NULL &&
@@ -1273,7 +1348,8 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1273
1348
return ;
1274
1349
}
1275
1350
1276
- fclose (csvlogFile );
1351
+ if (csvlogFile != NULL )
1352
+ fclose (csvlogFile );
1277
1353
csvlogFile = fh ;
1278
1354
1279
1355
/* instead of pfree'ing filename, remember it for next time */
@@ -1282,6 +1358,16 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1282
1358
last_csv_file_name = csvfilename ;
1283
1359
csvfilename = NULL ;
1284
1360
}
1361
+ else if (!(Log_destination & LOG_DESTINATION_CSVLOG ) &&
1362
+ csvlogFile != NULL )
1363
+ {
1364
+ /* CSVLOG was just turned off, so close the old file */
1365
+ fclose (csvlogFile );
1366
+ csvlogFile = NULL ;
1367
+ if (last_csv_file_name != NULL )
1368
+ pfree (last_csv_file_name );
1369
+ last_csv_file_name = NULL ;
1370
+ }
1285
1371
1286
1372
if (filename )
1287
1373
pfree (filename );
0 commit comments