09/03/2026, 16:48 Logging e Profiling Rust
Sou programador Python aprendendo Rust, tenha ótima
didática e faça correlação entre as linguagens, mostre
como o rust trabalha comSou programador Python
aprendendo Rust, tenha ótima didática e faça correlação
entre as linguagens, mostre como o rust trabalha com
Logging profissional e Profiling de Performance
Vou organizar isso em duas frentes: logging profissional e profiling/performance, sempre
puxando paralelo com Python para ficar natural na sua transição para Rust. Depois fecho
com uma arquitetura prática de projeto e exemplos de código prontos para você adaptar.
Já tenho a base certa: em Rust, o caminho mais moderno e profissional é tracing para
observabilidade e uma combinação de bench/profile dedicado para performance. Agora
vou amarrar isso com equivalentes de Python e com o que faz sentido no Windows.
Pensou por 35s
Perfeito. Vou te explicar do jeito que eu ensinaria um dev Python entrando em Rust para
escrever software de produção, não só exemplo de tutorial.
Visão geral: Python vs Rust
Em Python, normalmente você pensa assim:
Logging: logging , structlog , loguru
Profiling: cProfile , py-spy , line_profiler , perf_counter
Observabilidade async/web: middleware, APM, OpenTelemetry
Em Rust, a divisão profissional costuma ficar assim:
log = fachada simples de logging, parecida com a ideia de “API mínima” que várias
libs conseguem usar. [Link]
tracing = observabilidade moderna, com eventos estruturados, spans e contexto,
muito melhor para async e sistemas concorrentes. A própria documentação diz que
ele vai além do log com diagnósticos mais ricos e estruturados. [Link] +1
tracing-subscriber = configuração de saída, filtros, formatação e camadas do
tracing . [Link] +1
criterion = microbenchmark estatístico, excelente para medir regressão de
performance. [Link] +1
[Link] 1/22
09/03/2026, 16:48 Logging e Profiling Rust
pprof / flamegraph / tokio-console = ferramentas para descobrir onde o tempo está
sendo gasto, especialmente em CPU e async. [Link] +2
A primeira correlação importante é esta:
Regra prática
Quer só registrar mensagens? log
Quer observabilidade séria, contexto, spans, async, request tracing? tracing
Quer medir performance com método? criterion
Quer investigar gargalo real? profiler/flamegraph/tokio-console
1) Logging em Rust: o jeito profissional
1.1. O paralelo mental com Python
Em Python, você faz algo assim:
import logging
logger = [Link](__name__)
def processar(user_id: int):
[Link]("processando usuário", extra={"user_id": user_id})
Em Rust, o equivalente mais simples seria com log :
use log::{info, warn, error};
fn processar(user_id: u64) {
info!("processando usuário {}", user_id);
}
R t
Mas em projeto profissional, o mais comum hoje é você preferir tracing , porque ele
trabalha com campos estruturados e spans.
Exemplo:
[Link] 2/22
09/03/2026, 16:48 Logging e Profiling Rust
use tracing::{info, instrument};
#[instrument]
fn processar(user_id: u64) {
info!(user_id = user_id, "processando usuário");
} Rust
Aqui já aparece uma diferença poderosa:
em Python, muitas vezes você “cola” contexto manualmente em strings
em Rust com tracing , você registra campos nomeados
isso facilita filtragem, correlação, tracing distribuído e análise em produção [Link] +1
1.2. log vs tracing
log
Pense nele como uma interface universal mínima.
A documentação define o crate como uma “lightweight logging facade”, e destaca que
bibliotecas podem usar essa API, deixando a implementação concreta para quem consome
a lib. [Link]
Quando usar
bibliotecas simples
compatibilidade com ecossistema
casos em que você só quer texto de log
tracing
tracing foi desenhado para instrumentação mais rica, com eventos, spans e contexto
estruturado. A documentação descreve o crate como um framework de diagnóstico
estruturado e consciente de contexto, especialmente forte para programas assíncronos.
[Link] +1
Quando usar
web APIs
serviços async com Tokio
filas, workers, microserviços
sistemas concorrentes
observabilidade séria
[Link] 3/22
09/03/2026, 16:48 Logging e Profiling Rust
2) O conceito mais importante: span
Esse é o ponto onde muita gente vinda de Python vira a chave.
Em Python
Você normalmente registra logs soltos:
[Link]("começando requisição")
[Link]("consultando banco")
[Link]("finalizando")
Python Executar
Em Rust com tracing
Você consegue modelar uma operação inteira como um contexto:
use tracing::{info_span, info};
fn executar() {
let span = info_span!("processar_pedido", pedido_id = 42);
let _enter = [Link]();
info!("consultando banco");
info!("calculando frete");
info!("finalizando pedido");
}
Ou, de forma ainda melhor, usando #[instrument] :
use tracing::{info, instrument};
#[instrument]
fn processar_pedido(pedido_id: u64, valor: f64) {
info!(valor = valor, "iniciando processamento");
}
O que isso muda?
Todos os eventos passam a estar ligados ao contexto daquela operação.
Isso é parecido com ter em Python:
[Link] 4/22
09/03/2026, 16:48 Logging e Profiling Rust
request_id
user_id
trace_id
contexto de função
contexto de tarefa async
Só que em Rust isso é uma parte central do modelo. Esse é o salto de “logging textual”
para observabilidade.
3) Estrutura recomendada para projeto real
Para uma aplicação de produção em Rust, eu recomendaria esta pilha:
[dependencies]
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
tracing-appender = "0.2"
TOML
Essa combinação é coerente com a documentação oficial:
tracing-subscriber fornece formatação, composição e filtros [Link] +1
EnvFilter permite configurar níveis por variável de ambiente ou diretivas de filtro
[Link] +1
tracing-appender oferece escrita não bloqueante e rolling file appender [Link] +1
4) Exemplo profissional de setup de logging
Código
use tracing_subscriber::{fmt, EnvFilter};
use tracing_appender::rolling;
use tracing_appender::non_blocking::WorkerGuard;
pub fn init_logging() -> WorkerGuard {
let file_appender = rolling::daily("logs", "[Link]");
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
let env_filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("info"));
[Link] 5/22
09/03/2026, 16:48 Logging e Profiling Rust
tracing_subscriber::fmt()
.with_env_filter(env_filter)
.with_writer(non_blocking)
.with_target(true)
.with_thread_ids(true)
.with_line_number(true)
.init();
guard
}
[Link]
use tracing::{info, warn, error, instrument};
mod observability;
Rust
#[instrument]
fn calcular_total(itens: &[i32]) -> i32 {
info!(quantidade = [Link](), "calculando total");
[Link]().sum()
}
fn main() {
let _guard = observability::init_logging();
info!("aplicação iniciando");
let total = calcular_total(&[10, 20, 30]);
warn!(total = total, "cálculo concluído");
if total > 50 {
error!(total = total, "total acima do limite de exemplo");
}
}
O que está acontecendo aqui
Em Python, seria equivalente a:
configurar [Link]
ajustar nível por variável de ambiente
mandar escrita para arquivo
enriquecer mensagem com contexto
[Link] 6/22
09/03/2026, 16:48 Logging e Profiling Rust
Em Rust, fizemos isso de forma mais robusta:
arquivo rotativo
escrita não bloqueante
filtro por ambiente
campos estruturados
instrumentação automática com #[instrument]
A parte da escrita não bloqueante é importante: a documentação de tracing-appender
explica que ele move a escrita para uma thread dedicada, tirando esse custo do caminho
principal da aplicação. [Link] +1
E o WorkerGuard precisa ser mantido vivo para garantir flush correto no encerramento. A
documentação diz que ele força o flush quando é destruído. [Link]
5) Filtros de log como um profissional
ChatGPT 5.4 Thinking Memória desativada
Python
Você faz algo tipo:
Python Executar
[Link]([Link])
ou define hierarquia por nome de logger.
Rust com EnvFilter
Você consegue algo bem mais fino, por exemplo:
PowerShell
$env:RUST_LOG="info,my_app=debug,sqlx=warn"
cargo run
O EnvFilter do tracing-subscriber foi feito exatamente para filtrar spans e eventos por
diretivas e níveis. [Link] +1
Isso é ouro em produção
Porque você pode:
deixar a aplicação inteira em info
subir só seu módulo para debug
[Link] 7/22
09/03/2026, 16:48 Logging e Profiling Rust
reduzir ruído de dependências barulhentas
6) Bibliotecas vs binários: regra de arquitetura
Isso é muito importante.
Para bibliotecas
Use log ou tracing , mas não inicialize o subscriber/logger dentro da lib.
A própria documentação de env_logger reforça que ele faz sentido em executáveis, e que
bibliotecas devem usar a fachada log . [Link] +1
Para executáveis
O main configura tudo:
formatação
destino
filtro
integração com OpenTelemetry
arquivo/console
Tradução mental para Python
lib = não chame basicConfig()
app = centralize a configuração no entrypoint
Essa disciplina em Rust faz muita diferença.
7) Logging estruturado: não monte string à toa
Em Python, muita gente escreve:
Python Executar
[Link](f"user={user_id} action=login")
Em Rust com tracing , prefira:
Rust
info!(user_id = user_id, action = "login", "evento de autenticação");
[Link] 8/22
09/03/2026, 16:48 Logging e Profiling Rust
Por quê?
Porque assim os dados ficam separados da mensagem humana.
Isso melhora:
busca
dashboards
agregação
correlação
exportação para observabilidade
Se você no futuro integrar com OpenTelemetry, essa estrutura ajuda muito. O crate
tracing-opentelemetry existe justamente para conectar spans do tracing a sistemas
compatíveis com OpenTelemetry. [Link] +2
8) Async: por que Rust usa muito tracing
Aqui está outra correlação forte com Python.
Em Python async
Você sofre para manter contexto entre coroutines, middlewares, workers e tasks.
Em Rust async
tracing é especialmente valioso porque spans e eventos representam bem o fluxo
concorrente e assíncrono. A própria documentação do ecossistema tokio-console
descreve a ferramenta como voltada a diagnósticos profundos de tarefas, recursos e
operações assíncronas. [Link] +1
Então, em aplicações Tokio, a recomendação prática é:
use tracing
instrumente funções importantes com #[instrument]
adicione campos como request_id , user_id , job_id
use tokio-console em desenvolvimento para ver tarefas async
9) Profiling em Rust: o mapa mental certo
Muita gente confunde três coisas:
[Link] 9/22
09/03/2026, 16:48 Logging e Profiling Rust
1. Logging
Responde: o que aconteceu?
2. Benchmark
Responde: esta função ficou mais rápida ou mais lenta?
3. Profiling
Responde: onde o tempo/CPU/memória está sendo gasto?
Você precisa dos três.
10) Benchmark: equivalente ao timeit e pytest-benchmark
O melhor caminho em Rust para microbenchmark sério costuma ser o [Link].
A documentação descreve o Criterion como uma ferramenta de microbenchmark
orientada por estatística, capaz de detectar regressões de performance e medir melhorias
com mais confiança. [Link] +1
Exemplo
[Link]
TOML
[dev-dependencies]
criterion = "0.7"
[[bench]]
name = "parser_bench"
harness = false
benches/parser_bench.rs
Rust
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn soma(v: &[u64]) -> u64 {
[Link]().sum()
}
fn bench_soma(c: &mut Criterion) {
[Link] 10/22
09/03/2026, 16:48 Logging e Profiling Rust
let dados: Vec<u64> = (0..10_000).collect();
c.bench_function("soma 10k", |b| {
[Link](|| soma(black_box(&dados)))
});
}
criterion_group!(benches, bench_soma);
criterion_main!(benches);
Rodar
PowerShell
cargo bench
Correlação com Python
Python
Python Executar
import timeit
[Link]("sum(dados)", globals=globals(), number=1000)
Rust com Criterion
Você ganha:
múltiplas amostras
análise estatística
comparação entre execuções
melhor proteção contra medições enganosas [Link] +1
11) Benchmark com entradas variadas
Isso também é forte no Criterion: testar vários tamanhos de entrada para enxergar
comportamento de escala. A documentação cobre benchmarking com diferentes inputs.
[Link] +1
Exemplo mental:
100 itens
[Link] 11/22
09/03/2026, 16:48 Logging e Profiling Rust
1.000 itens
10.000 itens
Isso te ajuda a responder algo que em Python às vezes passa batido:
“Meu algoritmo é rápido só no caso pequeno ou escala bem?”
12) Profiling real: flamegraph
Benchmark responde quanto.
Profiler responde onde.
Para achar gargalo de CPU, flamegraph é excelente. O projeto cargo-flamegraph descreve
a ferramenta como um plugin que gera flamegraph para workloads, não só projetos Rust.
GitHub +1
Ideia prática
Você executa um cenário real e gera um gráfico mostrando onde o tempo de CPU foi
consumido.
Mentalidade
barras largas = função custosa
profundidade = pilha de chamadas
não é “mais profundo = pior”; o importante é a largura
Atenção ao seu caso: Windows
Aqui vale uma observação honesta: a documentação do cargo-flamegraph menciona uso
de perf no Linux e dtrace em outros ambientes, e indica que suporte no Windows
depende de dtrace em evolução. GitHub
Então, para Windows, eu te aconselho esta estratégia:
Desenvolvimento diário
criterion para medir regressão
tracing para enxergar fluxo e latência
tokio-console para async
Investigação profunda de CPU
[Link] 12/22
09/03/2026, 16:48 Logging e Profiling Rust
preferencialmente em WSL2/Linux ou ambiente Linux real, quando for usar
flamegraph tradicional
Essa é a resposta prática e profissional, sem romantizar a ferramenta errada no SO errado.
13) Profiling embutido com pprof
O crate pprof fornece profiling integrado ao programa, com suporte a relatórios como
flamegraph e formatos protobuf, segundo a documentação do crate. [Link] +1
Exemplo conceitual:
Rust
use pprof::ProfilerGuard;
fn main() {
let guard = ProfilerGuard::new(100).unwrap();
// trecho pesado aqui
let mut acc = 0u64;
for i in 0..10_000_000 {
acc += i;
}
if let Ok(report) = [Link]().build() {
let file = std::fs::File::create("[Link]").unwrap();
[Link](file).unwrap();
}
println!("{}", acc);
}
Quando isso é útil?
quer ligar o profiler em um trecho específico
quer gerar artefato sob demanda
quer evitar ferramenta externa em alguns cenários
Mas cuidado
Profiler embutido é útil, porém benchmark e profiler não são a mesma coisa.
Não use profiler como substituto de benchmark.
[Link] 13/22
09/03/2026, 16:48 Logging e Profiling Rust
14) tokio-console : o “top/htop” do async Rust
Se você vai mexer com:
APIs
filas
workers
websocket
múltiplas tasks
concorrência com Tokio
o tokio-console é valioso. A documentação oficial e o repositório descrevem a
ferramenta como um debugger/diagnostics tool para aplicações async Rust, exibindo
tarefas, recursos e operações em tempo real. GitHub +2
Isso é parecido com o quê em Python?
Uma mistura de:
introspecção do event loop
tracing de coroutines
observabilidade operacional em tempo real
Por que isso importa?
Porque em código async o gargalo nem sempre é CPU puro.
Às vezes o problema é:
task parada esperando lock
task nunca acorda
fan-out exagerado
backpressure
fila congestionada
operação IO segurando fluxo
Flamegraph sozinho não conta essa história tão bem quanto uma ferramenta orientada a
runtime async.
15) Como pensar performance em Rust do jeito certo
Muita gente que vem de Python erra aqui.
Em Python
[Link] 14/22
09/03/2026, 16:48 Logging e Profiling Rust
Você já assume que muita coisa é lenta por natureza da VM e interpretações, então
otimiza “macro”.
Em Rust
Como a base já é rápida, o erro comum é cair em micro-otimização cedo demais.
A ordem profissional é:
Etapa 1 — meça
Use criterion para ver se existe regressão. [Link] +1
Etapa 2 — observe
Use tracing para entender:
latência por etapa
frequência de chamadas
tamanho de payload
retries
filas
Etapa 3 — localize o gargalo
Use flamegraph, pprof , tokio-console . [Link] +2
Etapa 4 — só então otimize
Ajuste:
alocação
cópias
lock contention
parsing
serialização
estrutura de dados
paralelismo
16) O que observar em Rust que em Python às vezes passa
despercebido
Aqui entra a correlação de linguagem que você pediu.
1. Ownership e cópias
[Link] 15/22
09/03/2026, 16:48 Logging e Profiling Rust
Em Python, muita coisa é referência implícita.
Em Rust, você precisa perceber quando está:
clonando sem necessidade
movendo dados grandes
alocando string demais
Sinal no profiling
funções de clone/alocação muito presentes
queda de throughput ao crescer entrada
2. String e Vec realocando
Em Python, listas e strings têm custo escondido mas você raramente pensa nisso tão
explicitamente.
Em Rust, reservar capacidade pode fazer diferença:
Rust
let mut s = String::with_capacity(1024);
let mut v = Vec::with_capacity(10_000);
3. Locks em async
Em Python async, o gargalo costuma ser IO ou GIL em contextos mistos.
Em Rust async, você pode ter gargalo em:
Mutex
RwLock
canais
tasks demais
Aí tokio-console brilha. [Link] +1
4. Zero-cost abstractions não significa custo zero mágico
Rust permite abstrações muito boas, mas elas não te livram de:
algoritmo ruim
alocação excessiva
[Link] 16/22
09/03/2026, 16:48 Logging e Profiling Rust
serialização cara
cópias desnecessárias
contenção de recursos
17) Exemplo completo de observabilidade simples e boa
[Link]
TOML
[dependencies]
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
tracing-appender = "0.2"
[Link]
Rust
use std::time::Instant;
use tracing::{info, instrument};
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::EnvFilter;
fn init_tracing() -> WorkerGuard {
let file_appender = tracing_appender::rolling::daily("logs", "[Link]");
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
let filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::fmt()
.with_env_filter(filter)
.with_writer(non_blocking)
.with_target(true)
.with_line_number(true)
.with_thread_ids(true)
.init();
guard
}
#[instrument(skip(dados), fields(tamanho = [Link]()))]
fn processar(dados: &[u64]) -> u64 {
let inicio = Instant::now();
let total: u64 = [Link]().map(|x| x * 2).sum();
[Link] 17/22
09/03/2026, 16:48 Logging e Profiling Rust
info!(
elapsed_ms = [Link]().as_millis(),
total = total,
"processamento concluído"
);
total
}
fn main() {
let _guard = init_tracing();
let dados: Vec<u64> = (0..100_000).collect();
let total = processar(&dados);
info!(resultado = total, "fim da aplicação");
}
O que esse exemplo ensina
Equivalente em Python
Você talvez faria:
logging
time.perf_counter()
decorator para medir função
Em Rust
Você combina:
#[instrument] para contexto
evento com campos estruturados
medição explícita de duração
saída robusta em arquivo
filtro por ambiente
Isso já está num nível bem profissional.
18) Quando usar log e quando usar tracing na prática
Use log se:
[Link] 18/22
09/03/2026, 16:48 Logging e Profiling Rust
você está escrevendo uma lib pequena
quer máxima compatibilidade
não precisa de spans/contexto
Use tracing se:
sua aplicação é async
quer campos estruturados
quer spans por operação
quer OpenTelemetry depois
quer diagnosticar produção com menos sofrimento
Hoje, para aplicação, eu te recomendaria aprender tracing primeiro.
19) Anti-padrões que você deve evitar
1. Usar log para substituir benchmark
Errado.
Log mostra fluxo, não mede com rigor estatístico.
2. Benchmarkar debug build
Errado.
Performance de Rust só faz sentido em geral com build otimizado.
Use:
PowerShell
cargo bench
cargo run --release
3. Montar string em vez de registrar campos
Prefira:
Rust
info!(user_id = user_id, status = "ok", "login realizado");
não:
[Link] 19/22
09/03/2026, 16:48 Logging e Profiling Rust
Rust
info!("user_id={} status=ok", user_id);
4. Inicializar logger dentro de biblioteca
Configuração é papel do binário/app, não da lib. [Link]
5. Otimizar antes de medir
Esse erro em Rust é muito comum porque a linguagem já passa sensação de performance.
20) Minha recomendação para seu roadmap
Se eu estivesse te treinando em migração Python → Rust, eu faria nesta ordem:
Fase 1 — Logging moderno
Aprenda:
tracing::info!
warn! , error!
#[instrument]
EnvFilter
arquivo com tracing-appender
Fase 2 — Benchmark
Aprenda:
criterion
black_box
comparar funções
testar diferentes tamanhos de entrada
Fase 3 — Profiling real
Aprenda:
flamegraph
pprof
leitura de gargalo
relação entre algoritmo e alocação
Fase 4 — Async observability
[Link] 20/22
09/03/2026, 16:48 Logging e Profiling Rust
Aprenda:
tokio-console
spans em handlers
contexto por request/job
locks, filas e tasks
21) Resumo direto
Em Python você pensa:
log textual
profiler separado
contexto muitas vezes manual
Em Rust profissional você pensa:
tracing para observabilidade com contexto
criterion para benchmark confiável
pprof / flamegraph para gargalo de CPU
tokio-console para async/concurrency
A melhor correlação mental é esta:
logging do Python ≈ log ou tracing
structlog / observabilidade estruturada ≈ tracing
timeit / benchmark libs ≈ criterion
py-spy / profiling ≈ pprof + flamegraph
inspeção de async ≈ tokio-console
22) O que eu faria no seu lugar hoje
No Windows, para começar sem complicar:
1. monte um projeto com tracing + tracing-subscriber + tracing-appender
2. instrumente 2 ou 3 funções com #[instrument]
3. adicione medição simples com Instant
4. crie um benchmark com criterion
5. deixe flamegraph mais para frente, de preferência via WSL2/Linux
6. se for entrar em Tokio, estude tokio-console cedo
[Link] 21/22
09/03/2026, 16:48 Logging e Profiling Rust
Isso te coloca numa trilha de engenharia muito melhor do que só aprender sintaxe de
Rust.
Se você quiser, no próximo passo eu posso te entregar um projeto Rust completo, estilo
produção, com:
logs em arquivo + console, filtros por ambiente, #[instrument] , benchmark com
Criterion e exemplo de profiling.
[Link] 22/22