Skip to content

Commit

Permalink
Add the WithTimeFormat function for Logger interface to set the time …
Browse files Browse the repository at this point in the history
…format and return logger self (#16)
  • Loading branch information
mstmdev authored Jun 26, 2023
1 parent 6da419e commit 7e3e279
Show file tree
Hide file tree
Showing 22 changed files with 287 additions and 87 deletions.
17 changes: 16 additions & 1 deletion base_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type baseLogger struct {
lvl level.Level // min log level
f formatter.Formatter
appendTime bool
timeFormat string
}

func (l *baseLogger) Debug(format string, args ...interface{}) {
Expand Down Expand Up @@ -48,7 +49,7 @@ func (l *baseLogger) log(lvl level.Level, format string, args ...interface{}) {

func (l *baseLogger) logWithErr(err error, lvl level.Level, format string, args ...interface{}) {
if checkLogLevel(l.lvl, lvl) {
data, _ := l.f.Serialize(content.NewContent(lvl, err, l.appendTime, format, args...))
data, _ := l.f.Serialize(content.NewContent(lvl, err, l.appendTime, l.timeFormat, format, args...))
l.Log(string(data))
}
}
Expand All @@ -66,6 +67,20 @@ func (l *baseLogger) init(w Writer, lvl level.Level, appendTime bool) {
l.lvl = lvl
l.f = formatter.Default()
l.appendTime = appendTime
l.setTimeFormat(content.DefaultLogTimeFormat)
}

func (l *baseLogger) setFormatter(f formatter.Formatter) {
if f != nil {
l.f = f
}
}

func (l *baseLogger) setTimeFormat(f string) {
if len(f) == 0 {
f = content.DefaultLogTimeFormat
}
l.timeFormat = f
}

func checkLogLevel(lvl level.Level, currentLevel level.Level) bool {
Expand Down
9 changes: 6 additions & 3 deletions console_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ func (l *consoleLogger) Close() error {
}

func (l *consoleLogger) WithFormatter(f formatter.Formatter) Logger {
if f != nil {
l.f = f
}
l.setFormatter(f)
return l
}

func (l *consoleLogger) WithTimeFormat(f string) Logger {
l.setTimeFormat(f)
return l
}
50 changes: 50 additions & 0 deletions console_logger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package log

import (
"testing"

"github.com/no-src/log/formatter"
"github.com/no-src/log/level"
)

func TestConsoleLogger(t *testing.T) {
testCases := []struct {
name string
formatter string
concurrency bool
timeFormat string
}{
{"TextFormatter", formatter.TextFormatter, false, testTimeFormat},
{"JsonFormatter", formatter.JsonFormatter, false, ""},
{"TextFormatter Concurrency", formatter.TextFormatter, true, testTimeFormat},
{"JsonFormatter Concurrency", formatter.JsonFormatter, true, ""},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
InitDefaultLogger(NewConsoleLogger(level.DebugLevel).WithFormatter(formatter.New(tc.formatter)).WithTimeFormat(tc.timeFormat))
defer Close()
if tc.concurrency {
testLogsConcurrency(t, "TestConsoleLogger")
} else {
testLogs(t)
}
})
}
}

func TestConsoleLoggerWithBuffer(t *testing.T) {
testCases := []struct {
name string
formatter string
}{
{"TextFormatter", formatter.TextFormatter},
{"JsonFormatter", formatter.JsonFormatter},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
InitDefaultLogger(newConsoleLoggerWithBuffer(level.DebugLevel, true).WithFormatter(formatter.New(tc.formatter)).WithTimeFormat(testTimeFormat))
defer Close()
testLogs(t)
})
}
}
8 changes: 3 additions & 5 deletions content/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ type Content struct {
}

// NewContent return an instance of Content
func NewContent(lvl level.Level, err error, appendTime bool, log string, args ...interface{}) Content {
func NewContent(lvl level.Level, err error, appendTime bool, timeFormat string, log string, args ...interface{}) Content {
var t *Time
if appendTime {
t = NewTime(time.Now())
t = NewTimeWithFormat(time.Now(), timeFormat)
}
return NewContentWithTime(lvl, err, t, log, args...)
}
Expand All @@ -35,9 +35,7 @@ func NewContentWithTime(lvl level.Level, err error, t *Time, log string, args ..
Time: t,
}
if err != nil {
c.Error = Error{
err: err,
}
c.Error = NewError(err)
}
return c
}
50 changes: 50 additions & 0 deletions content/content_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package content

