所以我在golang中创建了一些日志分析器,我需要的是新创建文件的实时tail -f。
我正在使用tail包和fsnotify包,但我不太熟悉其中的频道和例程,所以我需要一些帮助。
目前的计划如下:
package main
import(
"fmt"
"github.com/hpcloud/tail"
"strings"
"log"
"net/smtp"
"time"
"github.com/fsnotify/fsnotify"
)
//this function needs to monitor for new files in directory
func newFileCheck() (newFilename chan string, err error) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return
}
err = watcher.Add("myDir")
if err != nil {
return
}
newFilename = make(chan string)
// Process events
go func() {
for {
select {
case ev := <-watcher.Events:
log.Println("event:", ev)
newFilename <- ev.Name // Relative path to the file
//t.Stop() //if I pass reference to t THIS IS NOT HAPPENING ?
case err := <-watcher.Errors:
log.Println("error:", err)
}
}
}()
return
}
func main() {
newFileName = "mylog_0000.log.txt"
fmt.Println("Processing log: ",newFileName)
newFilenameChan, err := newFileCheck()
if err != nil {
fmt.Println("ERR: ",err)
}
t := tailLog(newFileName)
go func() {
for {
select {
case name := <-newFilenameChan:
fmt.Println("New file created: ",name) //this will be printed only once and then on new events nothing is printed ?
//NONE of the lines abowe doesn't work
t.Stop()
t.Dead()
t.Done()
t = tailLog(name)
}
}
}()
}
func tailLog(fileName string) *tail.Tail{
var count = 0
// close the old one and read new file
t, err := tail.TailFile("/mydir/"+fileName, tail.Config{Follow: true, ReOpen: true})
for line := range t.Lines {
//fmt.Println("Line is:", line.Text)
//check do we have what we need
if strings.Contains(strings.ToLower(line.Text), "mfc"){
count++
//do other stuff
}
}
fmt.Println(err)
return t
}
所以我无法弄清楚为什么newFileCheck函数只会在第一时间打印事件,而且我也无法弄清楚当新事件发生时如何取消活动尾部,然后在该事件之后再次启动尾部?
答案 0 :(得分:0)
考虑一下:
当函数main返回时,程序退出。它不等待 其他(非主要)goroutines完成。
看看你的代码块:
func main() {
newFileName = "mylog_0000.log.txt"
fmt.Println("Processing log: ",newFileName)
newFilenameChan, err := newFileCheck()
if err != nil {
fmt.Println("ERR: ",err)
}
t := tailLog(newFileName)
go func() {
for {
select {
case name := <-newFilenameChan:
fmt.Println("New file created: ",name) //this will be printed only once and then on new events nothing is printed ?
//NONE of the lines abowe doesn't work
t.Stop()
t.Dead()
t.Done()
t = tailLog(name)
}
}
}()
}
要优雅地处理这项工作,你应该在Golang中了解更多关于并发性的知识。如果您对执行/完成任务的顺序感兴趣,请使用通道来控制goroutines,例如停止/启动/ etc和WaitGroup。当无法控制你的程序流程时,goroutines可以过自己的生活,这是不好的做法。
答案 1 :(得分:0)
如果您对此包装https://github.com/hpcloud/tail
打开文件后,您需要创建一个goroutine,然后需要检查一个新文件。
我将其用于检查SoftetherVPN服务器的新日志文件:
package main
import (
"fmt"
"github.com/hpcloud/tail"
"log"
"time"
)
func CheckFileName(filename string, f chan<- string) {
for {
newFilename := fmt.Sprintf("%v", time.Now().Format("vpn_20060102.log"))
// We have a new filename, that send it into channel
if newFilename != filename {
log.Println("A new logfile", newFilename)
f <- newFilename
return
}
}
}
func main() {
filenameChan := make(chan string)
for {
filename = fmt.Sprintf("%v", time.Now().Format("vpn_20060102.log"))
t, err := tail.TailFile(filename, tail.Config{Follow: true, ReOpen: true, MustExist: true})
if err != nil {
log.Println("No log file", filename, ". Waiting for 10 minute")
time.Sleep(time.Minute * 10)
continue
}
// Send goroutine for checking filename in loop
go CheckFileName(filename, filenameChan)
// Send goroutine that stops lines read in range
go func() {
for {
select {
case name := <-filenameChan:
log.Println("Received a new name for log:", name)
t.Stop()
return
}
}
}()
if err != nil {
log.Fatalln(err)
}
for line := range t.Lines {
fmt.Println(line)
}
}
}
所以,这对我有用