Logging in C++ Applications: Best Practices for Beginners
Logging is the process of recording events that occur during program execution. For a beginner C++ developer, knowing how to properly organize logging is not just "good form," but a critically important skill. It helps debug code, track errors in production, and analyze system behavior. In this article, we will cover best practices for logging in C++, from the simplest methods to using modern libraries, with concrete code examples.
Why is simply using std::cout a bad practice?
Many beginners start by outputting debug messages via std::cout or printf. It's fast and simple, but this approach has serious drawbacks:
- Lack of severity levels. You cannot separate error messages from informational notifications.
- Difficulty filtering. In production, you don't want to see tons of debug messages, but during debugging you need them.
- No log rotation. The log file will grow indefinitely until it fills the entire disk.
- Multithreading issues. Output from different threads can get mixed up.
Instead, you should use specialized tools. Let's look at three main approaches: from simple to complex.
1. Simple macro wrapper for beginners
If you are writing a small educational program or don't want to include third-party libraries, you can create a simple macro wrapper. This is already better than bare cout.
#include <iostream>#include <fstream>#include <ctime>#include <string>
enum LogLevel { DEBUG, INFO, WARNING, ERROR};
std::string getCurrentTime() { std::time_t now = std::time(nullptr); char buf[20]; std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", std::localtime(&now)); return std::string(buf);}
#define LOG(level, msg) \ do { \ std::ofstream logFile("app.log", std::ios::app); \ logFile << "[" << getCurrentTime() << "] " \ << "[" << #level << "] " \ << msg << std::endl; \ } while(0)
int main() { LOG(INFO, "Program started"); int x = 42; LOG(DEBUG, "Value of x: " << x); // ... LOG(ERROR, "Division by zero error occurred"); return 0;}Pros: simplicity, no external dependencies required.
Cons: no rotation, slow performance (opening/closing file for each message), threading issues.
2. Using the spdlog library (recommended for beginners)
spdlog is the most popular logging library in C++ (over 23,000 stars on GitHub). It is very fast, simple to use, and header-only.
Installation: simply download the files from the repository or use vcpkg/conan.
#include <spdlog/spdlog.h>#include <spdlog/sinks/basic_file_sink.h>#include <spdlog/sinks/stdout_color_sinks.h>
int main() { // Create a console logger with colored output auto console = spdlog::stdout_color_mt("console"); // Create a file logger auto file_logger = spdlog::basic_logger_mt("file_logger", "logs/app.log"); // Set the logging level spdlog::set_level(spdlog::level::debug); // Log everything from DEBUG and above // Examples of messages at different levels console->trace("This is a trace message (lowest level)"); console->debug("Debug message: variable x = {}", 42); console->info("Program started successfully"); console->warn("Wa