elog.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,491 行 · 第 1/5 页
C
2,491 行
syslog_level = LOG_WARNING; break; case FATAL: syslog_level = LOG_ERR; break; case PANIC: default: syslog_level = LOG_CRIT; break; } write_syslog(syslog_level, buf.data); }#endif /* HAVE_SYSLOG */#ifdef WIN32 /* Write to eventlog, if enabled */ if (Log_destination & LOG_DESTINATION_EVENTLOG) { write_eventlog(edata->elevel, buf.data); }#endif /* WIN32 */ /* Write to stderr, if enabled */ if ((Log_destination & LOG_DESTINATION_STDERR) || whereToSendOutput == DestDebug) { /* * Use the chunking protocol if we know the syslogger should be * catching stderr output, and we are not ourselves the syslogger. * Otherwise, just do a vanilla write to stderr. */ if (redirection_done && !am_syslogger) write_pipe_chunks(buf.data, buf.len, LOG_DESTINATION_STDERR);#ifdef WIN32 /* * In a win32 service environment, there is no usable stderr. Capture * anything going there and write it to the eventlog instead. * * If stderr redirection is active, it was OK to write to stderr above * because that's really a pipe to the syslogger process. */ else if (pgwin32_is_service()) write_eventlog(edata->elevel, buf.data);#endif else write(fileno(stderr), buf.data, buf.len); } /* If in the syslogger process, try to write messages direct to file */ if (am_syslogger) write_syslogger_file(buf.data, buf.len, LOG_DESTINATION_STDERR); /* Write to CSV log if enabled */ if (Log_destination & LOG_DESTINATION_CSVLOG) { if (redirection_done || am_syslogger) { /* * send CSV data if it's safe to do so (syslogger doesn't need the * pipe). First get back the space in the message buffer. */ pfree(buf.data); write_csvlog(edata); } else { char *msg = _("Not safe to send CSV data\n"); write(fileno(stderr), msg, strlen(msg)); if (!(Log_destination & LOG_DESTINATION_STDERR) && whereToSendOutput != DestDebug) { /* write message to stderr unless we just sent it above */ write(fileno(stderr), buf.data, buf.len); } pfree(buf.data); } } else { pfree(buf.data); }}/* * Send data to the syslogger using the chunked protocol */static voidwrite_pipe_chunks(char *data, int len, int dest){ PipeProtoChunk p; int fd = fileno(stderr); Assert(len > 0); p.proto.nuls[0] = p.proto.nuls[1] = '\0'; p.proto.pid = MyProcPid; /* write all but the last chunk */ while (len > PIPE_MAX_PAYLOAD) { p.proto.is_last = (dest == LOG_DESTINATION_CSVLOG ? 'F' : 'f'); p.proto.len = PIPE_MAX_PAYLOAD; memcpy(p.proto.data, data, PIPE_MAX_PAYLOAD); write(fd, &p, PIPE_HEADER_SIZE + PIPE_MAX_PAYLOAD); data += PIPE_MAX_PAYLOAD; len -= PIPE_MAX_PAYLOAD; } /* write the last chunk */ p.proto.is_last = (dest == LOG_DESTINATION_CSVLOG ? 'T' : 't'); p.proto.len = len; memcpy(p.proto.data, data, len); write(fd, &p, PIPE_HEADER_SIZE + len);}/* * Write error report to client */static voidsend_message_to_frontend(ErrorData *edata){ StringInfoData msgbuf; /* 'N' (Notice) is for nonfatal conditions, 'E' is for errors */ pq_beginmessage(&msgbuf, (edata->elevel < ERROR) ? 'N' : 'E'); if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) { /* New style with separate fields */ char tbuf[12]; int ssval; int i; pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY); pq_sendstring(&msgbuf, error_severity(edata->elevel)); /* unpack MAKE_SQLSTATE code */ ssval = edata->sqlerrcode; for (i = 0; i < 5; i++) { tbuf[i] = PGUNSIXBIT(ssval); ssval >>= 6; } tbuf[i] = '\0'; pq_sendbyte(&msgbuf, PG_DIAG_SQLSTATE); pq_sendstring(&msgbuf, tbuf); /* M field is required per protocol, so always send something */ pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_PRIMARY); if (edata->message) pq_sendstring(&msgbuf, edata->message); else pq_sendstring(&msgbuf, _("missing error text")); if (edata->detail) { pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_DETAIL); pq_sendstring(&msgbuf, edata->detail); } if (edata->hint) { pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_HINT); pq_sendstring(&msgbuf, edata->hint); } if (edata->context) { pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT); pq_sendstring(&msgbuf, edata->context); } if (edata->cursorpos > 0) { snprintf(tbuf, sizeof(tbuf), "%d", edata->cursorpos); pq_sendbyte(&msgbuf, PG_DIAG_STATEMENT_POSITION); pq_sendstring(&msgbuf, tbuf); } if (edata->internalpos > 0) { snprintf(tbuf, sizeof(tbuf), "%d", edata->internalpos); pq_sendbyte(&msgbuf, PG_DIAG_INTERNAL_POSITION); pq_sendstring(&msgbuf, tbuf); } if (edata->internalquery) { pq_sendbyte(&msgbuf, PG_DIAG_INTERNAL_QUERY); pq_sendstring(&msgbuf, edata->internalquery); } if (edata->filename) { pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_FILE); pq_sendstring(&msgbuf, edata->filename); } if (edata->lineno > 0) { snprintf(tbuf, sizeof(tbuf), "%d", edata->lineno); pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_LINE); pq_sendstring(&msgbuf, tbuf); } if (edata->funcname) { pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_FUNCTION); pq_sendstring(&msgbuf, edata->funcname); } pq_sendbyte(&msgbuf, '\0'); /* terminator */ } else { /* Old style --- gin up a backwards-compatible message */ StringInfoData buf; initStringInfo(&buf); appendStringInfo(&buf, "%s: ", error_severity(edata->elevel)); if (edata->show_funcname && edata->funcname) appendStringInfo(&buf, "%s: ", edata->funcname); if (edata->message) appendStringInfoString(&buf, edata->message); else appendStringInfoString(&buf, _("missing error text")); if (edata->cursorpos > 0) appendStringInfo(&buf, _(" at character %d"), edata->cursorpos); else if (edata->internalpos > 0) appendStringInfo(&buf, _(" at character %d"), edata->internalpos); appendStringInfoChar(&buf, '\n'); pq_sendstring(&msgbuf, buf.data); pfree(buf.data); } pq_endmessage(&msgbuf); /* * This flush is normally not necessary, since postgres.c will flush out * waiting data when control returns to the main loop. But it seems best * to leave it here, so that the client has some clue what happened if the * backend dies before getting back to the main loop ... error/notice * messages should not be a performance-critical path anyway, so an extra * flush won't hurt much ... */ pq_flush();}/* * Support routines for formatting error messages. *//* * expand_fmt_string --- process special format codes in a format string * * We must replace %m with the appropriate strerror string, since vsnprintf * won't know what to do with it. * * The result is a palloc'd string. */static char *expand_fmt_string(const char *fmt, ErrorData *edata){ StringInfoData buf; const char *cp; initStringInfo(&buf); for (cp = fmt; *cp; cp++) { if (cp[0] == '%' && cp[1] != '\0') { cp++; if (*cp == 'm') { /* * Replace %m by system error string. If there are any %'s in * the string, we'd better double them so that vsnprintf won't * misinterpret. */ const char *cp2; cp2 = useful_strerror(edata->saved_errno); for (; *cp2; cp2++) { if (*cp2 == '%') appendStringInfoCharMacro(&buf, '%'); appendStringInfoCharMacro(&buf, *cp2); } } else { /* copy % and next char --- this avoids trouble with %%m */ appendStringInfoCharMacro(&buf, '%'); appendStringInfoCharMacro(&buf, *cp); } } else appendStringInfoCharMacro(&buf, *cp); } return buf.data;}/* * A slightly cleaned-up version of strerror() */static const char *useful_strerror(int errnum){ /* this buffer is only used if errno has a bogus value */ static char errorstr_buf[48]; const char *str;#ifdef WIN32 /* Winsock error code range, per WinError.h */ if (errnum >= 10000 && errnum <= 11999) return pgwin32_socket_strerror(errnum);#endif str = strerror(errnum); /* * Some strerror()s return an empty string for out-of-range errno. This is * ANSI C spec compliant, but not exactly useful. */ if (str == NULL || *str == '\0') { snprintf(errorstr_buf, sizeof(errorstr_buf), /*------ translator: This string will be truncated at 47 characters expanded. */ _("operating system error %d"), errnum); str = errorstr_buf; } return str;}/* * error_severity --- get localized string representing elevel */static const char *error_severity(int elevel){ const char *prefix; switch (elevel) { case DEBUG1: case DEBUG2: case DEBUG3: case DEBUG4: case DEBUG5: prefix = _("DEBUG"); break; case LOG: case COMMERROR: prefix = _("LOG"); break; case INFO: prefix = _("INFO"); break; case NOTICE: prefix = _("NOTICE"); break; case WARNING: prefix = _("WARNING"); break; case ERROR: prefix = _("ERROR"); break; case FATAL: prefix = _("FATAL"); break; case PANIC: prefix = _("PANIC"); break; default: prefix = "???"; break; } return prefix;}/* * append_with_tabs * * Append the string to the StringInfo buffer, inserting a tab after any * newline. */static voidappend_with_tabs(StringInfo buf, const char *str){ char ch; while ((ch = *str++) != '\0') { appendStringInfoCharMacro(buf, ch); if (ch == '\n') appendStringInfoCharMacro(buf, '\t'); }}/* * Write errors to stderr (or by equal means when stderr is * not available). Used before ereport/elog can be used * safely (memory context, GUC load etc) */voidwrite_stderr(const char *fmt,...){ va_list ap; fmt = _(fmt); va_start(ap, fmt);#ifndef WIN32 /* On Unix, we just fprintf to stderr */ vfprintf(stderr, fmt, ap); fflush(stderr);#else /* * On Win32, we print to stderr if running on a console, or write to * eventlog if running as a service */ if (pgwin32_is_service()) /* Running as a service */ { char errbuf[2048]; /* Arbitrary size? */ vsnprintf(errbuf, sizeof(errbuf), fmt, ap); write_eventlog(ERROR, errbuf); } else { /* Not running as service, write to stderr */ vfprintf(stderr, fmt, ap); fflush(stderr); }#endif va_end(ap);}/* * is_log_level_output -- is elevel logically >= log_min_level? * * We use this for tests that should consider LOG to sort out-of-order, * between ERROR and FATAL. Generally this is the right thing for testing * whether a message should go to the postmaster log, whereas a simple >= * test is correct for testing whether the message should go to the client. */static boolis_log_level_output(int elevel, int log_min_level){ if (elevel == LOG || elevel == COMMERROR) { if (log_min_level == LOG || log_min_level <= ERROR) return true; } else if (log_min_level == LOG) { /* elevel != LOG */ if (elevel >= FATAL) return true; } /* Neither is LOG */ else if (elevel >= log_min_level) return true; return false;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?