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
+4.8k Golang : Get a list of crosses(instruments) available to trade from Oanda account
+8.1k Golang : Implementing class(object-oriented programming style)
+17.3k How to enable MariaDB/MySQL logs ?
+27.1k PHP : Convert(cast) string to bigInt
+12.6k Golang : http.Get example
+6.2k Golang : Break string into a slice of characters example
+10.7k Golang : How to transmit update file to client by HTTP request example
+10.3k Golang : Interfacing with PayPal's IPN(Instant Payment Notification) example
+38.8k Golang : How to iterate over a []string(array)
+20.4k Golang : Convert date string to variants of time.Time type examples
+16.2k Golang : How to implement two-factor authentication?
+12k Golang : List running EC2 instances and descriptions