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"
@@ -133,7 +134,6 @@ static void syslogger_parseArgs(int argc, char *argv[]);
133
134
NON_EXEC_STATIC void SysLoggerMain (int argc , char * argv []) pg_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
@@ -269,11 +269,13 @@ SysLoggerMain(int argc, char *argv[])
269
269
#endif /* WIN32 */
270
270
271
271
/*
272
- * Remember active logfile's name. We recompute this from the reference
272
+ * Remember active logfiles' name(s) . We recompute 'em from the reference
273
273
* time because passing down just the pg_time_t is a lot cheaper than
274
274
* passing a whole file path in the EXEC_BACKEND case.
275
275
*/
276
276
last_file_name = logfile_getname (first_syslogger_file_time , NULL );
277
+ if (csvlogFile != NULL )
278
+ last_csv_file_name = logfile_getname (first_syslogger_file_time , ".csv" );
277
279
278
280
/* remember active logfile parameters */
279
281
currentLogDir = pstrdup (Log_directory );
@@ -282,6 +284,13 @@ SysLoggerMain(int argc, char *argv[])
282
284
/* set next planned rotation time */
283
285
set_next_rotation_time ();
284
286
287
+ /*
288
+ * Reset whereToSendOutput, as the postmaster will do (but hasn't yet, at
289
+ * the point where we forked). This prevents duplicate output of messages
290
+ * from syslogger itself.
291
+ */
292
+ whereToSendOutput = DestNone ;
293
+
285
294
/* main worker loop */
286
295
for (;;)
287
296
{
@@ -328,6 +337,14 @@ SysLoggerMain(int argc, char *argv[])
328
337
rotation_requested = true;
329
338
}
330
339
340
+ /*
341
+ * Force a rotation if CSVLOG output was just turned on or off and
342
+ * we need to open or close csvlogFile accordingly.
343
+ */
344
+ if (((Log_destination & LOG_DESTINATION_CSVLOG ) != 0 ) !=
345
+ (csvlogFile != NULL ))
346
+ rotation_requested = true;
347
+
331
348
/*
332
349
* If rotation time parameter changed, reset next rotation time,
333
350
* but don't immediately force a rotation.
@@ -567,12 +584,27 @@ SysLogger_Start(void)
567
584
* a time-based rotation.
568
585
*/
569
586
first_syslogger_file_time = time (NULL );
587
+
570
588
filename = logfile_getname (first_syslogger_file_time , NULL );
571
589
572
590
syslogFile = logfile_open (filename , "a" , false);
573
591
574
592
pfree (filename );
575
593
594
+ /*
595
+ * Likewise for the initial CSV log file, if that's enabled. (Note that
596
+ * we open syslogFile even when only CSV output is nominally enabled,
597
+ * since some code paths will write to syslogFile anyway.)
598
+ */
599
+ if (Log_destination & LOG_DESTINATION_CSVLOG )
600
+ {
601
+ filename = logfile_getname (first_syslogger_file_time , ".csv" );
602
+
603
+ csvlogFile = logfile_open (filename , "a" , false);
604
+
605
+ pfree (filename );
606
+ }
607
+
576
608
#ifdef EXEC_BACKEND
577
609
switch ((sysloggerPid = syslogger_forkexec ()))
578
610
#else
@@ -662,9 +694,14 @@ SysLogger_Start(void)
662
694
redirection_done = true;
663
695
}
664
696
665
- /* postmaster will never write the file; close it */
697
+ /* postmaster will never write the file(s) ; close 'em */
666
698
fclose (syslogFile );
667
699
syslogFile = NULL ;
700
+ if (csvlogFile != NULL )
701
+ {
702
+ fclose (csvlogFile );
703
+ csvlogFile = NULL ;
704
+ }
668
705
return (int ) sysloggerPid ;
669
706
}
670
707
@@ -686,6 +723,7 @@ syslogger_forkexec(void)
686
723
char * av [10 ];
687
724
int ac = 0 ;
688
725
char filenobuf [32 ];
726
+ char csvfilenobuf [32 ];
689
727
690
728
av [ac ++ ] = "postgres" ;
691
729
av [ac ++ ] = "--forklog" ;
@@ -707,6 +745,21 @@ syslogger_forkexec(void)
707
745
#endif /* WIN32 */
708
746
av [ac ++ ] = filenobuf ;
709
747
748
+ #ifndef WIN32
749
+ if (csvlogFile != NULL )
750
+ snprintf (csvfilenobuf , sizeof (csvfilenobuf ), "%d" ,
751
+ fileno (csvlogFile ));
752
+ else
753
+ strcpy (csvfilenobuf , "-1" );
754
+ #else /* WIN32 */
755
+ if (csvlogFile != NULL )
756
+ snprintf (csvfilenobuf , sizeof (csvfilenobuf ), "%ld" ,
757
+ (long ) _get_osfhandle (_fileno (csvlogFile )));
758
+ else
759
+ strcpy (csvfilenobuf , "0" );
760
+ #endif /* WIN32 */
761
+ av [ac ++ ] = csvfilenobuf ;
762
+
710
763
av [ac ] = NULL ;
711
764
Assert (ac < lengthof (av ));
712
765
@@ -723,16 +776,29 @@ syslogger_parseArgs(int argc, char *argv[])
723
776
{
724
777
int fd ;
725
778
726
- Assert (argc == 4 );
779
+ Assert (argc == 5 );
727
780
argv += 3 ;
728
781
782
+ /*
783
+ * Re-open the error output files that were opened by SysLogger_Start().
784
+ *
785
+ * We expect this will always succeed, which is too optimistic, but if it
786
+ * fails there's not a lot we can do to report the problem anyway. As
787
+ * coded, we'll just crash on a null pointer dereference after failure...
788
+ */
729
789
#ifndef WIN32
730
790
fd = atoi (* argv ++ );
731
791
if (fd != -1 )
732
792
{
733
793
syslogFile = fdopen (fd , "a" );
734
794
setvbuf (syslogFile , NULL , PG_IOLBF , 0 );
735
795
}
796
+ fd = atoi (* argv ++ );
797
+ if (fd != -1 )
798
+ {
799
+ csvlogFile = fdopen (fd , "a" );
800
+ setvbuf (csvlogFile , NULL , PG_IOLBF , 0 );
801
+ }
736
802
#else /* WIN32 */
737
803
fd = atoi (* argv ++ );
738
804
if (fd != 0 )
@@ -744,6 +810,16 @@ syslogger_parseArgs(int argc, char *argv[])
744
810
setvbuf (syslogFile , NULL , PG_IOLBF , 0 );
745
811
}
746
812
}
813
+ fd = atoi (* argv ++ );
814
+ if (fd != 0 )
815
+ {
816
+ fd = _open_osfhandle (fd , _O_APPEND | _O_TEXT );
817
+ if (fd > 0 )
818
+ {
819
+ csvlogFile = fdopen (fd , "a" );
820
+ setvbuf (csvlogFile , NULL , PG_IOLBF , 0 );
821
+ }
822
+ }
747
823
#endif /* WIN32 */
748
824
}
749
825
#endif /* EXEC_BACKEND */
@@ -985,13 +1061,29 @@ write_syslogger_file(const char *buffer, int count, int destination)
985
1061
int rc ;
986
1062
FILE * logfile ;
987
1063
988
- if (destination == LOG_DESTINATION_CSVLOG && csvlogFile == NULL )
989
- open_csvlogfile ();
1064
+ /*
1065
+ * If we're told to write to csvlogFile, but it's not open, dump the data
1066
+ * to syslogFile (which is always open) instead. This can happen if CSV
1067
+ * output is enabled after postmaster start and we've been unable to open
1068
+ * csvlogFile. There are also race conditions during a parameter change
1069
+ * whereby backends might send us CSV output before we open csvlogFile or
1070
+ * after we close it. Writing CSV-formatted output to the regular log
1071
+ * file isn't great, but it beats dropping log output on the floor.
1072
+ *
1073
+ * Think not to improve this by trying to open csvlogFile on-the-fly. Any
1074
+ * failure in that would lead to recursion.
1075
+ */
1076
+ logfile = (destination == LOG_DESTINATION_CSVLOG &&
1077
+ csvlogFile != NULL ) ? csvlogFile : syslogFile ;
990
1078
991
- logfile = destination == LOG_DESTINATION_CSVLOG ? csvlogFile : syslogFile ;
992
1079
rc = fwrite (buffer , 1 , count , logfile );
993
1080
994
- /* can't use ereport here because of possible recursion */
1081
+ /*
1082
+ * Try to report any failure. We mustn't use ereport because it would
1083
+ * just recurse right back here, but write_stderr is OK: it will write
1084
+ * either to the postmaster's original stderr, or to /dev/null, but never
1085
+ * to our input pipe which would result in a different sort of looping.
1086
+ */
995
1087
if (rc != count )
996
1088
write_stderr ("could not write to log file: %s\n" , strerror (errno ));
997
1089
}
@@ -1074,29 +1166,6 @@ pipeThread(void *arg)
1074
1166
}
1075
1167
#endif /* WIN32 */
1076
1168
1077
- /*
1078
- * Open the csv log file - we do this opportunistically, because
1079
- * we don't know if CSV logging will be wanted.
1080
- *
1081
- * This is only used the first time we open the csv log in a given syslogger
1082
- * process, not during rotations. As with opening the main log file, we
1083
- * always append in this situation.
1084
- */
1085
- static void
1086
- open_csvlogfile (void )
1087
- {
1088
- char * filename ;
1089
-
1090
- filename = logfile_getname (time (NULL ), ".csv" );
1091
-
1092
- csvlogFile = logfile_open (filename , "a" , false);
1093
-
1094
- if (last_csv_file_name != NULL ) /* probably shouldn't happen */
1095
- pfree (last_csv_file_name );
1096
-
1097
- last_csv_file_name = filename ;
1098
- }
1099
-
1100
1169
/*
1101
1170
* Open a new logfile with proper permissions and buffering options.
1102
1171
*
@@ -1164,7 +1233,7 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1164
1233
else
1165
1234
fntime = time (NULL );
1166
1235
filename = logfile_getname (fntime , NULL );
1167
- if (csvlogFile != NULL )
1236
+ if (Log_destination & LOG_DESTINATION_CSVLOG )
1168
1237
csvfilename = logfile_getname (fntime , ".csv" );
1169
1238
1170
1239
/*
@@ -1216,10 +1285,16 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1216
1285
filename = NULL ;
1217
1286
}
1218
1287
1219
- /* Same as above, but for csv file. */
1220
-
1221
- if (csvlogFile != NULL &&
1222
- (time_based_rotation || (size_rotation_for & LOG_DESTINATION_CSVLOG )))
1288
+ /*
1289
+ * Same as above, but for csv file. Note that if LOG_DESTINATION_CSVLOG
1290
+ * was just turned on, we might have to open csvlogFile here though it was
1291
+ * not open before. In such a case we'll append not overwrite (since
1292
+ * last_csv_file_name will be NULL); that is consistent with the normal
1293
+ * rules since it's not a time-based rotation.
1294
+ */
1295
+ if ((Log_destination & LOG_DESTINATION_CSVLOG ) &&
1296
+ (csvlogFile == NULL ||
1297
+ time_based_rotation || (size_rotation_for & LOG_DESTINATION_CSVLOG )))
1223
1298
{
1224
1299
if (Log_truncate_on_rotation && time_based_rotation &&
1225
1300
last_csv_file_name != NULL &&
@@ -1250,7 +1325,8 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1250
1325
return ;
1251
1326
}
1252
1327
1253
- fclose (csvlogFile );
1328
+ if (csvlogFile != NULL )
1329
+ fclose (csvlogFile );
1254
1330
csvlogFile = fh ;
1255
1331
1256
1332
/* instead of pfree'ing filename, remember it for next time */
@@ -1259,6 +1335,16 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
1259
1335
last_csv_file_name = csvfilename ;
1260
1336
csvfilename = NULL ;
1261
1337
}
1338
+ else if (!(Log_destination & LOG_DESTINATION_CSVLOG ) &&
1339
+ csvlogFile != NULL )
1340
+ {
1341
+ /* CSVLOG was just turned off, so close the old file */
1342
+ fclose (csvlogFile );
1343
+ csvlogFile = NULL ;
1344
+ if (last_csv_file_name != NULL )
1345
+ pfree (last_csv_file_name );
1346
+ last_csv_file_name = NULL ;
1347
+ }
1262
1348
1263
1349
if (filename )
1264
1350
pfree (filename );
0 commit comments