logrotate

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 4, 2026 License: MIT Imports: 6 Imported by: 0

README

logrotate

phuslu/log 為基礎的輕量 logging 套件,提供:

  • 檔案輪替:單檔超過上限自動 rotate,並保留指定數量的舊檔。
  • 動態 UDP fan-out:在程式執行中隨時新增/移除 UDP 輸出目標,把 log 同時轉送到遠端收集器(log server、SIEM…)。
  • 非同步轉發:UDP 送出走背景 goroutine,網路 I/O 不會拖慢應用程式的 logging 路徑。
  • 無鎖讀路徑:fan-out 用 atomic.Pointer 快照 + copy-on-write,高頻寫 log 不碰 mutex。

import 後即可直接使用套件層級的 logrotate.Info() 等函式,無需自行建立 logger。

安裝

go get github.com/CanerHuang/logrotate

需求:Go 1.26+。

快速開始

不做任何設定就能用,預設會寫到當前目錄的 app.log:

package main

import "github.com/CanerHuang/logrotate"

func main() {
	defer logrotate.Close() // 程式結束前 flush 緩衝、關閉檔案與連線

	logrotate.Info().Str("module", "main").Msg("service started")
	logrotate.Warn().Int("retry", 3).Msg("downstream slow")
	logrotate.Error().Err(err).Msg("request failed")
}

寫 log 的鏈式 API 直接沿用 phuslu/log 的 *log.Entry,常用方法:StrIntBoolFloat64ErrMsgMsgf

自訂設定

DefaultConfig() 拿一份預設值,改你在意的欄位後傳給 Init()請在開始寫 log 之前呼叫(例如 main 的開頭):

cfg := logrotate.DefaultConfig()
cfg.Filename = "logs/myapp.log"
cfg.MaxSize = 50 << 20 // 50 MiB 輪替一次
cfg.MaxBackups = 10    // 保留 10 個舊檔
cfg.Level = log.InfoLevel

logrotate.Init(cfg)
defer logrotate.Close()
Config 欄位
欄位 型別 預設 說明
Filename string app.log 輸出檔名
MaxSize int64 1 << 20 (1 MiB) 單檔最大位元組,超過即輪替
MaxBackups int 7 保留的舊檔數量
LocalTime bool false 輪替檔名是否用本地時間(否則 UTC)
Level log.Level InfoLevel 最低輸出等級
EnsureFolder bool true 寫檔前自動建出上層目錄(0755)
ChannelSize uint 4096 UDP 非同步緩衝長度
DiscardOnFull bool true 緩衝滿時丟棄新 entry(false 則背壓等待)

Init() 中字串/數值欄位若為零值,會自動套回 DefaultConfig() 的對應預設值。

動態轉發到 UDP

在執行中把 log 同時送往遠端,支援 JSON 與純文字兩種格式,可隨時增減:

// 轉送 JSON(適合給 log server / 結構化收集器)
logrotate.AddJSONUDP("10.0.0.5:5140")

// 轉送純文字(格式與檔案一致:<time> <LEVEL> <message> key=value …)
logrotate.AddTextUDP("10.0.0.6:5141")

logrotate.Info().Str("ev", "login").Msg("user signed in") // 同時寫檔 + 送兩個 UDP

logrotate.Targets()              // => ["10.0.0.5:5140", "10.0.0.6:5141"]
logrotate.Remove("10.0.0.5:5140") // 移除單一目標

所有 UDP 目標共用一個 send-only socket,增減目標只動內部清單,不開關連線。以相同 addr 重複 Add 會直接覆蓋舊設定。

觀測轉發錯誤

單一 target 寫失敗不會中斷其他 target,預設靜默。需要觀測時設定 callback:

logrotate.SetOnError(func(key string, err error) {
	// 注意:此 callback 在背景寫 log 的 goroutine 上同步呼叫,
	// 不要在裡面再寫同一個 logger,以免遞迴。
	fmt.Fprintf(os.Stderr, "udp target %s failed: %v\n", key, err)
})

關閉

Close() 會先排空非同步緩衝(沖出仍在 channel 裡的 entry)、關閉 UDP 連線,再 flush/關閉檔案。建議 defer logrotate.Close()。Close 後若要再記錄,需重新 Init()

進階存取

需要更底層的物件時:

logrotate.Logger()  // *log.Logger,需要把 logger 傳進其他套件時用
logrotate.Default() // *DynamicWriter,需要更細的 target 操作時用

