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 <nil>}
- msg: &{# contributor license agreements. See the NOTICE file distributed with 2017-11-18 19:22:49.194
- 6892 +0800 CST <nil>}
- msg: &{# this work for additional information regarding copyright ownership. 2017-11-18 19:22:49.20869
- 92 +0800 CST <nil>}
- 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 <nil>}
- 。。。。。。省略
我们看看源码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 }