リモートサーバーで実行されるWebアプリケーションを作成しようとしています。エラー/デバッグ/監査をキャプチャするためにログを記録する必要があります。標準の「log」パッケージを含む複数のロギングパッケージがgolangで利用できることがわかりました。ただし、次の3つの要件を満たす必要があります。
基本レベルのlog.Logを使用して満足した場合、代わりのロガー構造を作成する代わりに3つの要件をすべて満たす最良の方法は、代わりにロガーの出力を独自のio.Writerインスタンスに設定することです。
したがって、基本的にここで行うことは、独自のio.Writerを作成する例を示します。
import (
"os"
"sync"
"time"
)
type RotateWriter struct {
lock sync.Mutex
filename string // should be set to the actual filename
fp *os.File
}
// Make a new RotateWriter. Return nil if error occurs during setup.
func New(filename string) *RotateWriter {
w := &RotateWriter{filename: filename}
err := w.Rotate()
if err != nil {
return nil
}
return w
}
// Write satisfies the io.Writer interface.
func (w *RotateWriter) Write(output []byte) (int, error) {
w.lock.Lock()
defer w.lock.Unlock()
return w.fp.Write(output)
}
// Perform the actual act of rotating and reopening file.
func (w *RotateWriter) Rotate() (err error) {
w.lock.Lock()
defer w.lock.Unlock()
// Close existing file if open
if w.fp != nil {
err = w.fp.Close()
w.fp = nil
if err != nil {
return
}
}
// Rename dest file if it already exists
_, err = os.Stat(w.filename)
if err == nil {
err = os.Rename(w.filename, w.filename+"."+time.Now().Format(time.RFC3339))
if err != nil {
return
}
}
// Create a file.
w.fp, err = os.Create(w.filename)
return
}
次に、RotateWriterを作成し、log.SetOutput
を使用してこのライターを設定するか(他のパッケージが標準ロガーインスタンスを使用している場合)、代わりにlog.New
を使用して独自のインスタンスを作成します。
Rotateをいつ呼び出すかという状況は解決していませんが、決定するのはあなたに任せます。時間に基づいてトリガーするのは非常に簡単です。あるいは、一定量の書き込みまたは一定量のバイトの後にトリガーすることもできます。
@Crastは非常に良い答えを出しましたが、私も通知にしたい- lumberjack logger by Nateフィンチ を使用しました。
使用方法は次のとおりです。
go install
コマンドはフォルダーに対して。インポート( "log" "github.com/natefinch/lumberjack")
Mainの外部で、ログ変数を宣言します。
var errLog *log.Logger
メイン内:
e, err := os.OpenFile("./foo.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Printf("error opening file: %v", err)
os.Exit(1)
}
errLog = log.New(e, "", log.Ldate|log.Ltime)
errLog.SetOutput(&lumberjack.Logger{
Filename: "./foo.log",
MaxSize: 1, // megabytes after which new file is created
MaxBackups: 3, // number of backups
MaxAge: 28, //days
})
これで、ファイルサイズが1MBになるとすぐに、新しいファイルが作成され、前のログを現在のタイムスタンプで保持し、新しいログはfoo.logファイルにログインし続けます。また、私はos.OpenFileを使用してファイルを作成しましたが、lumberjackが内部的に行うので、必要ないかもしれませんが、そのようにしたほうが好ましいです。おかげで、それが役立つことを願っています。もう一度@Crastと NateFinch に感謝します。
以下は、ログのローテーションと自動パージをサポートする軽量のロギングパッケージです。
https://github.com/antigloss/go/tree/master/logger
// logger.Init must be called first to setup logger
logger.Init("./log", // specify the directory to save the logfiles
400, // maximum logfiles allowed under the specified log directory
20, // number of logfiles to delete when number of logfiles exceeds the configured limit
100, // maximum size of a logfile in MB
false) // whether logs with Trace level are written down
logger.Info("Failed to find player! uid=%d plid=%d cmd=%s xxx=%d", 1234, 678942, "getplayer", 102020101)
logger.Warn("Failed to parse protocol! uid=%d plid=%d cmd=%s", 1234, 678942, "getplayer")
https://github.com/jame2981/log 私のパッケージが役立ちます。
l1 := log.Pool.New("l1", "file:///tmp/test1.log")
l2 := log.Pool.New("l2", "file:///tmp/test2.log")
l3 := log.Pool.New("l3", "file:///tmp/test3.log")
l4 := log.Pool.New("l4", "file:///tmp/test4.log")
l1.Rotate() // rotate l1 only
log.Pool.Rotate() // was rotate all instances.
// rotate with signal
reopen := make(chan os.Signal, 1)
signal.Notify(reopen, syscall.SIGUSR1)
go func() {
for{
<-reopen
l.Pool.Rotate()
}
}()
stdロガーライターを設定して、まだ作業を回転させます。
// std logger writer
import "log"
logger := log.New("test", "", 0)
logger.SetOutput(l1.Writer())
思い浮かぶ1つのオプションは、独自のタイプでロギングをラップし、次のようなリロード機能を提供することです。
_type Logger struct {
l *log.Logger
f *os.File
m sync.RWMutex
}
func NewLogger(fn string) (*Logger, error) {
f, err := os.Create(fn)
if err != nil {
return nil, err
}
l := &Logger{
l: log.New(f, "your-app", log.Lshortfile),
f: f,
}
return l, nil
}
func (l *Logger) Logf(f string, args ...interface{}) {
l.m.RLock()
l.l.Printf(f, args...)
l.m.RUnlock()
}
func (l *Logger) Reload() (err error) {
l.m.Lock()
defer l.m.Unlock()
l.f.Close()
if l.f, err = os.Create(l.f.Name()); err != nil {
return
}
l.l = log.New(l.f, "your-app", log.Lshortfile)
return
}
_
次に、信号(通常は* nixの_-HUP
_)をリッスンするか、Logger.Reload()
を呼び出すエンドポイントをアプリに追加します。