Raspbian「stretch」上にGO言語をインストール」でGo言語をインストールしましたが、今回は定周期タイマーを持つアプリをGo言語で作成し、動作状態をログとして保存します。アプリはWindows10上のVisual Studio Codeで開発し、Raspberry Pi上で動作させます。

開発環境

  • Raspbian:buster
  • go言語のバージョン:go1.13.4
  • コーディング環境:Visual Studio Code 1.44.2

Go言語パッケージのインストール

次のコマンドでログ用のパッケージ「rotatelogs」「logf」をインストールします。

$ go get github.com/lestrrat-go/file-rotatelogs
$ go get github.com/spiegel-im-spiegel/logf

パッケージ「rotatelogs」

ログファイルの分割とローテーション機能を持つパッケージで、ログを作成するときに次のようにパラメータを与えることができます。3行目でログ出力ファイル先、4行目でログファイルの切り替えタイミング、この場合1時間ごとを示します。詳細については「lestrrat-go/file-rotatelogs」に示します。

 
// Rotate every hour
  rotatelogs.New(
    "/var/log/myapp/log.%Y%m%d",
    rotatelogs.WithRotationTime(time.Hour),
  )

パッケージ「logf 」

ログメッセージ毎に 次のような出力レベルの設定を行い,あらかじめ指定したレベル以下のメッセージについては、フィルタリングできるパッケージで、詳細については「spiegel-im-spiegel/logf」に示します。

  • logf.SetMinLevel()  ← ログレベルの設定
  • logf.Tracef()
  • logf.Debugf()
  • logf.Printf()
  • logf.Warnf()
  • logf.Errorf()
  • logf.Fatalf()

アプリの作成

作業フォルダ「gotimer」に次に示す「timermain.go」「timerlib.go」「loglib.go」を作成します。

  1. package名は「main」固定とします。これにより、別ファイルの変数も参照可能となります。最初の文字が大文字で始まる変数、関数等は、外部パッケージ(package名が異なる)から参照可能になります。
  2. package名「main」の関数名「main」がメインルーチンとなります。メインルーチンの前には初期化ルーチン「init」が最初に一度だけ実行されます。
  3. アプリは、メインルーチンからゴルーチン「ticker」を起動し、ゴルーチン「ticker」からチャンネル「timerch」を使用して現在時刻をメインルーチンに通知します。

メインルーチン「main」と初期化ルーチン「init」を次に示します。

  • 10行目でログ機能を初期化します。4行目のように、importにログパッケージ「logf」を記述すれば、ログを取ることができます。
  • 7行目でチャンネル「timerch」を作成し、15行目でゴルーチン「ticker」を起動し、19行目でゴルーチン「ticker」からチャンネル「timerch」を受け取り、その内容をロギングします。

timermain.go

package main

import (
	"github.com/spiegel-im-spiegel/logf"
)

var timerch = make(chan string)

func init() {
	loglib()
	logf.Print("************** Start Vital App *******") // this will not print
}

func main() {
	go ticker()

	for {
		select {
		case time := <-timerch:
			logf.Printf(time)
		}
	}
	logf.Printf("Exit")
}

1秒周期の tickerを作成する「ticker」を次に示します。

  • 10行目で1秒周期の tickerを作成します。
  • 11行目のdeferキーワードで作成したtickerを関数終了時に実行します。
  • 13行目でループ状態にして、15行目で1秒のイベントを検出すると、17行目でチャンネル「timerch」を発生します。

timerlib.go

package main

import (
	"time"

	"github.com/spiegel-im-spiegel/logf"
)

func ticker() {
	t := time.NewTicker(1 * time.Second) //1秒周期の ticker
	defer t.Stop()

	for {
		select {
		case now := <-t.C:
			logf.Printf(now.Format(time.RFC3339))
			timerch <- now.Format(time.RFC3339)
		}
	}
}

ログ機能を設定する「loglib」を次に示します。

  • 20行目で、golangでlogを標準出力とテキストファイルの2箇所の出力するために、io.MultiWriterを使用します。

loglib.go

package main

import (
	"io"
	"os"

	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/spiegel-im-spiegel/logf"
)

var logpoint = 0

func loglib() {
	logf.SetMinLevel(logf.DEBUG)
	rl, err := rotatelogs.New("log/log.%Y%m%d%H%M.txt")
	if err != nil {
		logf.Fatal(err)
		return
	}
	ws := io.MultiWriter(
		rl,
		os.Stdout,
	)

	logf.SetOutput(ws)

}

アプリの実行

次のコマンドで作成したアプリをコンパイルして実行します。1秒ごとにtickerタイマーが起動し、チャンネル「timerch」を使用して現在時刻が送られていることが確認できます。

$ go build
$ ./gotimer
2020/05/07 17:18:21 [INFO] ************** Start Vital App *******
2020/05/07 17:18:22 [INFO] 2020-05-07T17:18:22+09:00
2020/05/07 17:18:22 [INFO] 2020-05-07T17:18:22+09:00
2020/05/07 17:18:23 [INFO] 2020-05-07T17:18:23+09:00
2020/05/07 17:18:23 [INFO] 2020-05-07T17:18:23+09:00
2020/05/07 17:18:24 [INFO] 2020-05-07T17:18:24+09:00
2020/05/07 17:18:24 [INFO] 2020-05-07T17:18:24+09:00
2020/05/07 17:18:25 [INFO] 2020-05-07T17:18:25+09:00
2020/05/07 17:18:25 [INFO] 2020-05-07T17:18:25+09:00
2020/05/07 17:18:26 [INFO] 2020-05-07T17:18:26+09:00
2020/05/07 17:18:26 [INFO] 2020-05-07T17:18:26+09:00

フォルダ「log」のファイル「log.202005070000.txt」に上記と同様なログが保存されます。