package engine import ( "os" "path/filepath" "sync" ) // RingLog keeps last N log lines in memory and optionally writes to file. type RingLog struct { mu sync.Mutex lines []string max int file *os.File } // NewRingLog creates a ring buffer logger. func NewRingLog(maxLines int, dataDir string) *RingLog { rl := &RingLog{ lines: make([]string, 0, maxLines), max: maxLines, } if dataDir != "" { f, err := os.OpenFile(filepath.Join(dataDir, "vpnem.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644) if err == nil { rl.file = f } } return rl } // Add appends a line. func (rl *RingLog) Add(line string) { rl.mu.Lock() defer rl.mu.Unlock() if len(rl.lines) >= rl.max { rl.lines = rl.lines[1:] } rl.lines = append(rl.lines, line) if rl.file != nil { rl.file.WriteString(line + "\n") } } // Lines returns all current lines. func (rl *RingLog) Lines() []string { rl.mu.Lock() defer rl.mu.Unlock() cp := make([]string, len(rl.lines)) copy(cp, rl.lines) return cp } // Close closes the log file. func (rl *RingLog) Close() { if rl.file != nil { rl.file.Close() } }