00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "postgres.h"
00025
00026 #include <fcntl.h>
00027 #include <limits.h>
00028 #include <signal.h>
00029 #include <time.h>
00030 #include <unistd.h>
00031 #include <sys/stat.h>
00032 #include <sys/time.h>
00033
00034 #include "lib/stringinfo.h"
00035 #include "libpq/pqsignal.h"
00036 #include "miscadmin.h"
00037 #include "nodes/pg_list.h"
00038 #include "pgtime.h"
00039 #include "postmaster/fork_process.h"
00040 #include "postmaster/postmaster.h"
00041 #include "postmaster/syslogger.h"
00042 #include "storage/ipc.h"
00043 #include "storage/latch.h"
00044 #include "storage/pg_shmem.h"
00045 #include "utils/guc.h"
00046 #include "utils/ps_status.h"
00047 #include "utils/timestamp.h"
00048
00049
00050
00051
00052
00053
00054 #ifdef WIN32
00055 #define LBF_MODE _IONBF
00056 #else
00057 #define LBF_MODE _IOLBF
00058 #endif
00059
00060
00061
00062
00063
00064
00065 #define READ_BUF_SIZE (2 * PIPE_CHUNK_SIZE)
00066
00067
00068
00069
00070
00071
00072 bool Logging_collector = false;
00073 int Log_RotationAge = HOURS_PER_DAY * MINS_PER_HOUR;
00074 int Log_RotationSize = 10 * 1024;
00075 char *Log_directory = NULL;
00076 char *Log_filename = NULL;
00077 bool Log_truncate_on_rotation = false;
00078 int Log_file_mode = S_IRUSR | S_IWUSR;
00079
00080
00081
00082
00083 bool am_syslogger = false;
00084
00085 extern bool redirection_done;
00086
00087
00088
00089
00090 static pg_time_t next_rotation_time;
00091 static bool pipe_eof_seen = false;
00092 static bool rotation_disabled = false;
00093 static FILE *syslogFile = NULL;
00094 static FILE *csvlogFile = NULL;
00095 NON_EXEC_STATIC pg_time_t first_syslogger_file_time = 0;
00096 static char *last_file_name = NULL;
00097 static char *last_csv_file_name = NULL;
00098 static Latch sysLoggerLatch;
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 typedef struct
00112 {
00113 int32 pid;
00114 StringInfoData data;
00115 } save_buffer;
00116
00117 #define NBUFFER_LISTS 256
00118 static List *buffer_lists[NBUFFER_LISTS];
00119
00120
00121 #ifndef WIN32
00122 int syslogPipe[2] = {-1, -1};
00123 #else
00124 HANDLE syslogPipe[2] = {0, 0};
00125 #endif
00126
00127 #ifdef WIN32
00128 static HANDLE threadHandle = 0;
00129 static CRITICAL_SECTION sysloggerSection;
00130 #endif
00131
00132
00133
00134
00135 static volatile sig_atomic_t got_SIGHUP = false;
00136 static volatile sig_atomic_t rotation_requested = false;
00137
00138
00139
00140 #ifdef EXEC_BACKEND
00141 static pid_t syslogger_forkexec(void);
00142 static void syslogger_parseArgs(int argc, char *argv[]);
00143 #endif
00144 NON_EXEC_STATIC void SysLoggerMain(int argc, char *argv[]) __attribute__((noreturn));
00145 static void process_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
00146 static void flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
00147 static void open_csvlogfile(void);
00148 static FILE *logfile_open(const char *filename, const char *mode,
00149 bool allow_errors);
00150
00151 #ifdef WIN32
00152 static unsigned int __stdcall pipeThread(void *arg);
00153 #endif
00154 static void logfile_rotate(bool time_based_rotation, int size_rotation_for);
00155 static char *logfile_getname(pg_time_t timestamp, const char *suffix);
00156 static void set_next_rotation_time(void);
00157 static void sigHupHandler(SIGNAL_ARGS);
00158 static void sigUsr1Handler(SIGNAL_ARGS);
00159
00160
00161
00162
00163
00164
00165 NON_EXEC_STATIC void
00166 SysLoggerMain(int argc, char *argv[])
00167 {
00168 #ifndef WIN32
00169 char logbuffer[READ_BUF_SIZE];
00170 int bytes_in_logbuffer = 0;
00171 #endif
00172 char *currentLogDir;
00173 char *currentLogFilename;
00174 int currentLogRotationAge;
00175 pg_time_t now;
00176
00177 IsUnderPostmaster = true;
00178
00179 MyProcPid = getpid();
00180
00181 MyStartTime = time(NULL);
00182 now = MyStartTime;
00183
00184 #ifdef EXEC_BACKEND
00185 syslogger_parseArgs(argc, argv);
00186 #endif
00187
00188 am_syslogger = true;
00189
00190 init_ps_display("logger process", "", "", "");
00191
00192
00193
00194
00195
00196
00197
00198
00199 if (redirection_done)
00200 {
00201 int fd = open(DEVNULL, O_WRONLY, 0);
00202
00203
00204
00205
00206
00207
00208
00209 close(fileno(stdout));
00210 close(fileno(stderr));
00211 if (fd != -1)
00212 {
00213 dup2(fd, fileno(stdout));
00214 dup2(fd, fileno(stderr));
00215 close(fd);
00216 }
00217 }
00218
00219
00220
00221
00222
00223
00224 #ifdef WIN32
00225 else
00226 _setmode(_fileno(stderr), _O_TEXT);
00227 #endif
00228
00229
00230
00231
00232
00233
00234 #ifndef WIN32
00235 if (syslogPipe[1] >= 0)
00236 close(syslogPipe[1]);
00237 syslogPipe[1] = -1;
00238 #else
00239 if (syslogPipe[1])
00240 CloseHandle(syslogPipe[1]);
00241 syslogPipe[1] = 0;
00242 #endif
00243
00244
00245
00246
00247
00248
00249
00250 #ifdef HAVE_SETSID
00251 if (setsid() < 0)
00252 elog(FATAL, "setsid() failed: %m");
00253 #endif
00254
00255 InitializeLatchSupport();
00256
00257
00258 InitLatch(&sysLoggerLatch);
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 pqsignal(SIGHUP, sigHupHandler);
00269 pqsignal(SIGINT, SIG_IGN);
00270 pqsignal(SIGTERM, SIG_IGN);
00271 pqsignal(SIGQUIT, SIG_IGN);
00272 pqsignal(SIGALRM, SIG_IGN);
00273 pqsignal(SIGPIPE, SIG_IGN);
00274 pqsignal(SIGUSR1, sigUsr1Handler);
00275 pqsignal(SIGUSR2, SIG_IGN);
00276
00277
00278
00279
00280 pqsignal(SIGCHLD, SIG_DFL);
00281 pqsignal(SIGTTIN, SIG_DFL);
00282 pqsignal(SIGTTOU, SIG_DFL);
00283 pqsignal(SIGCONT, SIG_DFL);
00284 pqsignal(SIGWINCH, SIG_DFL);
00285
00286 PG_SETMASK(&UnBlockSig);
00287
00288 #ifdef WIN32
00289
00290 InitializeCriticalSection(&sysloggerSection);
00291 EnterCriticalSection(&sysloggerSection);
00292
00293 threadHandle = (HANDLE) _beginthreadex(NULL, 0, pipeThread, NULL, 0, NULL);
00294 if (threadHandle == 0)
00295 elog(FATAL, "could not create syslogger data transfer thread: %m");
00296 #endif
00297
00298
00299
00300
00301
00302
00303 last_file_name = logfile_getname(first_syslogger_file_time, NULL);
00304
00305
00306 currentLogDir = pstrdup(Log_directory);
00307 currentLogFilename = pstrdup(Log_filename);
00308 currentLogRotationAge = Log_RotationAge;
00309
00310 set_next_rotation_time();
00311
00312
00313 for (;;)
00314 {
00315 bool time_based_rotation = false;
00316 int size_rotation_for = 0;
00317 long cur_timeout;
00318 int cur_flags;
00319
00320 #ifndef WIN32
00321 int rc;
00322 #endif
00323
00324
00325 ResetLatch(&sysLoggerLatch);
00326
00327
00328
00329
00330 if (got_SIGHUP)
00331 {
00332 got_SIGHUP = false;
00333 ProcessConfigFile(PGC_SIGHUP);
00334
00335
00336
00337
00338
00339
00340 if (strcmp(Log_directory, currentLogDir) != 0)
00341 {
00342 pfree(currentLogDir);
00343 currentLogDir = pstrdup(Log_directory);
00344 rotation_requested = true;
00345
00346
00347
00348
00349 mkdir(Log_directory, S_IRWXU);
00350 }
00351 if (strcmp(Log_filename, currentLogFilename) != 0)
00352 {
00353 pfree(currentLogFilename);
00354 currentLogFilename = pstrdup(Log_filename);
00355 rotation_requested = true;
00356 }
00357
00358
00359
00360
00361
00362 if (currentLogRotationAge != Log_RotationAge)
00363 {
00364 currentLogRotationAge = Log_RotationAge;
00365 set_next_rotation_time();
00366 }
00367
00368
00369
00370
00371
00372 if (rotation_disabled)
00373 {
00374 rotation_disabled = false;
00375 rotation_requested = true;
00376 }
00377 }
00378
00379 if (Log_RotationAge > 0 && !rotation_disabled)
00380 {
00381
00382 now = (pg_time_t) time(NULL);
00383 if (now >= next_rotation_time)
00384 rotation_requested = time_based_rotation = true;
00385 }
00386
00387 if (!rotation_requested && Log_RotationSize > 0 && !rotation_disabled)
00388 {
00389
00390 if (ftell(syslogFile) >= Log_RotationSize * 1024L)
00391 {
00392 rotation_requested = true;
00393 size_rotation_for |= LOG_DESTINATION_STDERR;
00394 }
00395 if (csvlogFile != NULL &&
00396 ftell(csvlogFile) >= Log_RotationSize * 1024L)
00397 {
00398 rotation_requested = true;
00399 size_rotation_for |= LOG_DESTINATION_CSVLOG;
00400 }
00401 }
00402
00403 if (rotation_requested)
00404 {
00405
00406
00407
00408
00409 if (!time_based_rotation && size_rotation_for == 0)
00410 size_rotation_for = LOG_DESTINATION_STDERR | LOG_DESTINATION_CSVLOG;
00411 logfile_rotate(time_based_rotation, size_rotation_for);
00412 }
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 if (Log_RotationAge > 0 && !rotation_disabled)
00427 {
00428 pg_time_t delay;
00429
00430 delay = next_rotation_time - now;
00431 if (delay > 0)
00432 {
00433 if (delay > INT_MAX / 1000)
00434 delay = INT_MAX / 1000;
00435 cur_timeout = delay * 1000L;
00436 }
00437 else
00438 cur_timeout = 0;
00439 cur_flags = WL_TIMEOUT;
00440 }
00441 else
00442 {
00443 cur_timeout = -1L;
00444 cur_flags = 0;
00445 }
00446
00447
00448
00449
00450 #ifndef WIN32
00451 rc = WaitLatchOrSocket(&sysLoggerLatch,
00452 WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags,
00453 syslogPipe[0],
00454 cur_timeout);
00455
00456 if (rc & WL_SOCKET_READABLE)
00457 {
00458 int bytesRead;
00459
00460 bytesRead = read(syslogPipe[0],
00461 logbuffer + bytes_in_logbuffer,
00462 sizeof(logbuffer) - bytes_in_logbuffer);
00463 if (bytesRead < 0)
00464 {
00465 if (errno != EINTR)
00466 ereport(LOG,
00467 (errcode_for_socket_access(),
00468 errmsg("could not read from logger pipe: %m")));
00469 }
00470 else if (bytesRead > 0)
00471 {
00472 bytes_in_logbuffer += bytesRead;
00473 process_pipe_input(logbuffer, &bytes_in_logbuffer);
00474 continue;
00475 }
00476 else
00477 {
00478
00479
00480
00481
00482
00483
00484 pipe_eof_seen = true;
00485
00486
00487 flush_pipe_input(logbuffer, &bytes_in_logbuffer);
00488 }
00489 }
00490 #else
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 LeaveCriticalSection(&sysloggerSection);
00502
00503 (void) WaitLatch(&sysLoggerLatch,
00504 WL_LATCH_SET | cur_flags,
00505 cur_timeout);
00506
00507 EnterCriticalSection(&sysloggerSection);
00508 #endif
00509
00510 if (pipe_eof_seen)
00511 {
00512
00513
00514
00515
00516 ereport(DEBUG1,
00517 (errmsg("logger shutting down")));
00518
00519
00520
00521
00522
00523
00524
00525
00526 proc_exit(0);
00527 }
00528 }
00529 }
00530
00531
00532
00533
00534 int
00535 SysLogger_Start(void)
00536 {
00537 pid_t sysloggerPid;
00538 char *filename;
00539
00540 if (!Logging_collector)
00541 return 0;
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 #ifndef WIN32
00556 if (syslogPipe[0] < 0)
00557 {
00558 if (pipe(syslogPipe) < 0)
00559 ereport(FATAL,
00560 (errcode_for_socket_access(),
00561 (errmsg("could not create pipe for syslog: %m"))));
00562 }
00563 #else
00564 if (!syslogPipe[0])
00565 {
00566 SECURITY_ATTRIBUTES sa;
00567
00568 memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
00569 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
00570 sa.bInheritHandle = TRUE;
00571
00572 if (!CreatePipe(&syslogPipe[0], &syslogPipe[1], &sa, 32768))
00573 ereport(FATAL,
00574 (errcode_for_file_access(),
00575 (errmsg("could not create pipe for syslog: %m"))));
00576 }
00577 #endif
00578
00579
00580
00581
00582 mkdir(Log_directory, S_IRWXU);
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596 first_syslogger_file_time = time(NULL);
00597 filename = logfile_getname(first_syslogger_file_time, NULL);
00598
00599 syslogFile = logfile_open(filename, "a", false);
00600
00601 pfree(filename);
00602
00603 #ifdef EXEC_BACKEND
00604 switch ((sysloggerPid = syslogger_forkexec()))
00605 #else
00606 switch ((sysloggerPid = fork_process()))
00607 #endif
00608 {
00609 case -1:
00610 ereport(LOG,
00611 (errmsg("could not fork system logger: %m")));
00612 return 0;
00613
00614 #ifndef EXEC_BACKEND
00615 case 0:
00616
00617
00618 ClosePostmasterPorts(true);
00619
00620
00621 on_exit_reset();
00622
00623
00624 PGSharedMemoryDetach();
00625
00626
00627 SysLoggerMain(0, NULL);
00628 break;
00629 #endif
00630
00631 default:
00632
00633
00634
00635 if (!redirection_done)
00636 {
00637 #ifndef WIN32
00638 fflush(stdout);
00639 if (dup2(syslogPipe[1], fileno(stdout)) < 0)
00640 ereport(FATAL,
00641 (errcode_for_file_access(),
00642 errmsg("could not redirect stdout: %m")));
00643 fflush(stderr);
00644 if (dup2(syslogPipe[1], fileno(stderr)) < 0)
00645 ereport(FATAL,
00646 (errcode_for_file_access(),
00647 errmsg("could not redirect stderr: %m")));
00648
00649 close(syslogPipe[1]);
00650 syslogPipe[1] = -1;
00651 #else
00652 int fd;
00653
00654
00655
00656
00657
00658
00659 fflush(stderr);
00660 fd = _open_osfhandle((intptr_t) syslogPipe[1],
00661 _O_APPEND | _O_BINARY);
00662 if (dup2(fd, _fileno(stderr)) < 0)
00663 ereport(FATAL,
00664 (errcode_for_file_access(),
00665 errmsg("could not redirect stderr: %m")));
00666 close(fd);
00667 _setmode(_fileno(stderr), _O_BINARY);
00668
00669
00670
00671
00672
00673
00674 syslogPipe[1] = 0;
00675 #endif
00676 redirection_done = true;
00677 }
00678
00679
00680 fclose(syslogFile);
00681 syslogFile = NULL;
00682 return (int) sysloggerPid;
00683 }
00684
00685
00686 return 0;
00687 }
00688
00689
00690 #ifdef EXEC_BACKEND
00691
00692
00693
00694
00695
00696
00697 static pid_t
00698 syslogger_forkexec(void)
00699 {
00700 char *av[10];
00701 int ac = 0;
00702 char filenobuf[32];
00703
00704 av[ac++] = "postgres";
00705 av[ac++] = "--forklog";
00706 av[ac++] = NULL;
00707
00708
00709 #ifndef WIN32
00710 if (syslogFile != NULL)
00711 snprintf(filenobuf, sizeof(filenobuf), "%d",
00712 fileno(syslogFile));
00713 else
00714 strcpy(filenobuf, "-1");
00715 #else
00716 if (syslogFile != NULL)
00717 snprintf(filenobuf, sizeof(filenobuf), "%ld",
00718 (long) _get_osfhandle(_fileno(syslogFile)));
00719 else
00720 strcpy(filenobuf, "0");
00721 #endif
00722 av[ac++] = filenobuf;
00723
00724 av[ac] = NULL;
00725 Assert(ac < lengthof(av));
00726
00727 return postmaster_forkexec(ac, av);
00728 }
00729
00730
00731
00732
00733
00734
00735 static void
00736 syslogger_parseArgs(int argc, char *argv[])
00737 {
00738 int fd;
00739
00740 Assert(argc == 4);
00741 argv += 3;
00742
00743 #ifndef WIN32
00744 fd = atoi(*argv++);
00745 if (fd != -1)
00746 {
00747 syslogFile = fdopen(fd, "a");
00748 setvbuf(syslogFile, NULL, LBF_MODE, 0);
00749 }
00750 #else
00751 fd = atoi(*argv++);
00752 if (fd != 0)
00753 {
00754 fd = _open_osfhandle(fd, _O_APPEND | _O_TEXT);
00755 if (fd > 0)
00756 {
00757 syslogFile = fdopen(fd, "a");
00758 setvbuf(syslogFile, NULL, LBF_MODE, 0);
00759 }
00760 }
00761 #endif
00762 }
00763 #endif
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794 static void
00795 process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
00796 {
00797 char *cursor = logbuffer;
00798 int count = *bytes_in_logbuffer;
00799 int dest = LOG_DESTINATION_STDERR;
00800
00801
00802 while (count >= (int) sizeof(PipeProtoHeader))
00803 {
00804 PipeProtoHeader p;
00805 int chunklen;
00806
00807
00808 memcpy(&p, cursor, sizeof(PipeProtoHeader));
00809 if (p.nuls[0] == '\0' && p.nuls[1] == '\0' &&
00810 p.len > 0 && p.len <= PIPE_MAX_PAYLOAD &&
00811 p.pid != 0 &&
00812 (p.is_last == 't' || p.is_last == 'f' ||
00813 p.is_last == 'T' || p.is_last == 'F'))
00814 {
00815 List *buffer_list;
00816 ListCell *cell;
00817 save_buffer *existing_slot = NULL,
00818 *free_slot = NULL;
00819 StringInfo str;
00820
00821 chunklen = PIPE_HEADER_SIZE + p.len;
00822
00823
00824 if (count < chunklen)
00825 break;
00826
00827 dest = (p.is_last == 'T' || p.is_last == 'F') ?
00828 LOG_DESTINATION_CSVLOG : LOG_DESTINATION_STDERR;
00829
00830
00831 buffer_list = buffer_lists[p.pid % NBUFFER_LISTS];
00832 foreach(cell, buffer_list)
00833 {
00834 save_buffer *buf = (save_buffer *) lfirst(cell);
00835
00836 if (buf->pid == p.pid)
00837 {
00838 existing_slot = buf;
00839 break;
00840 }
00841 if (buf->pid == 0 && free_slot == NULL)
00842 free_slot = buf;
00843 }
00844
00845 if (p.is_last == 'f' || p.is_last == 'F')
00846 {
00847
00848
00849
00850 if (existing_slot != NULL)
00851 {
00852
00853 str = &(existing_slot->data);
00854 appendBinaryStringInfo(str,
00855 cursor + PIPE_HEADER_SIZE,
00856 p.len);
00857 }
00858 else
00859 {
00860
00861 if (free_slot == NULL)
00862 {
00863
00864
00865
00866
00867 free_slot = palloc(sizeof(save_buffer));
00868 buffer_list = lappend(buffer_list, free_slot);
00869 buffer_lists[p.pid % NBUFFER_LISTS] = buffer_list;
00870 }
00871 free_slot->pid = p.pid;
00872 str = &(free_slot->data);
00873 initStringInfo(str);
00874 appendBinaryStringInfo(str,
00875 cursor + PIPE_HEADER_SIZE,
00876 p.len);
00877 }
00878 }
00879 else
00880 {
00881
00882
00883
00884
00885 if (existing_slot != NULL)
00886 {
00887 str = &(existing_slot->data);
00888 appendBinaryStringInfo(str,
00889 cursor + PIPE_HEADER_SIZE,
00890 p.len);
00891 write_syslogger_file(str->data, str->len, dest);
00892
00893 existing_slot->pid = 0;
00894 pfree(str->data);
00895 }
00896 else
00897 {
00898
00899 write_syslogger_file(cursor + PIPE_HEADER_SIZE, p.len,
00900 dest);
00901 }
00902 }
00903
00904
00905 cursor += chunklen;
00906 count -= chunklen;
00907 }
00908 else
00909 {
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921 for (chunklen = 1; chunklen < count; chunklen++)
00922 {
00923 if (cursor[chunklen] == '\0')
00924 break;
00925 }
00926
00927 write_syslogger_file(cursor, chunklen, LOG_DESTINATION_STDERR);
00928 cursor += chunklen;
00929 count -= chunklen;
00930 }
00931 }
00932
00933
00934 if (count > 0 && cursor != logbuffer)
00935 memmove(logbuffer, cursor, count);
00936 *bytes_in_logbuffer = count;
00937 }
00938
00939
00940
00941
00942
00943
00944
00945 static void
00946 flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
00947 {
00948 int i;
00949
00950
00951 for (i = 0; i < NBUFFER_LISTS; i++)
00952 {
00953 List *list = buffer_lists[i];
00954 ListCell *cell;
00955
00956 foreach(cell, list)
00957 {
00958 save_buffer *buf = (save_buffer *) lfirst(cell);
00959
00960 if (buf->pid != 0)
00961 {
00962 StringInfo str = &(buf->data);
00963
00964 write_syslogger_file(str->data, str->len,
00965 LOG_DESTINATION_STDERR);
00966
00967 buf->pid = 0;
00968 pfree(str->data);
00969 }
00970 }
00971 }
00972
00973
00974
00975
00976
00977 if (*bytes_in_logbuffer > 0)
00978 write_syslogger_file(logbuffer, *bytes_in_logbuffer,
00979 LOG_DESTINATION_STDERR);
00980 *bytes_in_logbuffer = 0;
00981 }
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996 void
00997 write_syslogger_file(const char *buffer, int count, int destination)
00998 {
00999 int rc;
01000 FILE *logfile;
01001
01002 if (destination == LOG_DESTINATION_CSVLOG && csvlogFile == NULL)
01003 open_csvlogfile();
01004
01005 logfile = destination == LOG_DESTINATION_CSVLOG ? csvlogFile : syslogFile;
01006 rc = fwrite(buffer, 1, count, logfile);
01007
01008
01009 if (rc != count)
01010 write_stderr("could not write to log file: %s\n", strerror(errno));
01011 }
01012
01013 #ifdef WIN32
01014
01015
01016
01017
01018
01019
01020
01021
01022 static unsigned int __stdcall
01023 pipeThread(void *arg)
01024 {
01025 char logbuffer[READ_BUF_SIZE];
01026 int bytes_in_logbuffer = 0;
01027
01028 for (;;)
01029 {
01030 DWORD bytesRead;
01031 BOOL result;
01032
01033 result = ReadFile(syslogPipe[0],
01034 logbuffer + bytes_in_logbuffer,
01035 sizeof(logbuffer) - bytes_in_logbuffer,
01036 &bytesRead, 0);
01037
01038
01039
01040
01041
01042
01043
01044 EnterCriticalSection(&sysloggerSection);
01045 if (!result)
01046 {
01047 DWORD error = GetLastError();
01048
01049 if (error == ERROR_HANDLE_EOF ||
01050 error == ERROR_BROKEN_PIPE)
01051 break;
01052 _dosmaperr(error);
01053 ereport(LOG,
01054 (errcode_for_file_access(),
01055 errmsg("could not read from logger pipe: %m")));
01056 }
01057 else if (bytesRead > 0)
01058 {
01059 bytes_in_logbuffer += bytesRead;
01060 process_pipe_input(logbuffer, &bytes_in_logbuffer);
01061 }
01062
01063
01064
01065
01066
01067 if (Log_RotationSize > 0)
01068 {
01069 if (ftell(syslogFile) >= Log_RotationSize * 1024L ||
01070 (csvlogFile != NULL && ftell(csvlogFile) >= Log_RotationSize * 1024L))
01071 SetLatch(&sysLoggerLatch);
01072 }
01073 LeaveCriticalSection(&sysloggerSection);
01074 }
01075
01076
01077 pipe_eof_seen = true;
01078
01079
01080 flush_pipe_input(logbuffer, &bytes_in_logbuffer);
01081
01082
01083 SetLatch(&sysLoggerLatch);
01084
01085 LeaveCriticalSection(&sysloggerSection);
01086 _endthread();
01087 return 0;
01088 }
01089 #endif
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099 static void
01100 open_csvlogfile(void)
01101 {
01102 char *filename;
01103
01104 filename = logfile_getname(time(NULL), ".csv");
01105
01106 csvlogFile = logfile_open(filename, "a", false);
01107
01108 if (last_csv_file_name != NULL)
01109 pfree(last_csv_file_name);
01110
01111 last_csv_file_name = filename;
01112 }
01113
01114
01115
01116
01117
01118
01119
01120
01121 static FILE *
01122 logfile_open(const char *filename, const char *mode, bool allow_errors)
01123 {
01124 FILE *fh;
01125 mode_t oumask;
01126
01127
01128
01129
01130
01131 oumask = umask((mode_t) ((~(Log_file_mode | S_IWUSR)) & (S_IRWXU | S_IRWXG | S_IRWXO)));
01132 fh = fopen(filename, mode);
01133 umask(oumask);
01134
01135 if (fh)
01136 {
01137 setvbuf(fh, NULL, LBF_MODE, 0);
01138
01139 #ifdef WIN32
01140
01141 _setmode(_fileno(fh), _O_TEXT);
01142 #endif
01143 }
01144 else
01145 {
01146 int save_errno = errno;
01147
01148 ereport(allow_errors ? LOG : FATAL,
01149 (errcode_for_file_access(),
01150 errmsg("could not open log file \"%s\": %m",
01151 filename)));
01152 errno = save_errno;
01153 }
01154
01155 return fh;
01156 }
01157
01158
01159
01160
01161 static void
01162 logfile_rotate(bool time_based_rotation, int size_rotation_for)
01163 {
01164 char *filename;
01165 char *csvfilename = NULL;
01166 pg_time_t fntime;
01167 FILE *fh;
01168
01169 rotation_requested = false;
01170
01171
01172
01173
01174
01175
01176 if (time_based_rotation)
01177 fntime = next_rotation_time;
01178 else
01179 fntime = time(NULL);
01180 filename = logfile_getname(fntime, NULL);
01181 if (csvlogFile != NULL)
01182 csvfilename = logfile_getname(fntime, ".csv");
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192 if (time_based_rotation || (size_rotation_for & LOG_DESTINATION_STDERR))
01193 {
01194 if (Log_truncate_on_rotation && time_based_rotation &&
01195 last_file_name != NULL &&
01196 strcmp(filename, last_file_name) != 0)
01197 fh = logfile_open(filename, "w", true);
01198 else
01199 fh = logfile_open(filename, "a", true);
01200
01201 if (!fh)
01202 {
01203
01204
01205
01206
01207
01208
01209 if (errno != ENFILE && errno != EMFILE)
01210 {
01211 ereport(LOG,
01212 (errmsg("disabling automatic rotation (use SIGHUP to re-enable)")));
01213 rotation_disabled = true;
01214 }
01215
01216 if (filename)
01217 pfree(filename);
01218 if (csvfilename)
01219 pfree(csvfilename);
01220 return;
01221 }
01222
01223 fclose(syslogFile);
01224 syslogFile = fh;
01225
01226
01227 if (last_file_name != NULL)
01228 pfree(last_file_name);
01229 last_file_name = filename;
01230 filename = NULL;
01231 }
01232
01233
01234
01235 if (csvlogFile != NULL &&
01236 (time_based_rotation || (size_rotation_for & LOG_DESTINATION_CSVLOG)))
01237 {
01238 if (Log_truncate_on_rotation && time_based_rotation &&
01239 last_csv_file_name != NULL &&
01240 strcmp(csvfilename, last_csv_file_name) != 0)
01241 fh = logfile_open(csvfilename, "w", true);
01242 else
01243 fh = logfile_open(csvfilename, "a", true);
01244
01245 if (!fh)
01246 {
01247
01248
01249
01250
01251
01252
01253 if (errno != ENFILE && errno != EMFILE)
01254 {
01255 ereport(LOG,
01256 (errmsg("disabling automatic rotation (use SIGHUP to re-enable)")));
01257 rotation_disabled = true;
01258 }
01259
01260 if (filename)
01261 pfree(filename);
01262 if (csvfilename)
01263 pfree(csvfilename);
01264 return;
01265 }
01266
01267 fclose(csvlogFile);
01268 csvlogFile = fh;
01269
01270
01271 if (last_csv_file_name != NULL)
01272 pfree(last_csv_file_name);
01273 last_csv_file_name = csvfilename;
01274 csvfilename = NULL;
01275 }
01276
01277 if (filename)
01278 pfree(filename);
01279 if (csvfilename)
01280 pfree(csvfilename);
01281
01282 set_next_rotation_time();
01283 }
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294 static char *
01295 logfile_getname(pg_time_t timestamp, const char *suffix)
01296 {
01297 char *filename;
01298 int len;
01299
01300 filename = palloc(MAXPGPATH);
01301
01302 snprintf(filename, MAXPGPATH, "%s/", Log_directory);
01303
01304 len = strlen(filename);
01305
01306
01307 pg_strftime(filename + len, MAXPGPATH - len, Log_filename,
01308 pg_localtime(×tamp, log_timezone));
01309
01310 if (suffix != NULL)
01311 {
01312 len = strlen(filename);
01313 if (len > 4 && (strcmp(filename + (len - 4), ".log") == 0))
01314 len -= 4;
01315 strlcpy(filename + len, suffix, MAXPGPATH - len);
01316 }
01317
01318 return filename;
01319 }
01320
01321
01322
01323
01324 static void
01325 set_next_rotation_time(void)
01326 {
01327 pg_time_t now;
01328 struct pg_tm *tm;
01329 int rotinterval;
01330
01331
01332 if (Log_RotationAge <= 0)
01333 return;
01334
01335
01336
01337
01338
01339
01340
01341 rotinterval = Log_RotationAge * SECS_PER_MINUTE;
01342 now = (pg_time_t) time(NULL);
01343 tm = pg_localtime(&now, log_timezone);
01344 now += tm->tm_gmtoff;
01345 now -= now % rotinterval;
01346 now += rotinterval;
01347 now -= tm->tm_gmtoff;
01348 next_rotation_time = now;
01349 }
01350
01351
01352
01353
01354
01355
01356
01357 static void
01358 sigHupHandler(SIGNAL_ARGS)
01359 {
01360 int save_errno = errno;
01361
01362 got_SIGHUP = true;
01363 SetLatch(&sysLoggerLatch);
01364
01365 errno = save_errno;
01366 }
01367
01368
01369 static void
01370 sigUsr1Handler(SIGNAL_ARGS)
01371 {
01372 int save_errno = errno;
01373
01374 rotation_requested = true;
01375 SetLatch(&sysLoggerLatch);
01376
01377 errno = save_errno;
01378 }