Golang : simulate tail -f or read last line from log file example
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.
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
Tutorials
+11.2k Golang : Sort and reverse sort a slice of bytes
+7k Golang : Auto-generate reply email with text/template package
+10.6k Golang : How to detect a server/machine network interface capabilities?
+12.6k Golang : How to pass map to html template and access the map's elements
+22.6k Golang : Upload to S3 with official aws-sdk-go package
+7.9k Golang : Generate random Chinese, Japanese, Korean and other runes
+12.4k Golang : Check if an integer is negative or positive
+8.1k Golang : Temperatures conversion example
+10.8k Golang : Flush and close file created by os.Create and bufio.NewWriter example