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.

loggingC++Googlethread-safemacro-based

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;
}