import (
"io"
"testing"
"time"

"github.com/no-src/log/level"
)

func TestNewContent(t *testing.T) {
testCases := []struct {
name string
err error
appendTime bool
timeFormat string
}{
{"with nil error and no append time", nil, false, time.RFC3339},
{"with error and no append time", io.EOF, false, time.RFC3339},
{"with nil error and append time", nil, true, time.RFC3339},
{"with error and append time", io.EOF, true, time.RFC3339},
{"with empty time format", io.EOF, true, ""},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
c := NewContent(level.DebugLevel, tc.err, tc.appendTime, tc.timeFormat, tc.name)
if c.AppendTime != tc.appendTime {
t.Errorf("test NewContent failed, expect to get %v, but actual get %v", tc.appendTime, c.AppendTime)
return
}
if tc.appendTime && c.Time == nil {
t.Errorf("test NewContent failed, time can't be nil")
return
}

if !tc.appendTime && c.Time != nil {
t.Errorf("test NewContent failed, time should be nil")
return
}

if tc.err != nil && c.Error == nil {
t.Errorf("test NewContent failed, error can't be nil")
}

if tc.err == nil && c.Error != nil {
t.Errorf("test NewContent failed, error should be nil")
}
})
}
}
7 changes: 7 additions & 0 deletions content/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ type Error struct {
err error
}

// NewError return a custom error wrap the real error
func NewError(err error) error {
return Error{
err: err,
}
}

