open-nomad/client/driver/logs.go

149 lines
3.2 KiB
Go
Raw Normal View History

2016-01-14 01:16:25 +00:00
package driver
import (
"fmt"
"io"
"io/ioutil"
2016-01-15 07:16:30 +00:00
"log"
2016-01-14 01:16:25 +00:00
"os"
"path/filepath"
2016-01-17 03:19:52 +00:00
"sort"
2016-01-14 01:16:25 +00:00
"strconv"
"strings"
)
2016-01-15 07:16:30 +00:00
const (
2016-01-17 03:21:16 +00:00
bufSize = 32 * 1024 // Max number of bytes read from a buffer
2016-01-15 07:16:30 +00:00
)
2016-01-17 03:19:52 +00:00
// LogRotator rotates files for a buffer and retains only the last N rotated
// files
2016-01-14 01:16:25 +00:00
type LogRotator struct {
maxFiles int
fileSize int64
path string
fileName string
logFileIdx int
2016-01-15 07:16:30 +00:00
logger *log.Logger
2016-01-14 01:16:25 +00:00
}
2016-01-17 03:19:52 +00:00
// NewLogRotator configures and returns a new LogRotator
2016-01-15 19:18:02 +00:00
func NewLogRotator(path string, fileName string, maxFiles int, fileSize int64, logger *log.Logger) (*LogRotator, error) {
2016-01-14 01:16:25 +00:00
files, err := ioutil.ReadDir(path)
if err != nil {
return nil, err
}
logFileIdx := 0
2016-01-14 01:16:25 +00:00
for _, f := range files {
if strings.HasPrefix(f.Name(), fileName) {
fileIdx := strings.TrimPrefix(f.Name(), fmt.Sprintf("%s.", fileName))
n, err := strconv.Atoi(fileIdx)
if err != nil {
continue
}
if n > logFileIdx {
logFileIdx = n
}
}
}
return &LogRotator{
maxFiles: maxFiles,
fileSize: fileSize,
path: path,
fileName: fileName,
logFileIdx: logFileIdx,
2016-01-15 19:18:02 +00:00
logger: logger,
2016-01-14 01:16:25 +00:00
}, nil
}
2016-01-17 03:19:52 +00:00
// Start reads from a Reader and writes them to files and rotates them when the
// size of the file becomes equal to the max size configured
2016-01-14 01:16:25 +00:00
func (l *LogRotator) Start(r io.Reader) error {
2016-01-15 07:16:30 +00:00
buf := make([]byte, bufSize)
2016-01-14 01:16:25 +00:00
for {
logFileName := filepath.Join(l.path, fmt.Sprintf("%s.%d", l.fileName, l.logFileIdx))
if f, err := os.Stat(logFileName); err == nil {
if f.IsDir() {
l.logFileIdx += 1
continue
}
}
2016-01-15 06:36:55 +00:00
f, err := os.OpenFile(logFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
2016-01-14 01:16:25 +00:00
if err != nil {
return err
}
2016-01-15 07:16:30 +00:00
l.logger.Println("[INFO] logrotator: opened a new file: %s", logFileName)
2016-01-14 01:16:25 +00:00
remainingSize := l.fileSize
if finfo, err := os.Stat(logFileName); err == nil {
remainingSize -= finfo.Size()
2016-01-14 01:16:25 +00:00
}
if remainingSize < 1 {
l.logFileIdx = l.logFileIdx + 1
f.Close()
2016-01-14 01:16:25 +00:00
continue
}
for {
2016-01-15 06:36:55 +00:00
var nr int
var err error
2016-01-15 07:16:30 +00:00
if remainingSize < bufSize {
2016-01-15 06:36:55 +00:00
nr, err = r.Read(buf[0:remainingSize])
} else {
nr, err = r.Read(buf)
}
if err != nil {
f.Close()
return err
}
nw, err := f.Write(buf[:nr])
if err != nil {
f.Close()
return err
}
if nr != nw {
f.Close()
return fmt.Errorf("Failed to write data R: %d W: %d", nr, nw)
}
remainingSize -= int64(nr)
2016-01-15 06:36:55 +00:00
if remainingSize < 1 {
f.Close()
break
}
2016-01-14 01:16:25 +00:00
}
l.logFileIdx = l.logFileIdx + 1
}
return nil
}
2016-01-17 03:19:52 +00:00
// PurgeOldFiles removes older files and keeps only the last N files rotated for
// a file
func (l *LogRotator) PurgeOldFiles() {
fIndexes := make([]int, l.maxFiles)
files, err := ioutil.ReadDir(l.path)
if err != nil {
return
}
count := 0
for _, f := range files {
if strings.HasPrefix(f.Name(), l.fileName) {
fileIdx := strings.TrimPrefix(f.Name(), fmt.Sprintf("%s.", l.fileName))
n, err := strconv.Atoi(fileIdx)
if err != nil {
continue
}
if count == l.maxFiles {
sort.Sort(sort.Reverse(sort.IntSlice(fIndexes)))
fname := filepath.Join(l.path, fmt.Sprintf("%s.%d", l.fileName, fIndexes[count-1]))
l.logger.Printf("[INFO] removing file: %v", fname)
os.RemoveAll(fname)
count -= 1
}
fIndexes[count] = n
count += 1
}
}
}