Streaming de logs em Rust com Tokio

🇺🇸 Read in English
O que você ganha

Você ganha um tailer de logs pequeno e focado que pode ser adicionado a qualquer serviço:

  • baixa latência: eventos são enviados assim que chegam
  • memória limitada: backpressure via leituras em streaming
  • JSON estruturado pronto para qualquer pipeline de logs

Enviar logs linha por linha mantém a latência baixa e a memória estável. Este trecho mostra um tailer assíncrono mínimo que emite JSON.

O streamer

use tokio::{fs::File, io::{AsyncBufReadExt, BufReader}};
use serde::Serialize;

#[derive(Serialize)]
struct LogLine<'a> {
    line: &'a str,
    source: &'a str,
}

async fn stream_file(path: &str, source: &str) -> anyhow::Result<()> {
    let file = File::open(path).await?;
    let reader = BufReader::new(file);
    let mut lines = reader.lines();

    while let Some(line) = lines.next_line().await? {
        let payload = LogLine { line: &line, source };
        let json = serde_json::to_string(&payload)?;
        // Replace with your sink: TCP, HTTP, Kafka, etc.
        println!("{}", json);
    }
    Ok(())
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Run with: cargo run -- path/to/app.log
    let path = std::env::args().nth(1).expect("missing log path");
    stream_file(&path, "app").await
}

Observações

  • BufReader mantém a memória limitada; lines() produz valores de forma lazy.
  • Substitua println! pelo cliente do sink de sua preferência.
  • Use tokio::select! para combinar múltiplos arquivos ou sinais de encerramento.
  • Emita JSON estruturado para que consumidores downstream possam parsear de forma confiável.