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