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