Skip to content

Instantly share code, notes, and snippets.

@SteveBate
Last active August 29, 2015 14:13
Show Gist options
  • Save SteveBate/54f82fe3ea171223450f to your computer and use it in GitHub Desktop.
Save SteveBate/54f82fe3ea171223450f to your computer and use it in GitHub Desktop.
Sample of monitoring a log file for changes and filtering out lines that describe an error
package main
import (
"bufio"
"flag"
"fmt"
"log"
"os"
"regexp"
"strings"
"time"
"gopkg.in/fsnotify.v1"
)
var (
fileToWatch string
appName string
keyword string
interval int
)
func init() {
flag.StringVar(&fileToWatch, "file", "", "the path and name of the file to be monitored for changes")
flag.StringVar(&appName, "appname", "", "the name of the application being monitored")
flag.StringVar(&keyword, "keyword", "EXCEPTION", "the word to look for that indicates an error line")
flag.IntVar(&interval, "interval", 20, "time to wait in seconds before parsing file contents")
flag.Parse()
}
func main() {
dateRegex := regexp.MustCompile(`^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}`)
keywordRegex := regexp.MustCompile(keyword + ` - (.*)`)
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
done := make(chan bool)
analyze := make(chan bool)
// monitor for file changes or errors
go func() {
for {
select {
case event := <-watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write {
analyze <- true
}
case err := <-watcher.Errors:
fmt.Println("error", err)
}
}
}()
// parse file when change detected every <interval> seconds
go func() {
lineNo := 0
on := true
for {
select {
case <-time.After(time.Duration(interval) * time.Second):
fmt.Println("checking...")
select {
case <-analyze:
go func() {
if on {
f, err := os.Open(fileToWatch)
if err != nil {
log.Fatal(err)
}
defer f.Close()
reader := bufio.NewReader(f)
scanner := bufio.NewScanner(reader)
current := 0
for scanner.Scan() {
current += 1
if current > lineNo {
str := scanner.Text()
if strings.Contains(str, keyword) {
date := dateRegex.FindString(str)
groups := keywordRegex.FindStringSubmatch(str)
if len(groups) == 2 {
// insert into db
fmt.Printf("App: %s - Date: %s - Error: %s\n", appName, date, groups[1])
}
}
}
}
lineNo = current
}
on = !on
}()
default:
// nothing to do here but stop the routine from blocking
}
}
}
}()
err = watcher.Add(fileToWatch)
if err != nil {
log.Fatal(err)
}
fmt.Println("monitoring...")
<-done
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment