Logging em aplicações Rust: melhores práticas na prática

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Logging em aplicações Rust: melhores práticas na prática



Logging é um dos elementos-chave de qualquer aplicação em produção. Ajuda a diagnosticar erros, monitorar o comportamento do sistema e coletar métricas. No ecossistema Rust, existem várias soluções maduras para isso. Neste artigo, vamos explorar as melhores práticas de logging com exemplos reais de código.



1. Fundamentos: crate log e arquitetura de fachada



Em Rust, o padrão de facto é o crate log. Ele fornece uma fachada abstrata, não vinculada a uma implementação específica. Isso significa que você escreve logs através das macros log, e qual backend irá processá-los (exibir no console, salvar em arquivo, enviar para ELK) é decidido no momento da inclusão de outro crate.



Configuração básica de logging



// Cargo.toml[dependencies]log = "0.4"env_logger = "0.11"


// main.rsuse log::{info, warn, error, debug};

fn main() { // Inicializa o env_logger (lê a variável RUST_LOG) env_logger::init();

info!("Aplicação iniciada"); warn!("Usando configuração padrão"); error!("Erro crítico: {}", "arquivo não encontrado");}


Execute a aplicação com a variável de ambiente:

RUST_LOG=info cargo run


Na tela, você verá:

[2025-01-15T10:30:00Z INFO  my_app] Aplicação iniciada[2025-01-15T10:30:00Z WARN  my_app] Usando configuração padrão[2025-01-15T10:30:00Z ERROR my_app] Erro crítico: arquivo não encontrado


2. Configuração flexível de níveis de logging



A variável RUST_LOG permite filtrar mensagens de forma flexível por módulos e níveis. Isso é crítico para projetos grandes, onde o ruído de logs de depuração pode ocultar eventos importantes.



Exemplos de filtragem



# Apenas erros e avisos de toda a aplicaçãoRUST_LOG=warn

# Depuração apenas no módulo database, o resto infoRUST_LOG=info,my_crate::database=debug

# Todos os níveis, incluindo traceRUST_LOG=trace


Na prática, use esta abordagem:

use std::env;

fn setup_logging() { if env::var("RUST_LOG").is_err() { // Valor padrão para desenvolvimento env::set_var("RUST_LOG", "info,my_crate=debug"); } env_logger::init();}


3. Logging estruturado com tracing



Para sistemas complexos (microsserviços, aplicações assíncronas), é melhor usar o crate tracing. Ele suporta spans e campos estruturados, permitindo vincular logs em cadeias de requisições.



Comparação entre log e tracing



  • log — simples, leve, adequado para projetos pequenos.
  • tracing — poderoso, suporta spans, eventos, campos estruturados; ideal para código async e sistemas com instrumentação tracing.


Exemplo com tracing e tracing-subscriber



// Cargo.toml[dependencies]tracing = "0.1"tracing-subscriber = "0.3"


use tracing::{info, error, span, Level};use tracing_subscriber::FmtSubscriber;

#[tokio::main]async fn main() { // Configura subscriber para saída no stdout let subscriber = FmtSubscriber::builder() .with_max_level(Level::TRACE) .finish(); tracing::subscriber::set_global_default(subscriber) .expect("Falha ao definir subscriber");

// Cria um span para requisição HTTP let request_span = span!(Level::INFO, "http_request", method = "GET", path = "/api/users"); let _guard = request_span.enter();

info!("Processamento da requisição iniciado");

// Span aninhado para operação com BD let db_span = span!(Level::DEBUG, "db_query", query = "SELECT * FROM users"); let _db_gu

Blogs

Book Recommendations