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 + -
显示快捷键?