refactor internally a little to clean up the code. Make the main example a real example so we make sure it compiles
This commit is contained in:
@@ -11,22 +11,26 @@ to which logs are written.
|
|||||||
Lumberjack plays well with any logger that can write to an io.Writer,
|
Lumberjack plays well with any logger that can write to an io.Writer,
|
||||||
including the standard library's log package.
|
including the standard library's log package.
|
||||||
|
|
||||||
For example, to use lumberjack with the std lib's log package, just pass it
|
|
||||||
into the SetOutput function when your application starts:
|
|
||||||
|
|
||||||
|
|
||||||
log.SetOutput(&lumberjack.Logger{
|
|
||||||
Dir: "/var/log/myapp/"
|
|
||||||
NameFormat: time.RFC822+".log",
|
|
||||||
MaxSize: lumberjack.Gigabyte,
|
|
||||||
MaxBackups: 3,
|
|
||||||
MaxAge: lumberjack.Week * 4,
|
|
||||||
))
|
|
||||||
|
|
||||||
Lumberjack assumes that only one process is writing to the output files.
|
Lumberjack assumes that only one process is writing to the output files.
|
||||||
Using the same lumberjack configuration from multiple processes on the same
|
Using the same lumberjack configuration from multiple processes on the same
|
||||||
machine will result in improper behavior.
|
machine will result in improper behavior.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
To use lumberjack with the standard library's log package, just pass it into the
|
||||||
|
SetOutput function when your application starts.
|
||||||
|
|
||||||
|
Code:
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.SetOutput(&lumberjack.Logger{
|
||||||
|
Dir: "/var/log/myapp/",
|
||||||
|
NameFormat: time.RFC822 + ".log",
|
||||||
|
MaxSize: lumberjack.Gigabyte,
|
||||||
|
MaxBackups: 3,
|
||||||
|
MaxAge: lumberjack.Week * 4,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/natefinch/lumberjack"
|
"github.com/natefinch/lumberjack"
|
||||||
)
|
)
|
||||||
@@ -25,3 +26,15 @@ func ExampleLogger_Rotate() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To use lumberjack with the standard library's log package, just pass it into
|
||||||
|
// the SetOutput function when your application starts.
|
||||||
|
func Example() {
|
||||||
|
log.SetOutput(&lumberjack.Logger{
|
||||||
|
Dir: "/var/log/myapp/",
|
||||||
|
NameFormat: time.RFC822 + ".log",
|
||||||
|
MaxSize: lumberjack.Gigabyte,
|
||||||
|
MaxBackups: 3,
|
||||||
|
MaxAge: lumberjack.Week * 4,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
+46
-59
@@ -8,17 +8,6 @@
|
|||||||
// Lumberjack plays well with any logger that can write to an io.Writer,
|
// Lumberjack plays well with any logger that can write to an io.Writer,
|
||||||
// including the standard library's log package.
|
// including the standard library's log package.
|
||||||
//
|
//
|
||||||
// For example, to use lumberjack with the std lib's log package, just pass it
|
|
||||||
// into the SetOutput function when your application starts:
|
|
||||||
//
|
|
||||||
// log.SetOutput(&lumberjack.Logger{
|
|
||||||
// Dir: "/var/log/myapp/"
|
|
||||||
// NameFormat: time.RFC822+".log",
|
|
||||||
// MaxSize: lumberjack.Gigabyte,
|
|
||||||
// MaxBackups: 3,
|
|
||||||
// MaxAge: lumberjack.Week * 4,
|
|
||||||
// ))
|
|
||||||
//
|
|
||||||
// Lumberjack assumes that only one process is writing to the output files.
|
// Lumberjack assumes that only one process is writing to the output files.
|
||||||
// Using the same lumberjack configuration from multiple processes on the same
|
// Using the same lumberjack configuration from multiple processes on the same
|
||||||
// machine will result in improper behavior.
|
// machine will result in improper behavior.
|
||||||
@@ -123,51 +112,46 @@ var currentTime = time.Now
|
|||||||
func (l *Logger) Write(p []byte) (n int, err error) {
|
func (l *Logger) Write(p []byte) (n int, err error) {
|
||||||
l.mu.Lock()
|
l.mu.Lock()
|
||||||
defer l.mu.Unlock()
|
defer l.mu.Unlock()
|
||||||
|
|
||||||
writeLen := int64(len(p))
|
writeLen := int64(len(p))
|
||||||
if writeLen > l.max() {
|
if writeLen > l.max() {
|
||||||
return 0, fmt.Errorf(
|
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(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
f := l.file
|
if l.size+writeLen > l.max() {
|
||||||
rotate := l.size+writeLen > l.max()
|
if err := l.rotate(); err != nil {
|
||||||
if f == nil {
|
|
||||||
if f, err = l.openExistingOrNew(len(p)); err != nil {
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
} else if rotate {
|
}
|
||||||
if f, err = l.openNew(); err != nil {
|
if l.file == nil {
|
||||||
|
if err = l.openExistingOrNew(len(p)); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err = f.Write(p)
|
n, err = l.file.Write(p)
|
||||||
l.size += int64(n)
|
l.size += int64(n)
|
||||||
|
|
||||||
if l.file != nil && rotate {
|
|
||||||
l.file.Close()
|
|
||||||
}
|
|
||||||
l.file = f
|
|
||||||
|
|
||||||
if rotate {
|
|
||||||
if err := l.cleanup(); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close implements io.Closer, and closes the current logfile.
|
// Close implements io.Closer, and closes the current logfile.
|
||||||
func (l *Logger) Close() error {
|
func (l *Logger) Close() error {
|
||||||
l.mu.Lock()
|
l.mu.Lock()
|
||||||
defer l.mu.Unlock()
|
err := l.close()
|
||||||
if l.file != nil {
|
l.mu.Unlock()
|
||||||
err := l.file.Close()
|
return err
|
||||||
l.file = nil
|
}
|
||||||
return err
|
|
||||||
|
// close closes the file if it is open.
|
||||||
|
func (l *Logger) close() error {
|
||||||
|
if l.file == nil {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
err := l.file.Close()
|
||||||
|
l.file = nil
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotate causes Logger to close the existing log file and immediately create a
|
// Rotate causes Logger to close the existing log file and immediately create a
|
||||||
@@ -177,47 +161,49 @@ func (l *Logger) Close() error {
|
|||||||
// to the normal rules.
|
// to the normal rules.
|
||||||
func (l *Logger) Rotate() error {
|
func (l *Logger) Rotate() error {
|
||||||
l.mu.Lock()
|
l.mu.Lock()
|
||||||
defer l.mu.Unlock()
|
err := l.rotate()
|
||||||
if l.file != nil {
|
l.mu.Unlock()
|
||||||
if err := l.file.Close(); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
l.file = nil
|
// rotate closes the current file, if any, opens a new file, and then calls
|
||||||
|
// cleanup.
|
||||||
|
func (l *Logger) rotate() error {
|
||||||
|
if err := l.close(); err != nil {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
var err error
|
if err := l.openNew(); err != nil {
|
||||||
l.file, err = l.openNew()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return l.cleanup()
|
return l.cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
// openNew opens a new log file for writing.
|
// openNew opens a new log file for writing.
|
||||||
func (l *Logger) openNew() (*os.File, error) {
|
func (l *Logger) openNew() error {
|
||||||
err := os.MkdirAll(l.dir(), 0744)
|
err := os.MkdirAll(l.dir(), 0744)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't make directories for new logfile: %s", err)
|
return fmt.Errorf("can't make directories for new logfile: %s", err)
|
||||||
}
|
}
|
||||||
filename := l.genFilename()
|
f, err := os.OpenFile(l.genFilename(), os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't open new logfile: %s", err)
|
return fmt.Errorf("can't open new logfile: %s", err)
|
||||||
}
|
}
|
||||||
info, err := f.Stat()
|
info, err := f.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// can't really do anything if close fails here
|
// can't really do anything if close fails here
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
return nil, fmt.Errorf("can't get size of new logfile: %s", err)
|
return fmt.Errorf("can't get size of new logfile: %s", err)
|
||||||
}
|
}
|
||||||
l.size = info.Size()
|
l.size = info.Size()
|
||||||
return f, nil
|
l.file = f
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// openExistingOrNew opens the most recently modified logfile in the log
|
// openExistingOrNew opens the most recently modified logfile in the log
|
||||||
// directory, if the current write would not put it over MaxSize. If there is
|
// directory, 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
|
// no such file or the write would put it over the MaxSize, a new file is
|
||||||
// created.
|
// created.
|
||||||
func (l *Logger) openExistingOrNew(writeLen int) (*os.File, error) {
|
func (l *Logger) openExistingOrNew(writeLen int) error {
|
||||||
if l.Dir == "" && l.NameFormat == "" {
|
if l.Dir == "" && l.NameFormat == "" {
|
||||||
return l.openNew()
|
return l.openNew()
|
||||||
}
|
}
|
||||||
@@ -226,25 +212,26 @@ func (l *Logger) openExistingOrNew(writeLen int) (*os.File, error) {
|
|||||||
return l.openNew()
|
return l.openNew()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't read files in log file directory: %s", err)
|
return fmt.Errorf("can't read files in log file directory: %s", err)
|
||||||
}
|
}
|
||||||
sort.Sort(byFormatTime{files, l.format()})
|
sort.Sort(byFormatTime{files, l.format()})
|
||||||
for _, f := range files {
|
for _, info := range files {
|
||||||
if f.IsDir() {
|
if info.IsDir() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !l.isLogFile(f) {
|
if !l.isLogFile(info) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// the first file we find that matches our pattern will be the most
|
// the first file we find that matches our pattern will be the most
|
||||||
// recently modified log file.
|
// recently modified log file.
|
||||||
if f.Size()+int64(writeLen) < l.max() {
|
if info.Size()+int64(writeLen) < l.max() {
|
||||||
filename := filepath.Join(l.dir(), f.Name())
|
filename := filepath.Join(l.dir(), info.Name())
|
||||||
file, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0644)
|
file, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0644)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return file, nil
|
l.file = file
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
// if we fail to open the old log file for some reason, just ignore
|
// if we fail to open the old log file for some reason, just ignore
|
||||||
// it and open a new log file.
|
// it and open a new log file.
|
||||||
|
|||||||
Reference in New Issue
Block a user