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