Example #1
0
// lineのNotifyType別に処理を分岐
func (f *Ftail) lineNotifyAction(ctx context.Context, line *tail.Line, w chan bool) error {
	var err error

	if line.NotifyType == tail.NewLineNotify { // 新しいライン
		if err = f.Write(line); err != nil {
			return err
		}
		if f.buf.Len() < f.MaxBufSize {
			return err
		}
		w <- true
		defer func() { <-w }()
		return f.Flush()
	}
	w <- true
	defer func() { <-w }()
	switch line.NotifyType {
	case tail.TickerNotify, tailex.GlobLoopNotify: // 定期flush処理
		if err := f.Flush(); err != nil {
			return err
		}
		timeSlice := tailex.Truncate(line.Time, f.Period)
		if f.lastSlice.Sub(timeSlice) < 0 {
			// 新しいDBを開く
			if _, err = f.rec.CreateDB(timeSlice, f.Pos); err != nil {
				log.Printf("CreateDB err:%s", err)
				return err
			}
			f.lastSlice = timeSlice
		}
		// 古いDBを閉じる
		if _, cerr := f.rec.CloseOldDbs(line.Time); cerr != nil {
			log.Printf("CloseOldDbs err:%s", cerr)
			return cerr
		}
	case tail.NewFileNotify:
		f.lastTime = line.Time
		f.Pos.Name = line.Filename
		f.Pos.CreateAt = line.OpenTime
		f.Pos.Offset = line.Offset
		maxsize := line.Offset
		if f.MaxHeadHashSize < line.Offset {
			maxsize = f.MaxHeadHashSize
		}
		f.Pos.HeadHash, f.Pos.HashLength, err = f.getHeadHash(f.Pos.Name, maxsize)
		if err != nil {
			log.Printf("getHeadHash err:%s", err)
			return err
		}
		log.Printf("NewFileNotify getHeadHash :%s", f.Pos)
	}
	return nil
}
Example #2
0
// ポジション情報がない場合に実ファイルから取得
func (f *Ftail) position(c Config) (pos *core.Position, err error) {
	var fi os.FileInfo
	var filePath string
	if c.PathFmt != "" { // cronolog
		timeSlice := tailex.Truncate(c.Config.Time, c.RotatePeriod)
		searchPath := tailex.Time2Path(c.PathFmt, timeSlice)
		filePath, err = tailex.GlobSearch(searchPath)
		if err == tailex.ErrNoSuchFile {
			log.Printf("ftail position() GlobSearch(%s)  err: %s", searchPath, err)
			return &core.Position{}, nil
		} else if err != nil {
			log.Printf("ftail position() GlobSearch(%s)  err: %s", searchPath, err)
			return nil, err
		}
	} else {
		filePath, err = tailex.GlobSearch(c.Path)
		if err == tailex.ErrNoSuchFile {
			log.Printf("ftail position() GlobSearch(%s)  err: %s", c.Path, err)
			return &core.Position{}, nil
		} else if err != nil {
			log.Printf("ftail position() GlobSearch(%s)  err: %s", c.Path, err)
			return nil, err
		}
	}
	if fi, err = os.Stat(filePath); err != nil {
		log.Printf("Start os.Stat('%s')  err: %s,  ", filePath, err)
		return nil, err
	}
	offset := int64(0)
	// 現在のファイルサイズがf.MaxHeadHashSizeより大きいものだけオフセットを現在のサイズにする。
	if (!c.Config.NoSeek) && (fi.Size() > f.MaxHeadHashSize) {
		offset = fi.Size()
	}
	pos = &core.Position{
		Name:     filePath,
		CreateAt: fi.ModTime(),
		Offset:   offset,
	}
	return
}
Example #3
0
func Start(ctx context.Context, c Config, w chan bool) error {
	w <- true
	f := &Ftail{
		Config:   c,
		headHash: fnv.New64(),
		head:     []byte{},
	}
	//if f.MaxHeadHashSize == 0 {
	//	f.MaxHeadHashSize = defaultMaxHeadHashSize
	//}
	var err error
	f.rec, err = core.NewRecorder(c.BufDir, c.Name, c.Period)
	if err != nil {
		log.Fatalln("NewRecorder err:", err)
	}
	defer f.rec.AllClose()

	f.Pos = f.rec.Position()
	if f.Pos == nil {
		if f.Pos, err = f.position(c); err != nil {
			log.Fatalln("position err:", err)
		}
	}
	f.Config.Config.Config = tailDefaultConfig
	f.ReOpenDelay = 5 * time.Second
	if f.Delay != 0 {
		f.ReOpenDelay = f.Delay
	}
	log.Printf("f.Pos: %s", f.Pos)

	if f.MaxHeadHashSize != 0 && f.Pos.Name != "" {
		oldhead := f.head
		hash, length, hherr := f.getHeadHash(f.Pos.Name, f.Pos.HashLength)
		if hherr != nil {
			log.Printf("getHeadHash err:%s", hherr)
		} else {
			if f.Pos.HeadHash == hash && f.Pos.HashLength == length { // ポジションファイルのハッシュ値と一致した場合はSeekInfoをセット
				log.Printf("match headHash: %s, head:%s", f.Pos, f.head)
				f.Location = &tail.SeekInfo{Offset: f.Pos.Offset}
			} else {
				log.Printf("not match headHash old: %s, head:%s", f.Pos, oldhead)
				f.Pos.HeadHash = hash
				f.Pos.HashLength = length
				log.Printf("not match headHash new: %s, head:%s", f.Pos, f.head)
			}
		}
	} else {
		posTimeSlise := tailex.Truncate(f.Pos.CreateAt, c.RotatePeriod)
		nowTimeSlise := tailex.Truncate(time.Now(), c.RotatePeriod)
		if nowTimeSlise.Equal(posTimeSlise) { // 読み込んだポジションのcreateAtが現在のtimesliseと同じ場合
			f.Location = &tail.SeekInfo{Offset: f.Pos.Offset}
		}
	}
	t := tailex.NewTailEx(ctx, f.Config.Config, w)
	//var buf bytes.Buffer
	f.buf = bytes.Buffer{}
	/*
		f.Writer, err = zlib.NewWriterLevel(&f.buf, zlib.BestCompression)
		if err != nil {
			log.Fatalln("NewZlibWriter err:", err)
		}
	*/
	<-w
	f.Writer = NopCloser(&f.buf)
	defer func() {
		if err := f.Flush(); err != nil {
			log.Printf("f.Flush err:%s", err)
		}
	}()

	for {
		select {
		case <-ctx.Done(): // キャンセル処理
			return ctx.Err()
		case line, ok := <-t.Lines: // 新しい入力行の取得
			if !ok {
				return err
			}
			err := f.lineNotifyAction(ctx, line, w)
			if err != nil {
				return err
			}
		}

	}

}