123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- 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 := os.Rename(fromPath, toPath); err != nil && !os.IsNotExist(err) {
- return err
- }
- }
- if err := os.Rename(name, name+".1"); err != nil && !os.IsNotExist(err) {
- return err
- }
- return nil
- }
- // 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()
- }
|