Golang日志如何实现异步写入

在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.WaitGroupwg)以及一个用于通知写入器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方法关闭日志记录器。