From 0cd8ed95f53abbb6ad790b271b7389b57bb2dd01 Mon Sep 17 00:00:00 2001 From: RainyBow Date: Wed, 10 Jul 2024 11:14:15 +0800 Subject: [PATCH 1/8] Update lumberjack.go close millCh when close the logger --- lumberjack.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lumberjack.go b/lumberjack.go index 3447cdc..578bc51 100644 --- a/lumberjack.go +++ b/lumberjack.go @@ -111,7 +111,7 @@ type Logger struct { file *os.File mu sync.Mutex - millCh chan bool + millCh chan struct{} startMill sync.Once } @@ -175,6 +175,10 @@ func (l *Logger) close() error { } err := l.file.Close() l.file = nil + if l.millCh != nil { + close(l.millCh) + l.millCh = nil + } return err } @@ -386,11 +390,13 @@ func (l *Logger) millRun() { // starting the mill goroutine if necessary. func (l *Logger) mill() { l.startMill.Do(func() { - l.millCh = make(chan bool, 1) + l.millCh = make(chan struct{},1) go l.millRun() }) select { - case l.millCh <- true: + case l.millCh <- struct{}{}: + close(l.millCh) + l.millCh = nil default: } } From 764427f87ee3e33990f7936e4ae13005e03c94a8 Mon Sep 17 00:00:00 2001 From: RainyBow Date: Wed, 10 Jul 2024 11:17:19 +0800 Subject: [PATCH 2/8] change module name --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c63e57a..06e20dc 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module gopkg.in/natefinch/lumberjack.v2 +module github.com/RainyBow/lumberjack go 1.13 From 71f39d6d4e525c6ad92a7a14c86c04a210b407b5 Mon Sep 17 00:00:00 2001 From: RainyBow Date: Wed, 10 Jul 2024 13:05:45 +0800 Subject: [PATCH 3/8] fix: do not close channel millCh after send data --- lumberjack.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lumberjack.go b/lumberjack.go index 578bc51..5920915 100644 --- a/lumberjack.go +++ b/lumberjack.go @@ -390,13 +390,11 @@ func (l *Logger) millRun() { // starting the mill goroutine if necessary. func (l *Logger) mill() { l.startMill.Do(func() { - l.millCh = make(chan struct{},1) + l.millCh = make(chan struct{}, 1) go l.millRun() }) select { case l.millCh <- struct{}{}: - close(l.millCh) - l.millCh = nil default: } } From 4d05feb68c6b303718decc729e6939954a6b4245 Mon Sep 17 00:00:00 2001 From: RainyBow Date: Thu, 11 Jul 2024 09:27:00 +0800 Subject: [PATCH 4/8] =?UTF-8?q?fix-bug:=20rotate=20=E4=B8=8D=E5=8E=8B?= =?UTF-8?q?=E7=BC=A9=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lumberjack.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lumberjack.go b/lumberjack.go index 5920915..a25e567 100644 --- a/lumberjack.go +++ b/lumberjack.go @@ -165,6 +165,10 @@ func (l *Logger) Write(p []byte) (n int, err error) { func (l *Logger) Close() error { l.mu.Lock() defer l.mu.Unlock() + if l.millCh != nil { + close(l.millCh) + l.millCh = nil + } return l.close() } @@ -175,10 +179,6 @@ func (l *Logger) close() error { } err := l.file.Close() l.file = nil - if l.millCh != nil { - close(l.millCh) - l.millCh = nil - } return err } From 32cba92d54b0b21497d135333e30c5c3937ce6fc Mon Sep 17 00:00:00 2001 From: RainyBow Date: Mon, 15 Jul 2024 19:59:51 +0800 Subject: [PATCH 5/8] ensure close the logger --- lumberjack.go | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/lumberjack.go b/lumberjack.go index a25e567..496f4c6 100644 --- a/lumberjack.go +++ b/lumberjack.go @@ -112,6 +112,8 @@ type Logger struct { mu sync.Mutex millCh chan struct{} + closeCh chan struct{} + closed bool startMill sync.Once } @@ -135,7 +137,9 @@ var ( func (l *Logger) Write(p []byte) (n int, err error) { l.mu.Lock() defer l.mu.Unlock() - + if l.closed { + return 0, fmt.Errorf("logger has been closed") + } writeLen := int64(len(p)) if writeLen > l.max() { return 0, fmt.Errorf( @@ -162,13 +166,19 @@ func (l *Logger) Write(p []byte) (n int, err error) { } // Close implements io.Closer, and closes the current logfile. +// After Close, the logger can not be used func (l *Logger) Close() error { l.mu.Lock() defer l.mu.Unlock() + l.closed = true if l.millCh != nil { close(l.millCh) l.millCh = nil } + if l.closeCh == nil { + l.closeCh = make(chan struct{}, 2) + l.closeCh <- struct{}{} + } return l.close() } @@ -190,6 +200,9 @@ func (l *Logger) close() error { func (l *Logger) Rotate() error { l.mu.Lock() defer l.mu.Unlock() + if l.closed { + return fmt.Errorf("logger has been closed") + } return l.rotate() } @@ -380,9 +393,13 @@ func (l *Logger) millRunOnce() error { // millRun runs in a goroutine to manage post-rotation compression and removal // of old log files. func (l *Logger) millRun() { - for range l.millCh { - // what am I going to do, log this? - _ = l.millRunOnce() + for { + select { + case <-l.millCh: + _ = l.millRunOnce() + case <-l.closeCh: + return + } } } From e0b2d63c70a1f27759155e9ec53d6f15d20d98a2 Mon Sep 17 00:00:00 2001 From: RainyBow Date: Mon, 15 Jul 2024 20:04:20 +0800 Subject: [PATCH 6/8] mod name --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 06e20dc..c63e57a 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module github.com/RainyBow/lumberjack +module gopkg.in/natefinch/lumberjack.v2 go 1.13 From 30468e2c3f8f61f17310702e72e63d1f97aa69a0 Mon Sep 17 00:00:00 2001 From: RainyBow Date: Tue, 16 Jul 2024 19:25:35 +0800 Subject: [PATCH 7/8] =?UTF-8?q?fix-bug:=20=E6=9C=89=E6=97=B6=E5=80=99?= =?UTF-8?q?=E5=8E=8B=E7=BC=A9=E4=B8=8D=E6=89=A7=E8=A1=8C=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lumberjack.go | 7 ++-- lumberjack_test.go | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/lumberjack.go b/lumberjack.go index 496f4c6..2dbca49 100644 --- a/lumberjack.go +++ b/lumberjack.go @@ -407,13 +407,10 @@ func (l *Logger) millRun() { // starting the mill goroutine if necessary. func (l *Logger) mill() { l.startMill.Do(func() { - l.millCh = make(chan struct{}, 1) + l.millCh = make(chan struct{}) go l.millRun() }) - select { - case l.millCh <- struct{}{}: - default: - } + l.millCh <- struct{}{} } // oldLogFiles returns the list of backup log files stored in the same diff --git a/lumberjack_test.go b/lumberjack_test.go index f89756c..e678b8a 100644 --- a/lumberjack_test.go +++ b/lumberjack_test.go @@ -8,6 +8,8 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" + "strings" "testing" "time" ) @@ -770,3 +772,83 @@ func exists(path string, t testing.TB) { _, err := os.Stat(path) assertUp(err == nil, t, 1, "expected file to exist, but got error from os.Stat: %v", err) } + +func TestClose(t *testing.T) { + tmp, err := os.MkdirTemp("", "") + assertUp(err == nil, t, 1, "expected to create temp dir but failed with error:%v", err) + defer os.RemoveAll(tmp) + runtime.GC() + grs := runtime.NumGoroutine() + tmpfile := filepath.Join(tmp, "tmp.log") + for i := 0; i < 1000; i++ { + logger := Logger{ + Filename: tmpfile, + MaxSize: 1, + MaxBackups: 1, + Compress: true, + } + logger.Write([]byte(fmt.Sprintf("%d\n", i))) + logger.Close() + } + runtime.GC() + grs2 := runtime.NumGoroutine() + assertUp(grs == grs2, t, 1, "expected goroutine number %d but got %d", grs, grs2) +} + +func TestCloseLargeFile(t *testing.T) { + tmp, err := os.MkdirTemp("", "") + assertUp(err == nil, t, 1, "expected to create temp dir but failed with error:%v", err) + defer os.RemoveAll(tmp) + runtime.GC() + grs := runtime.NumGoroutine() + + content := repeatCharString("*", 1024*1025) + for i := 0; i < 100; i++ { + tmpfile := filepath.Join(tmp, fmt.Sprintf("tmp_%d.log", i)) + f, err := os.Create(tmpfile) + assertUp(err == nil, t, 1, "expected create tmp file but got err :%v", err) + _, err = f.WriteString(content) + assertUp(err == nil, t, 1, "expected write tmp file but got err :%v", err) + err = f.Close() + assertUp(err == nil, t, 1, "expected close tmp file but got err :%v", err) + logger := Logger{ + Filename: tmpfile, + MaxSize: 1, + MaxBackups: 101, + Compress: true, + } + err = logger.Rotate() + assertUp(err == nil, t, 1, "expected Rotate logger but got err :%v", err) + err = logger.Close() + assertUp(err == nil, t, 1, "expected close logger but got err :%v", err) + } + time.Sleep(time.Second * 5) + count := getDirFileCount(tmp, ".log.gz") + assertUp(count == 100, t, 1, "expected log.gz file 100 but got %d", count) + runtime.GC() + grs2 := runtime.NumGoroutine() + assertUp(grs == grs2, t, 1, "expected goroutine number %d but got %d", grs, grs2) +} + +func repeatCharString(cs string, repeat int) string { + var builder strings.Builder + builder.Grow(len(cs) * repeat) + for i := 0; i < repeat; i++ { + builder.WriteString(cs) + } + return builder.String() +} +func getDirFileCount(dir string, suffix string) (num int) { + if fs, err := os.ReadDir(dir); err == nil { + for _, entry := range fs { + if entry.IsDir() { + num += getDirFileCount(filepath.Join(dir, entry.Name()), suffix) + } else { + if suffix == "" || strings.HasSuffix(entry.Name(), suffix) { + num++ + } + } + } + } + return +} From 39f1a614b0442a284f9f410fd639f0348e8f73cd Mon Sep 17 00:00:00 2001 From: RainyBow Date: Fri, 19 Jul 2024 10:52:00 +0800 Subject: [PATCH 8/8] fix-bug: millRun block on select --- lumberjack.go | 11 ++++------- lumberjack_test.go | 1 - 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lumberjack.go b/lumberjack.go index 2dbca49..f81054a 100644 --- a/lumberjack.go +++ b/lumberjack.go @@ -3,7 +3,7 @@ // Note that this is v2.0 of lumberjack, and should be imported using gopkg.in // thusly: // -// import "gopkg.in/natefinch/lumberjack.v2" +// import "gopkg.in/natefinch/lumberjack.v2" // // The package name remains simply lumberjack, and the code resides at // https://github.com/natefinch/lumberjack under the v2.0 branch. @@ -66,7 +66,7 @@ var _ io.WriteCloser = (*Logger)(nil) // `/var/log/foo/server.log`, a backup created at 6:30pm on Nov 11 2016 would // use the filename `/var/log/foo/server-2016-11-04T18-30-00.000.log` // -// Cleaning Up Old Log Files +// # Cleaning Up Old Log Files // // Whenever a new logfile gets created, old log files may be deleted. The most // recent files according to the encoded timestamp will be retained, up to a @@ -171,12 +171,8 @@ func (l *Logger) Close() error { l.mu.Lock() defer l.mu.Unlock() l.closed = true - if l.millCh != nil { - close(l.millCh) - l.millCh = nil - } if l.closeCh == nil { - l.closeCh = make(chan struct{}, 2) + l.closeCh <- struct{}{} } return l.close() @@ -408,6 +404,7 @@ func (l *Logger) millRun() { func (l *Logger) mill() { l.startMill.Do(func() { l.millCh = make(chan struct{}) + l.closeCh = make(chan struct{}) go l.millRun() }) l.millCh <- struct{}{} diff --git a/lumberjack_test.go b/lumberjack_test.go index e678b8a..480a7df 100644 --- a/lumberjack_test.go +++ b/lumberjack_test.go @@ -822,7 +822,6 @@ func TestCloseLargeFile(t *testing.T) { err = logger.Close() assertUp(err == nil, t, 1, "expected close logger but got err :%v", err) } - time.Sleep(time.Second * 5) count := getDirFileCount(tmp, ".log.gz") assertUp(count == 100, t, 1, "expected log.gz file 100 but got %d", count) runtime.GC()