1. 程式人生 > 其它 >Go(第三方庫):03---模擬tail命令(hpcloud/tail包)

Go(第三方庫):03---模擬tail命令(hpcloud/tail包)

技術標籤:Go(第三方庫)模擬tail命令hpcloud/tail包

一、包概述

tail命令

  • 這個包就是實現了tail命令中-f的功能,你可以用程式列印一個檔案,當檔案中有資料更新時,程式會自動列印,類似於一個持續檢視檔案內容的功能
  • 這個包在日誌收集中可以實時的監測日誌的變化

二、包的下載

  • 執行下面的命令下載:
go get github.com/hpcloud/tail/
  • 如果是Go Module專案,輸入包名,執行"go mod tidy"也可以

三、演示案例

  • 下面先給出一個演示案例,然後再慢慢講解各種資料結構
  • 程式碼如下:
package main

import (
	"fmt"
	"github.com/hpcloud/tail"
	"time"
)

func main() {
	// 設定相關選項
	config := tail.Config{
		ReOpen: true,
		Follow: true,
		Location: &tail.SeekInfo{Offset: 0, Whence:2},
		MustExist: false,
		Poll: true,
	}

	// 根據上面的選項, 跟蹤當前路徑下的my.log檔案
	tails, err := tail.TailFile("./my.log", config)
	if err != nil {
		fmt.Println("tail file failed, err: ", err)
		return
	}

	var (
		line *tail.Line
		ok bool
	)

	// 迴圈監聽
	for {
		// 如果檔案中有新的一行資料加入, 那麼這個管道中會有資料
		line, ok = <- tails.Lines
		if !ok {
			fmt.Printf("tail file close reopen, filename: %s\n", tails.Filename)
			time.Sleep(time.Second)
			continue
		}

		// 列印新的內容
		fmt.Println("line: ", line.Text)
	}
}
  • 啟動程式:

  • 上面的程式中監聽的是當前路徑下的my.log檔案,我們來到專案當前路徑下,向my.log檔案中加入一行資料(必須要換行,不是一行程式不會監聽到)

  • 再次來到程式,可以看到程式列印了相關內容

四、type Config

  • Config用來定義檔案被讀取和跟蹤的方式
// 配置用於指定檔案如何被跟蹤
type Config struct {
	Location    *SeekInfo // Seek to this location before tailing
	ReOpen      bool      // Reopen recreated files (tail -F)
	MustExist   bool      // Fail early if the file does not exist
	Poll        bool      // Poll for file changes instead of using inotify
	Pipe        bool      // Is a named pipe (mkfifo)
	RateLimiter *ratelimiter.LeakyBucket

	// Generic IO
	Follow      bool // Continue looking for new lines (tail -f)
	MaxLineSize int  // If non-zero, split longer lines into multiple lines

	// Logger, when nil, is set to tail.DefaultLogger
	// To disable logging: set field to tail.DiscardingLogger
	Logger logger
}

// SeekInfo represents arguments to `os.Seek`
type SeekInfo struct {
	Offset int64
	Whence int     // os.SEEK_*
}
  • 相關成員:
    • Location:指定開始讀取的位置
    • ReOpen:true則檔案被刪掉阻塞等待新建該檔案,false則檔案被刪掉時程式結束
    • MustExist:true則沒有找到檔案就報錯並結束,false則沒有找到檔案就阻塞保持住
    • Poll:使用Linux的Poll函式,poll的作用是把當前的檔案指標掛到等待佇列
    • Follow:true則一直阻塞並監聽指定檔案,false則一次讀完就結束程式

五、type Tail

  • TailFile可以用來跟蹤檔案
  • Lines通道:檔案的輸出流是Lines成員(可以從這個通道中讀取檔案的更新資料),再從Lines通道中讀取完資料之後可以呼叫' Wait '或' Err '方法
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
}

func TailFile()

  • 該函式在指定的filename檔案和指定的config配合下返回一個Tail物件
func TailFile(filename string, config Config) (*Tail, error)

func (tail *Tail) waitForChanges()

  • 等待更改直到檔案被新增、刪除、移動或截斷。當移動或刪除時,如果“重新開啟”為true,檔案將被重新開啟。截短的檔案總是被重新開啟
// waitForChanges waits until the file has been appended, deleted,
// moved or truncated. When moved or deleted - the file will be
// reopened if ReOpen is true. Truncated files are always reopened.
func (tail *Tail) waitForChanges() error

六、type Line

  • 這個結構體是用來儲存從Tail中讀取的資訊
type Line struct {
	Text string
	Time time.Time
	Err  error // Error from tail
}

func NewLine()

  • NewLine返回當前時間的一行
// NewLine returns a Line with present time.
func NewLine(text string) *Line {
	return &Line{text, time.Now(), nil}
}

七、總結使用流程

  • 首先初始化配置結構體Config
  • 呼叫TailFile函式,並傳入檔案路徑和config,返回有個tail的結構體,tail結構體的Lines欄位封裝了拿到的資訊
  • 遍歷tail.Lnes欄位,取出資訊(注意這裡要迴圈的取,因為tail可以實現實時監控)