162 lines
3.1 KiB
Go
162 lines
3.1 KiB
Go
package logger
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"sort"
|
|
"sync"
|
|
)
|
|
|
|
type File struct {
|
|
sync.RWMutex
|
|
Path string
|
|
File *os.File
|
|
}
|
|
|
|
func (v *File) Flush() error {
|
|
v.Lock()
|
|
defer v.Unlock()
|
|
if v.File != nil {
|
|
err := v.File.Sync()
|
|
v.File = nil
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (v *File) Close() error {
|
|
v.Lock()
|
|
defer v.Unlock()
|
|
if v.File != nil {
|
|
err := v.File.Close()
|
|
v.File = nil
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (v *File) getRotatedFileList() ([]logFile, error) {
|
|
var list []logFile
|
|
err := filepath.Walk(path.Dir(v.Path), func(p string,
|
|
info os.FileInfo, err error) error {
|
|
pattern := "*" + path.Base(v.Path) + "*"
|
|
if ok, err := path.Match(pattern, path.Base(p)); ok && err == nil {
|
|
i := extractIndex(info)
|
|
list = append(list, logFile{FileInfo: info, Index: i})
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s := &sortLogFiles{Items: list}
|
|
sort.Sort(s)
|
|
return s.Items, nil
|
|
}
|
|
|
|
func (v *File) doRotate(items []logFile, rotateMaxCount int) error {
|
|
if len(items) > 0 {
|
|
// delete last files
|
|
deleteCount := len(items) - rotateMaxCount + 1
|
|
if deleteCount > 0 {
|
|
for i := 0; i < deleteCount; i++ {
|
|
err := os.Remove(items[i].FileInfo.Name())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
items = items[deleteCount:]
|
|
}
|
|
// change names of rest files
|
|
baseFilePath := items[len(items)-1].FileInfo.Name()
|
|
movs := make([]int, len(items))
|
|
// 1st round to change names
|
|
for i, item := range items {
|
|
movs[i] = i + 100000
|
|
err := os.Rename(item.FileInfo.Name(),
|
|
fmt.Sprintf("%s.%d", baseFilePath, movs[i]))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// 2nd round to change names
|
|
for i, item := range movs {
|
|
err := os.Rename(fmt.Sprintf("%s.%d", baseFilePath, item),
|
|
fmt.Sprintf("%s.%d", baseFilePath, len(items)-i))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (v *File) rotateFiles(rotateMaxSize int64, rotateMaxCount int) error {
|
|
fs, err := v.File.Stat()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if fs.Size() > rotateMaxSize {
|
|
if v.File != nil {
|
|
err := v.File.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
v.File = nil
|
|
}
|
|
list, err := v.getRotatedFileList()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = v.doRotate(list, rotateMaxCount); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (v *File) getFile() (*os.File, error) {
|
|
v.Lock()
|
|
defer v.Unlock()
|
|
if v.File == nil {
|
|
file, err := os.OpenFile(v.Path, os.O_RDWR|os.O_APPEND, 0660)
|
|
if err != nil {
|
|
file, err = os.Create(v.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
v.File = file
|
|
}
|
|
return v.File, nil
|
|
}
|
|
|
|
func (v *File) writeToFile(msg string, rotateMaxSize int64, rotateMaxCount int) error {
|
|
file, err := v.getFile()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
v.Lock()
|
|
defer v.Unlock()
|
|
var buf bytes.Buffer
|
|
buf.WriteString(msg)
|
|
buf.WriteString(fmt.Sprintln())
|
|
if _, err := io.Copy(file, &buf); err != nil {
|
|
return err
|
|
}
|
|
// if err = file.Sync(); err != nil {
|
|
// return err
|
|
// }
|
|
if err := v.rotateFiles(rotateMaxSize, rotateMaxCount); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|