Newer
Older
/*-------------------------------------------------------------------------
*
* elog.c
* 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.
*
* First, distinguish between re-entrant use and actual recursion. It
* is possible for an error or warning message to be emitted while the
* parameters for an error message are being computed. In this case
* errstart has been called for the outer message, and some field values
* 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
* 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 case is to reset the
* ErrorContext to empty before trying to process the inner error. 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.
* Since we lose the prior error state due to the reset, we won't be able
* to return to processing the original error, but we wouldn't have anyway.
* (NOTE: the escape hatch is not used for recursive situations where the
* inner message is of less than ERROR severity; in that case we just
* try to process it and return normally. Usually this will work, but if
* it ends up in infinite recursion, we will PANIC due to error stack
* overflow.)
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
Alvaro Herrera
committed
* $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.166 2005/11/03 17:11:39 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <ctype.h>
#include <syslog.h>
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "postmaster/postmaster.h"
#include "postmaster/syslogger.h"
#include "storage/ipc.h"
#include "tcop/tcopprot.h"
#include "utils/memutils.h"
#include "utils/guc.h"
/* Global variables */
ErrorContextCallback *error_context_stack = NULL;
sigjmp_buf *PG_exception_stack = NULL;
/* GUC parameters */
PGErrorVerbosity Log_error_verbosity = PGERROR_VERBOSE;
char *Log_line_prefix = NULL; /* format for extra log line info */
int Log_destination = LOG_DESTINATION_STDERR;
static bool openlog_done = false;
static char *syslog_ident = NULL;
static int syslog_facility = LOG_LOCAL0;
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 */
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)
ErrorData *edata;
bool output_to_server = false;
bool output_to_client = false;
* Check some cases in which we want to promote an error into a more
* severe error. None of this logic applies for non-error messages.
*/
if (elevel >= ERROR)
/*
* If we are inside a critical section, all errors become PANIC
* errors. See miscadmin.h.
*/
if (CritSectionCount > 0)
elevel = PANIC;
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
* Check reasons for treating ERROR as FATAL:
*
* 1. we have no handler to pass the error to (implies we are in the
* postmaster or in backend startup).
*
* 2. ExitOnAnyError mode switch is set (initdb uses this).
*
* 3. the error occurred after proc_exit has begun to run. (It's
* proc_exit's responsibility to see that this doesn't turn into
* infinite recursion!)
*/
if (elevel == ERROR)
{
if (PG_exception_stack == NULL ||
ExitOnAnyError ||
proc_exit_inprogress)
elevel = FATAL;
}
/*
* If the error level is ERROR or more, errfinish is not going to
* return to caller; therefore, if there is any stacked error already
* in progress it will be lost. This is more or less okay, except we
* do not want to have a FATAL or PANIC error downgraded because the
* reporting process was interrupted by a lower-grade error. So check
* the stack and make sure we panic if panic is warranted.
*/
for (i = 0; i <= errordata_stack_depth; i++)
elevel = Max(elevel, errordata[i].elevel);
/*
* Now 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.
/* Determine whether message is enabled for server log output */
if (IsPostmasterEnvironment)
/* Complicated because LOG is sorted out-of-order for this purpose */
if (elevel == LOG || elevel == COMMERROR)
Loading
Loading full blame...