Journalisation C++ rapide sans la douleur ni les dépendances lourdes
Quiconque a écrit quelque chose de plus complexe que des scripts tutoriels en C++ a été confronté au choix d'une bibliothèque de journalisation. La bibliothèque standard std::cout est pratique pour les utilitaires console simples, mais devient rapidement un goulot d'étranglement en raison d'E/S lentes et d'un formatage peu pratique. Les alternatives comme Boost.Log ou log4cxx apportent leurs dépendances, prennent beaucoup de temps à compiler et sont intimidantes avec leur configuration complexe.
En 2014, le développeur Gabriel Melman a publié la bibliothèque spdlog. Le projet a rapidement gagné en popularité dans la communauté C++ et compte maintenant près de 30 000 étoiles sur GitHub.
Ce qui fait sa popularité
La raison principale du succès de cette bibliothèque réside dans l'équilibre entre performance et facilité d'intégration. spdlog est distribuée au format header-only : il suffit de copier le répertoire include dans votre projet, d'inclure le fichier d'en-tête et de commencer à travailler. Si vous avez besoin d'accélérer la compilation de votre application, la bibliothèque peut être pré-compilée via CMake ou installée depuis les gestionnaires de paquets les plus populaires (apt, brew, vcpkg, conan).
Le formatage des chaînes repose sur la bibliothèque fmt, qui a servi de base à std::format en C++20. Cela élimine les chaînes fastidieuses avec l'opérateur <<. L'alignement, la sortie des nombres hexadécimaux et les arguments positionnels s'écrivent facilement et clairement.
Fonctionnalités utiles pour le développement quotidien
Combiner les sinks de logs
En pratique, vous avez souvent besoin d'envoyer les erreurs vers la console avec coloration syntaxique, tout en écrivant des informations de débogage détaillées dans un fichier avec rotation. Dans spdlog, cette tâche se résout en combinant plusieurs sinks dans un seul objet logger :
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/basic_file_sink.h"
void setup_logging() {
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_level(spdlog::level::warn);
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/app.txt", true);
file_sink->set_level(spdlog::level::trace);
spdlog::logger logger("multi_sink", {console_sink, file_sink});
logger.info("Сообщение зафиксировано только в файле");
logger.warn("Сообщение попадет и в консоль, и в файл");
}
Mode asynchrone pour les tâches à forte charge
Dans les threads de travail des serveurs réseau ou des moteurs de jeux, les écritures directes sur le disque ralentissent l'exécution du code. spdlog peut fonctionner de manière asynchrone : un thread en arrière-plan extrait les messages d'un buffer circulaire et les vide sur le disque sans ralentir les calculs principaux.
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
void async_example() {
// Очередь на 8192 элемента и 1 фоновый поток
spdlog::init_thread_pool(8192, 1);
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>(
"async_logger", "logs/async_log.txt"
);
async_file->info("Запись лога не блокирует текущий поток");
}
Buffer circulaire pour le traçage des erreurs
Une fonctionnalité intéressante de la bibliothèque est la prise en charge du backtrace. Supposons que l'environnement de production ait le niveau de log défini sur info et que le débogage détaillé soit désactivé. Lorsque backtrace est activé, la bibliothèque conserve les N derniers messages de débogage en mémoire. En cas d'échec, ils peuvent être instantanément déversés dans le fichier de log.
spdlog::enable_backtrace(32); // Сохраняем последние 32 сообщения в буфер
for (int i = 0; i < 100; ++i) {
spdlog::debug("Отладочный шаг №{}", i); // Сообщения пока не пишутся в диск
}
// При возникновении ошибки выгружаем накопленный буфер
spdlog::dump_backtrace();
Modifier le niveau de journalisation sans recompiler
Les niveaux de journalisation peuvent être lus directement depuis les variables d'environnement ou les arguments de ligne de commande au démarrage de l'application :
#include "spdlog/cfg/env.h"
int main(int argc, char* argv[]) {
spdlog::cfg::load_env_levels();
spdlog::info("Приложение успешно запущено");
}
L'exécution du binaire avec le flag SPDLOG_LEVEL=debug ./my_app active immédiatement la sortie des messages de débogage.
Benchmarks de performance
Un logger synchrone mono-thread gère environ 5,7 millions d'appels par seconde lors du travail avec des chaînes courtes (tests de l'auteur sur Intel i7-4770). Avec 10 threads concurrents, la vitesse reste autour de 1,6 million de messages par seconde.
En mode asynchrone avec la politique de débordement (overrun), la bibliothèque traite plus de 2,6 millions d'opérations par seconde. Ces chiffres sont obtenus grâce à des allocations mémoire minimales et une construction rapide des chaînes.
Intégrations prêtes à l'emploi
La bibliothèque est supportée sur Linux, Windows, macOS, Android et FreeBSD. Le package inclut des sinks prêts à l'emploi pour l'intégration avec syslog, Windows Event Log, Android logcat et les widgets texte Qt (QTextEdit). De plus, le code source inclut un chronomètre spdlog::stopwatch pour mesurer le temps d'exécution des segments de code et un utilitaire pour afficher les données binaires au format hexadécimal.
spdlog résout le problème de journalisation sans complexité superflue. Pour un petit utilitaire, il suffit de copier les fichiers d'en-tête, et pour un grand service, le mode asynchrone, la rotation des fichiers et le filtrage des messages à la volée s'avèrent pratiques. Si vous avez besoin d'un outil rapide et prévisible pour C++, ajouter spdlog à votre pile technologique devrait être une priorité absolue.
Projets similaires