package process import ( "os" "path/filepath" "sync" ) // rotatingFile appends to a log file and rotates it once it exceeds maxSize. type rotatingFile struct { mu sync.Mutex path string maxSize int64 f *os.File size int64 } func newRotatingFile(path string, maxSize int64) (*rotatingFile, error) { if maxSize <= 0 { maxSize = 10 * 1024 * 1024 } if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { return nil, err } f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644) if err != nil { return nil, err } info, err := f.Stat() if err != nil { _ = f.Close() return nil, err } return &rotatingFile{path: path, maxSize: maxSize, f: f, size: info.Size()}, nil } func (r *rotatingFile) Write(p []byte) (int, error) { r.mu.Lock() defer r.mu.Unlock() if r.f == nil { f, err := os.OpenFile(r.path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644) if err != nil { return 0, err } r.f = f } if r.size > 0 && r.size+int64(len(p)) > r.maxSize { _ = r.f.Close() _ = os.Rename(r.path, r.path+".1") f, err := os.OpenFile(r.path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644) if err != nil { r.f = nil return 0, err } r.f = f r.size = 0 } n, err := r.f.Write(p) r.size += int64(n) return n, err } func (r *rotatingFile) Close() error { r.mu.Lock() defer r.mu.Unlock() if r.f != nil { err := r.f.Close() r.f = nil return err } return nil }