- 减少I/O操作对性能的影响:
- 使用缓冲:
- 在Go中,可以使用
bufio.Writer
来缓冲日志数据。先将日志信息写入缓冲区,当缓冲区满或者达到一定条件(比如定时)时,再一次性将缓冲区的数据写入日志文件。例如:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, err := os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("Failed to open log file:", err)
return
}
defer file.Close()
writer := bufio.NewWriter(file)
for i := 0; i < 1000; i++ {
_, err = writer.WriteString(fmt.Sprintf("Log message %d\n", i))
if err != nil {
fmt.Println("Failed to write to buffer:", err)
return
}
// 可以根据需要设置缓冲区满时自动Flush,或者定时Flush
if i%100 == 0 {
err = writer.Flush()
if err != nil {
fmt.Println("Failed to flush buffer:", err)
return
}
}
}
// 确保最后缓冲区数据写入文件
err = writer.Flush()
if err != nil {
fmt.Println("Failed to flush buffer at end:", err)
return
}
}
- 异步写入:
- 使用Go的goroutine和channel实现异步日志写入。主线程将日志信息发送到channel,由专门的goroutine从channel中读取并写入日志文件。例如:
package main
import (
"fmt"
"os"
"sync"
)
func logWriter(ch <-chan string, wg *sync.WaitGroup) {
file, err := os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("Failed to open log file:", err)
return
}
defer file.Close()
defer wg.Done()
for msg := range ch {
_, err := file.WriteString(msg + "\n")
if err != nil {
fmt.Println("Failed to write to log file:", err)
}
}
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
logCh := make(chan string)
go logWriter(logCh, &wg)
for i := 0; i < 1000; i++ {
logCh <- fmt.Sprintf("Log message %d", i)
}
close(logCh)
wg.Wait()
}
- 保证日志记录的原子性和一致性:
- 使用互斥锁(Mutex):
- 当多个goroutine可能同时写入日志时,可以使用
sync.Mutex
来保证同一时间只有一个goroutine进行日志写入操作。例如:
package main
import (
"fmt"
"os"
"sync"
)
var (
mu sync.Mutex
file *os.File
err error
)
func init() {
file, err = os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("Failed to open log file:", err)
}
}
func logMessage(message string) {
mu.Lock()
defer mu.Unlock()
_, err := file.WriteString(message + "\n")
if err != nil {
fmt.Println("Failed to write to log file:", err)
}
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
logMessage(fmt.Sprintf("Goroutine %d log", id))
}(i)
}
wg.Wait()
file.Close()
}
- 使用原子操作(在特定场景):
- 如果日志记录涉及到一些简单的计数器等原子性操作,可以使用
atomic
包。例如记录日志的次数:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
var logCount uint64
func logMessage() {
atomic.AddUint64(&logCount, 1)
fmt.Printf("Log message. Count: %d\n", atomic.LoadUint64(&logCount))
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
logMessage()
}()
}
wg.Wait()
}
- 选择合适的日志库:
- zerolog:
- 是一个轻量级、高性能的日志库。它支持快速的日志记录,并且在高并发场景下性能表现良好。例如:
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"os"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout})
for i := 0; i < 10; i++ {
log.Info().Msgf("Log message %d", i)
}
}
- zap:
- 也是一个高性能的日志库,由Uber开发。它提供了不同级别的日志记录(如Debug, Info, Warn, Error等),并且支持各种编码器(如JSON编码器等)。例如:
package main
import (
"go.uber.org/zap"
)
func main() {
logger, err := zap.NewProduction()
if err != nil {
panic(err)
}
defer logger.Sync()
for i := 0; i < 10; i++ {
logger.Info("Log message", zap.Int("number", i))
}
}