package logger import ( "fmt" "io" "sync" "sync/atomic" "time" ) // asyncBufferSize 异步写盘队列长度。队列满时丢弃日志,优先保护抢购链路。 const asyncBufferSize = 8192 // AsyncWriter 异步日志写入器,队列满时丢弃日志以保护主链路。 type AsyncWriter struct { mu sync.RWMutex dst io.Writer ch chan []byte wg sync.WaitGroup closed uint32 dropped uint64 } // NewAsyncWriter 创建异步日志写入器。 func NewAsyncWriter(dst io.Writer, buffer int) *AsyncWriter { if buffer <= 0 { buffer = 1024 } w := &AsyncWriter{ dst: dst, ch: make(chan []byte, buffer), } w.wg.Add(1) go w.run() return w } // Write 异步写日志;队列满时丢弃,避免抢购请求被磁盘 I/O 阻塞。 func (w *AsyncWriter) Write(p []byte) (int, error) { if w == nil { return len(p), nil } w.mu.RLock() defer w.mu.RUnlock() if atomic.LoadUint32(&w.closed) == 1 { return len(p), nil } buf := append([]byte(nil), p...) select { case w.ch <- buf: default: atomic.AddUint64(&w.dropped, 1) } return len(p), nil } // Dropped 返回因队列满被丢弃的日志条数。 func (w *AsyncWriter) Dropped() uint64 { if w == nil { return 0 } return atomic.LoadUint64(&w.dropped) } func (w *AsyncWriter) run() { defer w.wg.Done() for p := range w.ch { _, _ = w.dst.Write(p) } if dropped := atomic.LoadUint64(&w.dropped); dropped > 0 { notice := formatLogLine(Entry{ Time: time.Now().Format(entryTimeLayout), Level: LevelWarn, Category: "日志", Message: fmt.Sprintf("日志队列已丢弃 %d 条,已优先保护抢购链路", dropped), at: time.Now(), }) _, _ = w.dst.Write([]byte(notice)) } } // Close 关闭写入器,等待队列清空。 func (w *AsyncWriter) Close() error { if w == nil { return nil } w.mu.Lock() defer w.mu.Unlock() if atomic.CompareAndSwapUint32(&w.closed, 0, 1) { close(w.ch) w.wg.Wait() } return nil }