LOG(INFO) vs LOG(WARNING) vs LOG(ERROR) vs CHECK in Abseil-C++: Key Differences Explained
LOG(INFO), LOG(WARNING), and LOG(ERROR) emit diagnostic messages at different severity levels without stopping execution, while CHECK macros verify conditions and abort the program immediately upon failure.
The Abseil C++ library (abseil/abseil-cpp) provides two distinct families of macros for observability and defense. While both LOG and CHECK write to the same underlying logging infrastructure, they serve fundamentally different purposes regarding program flow control and severity levels.
Understanding LOG Severity Levels
The LOG macros record messages at specific severities defined in absl/base/log_severity.h: kInfo, kWarning, kError, and kFatal.
LOG(INFO) for Routine Diagnostics
LOG(INFO) represents the lowest severity level and is used for routine diagnostics that are always safe to emit. It indicates normal program operation and provides tracing information for developers.
LOG(WARNING) for Potential Issues
LOG(WARNING) flags situations that might be problematic but do not prevent the program from continuing execution. Use this when the program encounters recoverable anomalies or unexpected but tolerated states.
LOG(ERROR) for Serious Conditions
LOG(ERROR) corresponds to kError severity and signals serious conditions that the program can tolerate but which require immediate developer attention. Execution continues normally after the message is logged.
How LOG Macros Work Under the Hood
All three macros expand to ABSL_LOG_INTERNAL_LOG_IMPL defined in absl/log/log.h. According to the Abseil source code, this implementation constructs a LogMessage object that streams the supplied expression(s). When the statement ends, the destructor forwards the built string to configured LogSinks. Execution always continues after the logging statement regardless of the severity level specified.
CHECK Macros Enforce Runtime Invariants
In contrast to observational logging, the CHECK family declared in absl/log/check.h performs defensive programming by enforcing runtime invariants.
Fatal Termination on Failure
A failing CHECK expands to ABSL_LOG_INTERNAL_CHECK_IMPL which evaluates the condition. If the expression evaluates to false, the macro creates a LogMessage with severity kFatal, prints a stack trace, runs registered error handlers, and calls abort(). The program terminates immediately; no subsequent code executes.
Comparison Variants (CHECK_EQ, CHECK_NE, etc.)
CHECK_EQ, CHECK_NE, CHECK_LT, CHECK_GT, CHECK_LE, and CHECK_GE provide syntactic sugar for binary comparisons. These variants automatically stringify both operands in the error message, providing more diagnostic context than a raw CHECK(a == b).
QCHECK for Quiet Fatal Failures
QCHECK uses QFATAL severity instead of FATAL, suppressing the stack trace output while still terminating the program immediately upon condition failure.
DCHECK for Debug Builds
DCHECK variants behave like CHECK only in debug builds (#ifndef NDEBUG). In release builds, they compile away completely, similar to how DLOG behaves compared to standard LOG macros.
Structured Comparison
Program Flow Control: LOG(severity) macros return normally and execution continues, while CHECK calls abort() and terminates the process.
Severity Assignment: LOG macros accept INFO, WARNING, ERROR, or FATAL as parameters. CHECK is fixed to FATAL severity (or QFATAL for QCHECK).
Compilation Behavior: LOG statements are always compiled unless stripped by ABSL_MIN_LOG_LEVEL. CHECK is always compiled in all builds, while DCHECK is debug-only.
Implementation Entry: LOG uses ABSL_LOG_INTERNAL_LOG_IMPL in absl/log/log.h, while CHECK uses ABSL_LOG_INTERNAL_CHECK_IMPL in absl/log/check.h.
Practical Code Examples
#include "absl/log/log.h"
#include "absl/log/check.h"
void InitializeServer(int port, const std::string& config) {
// Observational logging - execution continues after each line
LOG(INFO) << "Server starting on port " << port;
LOG(WARNING) << "Using default configuration for port " << port;
LOG(ERROR) << "Failed to load SSL certificates";
// Defensive checks - program aborts if condition is false
CHECK(!config.empty()) << "Configuration cannot be empty";
CHECK_EQ(port, 8080) << "Port mismatch detected";
// Debug-only check (removed in release builds)
DCHECK(port > 0) << "Port must be positive";
}
Summary
- LOG(INFO), LOG(WARNING), and LOG(ERROR) emit messages at increasing severity levels (
kInfo,kWarning,kError) without altering program flow - CHECK macros enforce invariants by calling
abort()when conditions evaluate to false, usingkFatalseverity internally - All
LOGseverities are defined inabsl/base/log_severity.hand processed throughABSL_LOG_INTERNAL_LOG_IMPLinabsl/log/log.h - DCHECK variants are stripped in release builds unlike CHECK which remains active in all configurations
- QCHECK provides quiet fatal failures without stack traces, using
QFATALseverity
Frequently Asked Questions
Does LOG(ERROR) stop program execution?
No. LOG(ERROR) records a message at kError severity and returns normally. Unlike CHECK or LOG(FATAL), it does not call abort() or terminate the process. The program continues executing the next statement immediately after the logging call.
What is the difference between CHECK and standard assert?
CHECK macros are always compiled into the binary (unless using DCHECK), whereas standard assert macros are typically disabled in release builds via NDEBUG. Additionally, CHECK integrates with the Abseil logging infrastructure (LogMessage in absl/log/internal/log_impl.h) and supports streaming operators for custom error messages, providing richer diagnostics than standard assert.
Can I disable LOG(INFO) at compile time?
Yes. You can define ABSL_MIN_LOG_LEVEL to exclude lower severity levels from the compiled binary. When set above kInfo, LOG(INFO) statements compile away completely, similar to how DCHECK behaves in release builds. This allows zero-cost omission of verbose logging in production binaries.
When should I use CHECK_EQ instead of CHECK?
Use CHECK_EQ, CHECK_NE, CHECK_LT, CHECK_GT, CHECK_LE, or CHECK_GE when comparing two values. These variants, defined in absl/log/check.h, automatically stringify both operands in the error message, providing more context than a raw CHECK(a == b) which would only show the expression text rather than the actual values.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →