在Golang中,實現異步日志寫入可以通過使用goroutine和channel來實現。下面是一個簡單的示例,展示了如何創建一個異步日志記錄器:
package main
import (
"fmt"
"os"
"sync"
"time"
)
type LogEntry struct {
Timestamp time.Time
Message string
}
type AsyncLogger struct {
logChan chan LogEntry
wg sync.WaitGroup
done chan bool
}
func NewAsyncLogger(bufferSize int) *AsyncLogger {
logger := &AsyncLogger{
logChan: make(chan LogEntry, bufferSize),
done: make(chan bool),
}
logger.wg.Add(1)
go logger.writer()
return logger
}
func (l *AsyncLogger) writer() {
defer l.wg.Done()
for {
select {
case entry := <-l.logChan:
file, err := os.OpenFile("async_log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("Error opening log file:", err)
continue
}
fmt.Fprintf(file, "%s - %s\n", entry.Timestamp.Format(time.RFC3339), entry.Message)
file.Close()
case <-l.done:
return
}
}
}
func (l *AsyncLogger) Log(message string) {
entry := LogEntry{
Timestamp: time.Now(),
Message: message,
}
l.logChan <- entry
}
func (l *AsyncLogger) Close() {
close(l.done)
l.wg.Wait()
}
func main() {
logger := NewAsyncLogger(100)
go func() {
for i := 0; i < 10; i++ {
logger.Log("Log entry #" + fmt.Sprintf("%d", i))
time.Sleep(1 * time.Second)
}
}()
time.Sleep(15 * time.Second)
logger.Close()
}
在這個示例中,我們創建了一個名為AsyncLogger
的結構體,它包含一個用于存儲日志條目的channel(logChan
),一個sync.WaitGroup
(wg
)以及一個用于通知寫入器goroutine退出的channel(done
)。
NewAsyncLogger
函數接收一個參數bufferSize
,用于設置logChan
的緩沖區大小。然后,它創建一個新的AsyncLogger
實例,并啟動一個名為writer
的goroutine,該goroutine負責將日志條目寫入文件。
Log
方法用于向logChan
發送新的日志條目。當調用此方法時,它將創建一個新的LogEntry
實例,并將其發送到logChan
。
Close
方法用于關閉done
channel并等待writer
goroutine完成。在程序結束時,應調用此方法以確保所有日志條目都已正確寫入文件。
在main
函數中,我們創建了一個AsyncLogger
實例,并啟動了一個goroutine,該goroutine每隔1秒記錄一條日志。然后,我們讓主goroutine等待15秒,以確保所有日志條目都已記錄。最后,我們調用Close
方法關閉日志記錄器。