package logfile import ( "fmt" "os" "time" ) type Logfile struct { file *os.File name string nlines int maxlines int } func NewLogfile(maxlines int) (*Logfile) { return &Logfile{nil, "", 0, maxlines} } func (lf *Logfile) Close() { if lf.file != nil { lf.writeln("EXIT") lf.file.Close() } } func (lf *Logfile) writeln(s string) error { _, err := fmt.Fprintf(lf.file, "%d %s\n", time.Now().Unix(), s) if err == nil { lf.nlines += 1 } return err } func (lf *Logfile) rotate() error { fn := fmt.Sprintf("%s.log", time.Now().UTC().Format(time.RFC3339)) newf, err := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666) if err != nil { return err } if lf.file == nil { // Set lf.file just so we can write out NEXTLOG. // If this fails, that's okay lf.file, _ = os.OpenFile("current", os.O_WRONLY|os.O_APPEND, 0666) } if lf.file != nil { // Note location of new log logmsg := fmt.Sprintf(". NEXTLOG %s", fn) lf.writeln(logmsg) // All done with the current log lf.file.Close() } // Point to new log file lf.file = newf // Record symlink to new log os.Remove("current") os.Symlink(fn, "current") logmsg := fmt.Sprintf(". PREVLOG %s", lf.name) lf.writeln(logmsg) lf.name = fn return nil } func (lf *Logfile) Log(s string) error { if lf.file == nil { lf.rotate() } err := lf.writeln(s) if err == nil { return err } if lf.nlines >= lf.maxlines { return lf.rotate() } return nil }