Skip to content
Snippets Groups Projects
elog.c 48 KiB
Newer Older
/*-------------------------------------------------------------------------
 *
 *	  error logging and reporting
 *
 * Some notes about recursion and errors during error processing:
 *
 * We need to be robust about recursive-error scenarios --- for example,
 * if we run out of memory, it's important to be able to report that fact.
 * There are a number of considerations that go into this.
 *
Bruce Momjian's avatar
Bruce Momjian committed
 * First, distinguish between re-entrant use and actual recursion.	It
 * is possible for an error or warning message to be emitted while the
Bruce Momjian's avatar
Bruce Momjian committed
 * parameters for an error message are being computed.	In this case
 * errstart has been called for the outer message, and some field values
Bruce Momjian's avatar
Bruce Momjian committed
 * may have already been saved, but we are not actually recursing.	We handle
 * this by providing a (small) stack of ErrorData records.	The inner message
 * can be computed and sent without disturbing the state of the outer message.
 * (If the inner message is actually an error, this isn't very interesting
 * because control won't come back to the outer message generator ... but
 * if the inner message is only debug or log data, this is critical.)
 *
 * Second, actual recursion will occur if an error is reported by one of
Bruce Momjian's avatar
Bruce Momjian committed
 * the elog.c routines or something they call.	By far the most probable
 * scenario of this sort is "out of memory"; and it's also the nastiest
 * to handle because we'd likely also run out of memory while trying to
 * report this error!  Our escape hatch for this condition is to force any
 * such messages up to ERROR level if they aren't already (so that we will
 * not need to return to the outer elog.c call), and to reset the ErrorContext
 * to empty before trying to process the inner message.  Since ErrorContext
 * is guaranteed to have at least 8K of space in it (see mcxt.c), we should
 * be able to process an "out of memory" message successfully.
 *
Bruce Momjian's avatar
Bruce Momjian committed
 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
Bruce Momjian's avatar
Bruce Momjian committed
 * Portions Copyright (c) 1994, Regents of the University of California
Bruce Momjian's avatar
Bruce Momjian committed
 *	  $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.147 2004/08/29 04:12:53 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#ifdef HAVE_SYSLOG
Marc G. Fournier's avatar
 
Marc G. Fournier committed
#endif

#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "postmaster/postmaster.h"
#include "postmaster/syslogger.h"
Marc G. Fournier's avatar
 
Marc G. Fournier committed


/* Global variables */
ErrorContextCallback *error_context_stack = NULL;

sigjmp_buf *PG_exception_stack = NULL;

PGErrorVerbosity Log_error_verbosity = PGERROR_VERBOSE;
char       *Log_line_prefix = NULL; /* format for extra log line info */
int			Log_destination = LOG_DESTINATION_STDERR;
#ifdef HAVE_SYSLOG
char	   *Syslog_facility;	/* openlog() parameters */
char	   *Syslog_ident;

static void write_syslog(int level, const char *line);
#endif
#ifdef WIN32
static void write_eventlog(int level, const char *line);
#endif
/* We provide a small stack of ErrorData records for re-entrant cases */
#define ERRORDATA_STACK_SIZE  5

static ErrorData errordata[ERRORDATA_STACK_SIZE];

static int	errordata_stack_depth = -1; /* index of topmost active frame */

Bruce Momjian's avatar
Bruce Momjian committed
static int	recursion_depth = 0;	/* to detect actual recursion */


/* Macro for checking errordata_stack_depth is reasonable */
#define CHECK_STACK_DEPTH() \
	do { \
		if (errordata_stack_depth < 0) \
		{ \
			errordata_stack_depth = -1; \
			ereport(ERROR, (errmsg_internal("errstart was not called"))); \
		} \
	} while (0)


static void log_line_prefix(StringInfo buf);
static void send_message_to_server_log(ErrorData *edata);
static void send_message_to_frontend(ErrorData *edata);
static char *expand_fmt_string(const char *fmt, ErrorData *edata);
static const char *useful_strerror(int errnum);
static const char *error_severity(int elevel);
static void append_with_tabs(StringInfo buf, const char *str);
/*
 * errstart --- begin an error-reporting cycle
 * Create a stack entry and store the given parameters in it.  Subsequently,
 * errmsg() and perhaps other routines will be called to further populate
 * the stack entry.  Finally, errfinish() will be called to actually process
 * the error report.
 * Returns TRUE in normal case.  Returns FALSE to short-circuit the error
 * report (if it's a warning or lower and not to be reported anywhere).
bool
errstart(int elevel, const char *filename, int lineno,
		 const char *funcname)
	bool		output_to_server = false;
	bool		output_to_client = false;
Bruce Momjian's avatar
Bruce Momjian committed
	 * First decide whether we need to process this report at all; if it's
	 * warning or less and not enabled for logging, just return FALSE
	 * without starting up any error logging machinery.
	 * Convert initialization errors into fatal errors. This is probably
	 * redundant, because PG_exception_stack will still be null anyway.
	if (elevel == ERROR && IsInitProcessingMode())
		elevel = FATAL;
	 * If we are inside a critical section, all errors become PANIC
	/* Determine whether message is enabled for server log output */
		/* Complicated because LOG is sorted out-of-order for this purpose */
		if (elevel == LOG || elevel == COMMERROR)
			if (log_min_messages == LOG)
				output_to_server = true;
			else if (log_min_messages < FATAL)
		else
		{
			/* elevel != LOG */
			if (log_min_messages == LOG)
			{
				if (elevel >= FATAL)
					output_to_server = true;
			}
			/* Neither is LOG */
			else if (elevel >= log_min_messages)
				output_to_server = true;
		}
	}
	else
	{
		/* In bootstrap/standalone case, do not sort LOG out-of-order */
		output_to_server = (elevel >= log_min_messages);
	}

	/* Determine whether message is enabled for client output */
	if (whereToSendOutput == Remote && elevel != COMMERROR)
	{
		/*
		 * client_min_messages is honored only after we complete the
		 * authentication handshake.  This is required both for security
		 * reasons and because many clients can't handle NOTICE messages
		 * during authentication.
		 */
		if (ClientAuthInProgress)
			output_to_client = (elevel >= ERROR);
Loading
Loading full blame...