1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/daemon/logger/loggerutils/rotatefilewriter.go
Shijiang Wei d7af031114 make the json log writer much faster
Signed-off-by: Shijiang Wei <mountkin@gmail.com>
2016-02-23 19:28:06 +08:00

140 lines
3.1 KiB
Go

package loggerutils
import (
"os"
"strconv"
"sync"
"github.com/docker/docker/pkg/pubsub"
)
// RotateFileWriter is Logger implementation for default Docker logging.
type RotateFileWriter struct {
f *os.File // store for closing
mu sync.Mutex
capacity int64 //maximum size of each file
currentSize int64 // current size of the latest file
maxFiles int //maximum number of files
notifyRotate *pubsub.Publisher
}
//NewRotateFileWriter creates new RotateFileWriter
func NewRotateFileWriter(logPath string, capacity int64, maxFiles int) (*RotateFileWriter, error) {
log, err := os.OpenFile(logPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0640)
if err != nil {
return nil, err
}
size, err := log.Seek(0, os.SEEK_END)
if err != nil {
return nil, err
}
return &RotateFileWriter{
f: log,
capacity: capacity,
currentSize: size,
maxFiles: maxFiles,
notifyRotate: pubsub.NewPublisher(0, 1),
}, nil
}
//WriteLog write log message to File
func (w *RotateFileWriter) Write(message []byte) (int, error) {
w.mu.Lock()
if err := w.checkCapacityAndRotate(); err != nil {
w.mu.Unlock()
return -1, err
}
n, err := w.f.Write(message)
if err == nil {
w.currentSize += int64(n)
}
w.mu.Unlock()
return n, err
}
func (w *RotateFileWriter) checkCapacityAndRotate() error {
if w.capacity == -1 {
return nil
}
if w.currentSize >= w.capacity {
name := w.f.Name()
if err := w.f.Close(); err != nil {
return err
}
if err := rotate(name, w.maxFiles); err != nil {
return err
}
file, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 06400)
if err != nil {
return err
}
w.f = file
w.currentSize = 0
w.notifyRotate.Publish(struct{}{})
}
return nil
}
func rotate(name string, maxFiles int) error {
if maxFiles < 2 {
return nil
}
for i := maxFiles - 1; i > 1; i-- {
toPath := name + "." + strconv.Itoa(i)
fromPath := name + "." + strconv.Itoa(i-1)
if err := backup(fromPath, toPath); err != nil && !os.IsNotExist(err) {
return err
}
}
if err := backup(name, name+".1"); err != nil {
return err
}
return nil
}
// backup renames a file from fromPath to toPath
func backup(fromPath, toPath string) error {
if _, err := os.Stat(fromPath); os.IsNotExist(err) {
return err
}
if _, err := os.Stat(toPath); !os.IsNotExist(err) {
err := os.Remove(toPath)
if err != nil {
return err
}
}
return os.Rename(fromPath, toPath)
}
// LogPath returns the location the given writer logs to.
func (w *RotateFileWriter) LogPath() string {
return w.f.Name()
}
// MaxFiles return maximum number of files
func (w *RotateFileWriter) MaxFiles() int {
return w.maxFiles
}
//NotifyRotate returns the new subscriber
func (w *RotateFileWriter) NotifyRotate() chan interface{} {
return w.notifyRotate.Subscribe()
}
//NotifyRotateEvict removes the specified subscriber from receiving any more messages.
func (w *RotateFileWriter) NotifyRotateEvict(sub chan interface{}) {
w.notifyRotate.Evict(sub)
}
// Close closes underlying file and signals all readers to stop.
func (w *RotateFileWriter) Close() error {
return w.f.Close()
}