ファイル出力とローテーション
DD は柔軟なファイル出力機能を提供し、自動ローテーション、バッファ書き込み、マルチ出力先ディスパッチをサポートし、本番環境での使用に適しています。
クイックスタート
基本的なファイル出力
go
package main
import (
"log"
"github.com/cybergodev/dd"
)
func main() {
logger, err := dd.New(dd.Config{
Targets: []dd.OutputTarget{
dd.FileOutput("logs/app.log"),
},
})
if err != nil {
log.Fatal(err)
}
defer logger.Close()
logger.Info("ログがファイルに書き込まれます") // 出力:logs/app.log に書き込まれる
}コンソール + ファイル デュアル出力
go
logger, err := dd.New(dd.Config{
Targets: []dd.OutputTarget{
dd.ConsoleOutput(),
dd.FileOutput("logs/app.log"),
},
})
if err != nil {
log.Fatal(err)
}
defer logger.Close()FileWriter ローテーション設定
FileWriter はサイズによる自動ローテーションと、時間による古いファイルのクリーンアップをサポートします:
デフォルト設定
go
cfg := dd.DefaultFileWriterConfig()
// MaxSizeMB: 100 — 単一ファイルの最大 100MB
// MaxAge: 30 * 24 * time.Hour — 30 日間保持
// MaxBackups: 10 — 最大 10 バックアップ保持
// Compress: false — 圧縮なしカスタムローテーションポリシー
go
// 高トラフィックサービス:小さいファイル、高速ローテーション
fwCfg := dd.DefaultFileWriterConfig()
fwCfg.MaxSizeMB = 50 // 50MB でローテーション
fwCfg.MaxBackups = 20 // 20 バックアップ保持
fwCfg.MaxAge = 7 * 24 * time.Hour // 7 日でクリーンアップ
fwCfg.Compress = true // 古いファイルを圧縮
fw, err := dd.NewFileWriter("logs/app.log", fwCfg)
if err != nil {
log.Fatal(err)
}
logger, err := dd.New(dd.Config{
Targets: []dd.OutputTarget{dd.CustomOutput(fw)},
})
if err != nil {
log.Fatal(err)
}
defer logger.Close()JSON フォーマットのログファイル
go
logger, err := dd.New(dd.Config{
Format: dd.FormatJSON,
Targets: []dd.OutputTarget{
dd.FileOutput("logs/app.json"),
},
})
if err != nil {
log.Fatal(err)
}
defer logger.Close()ローテーション後のファイル命名規則:
text
logs/app.log ← 現在のログ
logs/app_log_1.log ← 1 回目のローテーション(最新のバックアップ)
logs/app_log_2.log ← さらに古いバックアップ
logs/app_log_1.log.gz ← Compress 有効時に古いバックアップが .gz に圧縮される圧縮とバックアップは共存しない
Compress を有効にすると、圧縮はローテーション後に別の goroutine で非同期に行われます;圧縮完了時に元の .log バックアップは .log.gz にリネームされ、両者は共存しません。
BufferedWriter バッファ書き込み
高スループット環境では、BufferedWriter を使用して I/O 回数を削減:
go
// ファイル Writer を作成
fw, err := dd.NewFileWriter("logs/app.log", dd.DefaultFileWriterConfig())
if err != nil {
log.Fatal(err)
}
// バッファ Writer でラップ
bwCfg := dd.DefaultBufferedWriterConfig()
// BufferSize: 1024 — 1KB バッファ
// FlushTime: 100ms — 100ms 自動フラッシュ
bw, err := dd.NewBufferedWriter(fw, bwCfg)
if err != nil {
log.Fatal(err)
}
logger, err := dd.New(dd.Config{
Targets: []dd.OutputTarget{dd.CustomOutput(bw)},
})
if err != nil {
log.Fatal(err)
}
defer logger.Close() // Close 時に自動 Flushチューニングのヒント
| シナリオ | BufferSize | FlushTime | 説明 |
|---|---|---|---|
| 低遅延要件 | 512 | 50ms | 高速フラッシュ、遅延を削減 |
| 汎用シナリオ | 1024 | 100ms | デフォルト値、遅延とスループットのバランス |
| 高スループット | 4096 | 500ms | 大きなバッファ、スループットを最大化 |
| バッチ処理タスク | 8192 | 1000ms | 最大バッファ、オフライン処理に適している |
データ安全性
BufferedWriter はバッファが半分満たされた(BufferSize/2 に到達)またはタイマーが発動したときにフラッシュします。プログラムの異常終了時、バッファ内のデータが失われる可能性があります。データの完全性を確保するために Close() または Flush() を確実に呼び出してください。
MultiWriter マルチ出力先ディスパッチ
go
// ファイルとリモートサービスに同時書き込み
fw, err := dd.NewFileWriter("logs/app.log", dd.DefaultFileWriterConfig())
if err != nil {
log.Fatal(err)
}
remote := &RemoteLogWriter{endpoint: "http://log-service/ingest"}
mw := dd.NewMultiWriter(fw, remote)
logger, err := dd.New(dd.Config{
Targets: []dd.OutputTarget{dd.CustomOutput(mw)},
})
if err != nil {
log.Fatal(err)
}
defer logger.Close()MultiWriter は全ての Writer にログをディスパッチし、ある Writer の失敗が他の Writer に影響することはありません。
動的 Writer 管理
Logger は実行時の Writer の追加と削除をサポートします:
go
// 実行時に Writer を追加
fw, err := dd.NewFileWriter("logs/debug.log", dd.DefaultFileWriterConfig())
if err != nil {
log.Fatal(err)
}
err = logger.AddWriter(fw)
// 実行時に Writer を削除
err = logger.RemoveWriter(fw)
// 現在の Writer 数を確認
count := logger.WriterCount()
_ = count使用シナリオ
動的 Writer は、実行時にログ出力先を切り替える必要があるシナリオに適しています。例:デバッグモード時に詳細ログファイルを追加、ディスク容量不足時にリモートログサービスに切り替えなど。
カスタム Writer
io.Writer インターフェースを実装するだけで、カスタム出力先を作成できます:
go
// ネットワークログ送信器
type LogstashWriter struct {
endpoint string
client *http.Client
}
func (w *LogstashWriter) Write(p []byte) (n int, err error) {
resp, err := w.client.Post(w.endpoint, "application/json", bytes.NewReader(p))
if err != nil {
return 0, err
}
defer resp.Body.Close()
return len(p), nil
}
// カスタム Writer を使用
logger, err := dd.New(dd.Config{
Format: dd.FormatJSON,
Targets: []dd.OutputTarget{
dd.FileOutput("logs/app.json"),
dd.CustomOutput(&LogstashWriter{
endpoint: "http://logstash:5044",
client: &http.Client{Timeout: 5 * time.Second},
}),
},
})
if err != nil {
log.Fatal(err)
}
defer logger.Close()本番環境推奨設定
go
func NewProductionLogger() (*dd.Logger, error) {
// ファイル Writer:中規模ローテーション + 圧縮
fwCfg := dd.DefaultFileWriterConfig()
fwCfg.MaxSizeMB = 100
fwCfg.MaxAge = 30 * 24 * time.Hour
fwCfg.MaxBackups = 15
fwCfg.Compress = true
fw, err := dd.NewFileWriter("logs/app.json", fwCfg)
if err != nil {
return nil, err
}
// バッファラッパー
bw, err := dd.NewBufferedWriter(fw, dd.DefaultBufferedWriterConfig())
if err != nil {
return nil, err
}
return dd.New(dd.Config{
Level: dd.LevelInfo,
Format: dd.FormatJSON,
Targets: []dd.OutputTarget{
dd.ConsoleOutput(),
dd.CustomOutput(bw),
},
})
}次のステップ
- 構造化ログ -- フィールドとチェーン呼び出し
- 機密データフィルタリング -- 自動マスキング
- API リファレンス - Writers -- Writer 完全 API
- パフォーマンス最適化 -- パフォーマンスチューニングのヒント