Introducción: ¿Por qué es necesario un registro (logging) adecuado en C++?
El registro no es simplemente escribir mensajes en un archivo. En un entorno de producción, es su herramienta principal para monitoreo, depuración y auditoría. Un registro mal configurado puede provocar la pérdida de datos críticos, una reducción del rendimiento (I/O-bound) o, por el contrario, una saturación "ruidosa" de los discos. En este artículo, analizaremos las mejores prácticas de registro en C++ que le ayudarán a evitar errores típicos y construir un sistema confiable de recolección de registros.
1. Elección de la biblioteca: spdlog vs glog vs std::clog
La biblioteca estándar de C++ solo ofrece los flujos básicos std::clog y std::cerr, que no son adecuados para proyectos serios. Consideremos tres enfoques populares:
1.1. spdlog — el estándar moderno
spdlog es una biblioteca header-only con soporte para registro asíncrono, rotación de archivos, formato (al estilo fmtlib) y múltiples destinos (archivo, consola, syslog, Kafka).
Ventajas clave:
- Alto rendimiento (gracias a los flujos asíncronos)
- Configuración flexible de niveles y formatos
- Soporte para registro estructurado (JSON)
#include <spdlog/spdlog.h>#include <spdlog/sinks/rotating_file_sink.h>
int main() { // Creamos un registrador de archivo rotatorio (5 archivos de 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("Aplicación iniciada"); logger->warn("Poca memoria disponible: {} MB", free_memory); logger->error("Error de conexión a la BD: {}", err.what()); return 0;}1.2. Google glog — una solución probada
La biblioteca glog de Google es fácil de usar y tiene soporte integrado para registro condicional y volcados de pila. La desventaja es un formato menos flexible y la falta de asincronía.
#include <glog/logging.h>
int main(int argc, char* argv[]) { google::InitGoogleLogging(argv[0]); FLAGS_log_dir = "./logs"; FLAGS_stderrthreshold = google::WARNING; // Duplicar WARNING+ en stderr
LOG(INFO) << "Servidor iniciado en el puerto " << port; LOG_IF(WARNING, memory_usage > 0.9) << "Memoria casi agotada"; LOG(FATAL) << "Error crítico, terminando"; return 0;}1.3. Registrador propio con std::clog
Use std::clog solo para depuración o utilidades muy pequeñas. No soporta rotación, niveles ni multihilo.
#define LOG(level, msg) std::clog << "[" << level << "] " << msg << std::endl;LOG("INFO", "Inicio");LOG("ERROR", "Error: " + std::to_string(errno));2. Mejores prácticas de configuración y arquitectura
Ni siquiera la mejor biblioteca salvará si la arquitectura de registro está mal construida. Siga los siguientes principios:
2.1. Use niveles de registro
Defina 5-6 niveles y sígalos estrictamente:
- TRACE — depuración detallada (entrada/salida de funciones)
- DEBUG — información de depuración para desarrolladores
- INFO — funcionamiento normal de la aplicación (inicio, finalización)
- WARN — problemas potenciales (poco espacio en disco, alta carga)
- ERROR — errores que no interrumpen el funcionamiento (excepciones)
- FATAL — error crítico tras el cual la aplicación finaliza
// En producción configuramos WARN para no llenar los registros con mensajes INFOlogger->set_level(spdlog::level::warn);2.2. Registro estructurado (JSON)
Para