Introdução: Por que logging não é apenas exibir texto?
No desenvolvimento moderno em C++, o logging foi além do simples std::cout. É uma ferramenta criticamente importante para depuração, monitoramento e auditoria de aplicações. No entanto, uma implementação incorreta pode levar à queda de desempenho, perda de dados ou acúmulo de espaço em disco. Neste artigo, analisaremos as melhores práticas de logging em C++ com exemplos concretos que podem ser aplicados imediatamente em projetos reais.
1. Escolha da biblioteca de logging: spdlog e alternativas
A biblioteca padrão do C++ não fornece meios embutidos para logging flexível. Recomenda-se o uso de soluções de terceiros testadas. Spdlog é uma das bibliotecas mais populares devido ao seu alto desempenho e facilidade de integração.
Instalação do spdlog (vcpkg ou header-only)
// Instalação via vcpkgvcpkg install spdlog
// Ou use a versão header-only#include "spdlog/spdlog.h"#include "spdlog/sinks/basic_file_sink.h"#include "spdlog/sinks/rotating_file_sink.h"Exemplo básico de configuração do logger
#include <memory>#include "spdlog/spdlog.h"#include "spdlog/sinks/stdout_color_sinks.h"
int main() { // Criando um logger de console com saída colorida auto console = spdlog::stdout_color_mt("console"); // Definindo o nível de logging spdlog::set_level(spdlog::level::debug); // Exemplos de mensagens console->info("Aplicação iniciada"); console->warn("Potencial problema detectado"); console->error("Erro crítico: {}", errno); return 0;}Alternativas: Boost.Log (para projetos enterprise), Google Glog (se precisar de integração com Google Test). Para sistemas embarcados, use EasyLogger.
2. Níveis de logging e filtragem
O uso correto dos níveis de logging é a chave para a legibilidade dos logs. Em C++, adota-se a seguinte hierarquia (do mais ao menos crítico):
- TRACE — rastreamento detalhado da execução (apenas para depuração)
- DEBUG — informações de depuração
- INFO — mensagens informativas sobre o funcionamento da aplicação
- WARN — avisos sobre problemas potenciais
- ERROR — erros que não interrompem o funcionamento da aplicação
- CRITICAL — erros fatais que exigem intervenção imediata
Configuração de filtragem no spdlog
// Ativando apenas WARN e superioresspdlog::set_level(spdlog::level::warn);
// Para depuração, ative todos os níveis#ifdef _DEBUG spdlog::set_level(spdlog::level::trace);#endif
// Exemplo de uso com macros#define LOG_TRACE(...) spdlog::trace(__VA_ARGS__)#define LOG_ERROR(...) spdlog::error(__VA_ARGS__)
LOG_TRACE("Entrando na função processData()");LOG_ERROR("Não foi possível abrir o arquivo: {}", filename);Dica: Nunca use TRACE em builds de produção — isso pode reduzir o desempenho em 10 a 100 vezes devido à formatação de strings.
3. Desempenho do logging: modo síncrono vs assíncrono
Em sistemas de alta carga, o logging síncrono pode se tornar um gargalo. Cada chamada ao logger bloqueia a thread até a conclusão da gravação. A solução é o logging assíncrono.
Configuração do logger assíncrono no spdlog
#include "spdlog/async.h"#include "spdlog/sinks/rotating_file_sink.h"
int main() { // Criando um logger assíncrono com tamanho de fila 8192 spdlog::init_thread_pool(8192, 1); // 1 thread para processamento auto async_file = spdlog::rotating_logger_mt<spdlog::async_factory>( "async_logger", "logs/app.log", 102