# LOG(INFO) vs LOG(WARNING) vs LOG(ERROR) vs CHECK in Abseil-C++: Key Differences Explained

> Understand the core differences between Abseil-C++ LOG(INFO), LOG(WARNING), LOG(ERROR), and CHECK macros. Learn when to use each for effective debugging and program stability.

- Repository: [Abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)
- Tags: deep-dive
- Published: 2026-07-11

---

**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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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 `LogSink`s. **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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/absl/log/log.h), while `CHECK` uses `ABSL_LOG_INTERNAL_CHECK_IMPL` in [`absl/log/check.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/log/check.h).

## Practical Code Examples

```cpp
#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, using `kFatal` severity internally
- All `LOG` severities are defined in [`absl/base/log_severity.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/log_severity.h) and processed through `ABSL_LOG_INTERNAL_LOG_IMPL` in [`absl/log/log.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/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 `QFATAL` severity

## 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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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.