📄 elog.c
字号:
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();}/* * 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; /* 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) '\n'. */ len = strlen(line); if (len > PG_SYSLOG_LIMIT || strchr(line, '\n') != 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--; continue; } strncpy(buf, line, PG_SYSLOG_LIMIT); buf[PG_SYSLOG_LIMIT] = '\0'; if (strchr(buf, '\n') != NULL) *strchr(buf, '\n') = '\0'; buflen = strlen(buf); /* 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. */ if (log_my_pid != MyProcPid) { log_line_number = 0; log_my_pid = MyProcPid; } 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); } break; case 'c': if (MyProcPort) { appendStringInfo(buf, "%lx.%x", (long) (MyProcPort->session_start.tv_sec), MyProcPid); } break; case 'p': appendStringInfo(buf, "%d", MyProcPid); break; case 'l': appendStringInfo(buf, "%ld", log_line_number); break; case 'm': { /* * Note: for %m, %t, and %s we deliberately use the C * library's strftime/localtime, and not the equivalent * functions from src/timezone. This ensures that all * backends will report log entries in the same timezone, * namely whatever C-library setting they inherit from the * postmaster. If we used src/timezone then local * settings of the TimeZone GUC variable would confuse the * log. */ time_t stamp_time; char strfbuf[128], msbuf[8]; struct timeval tv; gettimeofday(&tv, NULL); stamp_time = tv.tv_sec; strftime(strfbuf, sizeof(strfbuf), /* leave room for milliseconds... */ /* Win32 timezone names are too long so don't print them. */#ifndef WIN32 "%Y-%m-%d %H:%M:%S %Z",#else "%Y-%m-%d %H:%M:%S ",#endif localtime(&stamp_time)); /* 'paste' milliseconds into place... */ sprintf(msbuf, ".%03d", (int) (tv.tv_usec / 1000)); strncpy(strfbuf + 19, msbuf, 4); appendStringInfoString(buf, strfbuf); } break; case 't': { time_t stamp_time = time(NULL); char strfbuf[128]; strftime(strfbuf, sizeof(strfbuf), /* Win32 timezone names are too long so don't print them. */#ifndef WIN32 "%Y-%m-%d %H:%M:%S %Z",#else "%Y-%m-%d %H:%M:%S",#endif localtime(&stamp_time)); appendStringInfoString(buf, strfbuf); } break; case 's': if (MyProcPort) { time_t stamp_time = MyProcPort->session_start.tv_sec; char strfbuf[128]; strftime(strfbuf, sizeof(strfbuf), "%Y-%m-%d %H:%M:%S %Z", localtime(&stamp_time)); appendStringInfoString(buf, strfbuf); } break; case 'i': if (MyProcPort) { const char *psdisp; int displen; psdisp = get_ps_display(&displen); appendStringInfo(buf, "%.*s", displen, psdisp); } break; case 'r': if (MyProcPort && MyProcPort->remote_host) { appendStringInfo(buf, "%s", MyProcPort->remote_host); if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0') appendStringInfo(buf, "(%s)", MyProcPort->remote_port); } break; case 'h': if (MyProcPort && MyProcPort->remote_host) appendStringInfo(buf, "%s", MyProcPort->remote_host); break; case 'q': /* in postmaster and friends, stop if %q is seen */ /* in a backend, just ignore */ if (MyProcPort == NULL) i = format_len; break; case 'x': if (MyProcPort) { if (IsTransactionState()) appendStringInfo(buf, "%u", GetTopTransactionId()); else appendStringInfo(buf, "%u", InvalidTransactionId); } break; case '%': appendStringInfoChar(buf, '%'); break; default: /* format error - ignore it */ break; } }}/* * Unpack MAKE_SQLSTATE code. Note that this returns a pointer to a * static buffer. */char *unpack_sql_state(int sql_state){ static char buf[12]; int i; for (i = 0; i < 5; i++) { buf[i] = PGUNSIXBIT(sql_state); sql_state >>= 6;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -