mirror of https://github.com/nealey/spongy
106 lines
1.9 KiB
Go
106 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"log"
|
|
"path"
|
|
"time"
|
|
)
|
|
|
|
type Logfile struct {
|
|
baseDir string
|
|
file *os.File
|
|
name string
|
|
nlines int
|
|
maxlines int
|
|
outq chan string
|
|
}
|
|
|
|
func timestamp(s string) string {
|
|
ret := fmt.Sprintf("%d %s", time.Now().Unix(), s)
|
|
return ret
|
|
}
|
|
|
|
func NewLogfile(baseDir string, maxlines int) (*Logfile) {
|
|
lf := Logfile{baseDir, nil, "", 0, maxlines, make(chan string, 50)}
|
|
go lf.processQueue();
|
|
return &lf
|
|
}
|
|
|
|
func (lf *Logfile) Close() {
|
|
if lf.file != nil {
|
|
lf.Log("EXIT")
|
|
close(lf.outq)
|
|
}
|
|
}
|
|
|
|
func (lf *Logfile) Log(s string) error {
|
|
lf.outq <- timestamp(s)
|
|
return nil
|
|
}
|
|
|
|
//
|
|
//
|
|
|
|
func (lf *Logfile) processQueue() {
|
|
for line := range lf.outq {
|
|
if (lf.file == nil) || (lf.nlines >= lf.maxlines) {
|
|
if err := lf.rotate(); err != nil {
|
|
// Just keep trying, I guess.
|
|
log.Print(err)
|
|
continue
|
|
}
|
|
lf.nlines = 0
|
|
}
|
|
|
|
if _, err := fmt.Fprintln(lf.file, line); err != nil {
|
|
log.Print(err)
|
|
continue
|
|
}
|
|
lf.nlines += 1
|
|
}
|
|
|
|
lf.file.Close()
|
|
}
|
|
|
|
func (lf *Logfile) rotate() error {
|
|
fn := fmt.Sprintf("%s.log", time.Now().UTC().Format(time.RFC3339))
|
|
pathn := path.Join(lf.baseDir, "log", fn)
|
|
newf, err := os.OpenFile(pathn, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
currentPath := path.Join(lf.baseDir, "log", "current")
|
|
|
|
if lf.file == nil {
|
|
// Open "current" to append a NEXTLOG line.
|
|
// If there's no "current", that's okay
|
|
lf.file, _ = os.OpenFile(currentPath, os.O_WRONLY|os.O_APPEND, 0666)
|
|
}
|
|
|
|
if lf.file != nil {
|
|
// Note location of new log
|
|
logmsg := fmt.Sprintf("NEXTLOG %s", fn)
|
|
fmt.Fprintln(lf.file, timestamp(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(currentPath)
|
|
os.Symlink(fn, currentPath)
|
|
|
|
logmsg := fmt.Sprintf("PREVLOG %s", lf.name)
|
|
fmt.Fprintln(lf.file, timestamp(logmsg))
|
|
|
|
lf.name = fn
|
|
|
|
return nil
|
|
}
|