rust 45 lines · 9 steps

Buffered log scanning in Rust

Two functions stream a log file line by line with buffered reads, aggregating stats and finding the first match without loading the whole file.

Explained by highlit
1use std::fs::File;
2use std::io::{self, BufRead, BufReader};
3use std::path::Path;
4 
5pub struct LogStats {
6 pub total_lines: usize,
7 pub error_lines: usize,
8 pub bytes_scanned: u64,
9}
10 
11pub fn scan_log<P: AsRef<Path>>(path: P) -> io::Result<LogStats> {
12 let file = File::open(path)?;
13 let reader = BufReader::with_capacity(64 * 1024, file);
14 
15 let mut stats = LogStats {
16 total_lines: 0,
17 error_lines: 0,
18 bytes_scanned: 0,
19 };
20 
21 for line in reader.lines() {
22 let line = line?;
23 stats.total_lines += 1;
24 stats.bytes_scanned += line.len() as u64 + 1;
25 
26 if line.contains("ERROR") || line.contains("FATAL") {
27 stats.error_lines += 1;
28 }
29 }
30 
31 Ok(stats)
32}
33 
34pub fn first_match<P: AsRef<Path>>(path: P, needle: &str) -> io::Result<Option<(usize, String)>> {
35 let reader = BufReader::new(File::open(path)?);
36 
37 for (idx, line) in reader.lines().enumerate() {
38 let line = line?;
39 if line.contains(needle) {
40 return Ok(Some((idx + 1, line)));
41 }
42 }
43 
44 Ok(None)
45}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Buffered readers let you stream large files line by line instead of loading them entirely into memory.
  2. 2Accepting `AsRef<Path>` makes a function callable with `&str`, `String`, or `PathBuf` interchangeably.
  3. 3Propagating `io::Result` with `?` keeps the happy path readable while surfacing every I/O failure.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Buffered log scanning in Rust — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code