⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 syslogger.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * syslogger.c * * The system logger (syslogger) is new in Postgres 8.0. It catches all * stderr output from the postmaster, backends, and other subprocesses * by redirecting to a pipe, and writes it to a set of logfiles. * It's possible to have size and age limits for the logfile configured * in postgresql.conf. If these limits are reached or passed, the * current logfile is closed and a new one is created (rotated). * The logfiles are stored in a subdirectory (configurable in * postgresql.conf), using an internal naming scheme that mangles * creation time and current postmaster pid. * * Author: Andreas Pflug <pgadmin@pse-consulting.de> * * Copyright (c) 2004-2005, PostgreSQL Global Development Group * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.20.2.1 2005/11/22 18:23:16 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <fcntl.h>#include <signal.h>#include <time.h>#include <unistd.h>#include <sys/stat.h>#include <sys/time.h>#include "libpq/pqsignal.h"#include "miscadmin.h"#include "postmaster/fork_process.h"#include "postmaster/postmaster.h"#include "postmaster/syslogger.h"#include "pgtime.h"#include "storage/ipc.h"#include "storage/pg_shmem.h"#include "utils/guc.h"#include "utils/ps_status.h"#include "utils/timestamp.h"/* * We really want line-buffered mode for logfile output, but Windows does * not have it, and interprets _IOLBF as _IOFBF (bozos).  So use _IONBF * instead on Windows. */#ifdef WIN32#define LBF_MODE	_IONBF#else#define LBF_MODE	_IOLBF#endif/* * GUC parameters.	Redirect_stderr cannot be changed after postmaster * start, but the rest can change at SIGHUP. */bool		Redirect_stderr = false;int			Log_RotationAge = HOURS_PER_DAY * MINS_PER_HOUR;int			Log_RotationSize = 10 * 1024;char	   *Log_directory = NULL;char	   *Log_filename = NULL;bool		Log_truncate_on_rotation = false;/* * Globally visible state (used by elog.c) */bool		am_syslogger = false;/* * Private state */static pg_time_t next_rotation_time;static bool redirection_done = false;static bool pipe_eof_seen = false;static FILE *syslogFile = NULL;static char *last_file_name = NULL;/* These must be exported for EXEC_BACKEND case ... annoying */#ifndef WIN32int			syslogPipe[2] = {-1, -1};#elseHANDLE		syslogPipe[2] = {0, 0};#endif#ifdef WIN32static HANDLE threadHandle = 0;static CRITICAL_SECTION sysfileSection;#endif/* * Flags set by interrupt handlers for later service in the main loop. */static volatile sig_atomic_t got_SIGHUP = false;static volatile sig_atomic_t rotation_requested = false;/* Local subroutines */#ifdef EXEC_BACKENDstatic pid_t syslogger_forkexec(void);static void syslogger_parseArgs(int argc, char *argv[]);#endifstatic void write_syslogger_file_binary(const char *buffer, int count);#ifdef WIN32static unsigned int __stdcall pipeThread(void *arg);#endifstatic void logfile_rotate(bool time_based_rotation);static char *logfile_getname(pg_time_t timestamp);static void set_next_rotation_time(void);static void sigHupHandler(SIGNAL_ARGS);static void sigUsr1Handler(SIGNAL_ARGS);/* * Main entry point for syslogger process * argc/argv parameters are valid only in EXEC_BACKEND case. */NON_EXEC_STATIC voidSysLoggerMain(int argc, char *argv[]){	char	   *currentLogDir;	char	   *currentLogFilename;	int			currentLogRotationAge;	IsUnderPostmaster = true;	/* we are a postmaster subprocess now */	MyProcPid = getpid();		/* reset MyProcPid */	/* Lose the postmaster's on-exit routines */	on_exit_reset();#ifdef EXEC_BACKEND	syslogger_parseArgs(argc, argv);#endif   /* EXEC_BACKEND */	am_syslogger = true;	init_ps_display("logger process", "", "");	set_ps_display("");	/*	 * If we restarted, our stderr is already redirected into our own input	 * pipe.  This is of course pretty useless, not to mention that it	 * interferes with detecting pipe EOF.	Point stderr to /dev/null. This	 * assumes that all interesting messages generated in the syslogger will	 * come through elog.c and will be sent to write_syslogger_file.	 */	if (redirection_done)	{		int			fd = open(NULL_DEV, O_WRONLY);		/*		 * The closes might look redundant, but they are not: we want to be		 * darn sure the pipe gets closed even if the open failed.	We can		 * survive running with stderr pointing nowhere, but we can't afford		 * to have extra pipe input descriptors hanging around.		 */		close(fileno(stdout));		close(fileno(stderr));		dup2(fd, fileno(stdout));		dup2(fd, fileno(stderr));		close(fd);	}	/*	 * Also close our copy of the write end of the pipe.  This is needed to	 * ensure we can detect pipe EOF correctly.  (But note that in the restart	 * case, the postmaster already did this.)	 */#ifndef WIN32	if (syslogPipe[1] >= 0)		close(syslogPipe[1]);	syslogPipe[1] = -1;#else	if (syslogPipe[1])		CloseHandle(syslogPipe[1]);	syslogPipe[1] = 0;#endif	/*	 * Properly accept or ignore signals the postmaster might send us	 *	 * Note: we ignore all termination signals, and instead exit only when all	 * upstream processes are gone, to ensure we don't miss any dying gasps of	 * broken backends...	 */	pqsignal(SIGHUP, sigHupHandler);	/* set flag to read config file */	pqsignal(SIGINT, SIG_IGN);	pqsignal(SIGTERM, SIG_IGN);	pqsignal(SIGQUIT, SIG_IGN);	pqsignal(SIGALRM, SIG_IGN);	pqsignal(SIGPIPE, SIG_IGN);	pqsignal(SIGUSR1, sigUsr1Handler);	/* request log rotation */	pqsignal(SIGUSR2, SIG_IGN);	/*	 * Reset some signals that are accepted by postmaster but not here	 */	pqsignal(SIGCHLD, SIG_DFL);	pqsignal(SIGTTIN, SIG_DFL);	pqsignal(SIGTTOU, SIG_DFL);	pqsignal(SIGCONT, SIG_DFL);	pqsignal(SIGWINCH, SIG_DFL);	PG_SETMASK(&UnBlockSig);#ifdef WIN32	/* Fire up separate data transfer thread */	InitializeCriticalSection(&sysfileSection);	{		unsigned int tid;		threadHandle = (HANDLE) _beginthreadex(0, 0, pipeThread, 0, 0, &tid);	}#endif   /* WIN32 */	/* remember active logfile parameters */	currentLogDir = pstrdup(Log_directory);	currentLogFilename = pstrdup(Log_filename);	currentLogRotationAge = Log_RotationAge;	/* set next planned rotation time */	set_next_rotation_time();	/* main worker loop */	for (;;)	{		bool		time_based_rotation = false;#ifndef WIN32		char		logbuffer[1024];		int			bytesRead;		int			rc;		fd_set		rfds;		struct timeval timeout;#endif		if (got_SIGHUP)		{			got_SIGHUP = false;			ProcessConfigFile(PGC_SIGHUP);			/*			 * Check if the log directory or filename pattern changed in			 * postgresql.conf. If so, force rotation to make sure we're			 * writing the logfiles in the right place.			 */			if (strcmp(Log_directory, currentLogDir) != 0)			{				pfree(currentLogDir);				currentLogDir = pstrdup(Log_directory);				rotation_requested = true;			}			if (strcmp(Log_filename, currentLogFilename) != 0)			{				pfree(currentLogFilename);				currentLogFilename = pstrdup(Log_filename);				rotation_requested = true;			}			/*			 * If rotation time parameter changed, reset next rotation time,			 * but don't immediately force a rotation.			 */			if (currentLogRotationAge != Log_RotationAge)			{				currentLogRotationAge = Log_RotationAge;				set_next_rotation_time();			}		}		if (!rotation_requested && Log_RotationAge > 0)		{			/* Do a logfile rotation if it's time */			pg_time_t	now = time(NULL);			if (now >= next_rotation_time)				rotation_requested = time_based_rotation = true;		}		if (!rotation_requested && Log_RotationSize > 0)		{			/* Do a rotation if file is too big */			if (ftell(syslogFile) >= Log_RotationSize * 1024L)				rotation_requested = true;		}		if (rotation_requested)			logfile_rotate(time_based_rotation);#ifndef WIN32		/*		 * Wait for some data, timing out after 1 second		 */		FD_ZERO(&rfds);		FD_SET(syslogPipe[0], &rfds);		timeout.tv_sec = 1;		timeout.tv_usec = 0;		rc = select(syslogPipe[0] + 1, &rfds, NULL, NULL, &timeout);		if (rc < 0)		{			if (errno != EINTR)				ereport(LOG,						(errcode_for_socket_access(),						 errmsg("select() failed in logger process: %m")));		}		else if (rc > 0 && FD_ISSET(syslogPipe[0], &rfds))		{			bytesRead = piperead(syslogPipe[0],								 logbuffer, sizeof(logbuffer));			if (bytesRead < 0)			{				if (errno != EINTR)					ereport(LOG,							(errcode_for_socket_access(),							 errmsg("could not read from logger pipe: %m")));			}			else if (bytesRead > 0)			{				write_syslogger_file_binary(logbuffer, bytesRead);				continue;			}			else			{				/*				 * Zero bytes read when select() is saying read-ready means				 * EOF on the pipe: that is, there are no longer any processes				 * with the pipe write end open.  Therefore, the postmaster				 * and all backends are shut down, and we are done.				 */				pipe_eof_seen = true;			}		}#else							/* WIN32 */		/*		 * On Windows we leave it to a separate thread to transfer data and		 * detect pipe EOF.  The main thread just wakes up once a second to		 * check for SIGHUP and rotation conditions.		 */		pgwin32_backend_usleep(1000000);#endif   /* WIN32 */		if (pipe_eof_seen)		{			ereport(LOG,					(errmsg("logger shutting down")));			/*			 * Normal exit from the syslogger is here.	Note that we			 * deliberately do not close syslogFile before exiting; this is to			 * allow for the possibility of elog messages being generated			 * inside proc_exit.  Regular exit() will take care of flushing			 * and closing stdio channels.			 */			proc_exit(0);		}	}}/* * Postmaster subroutine to start a syslogger subprocess. */intSysLogger_Start(void){	pid_t		sysloggerPid;	char	   *filename;	if (!Redirect_stderr)		return 0;	/*	 * If first time through, create the pipe which will receive stderr	 * output.	 *	 * If the syslogger crashes and needs to be restarted, we continue to use	 * the same pipe (indeed must do so, since extant backends will be writing	 * into that pipe).	 *	 * This means the postmaster must continue to hold the read end of the	 * pipe open, so we can pass it down to the reincarnated syslogger. This	 * is a bit klugy but we have little choice.	 */#ifndef WIN32	if (syslogPipe[0] < 0)	{		if (pgpipe(syslogPipe) < 0)			ereport(FATAL,					(errcode_for_socket_access(),					 (errmsg("could not create pipe for syslog: %m"))));	}#else	if (!syslogPipe[0])	{		SECURITY_ATTRIBUTES sa;		memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));		sa.nLength = sizeof(SECURITY_ATTRIBUTES);		sa.bInheritHandle = TRUE;		if (!CreatePipe(&syslogPipe[0], &syslogPipe[1], &sa, 32768))			ereport(FATAL,					(errcode_for_file_access(),					 (errmsg("could not create pipe for syslog: %m"))));	}#endif	/*	 * Create log directory if not present; ignore errors	 */	mkdir(Log_directory, 0700);	/*	 * The initial logfile is created right in the postmaster, to verify that	 * the Log_directory is writable.	 */	filename = logfile_getname(time(NULL));	syslogFile = fopen(filename, "a");	if (!syslogFile)		ereport(FATAL,				(errcode_for_file_access(),				 (errmsg("could not create log file \"%s\": %m",						 filename))));	setvbuf(syslogFile, NULL, LBF_MODE, 0);	pfree(filename);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -