Einleitung: Warum ist korrektes Logging in C++ wichtig?
Logging ist nicht einfach das Aufzeichnen von Nachrichten in eine Datei. In einer Production-Umgebung ist es Ihr wichtigstes Werkzeug für Monitoring, Debugging und Audit. Schlecht konfiguriertes Logging kann zum Verlust kritischer Daten, zu Leistungseinbußen (I/O-bound) oder im Gegenteil zu einer "Rausch"-Verschmutzung der Festplatten führen. In diesem Artikel analysieren wir die Best Practices für Logging in C++, die Ihnen helfen, typische Fehler zu vermeiden und ein zuverlässiges Log-Sammelsystem aufzubauen.
1. Bibliotheksauswahl: spdlog vs glog vs std::clog
Die Standard-C++-Bibliothek bietet nur die grundlegenden Streams std::clog und std::cerr, die für ernsthafte Projekte ungeeignet sind. Betrachten wir drei gängige Ansätze:
1.1. spdlog — der moderne Standard
spdlog ist eine Header-Only-Bibliothek mit Unterstützung für asynchrones Logging, Dateirotation, Formatierung (à la fmtlib) und viele Senken (Datei, Konsole, Syslog, Kafka).
Wichtigste Vorteile:
- Hohe Leistung (durch asynchrone Threads)
- Flexible Konfiguration von Stufen und Formaten
- Unterstützung für strukturiertes Logging (JSON)
#include <spdlog/spdlog.h>#include <spdlog/sinks/rotating_file_sink.h>
int main() { // Erstellen eines rotierenden Datei-Loggers (5 Dateien à 10 MB) auto logger = spdlog::rotating_logger_mt("file_logger", "logs/app.log", 1048576 * 10, 5); logger->set_level(spdlog::level::info); logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v");
logger->info("Anwendung gestartet"); logger->warn("Niedriger Arbeitsspeicher: {} MB", free_memory); logger->error("Fehler bei der Datenbankverbindung: {}", err.what()); return 0;}1.2. Google glog — bewährte Lösung
Die Bibliothek glog von Google ist einfach zu bedienen und bietet integrierte Unterstützung für bedingtes Logging und Stack-Dumps. Nachteil: weniger flexibles Formatieren und fehlende Asynchronität.
#include <glog/logging.h>
int main(int argc, char* argv[]) { google::InitGoogleLogging(argv[0]); FLAGS_log_dir = "./logs"; FLAGS_stderrthreshold = google::WARNING; // WARNING+ in stderr duplizieren
LOG(INFO) << "Server gestartet auf Port " << port; LOG_IF(WARNING, memory_usage > 0.9) << "Speicher fast erschöpft"; LOG(FATAL) << "Kritischer Fehler, Beendigung"; return 0;}1.3. Eigenbau-Logger mit std::clog
Verwenden Sie std::clog nur für Debugging oder sehr kleine Dienstprogramme. Es unterstützt keine Rotation, Stufen und Multithreading.
#define LOG(level, msg) std::clog << "[" << level << "] " << msg << std::endl;LOG("INFO", "Start");LOG("ERROR", "Fehler: " + std::to_string(errno));2. Best Practices für Konfiguration und Architektur
Selbst die beste Bibliothek hilft nicht, wenn die Logging-Architektur falsch aufgebaut ist. Halten Sie sich an die folgenden Prinzipien:
2.1. Verwenden Sie Logging-Stufen
Definieren Sie 5-6 Stufen und befolgen Sie diese strikt:
- TRACE — detailliertes Debugging (Funktionsein-/austritt)
- DEBUG — Debug-Informationen für Entwickler
- INFO — normaler Anwendungsbetrieb (Start, Beendigung)
- WARN — potenzielle Probleme (niedriger Speicherplatz, hohe Auslastung)
- ERROR — Fehler, die den Betrieb nicht unterbrechen (Ausnahmen)
- FATAL — kritischer Fehler, nach dem die Anwendung beendet wird
// In Production setzen wir WARN, um die Logs nicht mit INFO-Nachrichten zu überflutenlogger->set_level(spdlog::level::warn);2.2. Strukturiertes Logging (JSON)
Für