Registro rápido en C++ sin dolor ni dependencias pesadas
Cualquiera que haya escrito algo más complejo que scripts de tutorial en C++ se ha enfrentado a la elección de una biblioteca de registro. El std::cout estándar es conveniente para utilidades simples de consola, pero rápidamente se convierte en un cuello de botella debido a la E/S lenta y la falta de formateo conveniente. Alternativas como Boost.Log o log4cxx traen consigo sus dependencias, toman mucho tiempo para compilar y son intimidantes con su configuración compleja.
En 2014, el desarrollador Gabriel Melman publicó la biblioteca spdlog. El proyecto ganó rápidamente popularidad en la comunidad C++ y ahora tiene casi 30,000 estrellas en GitHub.
Cuál es el secreto de su popularidad
La razón principal del éxito de la biblioteca es el equilibrio entre rendimiento y facilidad de integración. spdlog se distribuye en formato solo de cabecera: simplemente copia el directorio include en tu proyecto, incluye el archivo de cabecera y comienza a trabajar. Si necesitas acelerar la compilación de tu aplicación, la biblioteca puede precompilarse mediante CMake o instalarse desde los gestores de paquetes más populares (apt, brew, vcpkg, conan).
El formateo de cadenas se basa en la biblioteca fmt, que se convirtió en la base para std::format en C++20. Esto elimina las engorrosas cadenas con el operador <<. La alineación, la salida de números hexadecimales y los argumentos posicionales se escriben de forma fácil y clara.
Funciones útiles para el desarrollo diario
Combinación de sinks de registro
En la práctica, a menudo necesitas enviar los errores a la consola con resaltado de color, mientras escribes información de depuración detallada en un archivo con rotación. En spdlog, esta tarea se resuelve combinando múltiples sinks en un único objeto 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("Сообщение попадет и в консоль, и в файл");
}
Modo asíncrono para tareas de alta carga
En los hilos de trabajo de servidores de red o motores de juegos, las escrituras directas a disco retrasan la ejecución del código. spdlog puede funcionar de forma asíncrona: un hilo en segundo plano extrae mensajes de un buffer circular y los vuelca al disco sin ralentizar los cálculos principales.
#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 circular para trazabilidad de errores
Una característica interesante de la biblioteca es el soporte para backtrace. Supongamos que el entorno de producción tiene el nivel de registro establecido en info y la depuración detallada está deshabilitada. Cuando se activa backtrace, la biblioteca guarda los últimos N mensajes de depuración en memoria. Cuando ocurre un fallo, pueden volcarse instantáneamente al archivo de registro.
spdlog::enable_backtrace(32); // Сохраняем последние 32 сообщения в буфер
for (int i = 0; i < 100; ++i) {
spdlog::debug("Отладочный шаг №{}", i); // Сообщения пока не пишутся в диск
}
// При возникновении ошибки выгружаем накопленный буфер
spdlog::dump_backtrace();
Cambiar el nivel de registro sin recompilar
Los niveles de registro se pueden leer directamente desde variables de entorno o argumentos de línea de comandos al iniciar la aplicación:
#include "spdlog/cfg/env.h"
int main(int argc, char* argv[]) {
spdlog::cfg::load_env_levels();
spdlog::info("Приложение успешно запущено");
}
Ejecutar el binario con el flag SPDLOG_LEVEL=debug ./my_app activa inmediatamente la salida de mensajes de depuración.
Benchmarks de rendimiento
Un registrador síncrono de un solo hilo procesa aproximadamente 5.7 millones de llamadas por segundo cuando trabaja con cadenas cortas (pruebas del autor en Intel i7-4770). Con 10 hilos competidores, la velocidad se mantiene alrededor de 1.6 millones de mensajes por segundo.
En modo asíncrono con la política de desbordamiento (overrun), la biblioteca procesa más de 2.6 millones de operaciones por segundo. Estas cifras se logran gracias a las asignaciones de memoria mínimas y la construcción rápida de cadenas.
Integraciones listas para usar
La biblioteca es compatible con Linux, Windows, macOS, Android y FreeBSD. El paquete incluye sinks listos para usar para integración con syslog, Windows Event Log, Android logcat y widgets de texto Qt (QTextEdit). Además, la base de código incluye un cronómetro spdlog::stopwatch para medir el tiempo de ejecución de segmentos de código y una utilidad para mostrar datos binarios en formato hexadecimal.
spdlog resuelve el problema del registro sin complejidad innecesaria. Para una utilidad pequeña, basta con copiar los archivos de cabecera, y para un servicio grande, el modo asíncrono, la rotación de archivos y el filtrado de mensajes sobre la marcha resultan útiles. Si necesitas una herramienta rápida y predecible para C++, agregar spdlog a tu stack debería ser una prioridad absoluta.
Proyectos relacionados