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

Multiple enhancements #158

Open
wants to merge 3 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
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ Code:
```go
log.SetOutput(&lumberjack.Logger{
Filename: "/var/log/myapp/foo.log",
MaxSize: 500, // megabytes
MaxSize: 500, // megabytes (Deprecated)
MaxBytes: 500, // bytes
MaxBackups: 3,
MaxAge: 28, //days
Compress: true, // disabled by default
Expand All @@ -53,8 +54,13 @@ type Logger struct {

// MaxSize is the maximum size in megabytes of the log file before it gets
// rotated. It defaults to 100 megabytes.
// Deprecated: use MaxBytes instead.
MaxSize int `json:"maxsize" yaml:"maxsize"`

// MaxBytes is the maximum size in bytes of the log file before it gets
// rotated. It defaults to 104857600 (100 megabytes).
MaxBytes int64 `json:"maxbytes" yaml:"maxbytes"`

// MaxAge is the maximum number of days to retain old log files based on the
// timestamp encoded in their filename. Note that a day is defined as 24
// hours and may not exactly correspond to calendar days due to daylight
Expand All @@ -81,13 +87,13 @@ type Logger struct {
Logger is an io.WriteCloser that writes to the specified filename.

Logger opens or creates the logfile on first Write. If the file exists and
is less than MaxSize megabytes, lumberjack will open and append to that file.
If the file exists and its size is >= MaxSize megabytes, the file is renamed
is less than MaxBytes, lumberjack will open and append to that file.
If the file exists and its size is >= MaxBytes, the file is renamed
by putting the current time in a timestamp in the name immediately before the
file's extension (or the end of the filename if there's no extension). A new
log file is then created using original filename.

Whenever a write would cause the current log file exceed MaxSize megabytes,
Whenever a write would cause the current log file exceed MaxBytes,
the current file is closed, renamed, and a new log file created with the
original name. Thus, the filename you give Logger is always the "current" log
file.
Expand Down Expand Up @@ -163,9 +169,9 @@ go func() {
func (l *Logger) Write(p []byte) (n int, err error)
```
Write implements io.Writer. If a write would cause the log file to be larger
than MaxSize, the file is closed, renamed to include a timestamp of the
than MaxBytes, the file is closed, renamed to include a timestamp of the
current time, and a new log file is created using the original log file name.
If the length of the write is greater than MaxSize, an error is returned.
If the length of the write is greater than MaxBytes, an error is returned.



Expand Down
1 change: 1 addition & 0 deletions chown.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux

package lumberjack
Expand Down
2 changes: 1 addition & 1 deletion example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
func Example() {
log.SetOutput(&Logger{
Filename: "/var/log/myapp/foo.log",
MaxSize: 500, // megabytes
MaxBytes: 500, // bytes
MaxBackups: 3,
MaxAge: 28, // days
Compress: true, // disabled by default
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module github.com/natefinch/lumberjack

require (
github.com/BurntSushi/toml v0.3.1
gopkg.in/yaml.v2 v2.2.2
github.com/BurntSushi/toml v1.1.0
gopkg.in/yaml.v2 v2.4.0
)

go 1.13
go 1.17
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
1 change: 1 addition & 0 deletions linux_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build linux
// +build linux

package lumberjack
Expand Down
37 changes: 25 additions & 12 deletions lumberjack.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ var _ io.WriteCloser = (*Logger)(nil)
// Logger is an io.WriteCloser that writes to the specified filename.
//
// Logger opens or creates the logfile on first Write. If the file exists and
// is less than MaxSize megabytes, lumberjack will open and append to that file.
// If the file exists and its size is >= MaxSize megabytes, the file is renamed
// is less than MaxBytes, lumberjack will open and append to that file.
// If the file exists and its size is >= MaxBytes, the file is renamed
// by putting the current time in a timestamp in the name immediately before the
// file's extension (or the end of the filename if there's no extension). A new
// log file is then created using original filename.
//
// Whenever a write would cause the current log file exceed MaxSize megabytes,
// Whenever a write would cause the current log file exceed MaxBytes,
// the current file is closed, renamed, and a new log file created with the
// original name. Thus, the filename you give Logger is always the "current" log
// file.
Expand Down Expand Up @@ -82,6 +82,12 @@ type Logger struct {
// os.TempDir() if empty.
Filename string `json:"filename" yaml:"filename"`

// MaxBytes is the maximum size in bytes of the log file before it gets
// rotated. It defaults to 104857600 (100 megabytes).
MaxBytes int64 `json:"maxbytes" yaml:"maxbytes"`

// Deprecated: use MaxBytes instead.
// This field is mutually exclusive with the “MaxBytes” field.
// 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 @@ -129,17 +135,18 @@ var (
)

// Write implements io.Writer. If a write would cause the log file to be larger
// than MaxSize, the file is closed, renamed to include a timestamp of the
// than MaxBytes, the file is closed, renamed to include a timestamp of the
// current time, and a new log file is created using the original log file name.
// If the length of the write is greater than MaxSize, an error is returned.
// If the length of the write is greater than MaxBytes, an error is returned.
func (l *Logger) Write(p []byte) (n int, err error) {
l.mu.Lock()
defer l.mu.Unlock()

writeLen := int64(len(p))
if writeLen > l.max() {

if writeLen > l.max(writeLen) {
return 0, fmt.Errorf(
"write length %d exceeds maximum file size %d", writeLen, l.max(),
"write length %d exceeds maximum file size %d", writeLen, l.max(writeLen),
)
}

Expand All @@ -149,7 +156,7 @@ func (l *Logger) Write(p []byte) (n int, err error) {
}
}

if l.size+writeLen > l.max() {
if l.size+writeLen > l.max(writeLen) {
if err := l.rotate(); err != nil {
return 0, err
}
Expand Down Expand Up @@ -259,8 +266,8 @@ func backupName(name string, local bool) string {
}

// openExistingOrNew opens the logfile if it exists and if the current write
// would not put it over MaxSize. If there is no such file or the write would
// put it over the MaxSize, a new file is created.
// would not put it over MaxBytes. If there is no such file or the write would
// put it over the MaxBytes, a new file is created.
func (l *Logger) openExistingOrNew(writeLen int) error {
l.mill()

Expand All @@ -273,7 +280,7 @@ func (l *Logger) openExistingOrNew(writeLen int) error {
return fmt.Errorf("error getting log file info: %s", err)
}

if info.Size()+int64(writeLen) >= l.max() {
if info.Size()+int64(writeLen) >= l.max(int64(writeLen)) {
return l.rotate()
}

Expand Down Expand Up @@ -442,7 +449,13 @@ func (l *Logger) timeFromName(filename, prefix, ext string) (time.Time, error) {
}

// max returns the maximum size in bytes of log files before rolling.
func (l *Logger) max() int64 {
func (l *Logger) max(writeLen int64) int64 {
if l.MaxBytes != 0 {
if l.MaxBytes == -1 {
return writeLen + l.size + 1
}
return l.MaxBytes
}
if l.MaxSize == 0 {
return int64(defaultMaxSize * megabyte)
}
Expand Down
35 changes: 17 additions & 18 deletions lumberjack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,20 +76,19 @@ func TestOpenExisting(t *testing.T) {

func TestWriteTooLong(t *testing.T) {
currentTime = fakeTime
megabyte = 1
dir := makeTempDir("TestWriteTooLong", t)
defer os.RemoveAll(dir)
l := &Logger{
Filename: logFile(dir),
MaxSize: 5,
MaxBytes: 5,
}
defer l.Close()
b := []byte("booooooooooooooo!")
n, err := l.Write(b)
notNil(err, t)
equals(0, n, t)
equals(err.Error(),
fmt.Sprintf("write length %d exceeds maximum file size %d", len(b), l.MaxSize), t)
fmt.Sprintf("write length %d exceeds maximum file size %d", len(b), l.MaxBytes), t)
_, err = os.Stat(logFile(dir))
assert(os.IsNotExist(err), t, "File exists, but should not have been created")
}
Expand Down Expand Up @@ -137,7 +136,7 @@ func TestAutoRotate(t *testing.T) {
filename := logFile(dir)
l := &Logger{
Filename: filename,
MaxSize: 10,
MaxBytes: 10,
}
defer l.Close()
b := []byte("boo!")
Expand Down Expand Up @@ -174,7 +173,7 @@ func TestFirstWriteRotate(t *testing.T) {
filename := logFile(dir)
l := &Logger{
Filename: filename,
MaxSize: 10,
MaxBytes: 10,
}
defer l.Close()

Expand Down Expand Up @@ -205,7 +204,7 @@ func TestMaxBackups(t *testing.T) {
filename := logFile(dir)
l := &Logger{
Filename: filename,
MaxSize: 10,
MaxBytes: 10,
MaxBackups: 1,
}
defer l.Close()
Expand Down Expand Up @@ -357,7 +356,7 @@ func TestCleanupExistingBackups(t *testing.T) {

l := &Logger{
Filename: filename,
MaxSize: 10,
MaxBytes: 10,
MaxBackups: 1,
}
defer l.Close()
Expand Down Expand Up @@ -387,7 +386,7 @@ func TestMaxAge(t *testing.T) {
filename := logFile(dir)
l := &Logger{
Filename: filename,
MaxSize: 10,
MaxBytes: 10,
MaxAge: 1,
}
defer l.Close()
Expand Down Expand Up @@ -515,7 +514,7 @@ func TestLocalTime(t *testing.T) {

l := &Logger{
Filename: logFile(dir),
MaxSize: 10,
MaxBytes: 10,
LocalTime: true,
}
defer l.Close()
Expand Down Expand Up @@ -543,7 +542,7 @@ func TestRotate(t *testing.T) {
l := &Logger{
Filename: filename,
MaxBackups: 1,
MaxSize: 100, // megabytes
MaxBytes: 100, // megabytes
}
defer l.Close()
b := []byte("boo!")
Expand Down Expand Up @@ -601,7 +600,7 @@ func TestCompressOnRotate(t *testing.T) {
l := &Logger{
Compress: true,
Filename: filename,
MaxSize: 10,
MaxBytes: 10,
}
defer l.Close()
b := []byte("boo!")
Expand Down Expand Up @@ -650,7 +649,7 @@ func TestCompressOnResume(t *testing.T) {
l := &Logger{
Compress: true,
Filename: filename,
MaxSize: 10,
MaxBytes: 10,
}
defer l.Close()

Expand Down Expand Up @@ -692,7 +691,7 @@ func TestJson(t *testing.T) {
data := []byte(`
{
"filename": "foo",
"maxsize": 5,
"MaxBytes": 5,
"maxage": 10,
"maxbackups": 3,
"localtime": true,
Expand All @@ -703,7 +702,7 @@ func TestJson(t *testing.T) {
err := json.Unmarshal(data, &l)
isNil(err, t)
equals("foo", l.Filename, t)
equals(5, l.MaxSize, t)
equals(int64(5), l.MaxBytes, t)
equals(10, l.MaxAge, t)
equals(3, l.MaxBackups, t)
equals(true, l.LocalTime, t)
Expand All @@ -713,7 +712,7 @@ func TestJson(t *testing.T) {
func TestYaml(t *testing.T) {
data := []byte(`
filename: foo
maxsize: 5
maxbytes: 5
maxage: 10
maxbackups: 3
localtime: true
Expand All @@ -723,7 +722,7 @@ compress: true`[1:])
err := yaml.Unmarshal(data, &l)
isNil(err, t)
equals("foo", l.Filename, t)
equals(5, l.MaxSize, t)
equals(int64(5), l.MaxBytes, t)
equals(10, l.MaxAge, t)
equals(3, l.MaxBackups, t)
equals(true, l.LocalTime, t)
Expand All @@ -733,7 +732,7 @@ compress: true`[1:])
func TestToml(t *testing.T) {
data := `
filename = "foo"
maxsize = 5
MaxBytes = 5
maxage = 10
maxbackups = 3
localtime = true
Expand All @@ -743,7 +742,7 @@ compress = true`[1:]
md, err := toml.Decode(data, &l)
isNil(err, t)
equals("foo", l.Filename, t)
equals(5, l.MaxSize, t)
equals(int64(5), l.MaxBytes, t)
equals(10, l.MaxAge, t)
equals(3, l.MaxBackups, t)
equals(true, l.LocalTime, t)
Expand Down
1 change: 1 addition & 0 deletions rotate_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build linux
// +build linux

package lumberjack
Expand Down