在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方法关闭日志记录器。