elog.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,491 行 · 第 1/5 页

C
2,491
字号
	 */	CHECK_STACK_DEPTH();	Assert(CurrentMemoryContext != ErrorContext);	/* Copy the struct itself */	newedata = (ErrorData *) palloc(sizeof(ErrorData));	memcpy(newedata, edata, sizeof(ErrorData));	/* Make copies of separately-allocated fields */	if (newedata->message)		newedata->message = pstrdup(newedata->message);	if (newedata->detail)		newedata->detail = pstrdup(newedata->detail);	if (newedata->hint)		newedata->hint = pstrdup(newedata->hint);	if (newedata->context)		newedata->context = pstrdup(newedata->context);	if (newedata->internalquery)		newedata->internalquery = pstrdup(newedata->internalquery);	return newedata;}/* * FreeErrorData --- free the structure returned by CopyErrorData. * * Error handlers should use this in preference to assuming they know all * the separately-allocated fields. */voidFreeErrorData(ErrorData *edata){	if (edata->message)		pfree(edata->message);	if (edata->detail)		pfree(edata->detail);	if (edata->hint)		pfree(edata->hint);	if (edata->context)		pfree(edata->context);	if (edata->internalquery)		pfree(edata->internalquery);	pfree(edata);}/* * FlushErrorState --- flush the error state after error recovery * * This should be called by an error handler after it's done processing * the error; or as soon as it's done CopyErrorData, if it intends to * do stuff that is likely to provoke another error.  You are not "out" of * the error subsystem until you have done this. */voidFlushErrorState(void){	/*	 * Reset stack to empty.  The only case where it would be more than one	 * deep is if we serviced an error that interrupted construction of	 * another message.  We assume control escaped out of that message	 * construction and won't ever go back.	 */	errordata_stack_depth = -1;	recursion_depth = 0;	/* Delete all data in ErrorContext */	MemoryContextResetAndDeleteChildren(ErrorContext);}/* * ReThrowError --- re-throw a previously copied error * * A handler can do CopyErrorData/FlushErrorState to get out of the error * subsystem, then do some processing, and finally ReThrowError to re-throw * the original error.	This is slower than just PG_RE_THROW() but should * be used if the "some processing" is likely to incur another error. */voidReThrowError(ErrorData *edata){	ErrorData  *newedata;	Assert(edata->elevel == ERROR);	/* Push the data back into the error context */	recursion_depth++;	MemoryContextSwitchTo(ErrorContext);	if (++errordata_stack_depth >= ERRORDATA_STACK_SIZE)	{		/*		 * Wups, stack not big enough.	We treat this as a PANIC condition		 * because it suggests an infinite loop of errors during error		 * recovery.		 */		errordata_stack_depth = -1;		/* make room on stack */		ereport(PANIC, (errmsg_internal("ERRORDATA_STACK_SIZE exceeded")));	}	newedata = &errordata[errordata_stack_depth];	memcpy(newedata, edata, sizeof(ErrorData));	/* Make copies of separately-allocated fields */	if (newedata->message)		newedata->message = pstrdup(newedata->message);	if (newedata->detail)		newedata->detail = pstrdup(newedata->detail);	if (newedata->hint)		newedata->hint = pstrdup(newedata->hint);	if (newedata->context)		newedata->context = pstrdup(newedata->context);	if (newedata->internalquery)		newedata->internalquery = pstrdup(newedata->internalquery);	recursion_depth--;	PG_RE_THROW();}/* * pg_re_throw --- out-of-line implementation of PG_RE_THROW() macro */voidpg_re_throw(void){	/* If possible, throw the error to the next outer setjmp handler */	if (PG_exception_stack != NULL)		siglongjmp(*PG_exception_stack, 1);	else	{		/*		 * If we get here, elog(ERROR) was thrown inside a PG_TRY block, which		 * we have now exited only to discover that there is no outer setjmp		 * handler to pass the error to.  Had the error been thrown outside		 * the block to begin with, we'd have promoted the error to FATAL, so		 * the correct behavior is to make it FATAL now; that is, emit it and		 * then call proc_exit.		 */		ErrorData  *edata = &errordata[errordata_stack_depth];		Assert(errordata_stack_depth >= 0);		Assert(edata->elevel == ERROR);		edata->elevel = FATAL;		/*		 * At least in principle, the increase in severity could have changed		 * where-to-output decisions, so recalculate.  This should stay in		 * sync with errstart(), which see for comments.		 */		if (IsPostmasterEnvironment)			edata->output_to_server = is_log_level_output(FATAL,														  log_min_messages);		else			edata->output_to_server = (FATAL >= log_min_messages);		if (whereToSendOutput == DestRemote)		{			if (ClientAuthInProgress)				edata->output_to_client = true;			else				edata->output_to_client = (FATAL >= client_min_messages);		}		/*		 * We can use errfinish() for the rest, but we don't want it to call		 * any error context routines a second time.  Since we know we are		 * about to exit, it should be OK to just clear the context stack.		 */		error_context_stack = NULL;		errfinish(0);	}	/* We mustn't return... */	ExceptionalCondition("pg_re_throw tried to return", "FailedAssertion",						 __FILE__, __LINE__);	/*	 * Since ExceptionalCondition isn't declared noreturn because of	 * TrapMacro(), we need this to keep gcc from complaining.	 */	abort();}/* * Initialization of error output file */voidDebugFileOpen(void){	int			fd,				istty;	if (OutputFileName[0])	{		/*		 * A debug-output file name was given.		 *		 * Make sure we can write the file, and find out if it's a tty.		 */		if ((fd = open(OutputFileName, O_CREAT | O_APPEND | O_WRONLY,					   0666)) < 0)			ereport(FATAL,					(errcode_for_file_access(),				  errmsg("could not open file \"%s\": %m", OutputFileName)));		istty = isatty(fd);		close(fd);		/*		 * Redirect our stderr to the debug output file.		 */		if (!freopen(OutputFileName, "a", stderr))			ereport(FATAL,					(errcode_for_file_access(),					 errmsg("could not reopen file \"%s\" as stderr: %m",							OutputFileName)));		/*		 * If the file is a tty and we're running under the postmaster, try to		 * send stdout there as well (if it isn't a tty then stderr will block		 * out stdout, so we may as well let stdout go wherever it was going		 * before).		 */		if (istty && IsUnderPostmaster)			if (!freopen(OutputFileName, "a", stdout))				ereport(FATAL,						(errcode_for_file_access(),						 errmsg("could not reopen file \"%s\" as stdout: %m",								OutputFileName)));	}}#ifdef HAVE_SYSLOG/* * Set or update the parameters for syslog logging */voidset_syslog_parameters(const char *ident, int facility){	/*	 * guc.c is likely to call us repeatedly with same parameters, so don't	 * thrash the syslog connection unnecessarily.	Also, we do not re-open	 * the connection until needed, since this routine will get called whether	 * or not Log_destination actually mentions syslog.	 *	 * Note that we make our own copy of the ident string rather than relying	 * on guc.c's.  This may be overly paranoid, but it ensures that we cannot	 * accidentally free a string that syslog is still using.	 */	if (syslog_ident == NULL || strcmp(syslog_ident, ident) != 0 ||		syslog_facility != facility)	{		if (openlog_done)		{			closelog();			openlog_done = false;		}		if (syslog_ident)			free(syslog_ident);		syslog_ident = strdup(ident);		/* if the strdup fails, we will cope in write_syslog() */		syslog_facility = facility;	}}#ifndef PG_SYSLOG_LIMIT#define PG_SYSLOG_LIMIT 128#endif/* * Write a message line to syslog */static voidwrite_syslog(int level, const char *line){	static unsigned long seq = 0;	int			len;	const char *nlpos;	/* Open syslog connection if not done yet */	if (!openlog_done)	{		openlog(syslog_ident ? syslog_ident : "postgres",				LOG_PID | LOG_NDELAY | LOG_NOWAIT,				syslog_facility);		openlog_done = true;	}	/*	 * We add a sequence number to each log message to suppress "same"	 * messages.	 */	seq++;	/*	 * Our problem here is that many syslog implementations don't handle long	 * messages in an acceptable manner. While this function doesn't help that	 * fact, it does work around by splitting up messages into smaller pieces.	 *	 * We divide into multiple syslog() calls if message is too long or if the	 * message contains embedded newline(s).	 */	len = strlen(line);	nlpos = strchr(line, '\n');	if (len > PG_SYSLOG_LIMIT || nlpos != NULL)	{		int			chunk_nr = 0;		while (len > 0)		{			char		buf[PG_SYSLOG_LIMIT + 1];			int			buflen;			int			i;			/* if we start at a newline, move ahead one char */			if (line[0] == '\n')			{				line++;				len--;				/* we need to recompute the next newline's position, too */				nlpos = strchr(line, '\n');				continue;			}			/* copy one line, or as much as will fit, to buf */			if (nlpos != NULL)				buflen = nlpos - line;			else				buflen = len;			buflen = Min(buflen, PG_SYSLOG_LIMIT);			memcpy(buf, line, buflen);			buf[buflen] = '\0';			/* trim to multibyte letter boundary */			buflen = pg_mbcliplen(buf, buflen, buflen);			if (buflen <= 0)				return;			buf[buflen] = '\0';			/* already word boundary? */			if (line[buflen] != '\0' &&				!isspace((unsigned char) line[buflen]))			{				/* try to divide at word boundary */				i = buflen - 1;				while (i > 0 && !isspace((unsigned char) buf[i]))					i--;				if (i > 0)		/* else couldn't divide word boundary */				{					buflen = i;					buf[i] = '\0';				}			}			chunk_nr++;			syslog(level, "[%lu-%d] %s", seq, chunk_nr, buf);			line += buflen;			len -= buflen;		}	}	else	{		/* message short enough */		syslog(level, "[%lu] %s", seq, line);	}}#endif   /* HAVE_SYSLOG */#ifdef WIN32/* * Write a message line to the windows event log */static voidwrite_eventlog(int level, const char *line){	int			eventlevel = EVENTLOG_ERROR_TYPE;	static HANDLE evtHandle = INVALID_HANDLE_VALUE;	if (evtHandle == INVALID_HANDLE_VALUE)	{		evtHandle = RegisterEventSource(NULL, "PostgreSQL");		if (evtHandle == NULL)		{			evtHandle = INVALID_HANDLE_VALUE;			return;		}	}	switch (level)	{		case DEBUG5:		case DEBUG4:		case DEBUG3:		case DEBUG2:		case DEBUG1:		case LOG:		case COMMERROR:		case INFO:		case NOTICE:			eventlevel = EVENTLOG_INFORMATION_TYPE;			break;		case WARNING:			eventlevel = EVENTLOG_WARNING_TYPE;			break;		case ERROR:		case FATAL:		case PANIC:		default:			eventlevel = EVENTLOG_ERROR_TYPE;			break;	}	ReportEvent(evtHandle,				eventlevel,				0,				0,				/* All events are Id 0 */				NULL,				1,				0,				&line,				NULL);}#endif   /* WIN32 *//* * Format tag info for log lines; append to the provided buffer. */static voidlog_line_prefix(StringInfo buf){	/* static counter for line numbers */	static long log_line_number = 0;	/* has counter been reset in current process? */	static int	log_my_pid = 0;	int			format_len;	int			i;	/*	 * This is one of the few places where we'd rather not inherit a static	 * variable's value from the postmaster.  But since we will, reset it when	 * MyProcPid changes. MyStartTime also changes when MyProcPid does, so	 * reset the formatted start timestamp too.	 */	if (log_my_pid != MyProcPid)	{		log_line_number = 0;		log_my_pid = MyProcPid;		formatted_start_time[0] = '\0';	}	log_line_number++;	if (Log_line_prefix == NULL)		return;					/* in case guc hasn't run yet */	format_len = strlen(Log_line_prefix);	for (i = 0; i < format_len; i++)	{		if (Log_line_prefix[i] != '%')		{			/* literal char, just copy */			appendStringInfoChar(buf, Log_line_prefix[i]);			continue;		}		/* go to char after '%' */		i++;		if (i >= format_len)			break;				/* format error - ignore it */		/* process the option */		switch (Log_line_prefix[i])		{			case 'u':				if (MyProcPort)				{					const char *username = MyProcPort->user_name;					if (username == NULL || *username == '\0')						username = _("[unknown]");					appendStringInfo(buf, "%s", username);				}				break;			case 'd':				if (MyProcPort)				{					const char *dbname = MyProcPort->database_name;					if (dbname == NULL || *dbname == '\0')						dbname = _("[unknown]");					appendStringInfo(buf, "%s", dbname);

⌨️ 快捷键说明

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