Google glog
Robust C++ logging library by Google. Distinguished as only library with crash handling capabilities (SIGSEGV, SIGILL, SIGFPE, etc.). Designed for simple and robust standalone applications. Developed as successor to G2log.
Library
glog
Overview
glog is a C++ logging library developed by Google. It provides a simple and efficient API with features including log level control, conditional log output, custom prefixes, and automatic log cleaning functionality. With thread-safe and high-performance design, it is suitable for use in large-scale applications and has a proven track record of being widely used in Google's production systems. It also provides assertion functionality through CHECK macros, making it useful for both debugging and production environments.
Details
glog was developed by Google in 2008 and continues to be actively developed as a C++ logging library. It features intuitive macro-based APIs such as LOG, VLOG, and CHECK, and provides hierarchical log management through log levels (INFO, WARNING, ERROR, FATAL). It includes a comprehensive feature set that meets enterprise-level requirements, including verbose log control through VLOG, conditional logging with LOG_IF/LOG_EVERY_N, custom prefix formatters, automatic stack trace output, and signal handling functionality.
Key Features
- Macro-based API: Intuitive and easy-to-use macros such as LOG, VLOG, and CHECK
- Hierarchical Log Levels: Systematic log management with INFO, WARNING, ERROR, and FATAL
- VLOG Verbose Control: Fine-grained debug log control through --v flags
- Conditional Logging: Efficient log control with LOG_IF, LOG_EVERY_N, LOG_FIRST_N, etc.
- CHECK Assertions: Program precondition and postcondition checking functionality
- Custom Sinks: Flexible output destination control through LogSink interface
Advantages and Disadvantages
Advantages
- High reliability and stability proven in Google production environments
- High development efficiency through simple and intuitive macro APIs
- Efficient debugging through graduated debug log control with VLOG
- Performance optimization through rich conditional logging features
- Robust error handling through CHECK macros
- Support for major build systems including CMake, Bazel, and vcpkg
Disadvantages
- C++ only, making unification difficult in multi-language environments
- Performance constraints under high load due to primarily synchronous logging
- Somewhat limited log format customization capabilities
- FATAL logs terminating programs may cause unexpected behavior
- Need to be careful about ERROR macro conflicts in Windows environments
- No default log rotation functionality, requiring external tools
Reference Pages
Code Examples
Basic Setup
#include <glog/logging.h>
int main(int argc, char* argv[]) {
// Initialize glog (usually pass program name)
google::InitGoogleLogging(argv[0]);
// Basic log configuration
FLAGS_logtostderr = 1; // Output logs to stderr
FLAGS_log_dir = "./logs/"; // Set log directory
LOG(INFO) << "glog initialized successfully";
// glog is usually automatically cleaned up on program exit
return 0;
}
Basic Log Output
#include <glog/logging.h>
void basicLogging() {
// Basic log levels
LOG(INFO) << "Application started successfully";
LOG(WARNING) << "Warning: Configuration file not found";
LOG(ERROR) << "Error: Database connection failed";
// FATAL log (terminates program)
// LOG(FATAL) << "Fatal error occurred"; // Program exits at this line
// Conditional logging
int num_users = 150;
LOG_IF(INFO, num_users > 100) << "Many users connected: " << num_users;
// Periodic logging (performance improvement)
for (int i = 0; i < 1000; ++i) {
LOG_EVERY_N(INFO, 100) << "Every 100th log: " << google::COUNTER;
}
// First N times only
for (int i = 0; i < 1000; ++i) {
LOG_FIRST_N(INFO, 5) << "First 5 times only: " << google::COUNTER;
}
// Time-based limited logging
LOG_EVERY_T(INFO, 2.0) << "Approximately every 2 seconds";
}
Advanced Configuration (VLOG, CHECK Macros, Custom Settings)
#include <glog/logging.h>
void advancedLogging() {
// VLOG (Verbose Logging) - controlled by --v flag
VLOG(1) << "Debug information at verbose level 1";
VLOG(2) << "More detailed debug information at level 2";
VLOG(3) << "Very detailed information at level 3";
// VLOG conditional macros
bool debug_mode = true;
VLOG_IF(1, debug_mode) << "Output only when debug mode is enabled";
VLOG_EVERY_N(2, 10) << "Every 10th time at VLOG level 2";
// Check if VLOG is enabled
if (VLOG_IS_ON(2)) {
// Expensive processing (only executed at VLOG level 2 or higher)
std::string expensive_debug_info = calculateDebugInfo();
VLOG(2) << "Expensive debug info: " << expensive_debug_info;
}
// CHECK macros (assertions)
int* ptr = getData();
CHECK(ptr != nullptr) << "Data pointer is null";
CHECK_NOTNULL(ptr); // Returns ptr (if not null)
// Comparison CHECKs
int expected = 42;
int actual = calculateValue();
CHECK_EQ(expected, actual) << "Expected and actual values differ";
CHECK_NE(0, actual) << "Value should not be zero";
CHECK_LT(actual, 100) << "Value is 100 or greater";
CHECK_LE(actual, 99) << "Value exceeds 99";
CHECK_GT(actual, 0) << "Value is zero or negative";
CHECK_GE(actual, 1) << "Value is less than 1";
// String comparison CHECK
const char* result = getResult();
CHECK_STREQ(result, "success") << "Operation was not successful";
CHECK_STRNE(result, "error") << "An error occurred";
// DLOG - only enabled in debug builds
DLOG(INFO) << "Log shown only in debug builds";
DLOG_IF(INFO, condition) << "Debug build + conditional log";
}
// Custom prefix formatter
void MyPrefixFormatter(std::ostream& s, const google::LogMessage& m, void* /*data*/) {
s << "[" << m.time().year() + 1900
<< "-" << std::setw(2) << std::setfill('0') << m.time().month() + 1
<< "-" << std::setw(2) << std::setfill('0') << m.time().day()
<< " " << std::setw(2) << std::setfill('0') << m.time().hour()
<< ":" << std::setw(2) << std::setfill('0') << m.time().min()
<< ":" << std::setw(2) << std::setfill('0') << m.time().sec()
<< "." << std::setw(6) << std::setfill('0') << m.time().usec()
<< "] [" << google::GetLogSeverityName(m.severity())[0]
<< "] [" << m.thread_id() << "] "
<< m.basename() << ":" << m.line() << "]";
}
void customConfiguration() {
// Set custom prefix formatter
google::InstallPrefixFormatter(&MyPrefixFormatter);
// Enable log cleaning feature (C++20 and later)
using namespace std::chrono_literals;
google::EnableLogCleaner(3 * 24h); // Keep logs for 3 days
LOG(INFO) << "Custom configuration applied";
}
Error Handling and Custom Sinks
#include <glog/logging.h>
// Custom failure function
void MyFailureFunction() {
std::cerr << "FATAL error detected, performing cleanup..." << std::endl;
// Cleanup processing
cleanup_resources();
exit(EXIT_FAILURE);
}
// Custom log sink implementation
class CustomLogSink : public google::LogSink {
public:
void send(google::LogSeverity severity, const char* full_filename,
const char* base_filename, int line,
const google::LogMessageTime& time, const char* message,
size_t message_len) override {
// Custom log processing
if (severity >= google::GLOG_ERROR) {
// Notify external monitoring system for error level and above
sendToMonitoringSystem(severity, message, message_len);
}
// Log to database
logToDatabase(severity, base_filename, line, time, message);
// Email notification (FATAL only)
if (severity == google::GLOG_FATAL) {
sendEmailAlert(message, message_len);
}
}
private:
void sendToMonitoringSystem(google::LogSeverity severity,
const char* message, size_t len) {
// Monitoring system notification implementation
}
void logToDatabase(google::LogSeverity severity,
const char* filename, int line,
const google::LogMessageTime& time,
const char* message) {
// Database logging implementation
}
void sendEmailAlert(const char* message, size_t len) {
// Email notification implementation
}
};
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
// Set custom failure function
google::InstallFailureFunction(&MyFailureFunction);
// Add custom log sink
CustomLogSink custom_sink;
google::AddLogSink(&custom_sink);
try {
// Application processing
performCriticalOperation();
} catch (const std::exception& e) {
LOG(ERROR) << "Exception occurred: " << e.what();
// Program continues
}
// Important: Remove custom sink
google::RemoveLogSink(&custom_sink);
return 0;
}
Practical Example (Web Server Application)
#include <glog/logging.h>
#include <thread>
#include <chrono>
class WebServerLogger {
public:
static void initialize(const std::string& program_name) {
google::InitGoogleLogging(program_name.c_str());
// Configuration flags
FLAGS_log_dir = "./logs";
FLAGS_max_log_size = 100; // 100MB
FLAGS_stop_logging_if_full_disk = true;
// Also output error level and above to stderr
FLAGS_alsologtostderr = true;
FLAGS_stderrthreshold = google::GLOG_ERROR;
// Log cleaning configuration
using namespace std::chrono_literals;
google::EnableLogCleaner(7 * 24h); // Keep for 1 week
LOG(INFO) << "Web server logging initialized";
}
static void logRequest(const std::string& client_ip,
const std::string& method,
const std::string& path,
int status_code,
std::chrono::milliseconds response_time) {
// Access log
LOG(INFO) << "REQUEST: " << client_ip << " " << method << " " << path
<< " " << status_code << " " << response_time.count() << "ms";
// Warning for abnormal response times
LOG_IF(WARNING, response_time.count() > 1000)
<< "Slow response detected: " << response_time.count() << "ms for " << path;
// Error status code logging
LOG_IF(ERROR, status_code >= 500)
<< "Server error: " << status_code << " for " << path;
LOG_IF(WARNING, status_code >= 400 && status_code < 500)
<< "Client error: " << status_code << " for " << path;
}
static void logError(const std::string& component,
const std::string& error_message,
bool is_fatal = false) {
if (is_fatal) {
LOG(FATAL) << "[" << component << "] " << error_message;
} else {
LOG(ERROR) << "[" << component << "] " << error_message;
}
}
static void logPerformanceMetric(const std::string& metric_name,
double value) {
// Limit performance metrics to about once every 5 minutes
LOG_EVERY_T(INFO, 300) << "METRIC: " << metric_name << " = " << value;
}
};
// Usage example
void handleHttpRequest(const std::string& client_ip,
const std::string& method,
const std::string& path) {
auto start_time = std::chrono::high_resolution_clock::now();
VLOG(1) << "Processing request: " << method << " " << path;
try {
// Request processing simulation
std::this_thread::sleep_for(std::chrono::milliseconds(50));
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
end_time - start_time);
// Success case
WebServerLogger::logRequest(client_ip, method, path, 200, duration);
} catch (const std::exception& e) {
WebServerLogger::logError("RequestHandler",
"Request processing failed: " + std::string(e.what()));
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
end_time - start_time);
WebServerLogger::logRequest(client_ip, method, path, 500, duration);
}
}
int main(int argc, char* argv[]) {
WebServerLogger::initialize(argv[0]);
LOG(INFO) << "Web server starting up";
// Process sample requests
handleHttpRequest("192.168.1.100", "GET", "/api/users");
handleHttpRequest("192.168.1.101", "POST", "/api/orders");
// Record performance metrics
WebServerLogger::logPerformanceMetric("cpu_usage", 75.5);
WebServerLogger::logPerformanceMetric("memory_usage", 1024.0);
LOG(INFO) << "Web server shutting down";
return 0;
}