010 Project 10: Build a tail -f Clone
010 Build a tail -f Clone
Read last N lines and follow appended content.
open file -> ring buffer last N -> print -> poll size growth -> print new data
Full main.go
package main
import (
"bufio"
"flag"
"fmt"
"io"
"os"
"time"
)
func lastNLines(path string, n int) ([]string, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
buf := make([]string, 0, n)
s := bufio.NewScanner(f)
for s.Scan() {
if len(buf) == n {
copy(buf, buf[1:])
buf[n-1] = s.Text()
} else {
buf = append(buf, s.Text())
}
}
return buf, s.Err()
}
func follow(path string, offset int64) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
if _, err := f.Seek(offset, io.SeekStart); err != nil {
return err
}
for {
_, _ = io.Copy(os.Stdout, f)
time.Sleep(500 * time.Millisecond)
}
}
func main() {
n := flag.Int("n", 10, "show last n lines")
followMode := flag.Bool("f", false, "follow file")
flag.Parse()
if flag.NArg() != 1 {
fmt.Fprintln(os.Stderr, "usage: gtail [-n N] [-f] <file>")
os.Exit(2)
}
path := flag.Arg(0)
lines, err := lastNLines(path, *n)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
for _, line := range lines {
fmt.Println(line)
}
if *followMode {
st, err := os.Stat(path)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if err := follow(path, st.Size()); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
}Run
go run . -n 50 app.log
go run . -n 20 -f app.logStep-by-Step Explanation
- Parse command-line flags and validate inputs early.
- Keep the core operation in a small, testable function.
- Process data as a stream when possible to reduce memory use.
- Print stable output and meaningful exit codes.
- Add one extension feature and test edge cases.
Code Anatomy
mainhandles flags, orchestration, and errors.- Worker/helper functions hold business logic.
- Output section should be deterministic for scripting and CI usage.
Learning Goals
- Write composable Unix-style Go tools.
- Improve error messages and operator experience.
- Practice iterative improvement over one clear baseline.