diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 03c553e7ea..9cd0b7c11b 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -5344,7 +5344,7 @@ static void ShowTransactionState(const char *str) { /* skip work if message will definitely not be printed */ - if (log_min_messages <= DEBUG5 || client_min_messages <= DEBUG5) + if (message_level_is_interesting(DEBUG5)) ShowTransactionStateRec(str, CurrentTransactionState); } @@ -5371,7 +5371,6 @@ ShowTransactionStateRec(const char *str, TransactionState s) if (s->parent) ShowTransactionStateRec(str, s->parent); - /* use ereport to suppress computation if msg will not be printed */ ereport(DEBUG5, (errmsg_internal("%s(%d) name: %s; blockState: %s; state: %s, xid/subid/cid: %u/%u/%u%s%s", str, s->nestingLevel, diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index 7e915bcadf..32a3099c1f 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -105,7 +105,7 @@ log_invalid_page(RelFileNode node, ForkNumber forkno, BlockNumber blkno, * tracing of the cause (note the elog context mechanism will tell us * something about the XLOG record that generated the reference). */ - if (log_min_messages <= DEBUG1 || client_min_messages <= DEBUG1) + if (message_level_is_interesting(DEBUG1)) report_invalid_page(DEBUG1, node, forkno, blkno, present); if (invalid_page_tab == NULL) @@ -159,7 +159,7 @@ forget_invalid_pages(RelFileNode node, ForkNumber forkno, BlockNumber minblkno) hentry->key.forkno == forkno && hentry->key.blkno >= minblkno) { - if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2) + if (message_level_is_interesting(DEBUG2)) { char *path = relpathperm(hentry->key.node, forkno); @@ -192,7 +192,7 @@ forget_invalid_pages_db(Oid dbid) { if (hentry->key.node.dbNode == dbid) { - if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2) + if (message_level_is_interesting(DEBUG2)) { char *path = relpathperm(hentry->key.node, hentry->key.forkno); diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index b0d037600e..245c2f4fc8 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -1146,15 +1146,9 @@ reportDependentObjects(const ObjectAddresses *targetObjects, * If no error is to be thrown, and the msglevel is too low to be shown to * either client or server log, there's no need to do any of the rest of * the work. - * - * Note: this code doesn't know all there is to be known about elog - * levels, but it works for NOTICE and DEBUG2, which are the only values - * msglevel can currently have. We also assume we are running in a normal - * operating environment. */ if (behavior == DROP_CASCADE && - msglevel < client_min_messages && - (msglevel < log_min_messages || log_min_messages == LOG)) + !message_level_is_interesting(msglevel)) return; /* diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index babee386c4..87c3ea450e 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -1215,7 +1215,7 @@ ProcessWalSndrMessage(XLogRecPtr walEnd, TimestampTz sendTime) walrcv->lastMsgReceiptTime = lastMsgReceiptTime; SpinLockRelease(&walrcv->mutex); - if (log_min_messages <= DEBUG2) + if (message_level_is_interesting(DEBUG2)) { char *sendtime; char *receipttime; diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 5d1b1a16be..2eb19ad293 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -1900,7 +1900,7 @@ ProcessStandbyReplyMessage(void) replyTime = pq_getmsgint64(&reply_message); replyRequested = pq_getmsgbyte(&reply_message); - if (log_min_messages <= DEBUG2) + if (message_level_is_interesting(DEBUG2)) { char *replyTimeStr; @@ -2082,7 +2082,7 @@ ProcessStandbyHSFeedbackMessage(void) feedbackCatalogXmin = pq_getmsgint(&reply_message, 4); feedbackCatalogEpoch = pq_getmsgint(&reply_message, 4); - if (log_min_messages <= DEBUG2) + if (message_level_is_interesting(DEBUG2)) { char *replyTimeStr; diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 40eac704dc..7dc3911590 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -1337,26 +1337,30 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) !(statusFlags & PROC_VACUUM_FOR_WRAPAROUND)) { int pid = autovac->pid; - StringInfoData locktagbuf; - StringInfoData logbuf; /* errdetail for server log */ /* report the case, if configured to do so */ - initStringInfo(&locktagbuf); - initStringInfo(&logbuf); - DescribeLockTag(&locktagbuf, &locktag_copy); - appendStringInfo(&logbuf, - _("Process %d waits for %s on %s."), - MyProcPid, - GetLockmodeName(lockmethod_copy, lockmode), - locktagbuf.data); + if (message_level_is_interesting(DEBUG1)) + { + StringInfoData locktagbuf; + StringInfoData logbuf; /* errdetail for server log */ - ereport(DEBUG1, - (errmsg("sending cancel to blocking autovacuum PID %d", - pid), - errdetail_log("%s", logbuf.data))); + initStringInfo(&locktagbuf); + initStringInfo(&logbuf); + DescribeLockTag(&locktagbuf, &locktag_copy); + appendStringInfo(&logbuf, + _("Process %d waits for %s on %s."), + MyProcPid, + GetLockmodeName(lockmethod_copy, lockmode), + locktagbuf.data); - pfree(logbuf.data); - pfree(locktagbuf.data); + ereport(DEBUG1, + (errmsg("sending cancel to blocking autovacuum PID %d", + pid), + errdetail_log("%s", logbuf.data))); + + pfree(locktagbuf.data); + pfree(logbuf.data); + } /* send the autovacuum worker Back to Old Kent Road */ if (kill(pid, SIGINT) < 0) diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 42c5e052b6..3558e660c7 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -184,7 +184,94 @@ static void write_pipe_chunks(char *data, int len, int dest); static void send_message_to_frontend(ErrorData *edata); static const char *error_severity(int elevel); static void append_with_tabs(StringInfo buf, const char *str); -static bool is_log_level_output(int elevel, int log_min_level); + + +/* + * 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 inline bool +is_log_level_output(int elevel, int log_min_level) +{ + if (elevel == LOG || elevel == LOG_SERVER_ONLY) + { + 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; +} + +/* + * Policy-setting subroutines. These are fairly simple, but it seems wise + * to have the code in just one place. + */ + +/* + * should_output_to_server --- should message of given elevel go to the log? + */ +static inline bool +should_output_to_server(int elevel) +{ + return is_log_level_output(elevel, log_min_messages); +} + +/* + * should_output_to_client --- should message of given elevel go to the client? + */ +static inline bool +should_output_to_client(int elevel) +{ + if (whereToSendOutput == DestRemote && elevel != LOG_SERVER_ONLY) + { + /* + * client_min_messages is honored only after we complete the + * authentication handshake. This is required both for security + * reasons and because many clients can't handle NOTICE messages + * during authentication. + */ + if (ClientAuthInProgress) + return (elevel >= ERROR); + else + return (elevel >= client_min_messages || elevel == INFO); + } + return false; +} + + +/* + * message_level_is_interesting --- would ereport/elog do anything? + * + * Returns true if ereport/elog with this elevel will not be a no-op. + * This is useful to short-circuit any expensive preparatory work that + * might be needed for a logging message. There is no point in + * prepending this to a bare ereport/elog call, however. + */ +bool +message_level_is_interesting(int elevel) +{ + /* + * Keep this in sync with the decision-making in errstart(). + */ + if (elevel >= ERROR || + should_output_to_server(elevel) || + should_output_to_client(elevel)) + return true; + return false; +} /* @@ -301,27 +388,8 @@ errstart(int elevel, const char *domain) * 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 */ - output_to_server = is_log_level_output(elevel, log_min_messages); - - /* Determine whether message is enabled for client output */ - if (whereToSendOutput == DestRemote && elevel != LOG_SERVER_ONLY) - { - /* - * client_min_messages is honored only after we complete the - * authentication handshake. This is required both for security - * reasons and because many clients can't handle NOTICE messages - * during authentication. - */ - if (ClientAuthInProgress) - output_to_client = (elevel >= ERROR); - else - output_to_client = (elevel >= client_min_messages || - elevel == INFO); - } - - /* Skip processing effort if non-error message will not be output */ + output_to_server = should_output_to_server(elevel); + output_to_client = should_output_to_client(elevel); if (elevel < ERROR && !output_to_server && !output_to_client) return false; @@ -1743,16 +1811,10 @@ pg_re_throw(void) /* * 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. + * where-to-output decisions, so recalculate. */ - 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) - edata->output_to_client = true; + edata->output_to_server = should_output_to_server(FATAL); + edata->output_to_client = should_output_to_client(FATAL); /* * We can use errfinish() for the rest, but we don't want it to call @@ -3505,35 +3567,6 @@ write_stderr(const char *fmt,...) } -/* - * 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 bool -is_log_level_output(int elevel, int log_min_level) -{ - if (elevel == LOG || elevel == LOG_SERVER_ONLY) - { - 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; -} - /* * Adjust the level of a recovery-related message per trace_recovery_messages. * diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 270bfbcfe5..cb7f8c30c3 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -157,8 +157,10 @@ #define TEXTDOMAIN NULL -extern bool pg_attribute_cold errstart_cold(int elevel, const char *domain); +extern bool message_level_is_interesting(int elevel); + extern bool errstart(int elevel, const char *domain); +extern bool pg_attribute_cold errstart_cold(int elevel, const char *domain); extern void errfinish(const char *filename, int lineno, const char *funcname); extern int errcode(int sqlerrcode);