Skip to content

Commit

Permalink
👔 up: add MustClose(), Close() for quick close logger and add more un…
Browse files Browse the repository at this point in the history
…it tests
  • Loading branch information
inhere committed Jul 28, 2023
1 parent 3a86900 commit 81af6cd
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 26 deletions.
2 changes: 1 addition & 1 deletion common.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ var exitHandlers = make([]func(), 0)
func runExitHandlers() {
defer func() {
if err := recover(); err != nil {
printlnStderr("slog: run exit handler error:", err)
printlnStderr("slog: run exit handler(global) recovered, error:", err)
}
}()

Expand Down
21 changes: 17 additions & 4 deletions common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"testing"

"github.com/gookit/goutil/byteutil"
"github.com/gookit/goutil/dump"
"github.com/gookit/goutil/errorx"
"github.com/gookit/goutil/testutil/assert"
Expand Down Expand Up @@ -122,6 +123,8 @@ func (w *closedBuffer) StringReset() string {
}

type testHandler struct {
slog.FormatterWrapper
byteutil.Buffer
errOnHandle bool
errOnFlush bool
errOnClose bool
Expand All @@ -131,28 +134,38 @@ func newTestHandler() *testHandler {
return &testHandler{}
}

func (h testHandler) IsHandling(_ slog.Level) bool {
func (h *testHandler) IsHandling(_ slog.Level) bool {
return true
}

func (h testHandler) Close() error {
func (h *testHandler) Close() error {
if h.errOnClose {
return errorx.Raw("close error")
}

h.Reset()
return nil
}

func (h testHandler) Flush() error {
func (h *testHandler) Flush() error {
if h.errOnFlush {
return errorx.Raw("flush error")
}

h.Reset()
return nil
}

func (h testHandler) Handle(_ *slog.Record) error {
func (h *testHandler) Handle(r *slog.Record) error {
if h.errOnHandle {
return errorx.Raw("handle error")
}

bs, err := h.Format(r)
if err != nil {
return err
}
h.Write(bs)
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion formatter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func TestTextFormatter_Format(t *testing.T) {
assert.NotContains(t, logTxt, "}}")
}

func TestJSONFormatter(t *testing.T) {
func TestNewJSONFormatter(t *testing.T) {
f := slog.NewJSONFormatter()
f.AddField(slog.FieldKeyTimestamp)

Expand Down
42 changes: 31 additions & 11 deletions logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"sync"
"time"

"github.com/gookit/goutil"
)

// Logger log dispatcher definition.
Expand All @@ -15,6 +17,8 @@ type Logger struct {
mu sync.Mutex
// logger latest error
err error
// mark logger is closed
closed bool

// log handlers for logger
handlers []Handler
Expand Down Expand Up @@ -220,9 +224,7 @@ func (l *Logger) Flush() error { return l.lockAndFlushAll() }

// MustFlush flush logs. will panic on error
func (l *Logger) MustFlush() {
if err := l.lockAndFlushAll(); err != nil {
panic(err)
}
goutil.PanicErr(l.lockAndFlushAll())
}

// FlushAll flushes all the logs and attempts to "sync" their data to disk.
Expand Down Expand Up @@ -251,33 +253,47 @@ func (l *Logger) flushAll() {
})
}

// Close the logger
// MustClose close logger. will panic on error
func (l *Logger) MustClose() {
goutil.PanicErr(l.Close())
}

// Close the logger, will flush all logs and close all handlers
//
// IMPORTANT:
//
// if enable async/buffer mode, please call the Close() before exit.
func (l *Logger) Close() error {
if l.closed {
return nil
}

_ = l.VisitAll(func(handler Handler) error {
// flush logs and then close
if err := handler.Close(); err != nil {
l.err = err
printlnStderr("slog: call handler.Close() error:", err)
}
return nil
})

l.closed = true
return l.err
}

// VisitAll logger handlers
func (l *Logger) VisitAll(fn func(handler Handler) error) error {
for _, handler := range l.handlers {
// you can return nil for ignore error
// TIP: you can return nil for ignore error
if err := fn(handler); err != nil {
return err
}
}
return nil
}

// Reset the logger
// Reset the logger. will reset: handlers, processors, closed=false
func (l *Logger) Reset() {
l.closed = false
l.ResetHandlers()
l.ResetProcessors()
}
Expand Down Expand Up @@ -307,7 +323,7 @@ func (l *Logger) Exit(code int) {
func (l *Logger) runExitHandlers() {
defer func() {
if err := recover(); err != nil {
printlnStderr("slog: run exit handler error:", err)
printlnStderr("slog: run exit handler recovered, error:", err)
}
}()

Expand All @@ -316,14 +332,18 @@ func (l *Logger) runExitHandlers() {
}
}

// DoNothingOnPanicFatal do nothing on panic or fatal level.
// useful on testing.
// DoNothingOnPanicFatal do nothing on panic or fatal level. useful on testing.
func (l *Logger) DoNothingOnPanicFatal() {
l.PanicFunc = DoNothingOnPanic
l.ExitFunc = DoNothingOnExit
}

// LastErr fetch, will clear after read.
// HandlersNum returns the number of handlers
func (l *Logger) HandlersNum() int {
return len(l.handlers)
}

// LastErr fetch, will clear it after read.
func (l *Logger) LastErr() error {
err := l.err
l.err = nil
Expand Down
10 changes: 10 additions & 0 deletions logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func TestLogger_PushHandler(t *testing.T) {
l.MustFlush()

assert.NoErr(t, l.Close())
l.MustClose()
l.Reset()
}

Expand Down Expand Up @@ -111,6 +112,15 @@ func TestLogger_panic(t *testing.T) {
err := l.LastErr()
assert.Err(t, err)
assert.Eq(t, "flush error", err.Error())

h.errOnClose = true
assert.Panics(t, func() {
l.MustClose()
})

err = l.LastErr()
assert.Err(t, err)
assert.Eq(t, "close error", err.Error())
}

func TestLogger_error(t *testing.T) {
Expand Down
28 changes: 28 additions & 0 deletions rotatefile/rotatefile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package rotatefile_test

import (
"fmt"
"log"
"testing"

"github.com/gookit/goutil"
"github.com/gookit/goutil/fsutil"
"github.com/gookit/slog/rotatefile"
)

func TestMain(m *testing.M) {
fmt.Println("TestMain: remove all test files in ./testdata")
goutil.PanicErr(fsutil.RemoveSub("./testdata", fsutil.ExcludeNames(".keep")))
m.Run()
}

func ExampleNewWriter_on_other_logger() {
logFile := "testdata/another_logger.log"
writer, err := rotatefile.NewConfig(logFile).Create()
if err != nil {
panic(err)
}

log.SetOutput(writer)
log.Println("log message")
}
16 changes: 13 additions & 3 deletions slog.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ var std = NewStdLogger()
// Std get std logger
func Std() *SugaredLogger { return std }

// Reset the std logger
// Reset the std logger and reset exit handlers
func Reset() {
ResetExitHandlers(true)
// new std
Expand All @@ -68,9 +68,19 @@ func Configure(fn func(l *SugaredLogger)) { std.Config(fn) }
// SetExitFunc to the std logger
func SetExitFunc(fn func(code int)) { std.ExitFunc = fn }

// Exit runs all the logger exit handlers and then terminates the program using os.Exit(code)
// Exit runs all exit handlers and then terminates the program using os.Exit(code)
func Exit(code int) { std.Exit(code) }

// Close logger, flush and close all handlers.
//
// IMPORTANT: please call Close() before app exit.
func Close() error { return std.Close() }

// MustClose logger, flush and close all handlers.
//
// IMPORTANT: please call Close() before app exit.
func MustClose() { goutil.PanicErr(Close()) }

// Flush log messages
func Flush() error { return std.Flush() }

Expand All @@ -82,7 +92,7 @@ func FlushTimeout(timeout time.Duration) { std.FlushTimeout(timeout) }

// FlushDaemon run flush handle on daemon.
//
// Usage please see ExampleFlushDaemon()
// Usage please see slog_test.ExampleFlushDaemon()
func FlushDaemon(onStops ...func()) {
std.FlushDaemon(onStops...)
}
Expand Down
41 changes: 35 additions & 6 deletions slog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package slog_test

import (
"bytes"
"context"
"errors"
"fmt"
"strconv"
Expand Down Expand Up @@ -101,6 +102,7 @@ func TestFlushTimeout(t *testing.T) {
defer slog.Reset()
slog.Info("print log message")
slog.FlushTimeout(timex.Second * 1)
slog.MustFlush()
}

func TestNewSugaredLogger(t *testing.T) {
Expand Down Expand Up @@ -191,23 +193,50 @@ func printfLogs(msg string, args ...any) {
slog.Fatalf(msg, args...)
}

func TestUseJSONFormat(t *testing.T) {
func TestSetFormatter_jsonFormat(t *testing.T) {
defer slog.Reset()
slog.SetLogLevel(slog.TraceLevel)
slog.SetFormatter(slog.NewJSONFormatter())

slog.Info("info log message")
slog.Warn("warning log message")
th := newTestHandler()
th.SetFormatter(slog.NewJSONFormatter().Configure(func(f *slog.JSONFormatter) {
f.Fields = slog.NoTimeFields
}))
slog.PushHandler(th)

assert.Eq(t, 2, slog.Std().HandlersNum())

slog.Info("info log message1")
slog.Warn("warning log message2")
s := th.ResetGet()
assert.StrContains(t, s, `"level":"INFO"`)
assert.StrContains(t, s, `info log message1`)
assert.StrContains(t, s, `"level":"WARN"`)
assert.StrContains(t, s, `warning log message2`)

slog.WithData(slog.M{
"key0": 134,
"key1": "abc",
}).Infof("info log %s", "message")
s = th.ResetGet()

r := slog.WithFields(slog.M{
"category": "service",
"IP": "127.0.0.1",
})
r.Infof("info %s", "message")
r.Debugf("debug %s", "message")
s = th.ResetGet()

r = slog.WithField("app", "order")
r.Trace("trace message")
r.Println("print message")
s = th.ResetGet()
assert.StrContains(t, s, `"app":"order"`)
assert.StrCount(t, s, `"app":"order"`, 2)

slog.WithContext(context.Background()).Print("print message with ctx")
assert.StrContains(t, th.ResetGet(), "print message with ctx")
}

func TestAddHandler(t *testing.T) {
Expand Down Expand Up @@ -344,7 +373,7 @@ func TestExitHandlerWithError(t *testing.T) {
testutil.RewriteStderr()
slog.Exit(23)
str := testutil.RestoreStderr()
assert.Eq(t, "slog: run exit handler error: test error\n", str)
assert.Eq(t, "slog: run exit handler(global) recovered, error: test error\n", str)
}

func TestLogger_ExitHandlerWithError(t *testing.T) {
Expand All @@ -361,7 +390,7 @@ func TestLogger_ExitHandlerWithError(t *testing.T) {
testutil.RewriteStderr()
l.Exit(23)
str := testutil.RestoreStderr()
assert.Eq(t, "slog: run exit handler error: test error\n", str)
assert.Eq(t, "slog: run exit handler recovered, error: test error\n", str)
}

func TestLogger_PrependExitHandler(t *testing.T) {
Expand All @@ -378,7 +407,7 @@ func TestLogger_PrependExitHandler(t *testing.T) {
testutil.RewriteStderr()
l.Exit(23)
str := testutil.RestoreStderr()
assert.Eq(t, "slog: run exit handler error: test error2\n", str)
assert.Eq(t, "slog: run exit handler recovered, error: test error2\n", str)
}

func TestSugaredLogger_Close(t *testing.T) {
Expand Down

0 comments on commit 81af6cd

Please sign in to comment.