0%

tail 包读取日志文件

tail 包读取日志文件

1 下载、安装 tail

1
go get github.com/hpcloud/tail

2 tail 读取日志文件 Demo

2.1 配置

2.1.1 初始化 config 对象

1
2
3
4
5
6
7
config := tail.Config{
ReOpen: true, // 重新打开,如果修改操作不是在日志文件末尾添加
Follow: true, // 持续寻找新行
Location: &tail.SeekInfo{Offset: 0, Whence: 2}, // 初始光标位置
MustExist: false, // 是否允许文件不存在
Poll: true, // 使用 Poll 监听文件的变化,而不是 inotify
}

2.1.2 SeekInfo 结构

1
2
3
4
type SeekInfo struct {        
Offset int64 // 偏移量
Whence int // 搜索起始位置
}
Whence 含义
0 文件开始处
1 当前位置
2 文件末尾

2.2 创建 Tail 对象

1
2
3
4
5
tails, err := tail.TailFile(fileName, config)
if err != nil {
fmt.Println("tail file failed, err:", err)
return
}

日志文件的路径配置信息初始化 Tail 对象。

2.3 读日志

1
2
3
4
5
6
7
8
9
for {
msg, ok := <-tails.Lines
if !ok {
fmt.Printf("tail file close reopen, filename:%s\n", tails.Filename)
time.Sleep(time.Second)
continue
}
fmt.Println("msg:", msg.Text)
}

Tail 对象内部维护了一个 channel,变量名为 Lines,其中储存着 Line 类型的对象,

1
2
3
4
5
type Line struct {        
Text string // 文本
Time time.Time // 时间
Err error // Error from tail
}

2.4 运行效果

2.4.1 运行程序

1
2
$ go run tail.go
2021/09/23 20:04:59 Waiting for ./log_file to appear...

2.4.2 创建日志文件

打开另一个命令行窗口,执行以下命令,

1
touch log_file

看到程序输出,

1
2021/09/23 20:06:46 Seeked ./log_file - &{Offset:0 Whence:2}

2.4.3 向日志文件末尾写入一行

1
echo "this is a test" >> log_file

看到程序输出,

1
msg: this is a test

2.5 完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
"fmt"
"time"

"github.com/hpcloud/tail"
)

func main() {
fileName := "./log_file"

config := tail.Config{
ReOpen: true,
Follow: true,
Location: &tail.SeekInfo{Offset: 0, Whence: 2},
MustExist: false,
Poll: true,
}

tails, err := tail.TailFile(fileName, config)
if err != nil {
fmt.Println("tail file failed, err:", err)
return
}

for {
msg, ok := <-tails.Lines
if !ok {
fmt.Printf("tail file close reopen, filename:%s\n", tails.Filename)
time.Sleep(time.Second)
continue
}
fmt.Println("msg:", msg.Text)
}
}