git上log日志组件
https://github.com/hpcloud/tail/blob/master/tail.go
我们写个test来测试下这个组件
package main
import (
"fmt"
"github.com/hpcloud/tail"
"time"
)
func main() {
filename := "E:\\develop\\kafka\\kafka_2.12-1.0.0\\config\\server.properties"
tails, err := tail.TailFile(filename, tail.Config{
ReOpen: true,
Follow: true,
// Location: &tail.SeekInfo{Offset: 0, Whence: 2},
MustExist: false,
Poll: true,
})
if err != nil {
fmt.Println("tail file err:", err)
return
}
var msg *tail.Line
var ok bool
for true {
msg, ok = <-tails.Lines
if !ok {
fmt.Printf("tail file close reopen, filename:%s\n", tails.Filename)
time.Sleep(100 * time.Millisecond)
continue
}
fmt.Println("msg:", msg)
}
}
执行代码会在终端输出如下该文件的信息:
PS E:\golang\go_pro\src\safly> go run safly.go
msg: &{# Licensed to the Apache Software Foundation (ASF) under one or more 2017-11-18 19:22:49.194689
2 +0800 CST }
msg: &{# contributor license agreements. See the NOTICE file distributed with 2017-11-18 19:22:49.194
6892 +0800 CST }
msg: &{# this work for additional information regarding copyright ownership. 2017-11-18 19:22:49.20869
92 +0800 CST }
msg: &{# The ASF licenses this file to You under the Apache License, Version 2.0 2017-11-18 19:22:49.2
102004 +0800 CST }
。。。。。。省略
我们看看源码tailf.go的执行流程:
func TailFile(filename string, config Config) (*Tail, error) {
if config.ReOpen && !config.Follow {
util.Fatal("cannot set ReOpen without Follow.")
}
t := &Tail{
Filename: filename,
Lines: make(chan *Line),
Config: config,
}
// when Logger was not specified in config, use default logger
if t.Logger == nil {
t.Logger = log.New(os.Stderr, "", log.LstdFlags)
}
if t.Poll {
t.watcher = watch.NewPollingFileWatcher(filename)
} else {
t.watcher = watch.NewInotifyFileWatcher(filename)
}
if t.MustExist {
var err error
t.file, err = OpenFile(t.Filename)
if err != nil {
return nil, err
}
}
go t.tailFileSync()
return t, nil
}
在最后go t.tailFileSync()启动goroutine
在tailFileSync方法中
tail.openReader()
看看做了什么操作?
func (tail *Tail) openReader() {
if tail.MaxLineSize > 0 {
// add 2 to account for newline characters
tail.reader = bufio.NewReaderSize(tail.file, tail.MaxLineSize+2)
} else {
tail.reader = bufio.NewReader(tail.file)
}
}
创建reader,然后for读取line, err := tail.readLine()
然后写入chan 中
// Process `line` even if err is EOF.
if err == nil {
cooloff := !tail.sendLine(line)
if cooloff {
// Wait a second before seeking till the end of
// file when rate limit is reached.
msg := ("Too much log activity; waiting a second " +
"before resuming tailing")
tail.Lines <- &Line{msg, time.Now(), errors.New(msg)}
select {
case <-time.After(time.Second):
case <-tail.Dying():
return
}
if err := tail.seekEnd(); err != nil {
tail.Kill(err)
return
}
}
}
tail.Lines <- &Line{msg, time.Now(), errors.New(msg)}中的Lines是在Tail定义的chan
type Tail struct {
Filename string
Lines chan *Line
Config
file *os.File
reader *bufio.Reader
watcher watch.FileWatcher
changes *watch.FileChanges
tomb.Tomb // provides: Done, Kill, Dying
lk sync.Mutex
}