diff options
Diffstat (limited to 'vendor/gopkg.in/clog.v1/file.go')
-rw-r--r-- | vendor/gopkg.in/clog.v1/file.go | 315 |
1 files changed, 0 insertions, 315 deletions
diff --git a/vendor/gopkg.in/clog.v1/file.go b/vendor/gopkg.in/clog.v1/file.go deleted file mode 100644 index 6b490f9c..00000000 --- a/vendor/gopkg.in/clog.v1/file.go +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2017 Unknwon -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package clog - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "log" - "os" - "path/filepath" - "strings" - "time" -) - -const ( - SIMPLE_DATE_FORMAT = "2006-01-02" - LOG_PREFIX_LENGTH = len("2017/02/06 21:20:08 ") -) - -// FileRotationConfig represents rotation related configurations for file mode logger. -// All the settings can take effect at the same time, remain zero values to disable them. -type FileRotationConfig struct { - // Do rotation for output files. - Rotate bool - // Rotate on daily basis. - Daily bool - // Maximum size in bytes of file for a rotation. - MaxSize int64 - // Maximum number of lines for a rotation. - MaxLines int64 - // Maximum lifetime of a output file in days. - MaxDays int64 -} - -type FileConfig struct { - // Minimum level of messages to be processed. - Level LEVEL - // Buffer size defines how many messages can be queued before hangs. - BufferSize int64 - // File name to outout messages. - Filename string - // Rotation related configurations. - FileRotationConfig -} - -type file struct { - // Indicates whether object is been used in standalone mode. - standalone bool - - *log.Logger - Adapter - - file *os.File - filename string - openDay int - currentSize int64 - currentLines int64 - rotate FileRotationConfig -} - -func newFile() Logger { - return &file{ - Adapter: Adapter{ - quitChan: make(chan struct{}), - }, - } -} - -// NewFileWriter returns an io.Writer for synchronized file logger in standalone mode. -func NewFileWriter(filename string, cfg FileRotationConfig) (io.Writer, error) { - f := &file{ - standalone: true, - } - if err := f.Init(FileConfig{ - Filename: filename, - FileRotationConfig: cfg, - }); err != nil { - return nil, err - } - - return f, nil -} - -func (f *file) Level() LEVEL { return f.level } - -var newLineBytes = []byte("\n") - -func (f *file) initFile() (err error) { - f.file, err = os.OpenFile(f.filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660) - if err != nil { - return fmt.Errorf("OpenFile '%s': %v", f.filename, err) - } - - f.Logger = log.New(f.file, "", log.Ldate|log.Ltime) - return nil -} - -// isExist checks whether a file or directory exists. -// It returns false when the file or directory does not exist. -func isExist(path string) bool { - _, err := os.Stat(path) - return err == nil || os.IsExist(err) -} - -// rotateFilename returns next available rotate filename with given date. -func (f *file) rotateFilename(date string) string { - filename := fmt.Sprintf("%s.%s", f.filename, date) - if !isExist(filename) { - return filename - } - - format := filename + ".%03d" - for i := 1; i < 1000; i++ { - filename := fmt.Sprintf(format, i) - if !isExist(filename) { - return filename - } - } - - panic("too many log files for yesterday") -} - -func (f *file) deleteOutdatedFiles() { - filepath.Walk(filepath.Dir(f.filename), func(path string, info os.FileInfo, err error) error { - if !info.IsDir() && - info.ModTime().Before(time.Now().Add(-24*time.Hour*time.Duration(f.rotate.MaxDays))) && - strings.HasPrefix(filepath.Base(path), filepath.Base(f.filename)) { - os.Remove(path) - } - return nil - }) -} - -func (f *file) initRotate() error { - // Gather basic file info for rotation. - fi, err := f.file.Stat() - if err != nil { - return fmt.Errorf("Stat: %v", err) - } - - f.currentSize = fi.Size() - - // If there is any content in the file, count the number of lines. - if f.rotate.MaxLines > 0 && f.currentSize > 0 { - data, err := ioutil.ReadFile(f.filename) - if err != nil { - return fmt.Errorf("ReadFile '%s': %v", f.filename, err) - } - - f.currentLines = int64(bytes.Count(data, newLineBytes)) + 1 - } - - if f.rotate.Daily { - now := time.Now() - f.openDay = now.Day() - - lastWriteTime := fi.ModTime() - if lastWriteTime.Year() != now.Year() || - lastWriteTime.Month() != now.Month() || - lastWriteTime.Day() != now.Day() { - - if err = f.file.Close(); err != nil { - return fmt.Errorf("Close: %v", err) - } - if err = os.Rename(f.filename, f.rotateFilename(lastWriteTime.Format(SIMPLE_DATE_FORMAT))); err != nil { - return fmt.Errorf("Rename: %v", err) - } - - if err = f.initFile(); err != nil { - return fmt.Errorf("initFile: %v", err) - } - } - } - - if f.rotate.MaxDays > 0 { - f.deleteOutdatedFiles() - } - return nil -} - -func (f *file) Init(v interface{}) (err error) { - cfg, ok := v.(FileConfig) - if !ok { - return ErrConfigObject{"FileConfig", v} - } - - if !isValidLevel(cfg.Level) { - return ErrInvalidLevel{} - } - f.level = cfg.Level - - f.filename = cfg.Filename - os.MkdirAll(filepath.Dir(f.filename), os.ModePerm) - if err = f.initFile(); err != nil { - return fmt.Errorf("initFile: %v", err) - } - - f.rotate = cfg.FileRotationConfig - if f.rotate.Rotate { - f.initRotate() - } - - if !f.standalone { - f.msgChan = make(chan *Message, cfg.BufferSize) - } - return nil -} - -func (f *file) ExchangeChans(errorChan chan<- error) chan *Message { - f.errorChan = errorChan - return f.msgChan -} - -func (f *file) write(msg *Message) int { - f.Logger.Print(msg.Body) - - bytesWrote := len(msg.Body) - if !f.standalone { - bytesWrote += LOG_PREFIX_LENGTH - } - if f.rotate.Rotate { - f.currentSize += int64(bytesWrote) - f.currentLines++ // TODO: should I care if log message itself contains new lines? - - var ( - needsRotate = false - rotateDate time.Time - ) - - now := time.Now() - if f.rotate.Daily && now.Day() != f.openDay { - needsRotate = true - rotateDate = now.Add(-24 * time.Hour) - - } else if (f.rotate.MaxSize > 0 && f.currentSize >= f.rotate.MaxSize) || - (f.rotate.MaxLines > 0 && f.currentLines >= f.rotate.MaxLines) { - needsRotate = true - rotateDate = now - } - - if needsRotate { - f.file.Close() - if err := os.Rename(f.filename, f.rotateFilename(rotateDate.Format(SIMPLE_DATE_FORMAT))); err != nil { - f.errorChan <- fmt.Errorf("fail to rename rotate file '%s': %v", f.filename, err) - } - - if err := f.initFile(); err != nil { - f.errorChan <- fmt.Errorf("fail to init log file '%s': %v", f.filename, err) - } - - f.openDay = now.Day() - f.currentSize = 0 - f.currentLines = 0 - } - } - return bytesWrote -} - -var _ io.Writer = new(file) - -// Write implements method of io.Writer interface. -func (f *file) Write(p []byte) (int, error) { - return f.write(&Message{ - Body: string(p), - }), nil -} - -func (f *file) Start() { -LOOP: - for { - select { - case msg := <-f.msgChan: - f.write(msg) - case <-f.quitChan: - break LOOP - } - } - - for { - if len(f.msgChan) == 0 { - break - } - - f.write(<-f.msgChan) - } - f.quitChan <- struct{}{} // Notify the cleanup is done. -} - -func (f *file) Destroy() { - f.quitChan <- struct{}{} - <-f.quitChan - - close(f.msgChan) - close(f.quitChan) - - f.file.Close() -} - -func init() { - Register(FILE, newFile) -} |