いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-396 (tail -f のような挙動をしたい)(github.com/nxadm/tail)

関連記事

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。忘れないうちにメモメモ。。。

諸事情により、Goで tail -f のような動きを作る必要がありましたので、ライブラリを探しました。

以下を発見。

github.com

欲しい機能がシンプルに実現出来たので、忘れないうちに使い方をここにメモメモ。。。

サンプル

package tail

import (
    "context"
    "io"
    "log"
    "os"
    "time"

    tailpkg "github.com/nxadm/tail"
    "golang.org/x/sync/errgroup"
)

// TailFile は、github.com/nxadm/tail のサンプルです。
//
// # REFERENCES
//
//   - https://github.com/nxadm/tail
func TailFile() error {
    const (
        FILE_PATH = "messages.log"
    )

    log.SetFlags(0)

    //
    // 対象となるファイルを作成
    //
    var (
        file *os.File
        err  error
    )

    file, err = os.Create(FILE_PATH)
    if err != nil {
        return err
    }
    defer file.Close()

    //
    // 1秒ごとにデータを書き込み
    //
    var (
        rootCtx            = context.Background()
        mainCtx, mainCxl   = context.WithCancel(rootCtx)
        writeCtx, writeCxl = context.WithTimeout(mainCtx, 5300*time.Millisecond)
        g, gCtx            = errgroup.WithContext(mainCtx)
    )
    defer mainCxl()
    defer writeCxl()

    g.Go(func() error {
        for {
            select {
            case <-writeCtx.Done():
                return nil
            case <-gCtx.Done():
                return nil
            case t := <-time.After(1 * time.Second):
                _, err = file.WriteString(t.Format(time.TimeOnly) + " helloworld\n")
                if err != nil {
                    return err
                }
            }
        }
    })

    //
    // ファイルをtailする
    //
    var (
        lines = make(chan *tailpkg.Line, 128)
        t     *tailpkg.Tail
        c     = tailpkg.Config{
            Location: &tailpkg.SeekInfo{
                Offset: 0,
                Whence: io.SeekEnd,
            },
            Follow: true,
            ReOpen: true,
        }
    )

    t, err = tailpkg.TailFile(FILE_PATH, c)
    if err != nil {
        return err
    }

    g.Go(func() error {
        stop := func() error {
            if err := t.Stop(); err != nil {
                return err
            }

            return nil
        }

        for {
            select {
            case <-writeCtx.Done():
                return stop()
            case <-gCtx.Done():
                return stop()
            case line, ok := <-t.Lines:
                if !ok {
                    return nil
                }

                lines <- line
            }
        }
    })

    // 出力
LOOP:
    for {
        select {
        case <-t.Dead():
            break LOOP
        case line, ok := <-lines:
            if !ok {
                break LOOP
            }

            log.Printf("[tail] %s", line.Text)
        }
    }

    err = g.Wait()
    if err != nil {
        return err
    }

    return nil
}

実行すると以下のようになります。

$ task run
task: [run] go run . -onetime

ENTER EXAMPLE NAME: tail_tailfile

[Name] "tail_tailfile"
[tail] 08:00:27 helloworld
[tail] 08:00:28 helloworld
[tail] 08:00:29 helloworld
[tail] 08:00:30 helloworld
[tail] 08:00:31 helloworld


[Elapsed] 5.301043068s

try-golang-extlib/examples/tail at main · devlights/try-golang-extlib · GitHub

参考情報

Goのおすすめ書籍


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。