温馨提示×

Golang日志如何实现异步写入

小樊
49
2025-08-16 10:03:21
栏目: 编程语言

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

0