設計重點

  • 讀寫分離:WriteEntry(讀路徑)無鎖,用 atomic 快照載入目標清單;Add/Remove(寫路徑)用 copy-on-write,mutex 只序列化彼此,不擋寫 log。
  • 檔案 vs UDP 分流:檔案輸出是同步寫(Linux 上走 writev,夠快),底層 FileWriter 負責 size-cap 輪替;UDP fan-out 走 AsyncWriter 背景 goroutine。
  • 錯誤隔離:任一 target 寫失敗只透過 OnError 觀測,不向上拋、不影響其他 target。

License

MIT

Documentation

Overview

Package logrotate 提供以 phuslu/log 為基礎、可在執行中動態增減輸出目標的 log.Writer。讀路徑無鎖,寫路徑 copy-on-write。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddJSONUDP

func AddJSONUDP(addr string) error

func AddTextUDP

func AddTextUDP(addr string) error

func Close

func Close() error

Close 先排空非同步緩衝並關閉 UDP 連線,再 flush/關閉檔案。Close 後需重新 Init 才能再記錄。

func Debug

func Debug() *log.Entry

func Error

func Error() *log.Entry

func Fatal

func Fatal() *log.Entry

func Info

func Info() *log.Entry

func Init

func Init(c Config)

Init 以自訂設定重建預設 logger,請在開始寫 log 之前呼叫。 字串/數值欄位若為零值會自動套用 DefaultConfig() 的對應預設。

func Logger

func Logger() *log.Logger

Logger 回傳預設 logger。

func Panic

func Panic() *log.Entry

func Remove

func Remove(key string)

func SetOnError

func SetOnError(fn func(key string, err error))

SetOnError 設定預設 DynamicWriter 的錯誤觀測 callback。

func Targets

func Targets() []string

func Trace

func Trace() *log.Entry

func Warn

func Warn() *log.Entry

Types

type Config

type Config struct {
	Filename   string    // 輸出檔名
	MaxSize    int64     // 單檔最大位元組,超過即輪替
	MaxBackups int       // 保留的舊檔數量
	LocalTime  bool      // 輪替檔名是否用本地時間
	Level      log.Level // 最低輸出等級

	// EnsureFolder 為 true 時,寫檔前自動建出 Filename 的上層目錄(0755)。
	EnsureFolder bool

	// ChannelSize 是 UDP 非同步緩衝的長度。
	ChannelSize uint
	// DiscardOnFull 為 true 時緩衝滿就丟棄新 entry(永不阻塞);false 則背壓等待。
	DiscardOnFull bool
}

Config 設定預設 logger 的寫檔行為、等級,以及 UDP 非同步緩衝。

func DefaultConfig

func DefaultConfig() Config

DefaultConfig 回傳一份帶預設值的 Config,建議從這裡開始改你在意的欄位。

type DynamicWriter

type DynamicWriter struct {

	// OnError 在某個 target 寫入失敗時被呼叫(nil = 靜默)。會在寫 log 的
	// goroutine 上同步呼叫,不要在裡面再寫同一個 logger。
	OnError func(key string, err error)
	// contains filtered or unexported fields
}

DynamicWriter 是可在執行中動態增減目標的 log.Writer。

  • 讀路徑(WriteEntry)無鎖,用 atomic.Pointer 載入目標快照。
  • 寫路徑(Add/Remove)用 copy-on-write,mu 只序列化彼此,不擋讀。
  • 所有 UDP target 共用一個 send-only socket。
  • 單一 target 寫失敗不中斷其他 target,錯誤可選擇性丟給 OnError。

func Default

func Default() *DynamicWriter

Default 回傳預設的 DynamicWriter。

func NewDynamicWriter

func NewDynamicWriter() *DynamicWriter

func (*DynamicWriter) AddJSONUDP

func (d *DynamicWriter) AddJSONUDP(addr string) error

AddJSONUDP 新增一個輸出 JSON 的 UDP target。

func (*DynamicWriter) AddTextUDP

func (d *DynamicWriter) AddTextUDP(addr string) error

AddTextUDP 新增一個輸出純文字的 UDP target,格式與檔案一致(textFormatter)。

func (*DynamicWriter) Close

func (d *DynamicWriter) Close() error

Close 清空所有 target 並關閉共用 socket。

func (*DynamicWriter) Remove

func (d *DynamicWriter) Remove(key string)

Remove 移除指定 key 的 target。

func (*DynamicWriter) Targets

func (d *DynamicWriter) Targets() []string

Targets 回傳目前的 target keys(快照)。

func (*DynamicWriter) WriteEntry

func (d *DynamicWriter) WriteEntry(e *log.Entry) (n int, err error)

WriteEntry 實作 log.Writer,無鎖讀取快照後 fan-out。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL