Introdução: Por que o logging adequado em C++ é necessário?
Logging não é apenas escrever mensagens em um arquivo. Em um ambiente de produção, é sua principal ferramenta para monitoramento, depuração e auditoria. Um logging mal configurado pode levar à perda de dados críticos, redução de desempenho (I/O-bound) ou, inversamente, ao entupimento "ruidoso" dos discos. Neste artigo, analisaremos as melhores práticas de logging em C++ que ajudarão você a evitar erros típicos e construir um sistema confiável de coleta de logs.
1. Escolha da biblioteca: spdlog vs glog vs std::clog
A biblioteca padrão do C++ oferece apenas os fluxos básicos std::clog e std::cerr, que não são adequados para projetos sérios. Vamos considerar três abordagens populares:
1.1. spdlog — o padrão moderno
spdlog é uma biblioteca header-only com suporte a logging assíncrono, rotação de arquivos, formatação (estilo fmtlib) e múltiplos sinks (arquivo, console, syslog, Kafka).
Principais vantagens:
- Alta performance (devido a threads assíncronas)
- Configuração flexível de níveis e formatos
- Suporte a logging estruturado (JSON)
#include <spdlog/spdlog.h>#include <spdlog/sinks/rotating_file_sink.h>
int main() { // Cria um logger de arquivo com rotação (5 arquivos 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("Aplicação iniciada"); logger->warn("Memória livre baixa: {} MB", free_memory); logger->error("Erro de conexão com o BD: {}", err.what()); return 0;}1.2. Google glog — uma solução testada
A biblioteca glog do Google é simples de usar e possui suporte embutido para logging condicional e dumps de pilha. Desvantagem — formatação menos flexível e ausência de assincronia.
#include <glog/logging.h>
int main(int argc, char* argv[]) { google::InitGoogleLogging(argv[0]); FLAGS_log_dir = "./logs"; FLAGS_stderrthreshold = google::WARNING; // Duplica WARNING+ no stderr
LOG(INFO) << "Servidor iniciado na porta " << port; LOG_IF(WARNING, memory_usage > 0.9) << "Memória quase esgotada"; LOG(FATAL) << "Erro crítico, encerrando"; return 0;}1.3. Logger próprio com std::clog
Use std::clog apenas para depuração ou utilitários muito pequenos. Ele não suporta rotação, níveis e multithreading.
#define LOG(level, msg) std::clog << "[" << level << "] " << msg << std::endl;LOG("INFO", "Iniciando");LOG("ERROR", "Erro: " + std::to_string(errno));2. Melhores práticas de configuração e arquitetura
Mesmo a melhor biblioteca não salvará se a arquitetura de logging estiver mal construída. Siga os seguintes princípios:
2.1. Use níveis de logging
Defina 5-6 níveis e siga-os rigorosamente:
- TRACE — depuração detalhada (entrada/saída de funções)
- DEBUG — informações de depuração para desenvolvedores
- INFO — operação normal da aplicação (inicialização, encerramento)
- WARN — problemas potenciais (disco baixo, alta carga)
- ERROR — erros que não interrompem a operação (exceções)
- FATAL — erro crítico, após o qual a aplicação é encerrada
// Em produção, defina WARN para não sobrecarregar os logs com mensagens INFOlogger->set_level(spdlog::level::warn);2.2. Logging estruturado (JSON)
Para