Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #152 #154

Open
wants to merge 2 commits into
base: v2.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 60 additions & 8 deletions lumberjack.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ type Logger struct {
// os.TempDir() if empty.
Filename string `json:"filename" yaml:"filename"`

// BackupDirectory is the directory to store logs to. It will store the
// backups in the same folder specified by Filename if empty.
BackupDirectory string `json:backupdirectory yaml:"backupdirectory"`

// MaxSize is the maximum size in megabytes of the log file before it gets
// rotated. It defaults to 100 megabytes.
MaxSize int `json:"maxsize" yaml:"maxsize"`
Expand Down Expand Up @@ -218,9 +222,20 @@ func (l *Logger) openNew() error {
// Copy the mode off the old logfile.
mode = info.Mode()
// move the existing file
newname := backupName(name, l.LocalTime)
if err := os.Rename(name, newname); err != nil {
return fmt.Errorf("can't rename log file: %s", err)
newname := l.backupName(name, l.LocalTime)

// If the backup directory is not located on the same partition as the
// active log directory, the os.Rename call might fail. Thus, we check if
// the active and the backup directories are the same first, and copy the
// content of the active log into the backup log if it is not the case.
if l.backupDirectory() == l.dir() {
if err := os.Rename(name, newname); err != nil {
return fmt.Errorf("can't rename log file: %s", err)
}
} else {
if err := moveFile(name, newname); err != nil {
return fmt.Errorf("can't move log file: %s", err)
}
}

// this is a no-op anywhere but linux
Expand All @@ -244,8 +259,8 @@ func (l *Logger) openNew() error {
// backupName creates a new filename from the given name, inserting a timestamp
// between the filename and the extension, using the local time if requested
// (otherwise UTC).
func backupName(name string, local bool) string {
dir := filepath.Dir(name)
func (l *Logger) backupName(name string, local bool) string {
dir := l.backupDirectory()
filename := filepath.Base(name)
ext := filepath.Ext(filename)
prefix := filename[:len(filename)-len(ext)]
Expand Down Expand Up @@ -297,6 +312,16 @@ func (l *Logger) filename() string {
return filepath.Join(os.TempDir(), name)
}

func (l *Logger) backupDirectory() (result string) {
if l.BackupDirectory != "" {
result = l.BackupDirectory
} else {
result = filepath.Dir(l.filename())
}

return result
}

// millRunOnce performs compression and removal of stale log files.
// Log files are compressed if enabled via configuration and old log
// files are removed, keeping at most l.MaxBackups files, as long as
Expand Down Expand Up @@ -357,13 +382,13 @@ func (l *Logger) millRunOnce() error {
}

for _, f := range remove {
errRemove := os.Remove(filepath.Join(l.dir(), f.Name()))
errRemove := os.Remove(filepath.Join(l.backupDirectory(), f.Name()))
if err == nil && errRemove != nil {
err = errRemove
}
}
for _, f := range compress {
fn := filepath.Join(l.dir(), f.Name())
fn := filepath.Join(l.backupDirectory(), f.Name())
errCompress := compressLogFile(fn, fn+compressSuffix)
if err == nil && errCompress != nil {
err = errCompress
Expand Down Expand Up @@ -398,7 +423,7 @@ func (l *Logger) mill() {
// oldLogFiles returns the list of backup log files stored in the same
// directory as the current log file, sorted by ModTime
func (l *Logger) oldLogFiles() ([]logInfo, error) {
files, err := ioutil.ReadDir(l.dir())
files, err := ioutil.ReadDir(l.backupDirectory())
if err != nil {
return nil, fmt.Errorf("can't read log file directory: %s", err)
}
Expand Down Expand Up @@ -518,6 +543,33 @@ func compressLogFile(src, dst string) (err error) {
return nil
}

// moveFile moves a file from a source to a destination. This function is used when
// the file is moved from locations in different partitions of the file system.
func moveFile(sourcePath, destPath string) error {
inputFile, err := os.Open(sourcePath)
if err != nil {
return err
}
outputFile, err := os.Create(destPath)
if err != nil {
_ = inputFile.Close()
return err
}
defer func() { _ = outputFile.Close() }()
if _, err = io.Copy(outputFile, inputFile); err != nil {
return err
}
if err = inputFile.Close(); err != nil {
return err
}
// The copy was successful, so now delete the original file
err = os.Remove(sourcePath)
if err != nil {
return err
}
return nil
}

// logInfo is a convenience struct to return the filename and its embedded
// timestamp.
type logInfo struct {
Expand Down
Loading