2
0

Change definition of maxage to make it easier (i.e. possible) to load from a json/yaml/etc

This commit is contained in:
Nate Finch
2014-06-18 08:09:40 -04:00
parent 06f4f4ea5e
commit 72cc861377
4 changed files with 69 additions and 40 deletions
+7 -9
View File
@@ -28,7 +28,7 @@ log.SetOutput(&lumberjack.Logger{
NameFormat: time.RFC822 + ".log", NameFormat: time.RFC822 + ".log",
MaxSize: lumberjack.Gigabyte, MaxSize: lumberjack.Gigabyte,
MaxBackups: 3, MaxBackups: 3,
MaxAge: lumberjack.Week * 4, MaxAge: 28,
}) })
``` ```
@@ -39,9 +39,6 @@ log.SetOutput(&lumberjack.Logger{
const ( const (
Megabyte = 1024 * 1024 Megabyte = 1024 * 1024
Gigabyte = 1024 * Megabyte Gigabyte = 1024 * Megabyte
Day = 24 * time.Hour
Week = 7 * Day
) )
``` ```
@@ -62,10 +59,11 @@ type Logger struct {
// rolled. It defaults to 100 megabytes. // rolled. It defaults to 100 megabytes.
MaxSize int64 `json:"maxsize" yaml:"maxsize"` MaxSize int64 `json:"maxsize" yaml:"maxsize"`
// MaxAge is the maximum time to retain old log files based on // MaxAge is the maximum number of days to retain old log files based on
// FileInfo.ModTime. The default is not to remove old log files based on // FileInfo.ModTime. Note that a day is defined as 24 hours and may not
// age. // exactly correspond to calendar days due to daylight savings, leap
MaxAge time.Duration `json:"maxage" yaml:"maxage"` // seconds, etc. The default is not to remove old log files based on age.
MaxAge int `json:"maxage" yaml:"maxage"`
// MaxBackups is the maximum number of old log files to retain. The default // MaxBackups is the maximum number of old log files to retain. The default
// is to retain all old log files (though MaxAge may still cause them to get // is to retain all old log files (though MaxAge may still cause them to get
@@ -100,7 +98,7 @@ Whenever a new file gets created, old log files may be deleted. The log file
directory is scanned for files that match NameFormat. The most recent files directory is scanned for files that match NameFormat. The most recent files
according to their NameFormat date will be retained, up to a number equal to according to their NameFormat date will be retained, up to a number equal to
MaxBackups (or all of them if MaxBackups is 0). Any files with a last MaxBackups (or all of them if MaxBackups is 0). Any files with a last
modified time (based on FileInfo.ModTime) older than MaxAge are deleted, modified time (based on FileInfo.ModTime) older than MaxAge days are deleted,
regardless of MaxBackups. regardless of MaxBackups.
If MaxBackups and MaxAge are both 0, no old log files will be deleted. If MaxBackups and MaxAge are both 0, no old log files will be deleted.
+1 -1
View File
@@ -35,6 +35,6 @@ func Example() {
NameFormat: time.RFC822 + ".log", NameFormat: time.RFC822 + ".log",
MaxSize: lumberjack.Gigabyte, MaxSize: lumberjack.Gigabyte,
MaxBackups: 3, MaxBackups: 3,
MaxAge: lumberjack.Week * 4, MaxAge: 28,
}) })
} }
+22 -14
View File
@@ -30,12 +30,6 @@ const (
Megabyte = 1024 * 1024 Megabyte = 1024 * 1024
Gigabyte = 1024 * Megabyte Gigabyte = 1024 * Megabyte
// Note that lumberjack days and weeks may not exactly conform to calendar
// days and weeks due to daylight savings, leap seconds, etc.
Day = 24 * time.Hour
Week = 7 * Day
defaultNameFormat = "2006-01-02T15-04-05.000.log" defaultNameFormat = "2006-01-02T15-04-05.000.log"
defaultMaxSize = 100 * Megabyte defaultMaxSize = 100 * Megabyte
) )
@@ -66,7 +60,7 @@ var _ io.WriteCloser = (*Logger)(nil)
// directory is scanned for files that match NameFormat. The most recent files // directory is scanned for files that match NameFormat. The most recent files
// according to their NameFormat date will be retained, up to a number equal to // according to their NameFormat date will be retained, up to a number equal to
// MaxBackups (or all of them if MaxBackups is 0). Any files with a last // MaxBackups (or all of them if MaxBackups is 0). Any files with a last
// modified time (based on FileInfo.ModTime) older than MaxAge are deleted, // modified time (based on FileInfo.ModTime) older than MaxAge days are deleted,
// regardless of MaxBackups. // regardless of MaxBackups.
// //
// If MaxBackups and MaxAge are both 0, no old log files will be deleted. // If MaxBackups and MaxAge are both 0, no old log files will be deleted.
@@ -83,10 +77,11 @@ type Logger struct {
// rolled. It defaults to 100 megabytes. // rolled. It defaults to 100 megabytes.
MaxSize int64 `json:"maxsize" yaml:"maxsize"` MaxSize int64 `json:"maxsize" yaml:"maxsize"`
// MaxAge is the maximum time to retain old log files based on // MaxAge is the maximum number of days to retain old log files based on
// FileInfo.ModTime. The default is not to remove old log files based on // FileInfo.ModTime. Note that a day is defined as 24 hours and may not
// age. // exactly correspond to calendar days due to daylight savings, leap
MaxAge time.Duration `json:"maxage" yaml:"maxage"` // seconds, etc. The default is not to remove old log files based on age.
MaxAge int `json:"maxage" yaml:"maxage"`
// MaxBackups is the maximum number of old log files to retain. The default // MaxBackups is the maximum number of old log files to retain. The default
// is to retain all old log files (though MaxAge may still cause them to get // is to retain all old log files (though MaxAge may still cause them to get
@@ -102,8 +97,14 @@ type Logger struct {
mu sync.Mutex mu sync.Mutex
} }
// currentTime is only used for testing. Normally it's the time.Now() function. var (
var currentTime = time.Now // currentTime exists so it can be mocked out by tests.
currentTime = time.Now
// day is the units that MaxAge converts into. It is a variable so we can
// change it during tests.
day = 24 * time.Hour
)
// Write implements io.Writer. If a write would cause the log file to be larger // Write implements io.Writer. If a write would cause the log file to be larger
// than MaxSize, a new log file is created using the current time formatted with // than MaxSize, a new log file is created using the current time formatted with
@@ -269,7 +270,9 @@ func (l *Logger) cleanup() error {
files = files[:l.MaxBackups] files = files[:l.MaxBackups]
} }
if l.MaxAge > 0 { if l.MaxAge > 0 {
cutoff := currentTime().Add(-1 * l.MaxAge) diff := time.Duration(-1 * int64(day) * int64(l.MaxAge))
cutoff := currentTime().Add(diff)
for _, f := range files { for _, f := range files {
if f.ModTime().Before(cutoff) { if f.ModTime().Before(cutoff) {
@@ -322,11 +325,14 @@ func (l *Logger) oldLogFiles() ([]os.FileInfo, error) {
return logFiles, nil return logFiles, nil
} }
// isLogFile reports where the name of f fits the format of a logfile created by
// this Logger.
func (l *Logger) isLogFile(f os.FileInfo) bool { func (l *Logger) isLogFile(f os.FileInfo) bool {
_, err := time.Parse(l.format(), filepath.Base(f.Name())) _, err := time.Parse(l.format(), filepath.Base(f.Name()))
return err == nil return err == nil
} }
// max returns the maximum size of log files before rolling..
func (l *Logger) max() int64 { func (l *Logger) max() int64 {
if l.MaxSize == 0 { if l.MaxSize == 0 {
return defaultMaxSize return defaultMaxSize
@@ -334,6 +340,7 @@ func (l *Logger) max() int64 {
return l.MaxSize return l.MaxSize
} }
// dir returns the directory in which log files should be stored.
func (l *Logger) dir() string { func (l *Logger) dir() string {
if l.Dir != "" { if l.Dir != "" {
return l.Dir return l.Dir
@@ -341,6 +348,7 @@ func (l *Logger) dir() string {
return os.TempDir() return os.TempDir()
} }
// format returns the name format for log files.
func (l *Logger) format() string { func (l *Logger) format() string {
if l.NameFormat != "" { if l.NameFormat != "" {
return l.NameFormat return l.NameFormat
+39 -16
View File
@@ -1,6 +1,7 @@
package lumberjack package lumberjack
import ( import (
"encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@@ -166,7 +167,7 @@ func TestAutoRotate(t *testing.T) {
fileCount(dir, 1, t) fileCount(dir, 1, t)
// set the current time one day later // set the current time one day later
defer newFakeTime(Day)() newFakeTime()
b2 := []byte("foooooo!") b2 := []byte("foooooo!")
n, err = l.Write(b2) n, err = l.Write(b2)
@@ -200,7 +201,7 @@ func TestFirstWriteRotate(t *testing.T) {
isNil(err, t) isNil(err, t)
// set the current time one day later // set the current time one day later
defer newFakeTime(Day)() newFakeTime()
// this would make us rotate // this would make us rotate
b := []byte("fooo!") b := []byte("fooo!")
@@ -236,7 +237,7 @@ func TestMaxBackups(t *testing.T) {
fileCount(dir, 1, t) fileCount(dir, 1, t)
// set the current time one day later // set the current time one day later
defer newFakeTime(Day)() newFakeTime()
// this will put us over the max // this will put us over the max
b2 := []byte("foooooo!") b2 := []byte("foooooo!")
@@ -254,7 +255,7 @@ func TestMaxBackups(t *testing.T) {
fileCount(dir, 2, t) fileCount(dir, 2, t)
// set the current time one day later // set the current time one day later
defer newFakeTime(Day)() newFakeTime()
// this will make us rotate again // this will make us rotate again
n, err = l.Write(b2) n, err = l.Write(b2)
@@ -281,7 +282,7 @@ func TestMaxBackups(t *testing.T) {
// now test that we don't delete directories or non-logfile files // now test that we don't delete directories or non-logfile files
// set the current time one day later // set the current time one day later
defer newFakeTime(Day)() newFakeTime()
// create a file that is close to but different from the logfile name. // create a file that is close to but different from the logfile name.
/// It shouldn't get caught by our deletion filters. /// It shouldn't get caught by our deletion filters.
@@ -295,7 +296,7 @@ func TestMaxBackups(t *testing.T) {
err = os.Mkdir(notlogfiledir, 0700) err = os.Mkdir(notlogfiledir, 0700)
isNil(err, t) isNil(err, t)
defer newFakeTime(Day)() newFakeTime()
// this will make us rotate again // this will make us rotate again
n, err = l.Write(b2) n, err = l.Write(b2)
@@ -329,6 +330,10 @@ func TestMaxBackups(t *testing.T) {
func TestMaxAge(t *testing.T) { func TestMaxAge(t *testing.T) {
currentTime = fakeTime currentTime = fakeTime
// change how maxage is interpreted from days to milliseconds
day = time.Millisecond
// This test uses ModTime on files, and so we need to make sure we're using // This test uses ModTime on files, and so we need to make sure we're using
// the most current time possible. // the most current time possible.
fakeCurrentTime = time.Now() fakeCurrentTime = time.Now()
@@ -339,7 +344,7 @@ func TestMaxAge(t *testing.T) {
Dir: dir, Dir: dir,
NameFormat: format, NameFormat: format,
MaxSize: 10, MaxSize: 10,
MaxAge: 10 * time.Millisecond, MaxAge: 10,
} }
defer l.Close() defer l.Close()
b := []byte("boo!") b := []byte("boo!")
@@ -415,7 +420,7 @@ func TestDefaultDirAndName(t *testing.T) {
err = l.Close() err = l.Close()
isNil(err, t) isNil(err, t)
defer newFakeTime(Day)() newFakeTime()
// even though the old file is under MaxSize, we should write a new file // even though the old file is under MaxSize, we should write a new file
// to prevent two processes using lumberjack from writing to the same file. // to prevent two processes using lumberjack from writing to the same file.
@@ -452,7 +457,7 @@ func TestRotate(t *testing.T) {
fileCount(dir, 1, t) fileCount(dir, 1, t)
// set the current time one day later // set the current time one day later
defer newFakeTime(Day)() newFakeTime()
err = l.Rotate() err = l.Rotate()
isNil(err, t) isNil(err, t)
@@ -467,7 +472,7 @@ func TestRotate(t *testing.T) {
fileCount(dir, 2, t) fileCount(dir, 2, t)
// set the current time one day later // set the current time one day later
defer newFakeTime(Day)() newFakeTime()
err = l.Rotate() err = l.Rotate()
isNil(err, t) isNil(err, t)
@@ -490,6 +495,28 @@ func TestRotate(t *testing.T) {
existsWithLen(filename3, n, t) existsWithLen(filename3, n, t)
} }
func TestUnmarshal(t *testing.T) {
data := []byte(`
{
"dir": "foo",
"nameformat": "bar",
"maxsize": 5,
"maxage": 10,
"maxbackups": 3,
"localtime": true
}`[1:])
l := Logger{}
err := json.Unmarshal(data, &l)
isNil(err, t)
equals("foo", l.Dir, t)
equals("bar", l.NameFormat, t)
equals(int64(5), l.MaxSize, t)
equals(10, l.MaxAge, t)
equals(3, l.MaxBackups, t)
equals(true, l.LocalTime, t)
}
// makeTempDir creates a file with a semi-unique name in the OS temp directory. // makeTempDir creates a file with a semi-unique name in the OS temp directory.
// It should be based on the name of the test, to keep parallel tests from // It should be based on the name of the test, to keep parallel tests from
// colliding, and must be cleaned up after the test is finished. // colliding, and must be cleaned up after the test is finished.
@@ -528,12 +555,8 @@ func fileCount(dir string, exp int, t testing.TB) {
} }
// newFakeTime sets the fake "current time" to one day later. // newFakeTime sets the fake "current time" to one day later.
func newFakeTime(later time.Duration) func() { func newFakeTime() {
old := fakeCurrentTime fakeCurrentTime = fakeCurrentTime.Add(time.Hour * 24)
fakeCurrentTime = fakeCurrentTime.Add(later)
return func() {
fakeCurrentTime = old
}
} }
func notExist(path string, t testing.TB) { func notExist(path string, t testing.TB) {