// Error implement interface error
func (e Error) Error() string {
if e.err == nil {
Expand Down
29 changes: 29 additions & 0 deletions content/error_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package content

import (
"io"
"testing"
)

func TestError_MarshalText(t *testing.T) {
testCases := []struct {
name string
err error
expect string
}{
{"with error", io.EOF, "EOF"},
{"with nil error", nil, ""},
}
for _, tc := range testCases {
cErr := NewError(tc.err).(Error)
data, err := cErr.MarshalText()
if err != nil {
t.Errorf("Error.MarshalText error => %v", err)
return
}
actual := string(data)
if tc.expect != actual {
t.Errorf("test Error.MarshalText failed, expect to get %s, but actual get %s", tc.expect, actual)
}
}
}
32 changes: 24 additions & 8 deletions content/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,41 @@ package content
import "time"

const (
// LogTimeFormat the default log time format
LogTimeFormat = "2006-01-02 15:04:05"
// DefaultLogTimeFormat the default log time format
DefaultLogTimeFormat = "2006-01-02 15:04:05"
)

// Time the custom Time for log
type Time time.Time
type Time struct {
time time.Time
format string
}

// NewTime convert time.Time to content.Time pointer with default format
func NewTime(time time.Time) *Time {
return NewTimeWithFormat(time, DefaultLogTimeFormat)
}

// NewTime convert time.Time to content.Time pointer
func NewTime(t time.Time) *Time {
nt := Time(t)
// NewTimeWithFormat convert time.Time to content.Time pointer with custom format
func NewTimeWithFormat(time time.Time, format string) *Time {
nt := Time{
time: time,
format: format,
}
return &nt
}

// MarshalText implement interface encoding.TextMarshaler
func (t Time) MarshalText() (text []byte, err error) {
return []byte(time.Time(t).Format(LogTimeFormat)), nil
return []byte(t.String()), nil
}

// Time convert to time.Time
func (t Time) Time() time.Time {
return time.Time(t)
return t.time
}

// String return a formatted time string
func (t Time) String() string {
return t.Time().Format(t.format)
}
21 changes: 21 additions & 0 deletions content/time_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package content

import (
"testing"
"time"
)

func TestTime_MarshalText(t *testing.T) {
now := time.Now()
expect := now.Format(DefaultLogTimeFormat)
ti := NewTime(time.Now())
data, err := ti.MarshalText()
if err != nil {
t.Errorf("Time.MarshalText error => %v", err)
return
}
actual := string(data)
if expect != actual {
t.Errorf("test Time.MarshalText failed, expect to get %s, but actual get %s", expect, actual)
}
}
4 changes: 4 additions & 0 deletions empty_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ func (l *emptyLogger) Write(p []byte) (n int, err error) {
func (l *emptyLogger) WithFormatter(f formatter.Formatter) Logger {
return l
}

func (l *emptyLogger) WithTimeFormat(f string) Logger {
return l
}
24 changes: 24 additions & 0 deletions empty_logger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package log

import (
"testing"

"github.com/no-src/log/formatter"
)

func TestEmptyLogger(t *testing.T) {
testCases := []struct {
name string
formatter string
}{
{"TextFormatter", formatter.TextFormatter},
{"JsonFormatter", formatter.JsonFormatter},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
InitDefaultLogger(NewEmptyLogger().WithFormatter(formatter.New(tc.formatter)).WithTimeFormat(testTimeFormat))
defer Close()
testLogs(t)
})
}
}
9 changes: 6 additions & 3 deletions file_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,11 @@ func (l *fileLogger) Write(p []byte) (n int, err error) {
}

func (l *fileLogger) WithFormatter(f formatter.Formatter) Logger {
if f != nil {
l.f = f
}
l.setFormatter(f)
return l
}

func (l *fileLogger) WithTimeFormat(f string) Logger {
l.setTimeFormat(f)
return l
}
11 changes: 6 additions & 5 deletions file_logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@ func TestFileLogger(t *testing.T) {
name string
formatter string
concurrency bool
timeFormat string
}{
{"TextFormatter", formatter.TextFormatter, false},
{"JsonFormatter", formatter.JsonFormatter, false},
{"TextFormatter Concurrency", formatter.TextFormatter, true},
{"JsonFormatter Concurrency", formatter.JsonFormatter, true},
{"TextFormatter", formatter.TextFormatter, false, testTimeFormat},
{"JsonFormatter", formatter.JsonFormatter, false, ""},
{"TextFormatter Concurrency", formatter.TextFormatter, true, testTimeFormat},
{"JsonFormatter Concurrency", formatter.JsonFormatter, true, ""},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
fLogger, err := NewFileLogger(level.DebugLevel, "./logs", "ns_"+tc.formatter)
if err != nil {
t.Fatal(err)
}
InitDefaultLogger(fLogger.WithFormatter(formatter.New(tc.formatter)))
InitDefaultLogger(fLogger.WithFormatter(formatter.New(tc.formatter)).WithTimeFormat(tc.timeFormat))
defer Close()
if tc.concurrency {
testLogsConcurrency(t, "TestFileLogger")
Expand Down
2 changes: 1 addition & 1 deletion formatter/json/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func TestJsonFormatter_Serialize(t *testing.T) {
logTime, _ := time.ParseInLocation(content.LogTimeFormat, "2022-06-25 23:59:59", time.UTC)
logTime, _ := time.ParseInLocation(content.DefaultLogTimeFormat, "2022-06-25 23:59:59", time.UTC)
logTimeP := content.NewTime(logTime)

testCases := []struct {
Expand Down
2 changes: 1 addition & 1 deletion formatter/text/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (f *textFormatter) Serialize(c content.Content) ([]byte, error) {
var format = "%s[%s] %s" // [time] [level] content<. error>
var timeSection string
if c.AppendTime && c.Time != nil {
timeSection = fmt.Sprintf("[%s] ", c.Time.Time().Format(content.LogTimeFormat))
timeSection = fmt.Sprintf("[%s] ", c.Time)
}
content := fmt.Sprintf(c.Log, c.Args...)
format = fmt.Sprintf(format, timeSection, c.Level.String(), content)
Expand Down
2 changes: 1 addition & 1 deletion formatter/text/text_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func TestTextFormatter_Serialize(t *testing.T) {
logTime, _ := time.ParseInLocation(content.LogTimeFormat, "2022-06-25 23:59:59", time.UTC)
logTime, _ := time.ParseInLocation(content.DefaultLogTimeFormat, "2022-06-25 23:59:59", time.UTC)
logTimeP := content.NewTime(logTime)

testCases := []struct {
Expand Down
Loading

0 comments on commit 7e3e279

Please sign in to comment.