- Published on
Log analyzer ultraveloce con Rust + Tokio (e confronto con Bash)
- Authors

- Name
- Alessandro Iannacone
Log analyzer ultraveloce con Rust + Tokio (e confronto "finto ma realistico" con Bash)
In questo articolo costruiamo un parser di log HTTP in Rust sfruttando Tokio per pipeline asincrona e parallelismo sul parsing. A fine guida trovi un confronto plausibile con uno script Bash/awk su un file da 1 GB, giusto per capire gli ordini di grandezza.
Obiettivi
- Leggere velocemente file di log stile Nginx/Apache (Combined Log Format).
- Estrarre per ogni riga: status code, path, timestamp (minuto).
- Calcolare:
- conteggio per status code,
- top 10 path per richieste,
- richieste per minuto (rate).
- Pipeline asincrona: reader → workers di parsing → aggregatore.
- Output in JSON e tabellare.
Prerequisiti
Rust 1.75+ (o recente) con
cargoFile di log in formato tipo:
127.0.0.1 - - [12/Oct/2025:10:15:42 +0000] "GET /api/items?id=7 HTTP/1.1" 200 123 "-" "curl/8.1.0"
Conoscenza base di regex.
Struttura del progetto
cargo new fastlog
cd fastlog
Cargo.toml
[package]
name = "fastlog"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1", features = ["full"] }
regex = "1"
clap = { version = "4", features = ["derive"] }
anyhow = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Implementazione
Strategia
- Reader (1 task): legge il file riga per riga (I/O asincrono) e immette le righe in un canale MPSC con backpressure (buffer limitato).
- Workers (N task): consumano le righe e applicano una regex compilata per estrarre campi; inviano risultati (strutturati) a un secondo canale.
- Aggregatore (1 task): consuma i risultati e aggiorna mappe in memoria (niente lock condivisi tra i worker; l'aggregazione è centralizzata e quindi lock-free per i worker).
Questo design massimizza throughput quando: - l'I/O è "abbastanza veloce", - il parsing/regex è la parte "costosa" parallelizzabile.
src/main.rs
// Codice completo come nell'articolo precedente...
Confronto (simulato) con Bash/awk
Script Bash (baseline)
#!/usr/bin/env bash
# Estrae status, path e minuto; produce top path e conteggi per status/minuto
LOG=${1:-/var/log/nginx/access.log}
awk '
{
match($0, /\[([^]]+)\]/, ts)
split(ts[1], a, ":"); minute=a[1] ":" a[2]
match($0, /"(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS) ([^ "]+)/, req)
path=req[2]
tail=substr($0, RSTART+RLENGTH)
match(tail, / ([0-9]{3}) /, st)
status=st[1]
by_status[status]++
by_path[path]++
by_minute[minute]++
}
END {
print "== by_status =="
for (s in by_status) print s, by_status[s]
}' "$LOG"
Benchmark indicativo
Implementazione Tempo medio Throughput stimato
Rust + Tokio (8 worker) ~1.8 s ~550 MB/s Bash + awk ~18 s ~55 MB/s
Conclusioni
Rust + Tokio offrono un'architettura moderna per processare grandi quantità di log con massimo parallelismo, basso overhead e controllo della memoria.
Il confronto con Bash/awk è simbolico, ma evidenzia la differenza tra un approccio scripting e uno nativo, compilato e asincrono.