Golang : simulate tail -f or read last line from log file example


Tags : golang tail offset read-at

In this tutorial, we will attempt to simulate the Linux/Unix tail command with -f option in Golang. What this code example does is to read the entire file line by line until the last line and calculate the last line size.

From the last line size, an offset will be calculated by subtracting the file size by the last line size. After that, we will read from the offset and display the last line content paused by 2 seconds delay. This will simulate the tail -f logfile command in Golang. Not exactly similar to what you get at http://trac.mondorescue.org/browser/trunk/mindi-busybox/coreutils/tail.c, but this tutorial is here for learning purpose :-)

Here you go!

gotail.go

 package main

 import (
 "bufio"
 "flag"
 "fmt"
 "io"
 "os"
 "time"
 )

 var previousOffset int64 = 0

 func main() {
 flag.Parse()

 filename := flag.Arg(0)

 delay := time.Tick(2 * time.Second)

 for _ = range delay {
 readLastLine(filename)
 }

 }

 func readLastLine(filename string) {

 file, err := os.Open(filename)
 if err != nil {
 panic(err)
 }

 defer file.Close()

 reader := bufio.NewReader(file)

 // we need to calculate the size of the last line for file.ReadAt(offset) to work

 // NOTE : not a very effective solution as we need to read
 // the entire file at least for 1 pass :(

 lastLineSize := 0

 for {
 line, _, err := reader.ReadLine()

 if err == io.EOF {
 break
 }

 lastLineSize = len(line)
 }

 fileInfo, err := os.Stat(filename)

 // make a buffer size according to the lastLineSize
 buffer := make([]byte, lastLineSize)

 // +1 to compensate for the initial 0 byte of the line
 // otherwise, the initial character of the line will be missing

 // instead of reading the whole file into memory, we just read from certain offset

 offset := fileInfo.Size() - int64(lastLineSize+1)
 numRead, err := file.ReadAt(buffer, offset)

 if previousOffset != offset {

 // print out last line content
 buffer = buffer[:numRead]
 fmt.Printf("%s \n", buffer)

 previousOffset = offset
 }

 }

Open up 2 terminal windows when you run it for the first time. On one window, run :

>gotail file.log

it will display the last line from the file.log. You can then add additional lines to the bottom of the file.log on another window. The additional lines will appear on the first window where gotail file.log is executing.

NOTE : Room for improvement. Instead of reading the file every time to get the last line size, try to make it read once.



Tags : golang tail offset read-at

By Adam Ng

IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.


Advertisement