42
42
#include "storage/ipc.h"
43
43
#include "storage/latch.h"
44
44
#include "storage/pg_shmem.h"
45
+ #include "tcop/tcopprot.h"
45
46
#include "utils/guc.h"
46
47
#include "utils/ps_status.h"
47
48
#include "utils/timestamp.h"
@@ -133,7 +134,6 @@ static void syslogger_parseArgs(int argc, char *argv[]);
133
134
NON_EXEC_STATIC void SysLoggerMain (int argc , char * argv []) __attribute__((noreturn ));
134
135
static void process_pipe_input (char * logbuffer , int * bytes_in_logbuffer );
135
136
static void flush_pipe_input (char * logbuffer , int * bytes_in_logbuffer );
136
- static void open_csvlogfile (void );
137
137
static FILE * logfile_open (const char * filename , const char * mode ,
138
138
bool allow_errors );
139
139
@@ -285,11 +285,13 @@ SysLoggerMain(int argc, char *argv[])
285
285
#endif /* WIN32 */
286
286
287
287
/*
288
- * Remember active logfile's name. We recompute this from the reference
288
+ * Remember active logfiles' name(s) . We recompute 'em from the reference
289
289
* time because passing down just the pg_time_t is a lot cheaper than
290
290
* passing a whole file path in the EXEC_BACKEND case.
291
291
*/
292
292
last_file_name = logfile_getname (first_syslogger_file_time , NULL );
293
+ if (csvlogFile != NULL )
294
+ last_csv_file_name = logfile_getname (first_syslogger_file_time , ".csv" );
293
295
294
296
/* remember active logfile parameters */
295
297
currentLogDir = pstrdup (Log_directory );
@@ -298,6 +300,13 @@ SysLoggerMain(int argc, char *argv[])
298
300
/* set next planned rotation time */
299
301
set_next_rotation_time ();
300
302
303
+ /*
304
+ * Reset whereToSendOutput, as the postmaster will do (but hasn't yet, at
305
+ * the point where we forked). This prevents duplicate output of messages
306
+ * from syslogger itself.
307
+ */
308
+ whereToSendOutput = DestNone ;
309
+
301
310
/* main worker loop */
302
311
for (;;)
303
312
{
@@ -344,6 +353,14 @@ SysLoggerMain(int argc, char *argv[])
344
353
rotation_requested = true;
345
354
}
346
355
356
+ /*
357
+ * Force a rotation if CSVLOG output was just turned on or off and
358
+ * we need to open or close csvlogFile accordingly.
359
+ */
360
+ if (((Log_destination & LOG_DESTINATION_CSVLOG ) != 0 ) !=
361
+ (csvlogFile != NULL ))
362
+ rotation_requested = true;
363
+
347
364
/*
348
365
* If rotation time parameter changed, reset next rotation time,
349
366
* but don't immediately force a rotation.
@@ -583,12 +600,27 @@ SysLogger_Start(void)
583
600
* a time-based rotation.
584
601
*/
585
602
first_syslogger_file_time = time (NULL );
603
+
586
604
filename = logfile_getname (first_syslogger_file_time , NULL );
587
605
588
606
syslogFile = logfile_open (filename , "a" , false);
589
607
590
608
pfree (filename );
591
609
610
+ /*
611
+ * Likewise for the initial CSV log file, if that's enabled. (Note that
612
+ * we open syslogFile even when only CSV output is nominally enabled,
613
+ * since some code paths will write to syslogFile anyway.)
614
+ */
615
+ if (Log_destination & LOG_DESTINATION_CSVLOG )
616
+ {
617
+ filename = logfile_getname (first_syslogger_file_time , ".csv" );
618
+
619
+ csvlogFile = logfile_open (filename , "a" , false);
620
+
621
+ pfree (filename );
622
+ }
623
+
592
624
#ifdef EXEC_BACKEND
593
625
switch ((sysloggerPid = syslogger_forkexec ()))
594
626
#else
@@ -677,9 +709,14 @@ SysLogger_Start(void)
677
709
redirection_done = true;
678
710
}
679
711
680
- /* postmaster will never write the file; close it */
712
+ /* postmaster will never write the file(s) ; close 'em */
681
713
fclose (syslogFile );
682
714
syslogFile = NULL ;
715
+ if (csvlogFile != NULL )
716
+ {
717
+ fclose (csvlogFile );
718
+ csvlogFile = NULL ;
719
+ }
683
720
return (int ) sysloggerPid ;
684
721
}
685
722
@@ -701,6 +738,7 @@ syslogger_forkexec(void)
701
738
char * av [10 ];
702
739
int ac = 0 ;
703
740
char filenobuf [32 ];
741
+ char csvfilenobuf [32 ];
704
742
705
743
av [ac ++ ] = "postgres" ;
706
744
av [ac ++ ] = "--forklog" ;
@@ -722,6 +760,21 @@ syslogger_forkexec(void)
722
760
#endif /* WIN32 */
723
761
av [ac ++ ] = filenobuf ;
724
762
763
+ #ifndef WIN32
764
+ if (csvlogFile != NULL )
765
+ snprintf (csvfilenobuf , sizeof (csvfilenobuf ), "%d" ,
766
+ fileno (csvlogFile ));
767
+ else
768
+ strcpy (csvfilenobuf , "-1" );
769
+ #else /* WIN32 */
770
+ if (csvlogFile != NULL )
771
+ snprintf (csvfilenobuf , sizeof (csvfilenobuf ), "%ld" ,
772
+ (long ) _get_osfhandle (_fileno (csvlogFile )));
773
+ else
774
+ strcpy (csvfilenobuf , "0" );
775
+ #endif /* WIN32 */
776
+ av [ac ++ ] = csvfilenobuf ;
777
+
725
778
av [ac ] = NULL ;
726
779
Assert (ac < lengthof (av ));
727
780
@@ -738,16 +791,29 @@ syslogger_parseArgs(int argc, char *argv[])
738
791
{
739
792
int fd ;
740
793
741
- Assert (argc == 4 );
794
+ Assert (argc == 5 );
742
795
argv += 3 ;
743
796
797
+ /*
798
+ * Re-open the error output files that were opened by SysLogger_Start().
799
+ *
800
+ * We expect this will always succeed, which is too optimistic, but if it
801
+ * fails there's not a lot we can do to report the problem anyway. As
802
+ * coded, we'll just crash on a null pointer dereference after failure...
803
+ */
744
804
#ifndef WIN32
745
805
fd = atoi (* argv ++ );
746
806
if (fd != -1 )
747
807
{
748
808
syslogFile = fdopen (fd , "a" );
749
809
setvbuf (syslogFile , NULL , PG_IOLBF , 0 );
750
810
}
811
+ fd = atoi (* argv ++ );
812
+ if (fd != -1 )
813
+ {
814
+ csvlogFile = fdopen (fd , "a" );
815
+ setvbuf (csvlogFile , NULL , PG_IOLBF , 0 );
816
+ }
751
817
#else /* WIN32 */
752
818
fd = atoi (* argv ++ );
753
819
if (fd != 0 )
@@ -759,6 +825,16 @@ syslogger_parseArgs(int argc, char *argv[])
759
825
setvbuf (syslogFile , NULL , PG_IOLBF , 0 );
760
826
}
761
827
}
828
+ fd = atoi (* argv ++ );
829
+ if (fd != 0 )
830
+ {
831
+ fd = _open_osfhandle (fd , _O_APPEND | _O_TEXT );
832
+ if (fd > 0 )
833
+ {
834
+ csvlogFile = fdopen (fd , "a" );
835
+ setvbuf (csvlogFile , NULL , PG_IOLBF , 0 );
836
+ }
837
+ }
762
838
#endif /* WIN32 */
763
839
}
764
840
#endif /* EXEC_BACKEND */
@@ -1000,13 +1076,29 @@ write_syslogger_file(const char *buffer, int count, int destination)
1000
1076
int rc ;
1001
1077
FILE * logfile ;
1002
1078
1003
- if (destination == LOG_DESTINATION_CSVLOG && csvlogFile == NULL )
1004
- open_csvlogfile ();
1079
+ /*
1080
+ * If we're told to write to csvlogFile, but it's not open, dump the data
1081
+ * to syslogFile (which is always open) instead. This can happen if CSV
1082
+ * output is enabled after postmaster start and we've been unable to open
1083
+ * csvlogFile. There are also race conditions during a parameter change
1084
+ * whereby backends might send us CSV output before we open csvlogFile or
1085
+ * after we close it. Writing CSV-formatted output to the regular log
1086
+ * file isn't great, but it beats dropping log output on the floor.
1087
+ *
1088
+ * Think not to improve this by trying to open csvlogFile on-the-fly. Any
1089
+ * failure in that would lead to recursion.
1090
+ */
1091
+ logfile = (destination == LOG_DESTINATION_CSVLOG &&
1092
+ csvlogFile != NULL ) ? csvlogFile : syslogFile ;
1005
1093
1006
- logfile = destination == LOG_DESTINATION_CSVLOG ? csvlogFile : syslogFile ;
1007
1094
rc = fwrite (buffer , 1 , count , logfile );
1008
1095
1009
- /* can't use ereport here because of possible recursion */
1096
+ /*
1097
+ * Try to report any failure. We mustn't use ereport because it would
1098
+ * just recurse right back here, but write_stderr is OK: it will write
1099
+ * either to the postmaster's original stderr, or to /dev/null, but never
1100
+ * to our input pipe which would result in a different sort of looping.
1101
+ */
1010
1102
if (rc != count )
1011
1103
write_stderr ("could not write to log file: %s\n" , strerror (errno ));
1012
1104
}
@@ -1089,29 +1181,6 @@ pipeThread(void *arg)
1089
1181
}
1090
1182
#endif /* WIN32 */
1091
1183
1092
- /*
1093
- * Open the csv log file - we do this opportunistically, because
1094
- * we don't know if CSV logging will be wanted.
1095
- *
1096
- * This is only used the first time we open the csv log in a given syslogger
1097
- * process, not during rotations. As with opening the main log file, we
1098
- * always append in this situation.
1099
- */
1100
- static void
1101
- open_csvlogfile (void )
1102
- {
1103
- char * filename ;
1104
-
1105
- filename = logfile_getname (time (NULL ), ".csv" );
1106
-
1107
- csvlogFile = logfile_open (filename , "a" , false);
1108
-
1109
- if (last_csv_file_name != NULL ) /* probably shouldn't happen */
1110
- pfree (last_csv_file_name );
1111
-
1112
- last_csv_file_name = filename ;
1113
- }
1114
-
1115
1184
/*
1116
1185
* Open a new logfile with proper permissions and buffering options.
1117
1186
*
@@ -1179,7 +1248,7 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1179
1248
else
1180
1249
fntime = time (NULL );
1181
1250
filename = logfile_getname (fntime , NULL );
1182
- if (csvlogFile != NULL )
1251
+ if (Log_destination & LOG_DESTINATION_CSVLOG )
1183
1252
csvfilename = logfile_getname (fntime , ".csv" );
1184
1253
1185
1254
/*
@@ -1231,10 +1300,16 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1231
1300
filename = NULL ;
1232
1301
}
1233
1302
1234
- /* Same as above, but for csv file. */
1235
-
1236
- if (csvlogFile != NULL &&
1237
- (time_based_rotation || (size_rotation_for & LOG_DESTINATION_CSVLOG )))
1303
+ /*
1304
+ * Same as above, but for csv file. Note that if LOG_DESTINATION_CSVLOG
1305
+ * was just turned on, we might have to open csvlogFile here though it was
1306
+ * not open before. In such a case we'll append not overwrite (since
1307
+ * last_csv_file_name will be NULL); that is consistent with the normal
1308
+ * rules since it's not a time-based rotation.
1309
+ */
1310
+ if ((Log_destination & LOG_DESTINATION_CSVLOG ) &&
1311
+ (csvlogFile == NULL ||
1312
+ time_based_rotation || (size_rotation_for & LOG_DESTINATION_CSVLOG )))
1238
1313
{
1239
1314
if (Log_truncate_on_rotation && time_based_rotation &&
1240
1315
last_csv_file_name != NULL &&
@@ -1265,7 +1340,8 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1265
1340
return ;
1266
1341
}
1267
1342
1268
- fclose (csvlogFile );
1343
+ if (csvlogFile != NULL )
1344
+ fclose (csvlogFile );
1269
1345
csvlogFile = fh ;
1270
1346
1271
1347
/* instead of pfree'ing filename, remember it for next time */
@@ -1274,6 +1350,16 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1274
1350
last_csv_file_name = csvfilename ;
1275
1351
csvfilename = NULL ;
1276
1352
}
1353
+ else if (!(Log_destination & LOG_DESTINATION_CSVLOG ) &&
1354
+ csvlogFile != NULL )
1355
+ {
1356
+ /* CSVLOG was just turned off, so close the old file */
1357
+ fclose (csvlogFile );
1358
+ csvlogFile = NULL ;
1359
+ if (last_csv_file_name != NULL )
1360
+ pfree (last_csv_file_name );
1361
+ last_csv_file_name = NULL ;
1362
+ }
1277
1363
1278
1364
if (filename )
1279
1365
pfree (filename );
0 commit comments