0% acharam este documento útil (0 voto)
6 visualizações22 páginas

Logging e Profiling Rust

O documento aborda o uso de logging e profiling em Rust, comparando com práticas em Python para facilitar a transição de desenvolvedores. Ele destaca a importância de ferramentas como 'tracing' para observabilidade e 'criterion' para benchmarking, além de fornecer exemplos práticos de implementação. A estrutura recomendada para projetos em Rust é apresentada, enfatizando a configuração adequada de logging e a instrumentação de funções.
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
6 visualizações22 páginas

Logging e Profiling Rust

O documento aborda o uso de logging e profiling em Rust, comparando com práticas em Python para facilitar a transição de desenvolvedores. Ele destaca a importância de ferramentas como 'tracing' para observabilidade e 'criterion' para benchmarking, além de fornecer exemplos práticos de implementação. A estrutura recomendada para projetos em Rust é apresentada, enfatizando a configuração adequada de logging e a instrumentação de funções.
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

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

Você também pode gostar