diff --git a/pkg/infrastructure/logs/accesslog.go b/pkg/infrastructure/logs/access_log.go similarity index 95% rename from pkg/infrastructure/logs/accesslog.go rename to pkg/infrastructure/logs/access_log.go index 1be711d8..10455fe9 100644 --- a/pkg/infrastructure/logs/accesslog.go +++ b/pkg/infrastructure/logs/access_log.go @@ -63,7 +63,17 @@ func disableEscapeHTML(i interface{}) { // AccessLog - Format and print access log. func AccessLog(r *AccessLogRecord, format string) { - var msg string + msg := r.format(format) + lm := &LogMsg{ + Msg: strings.TrimSpace(msg), + When: time.Now(), + Level: levelLoggerImpl, + } + beeLogger.writeMsg(lm) +} + +func (r *AccessLogRecord) format(format string) string { + msg := "" switch format { case apacheFormat: timeFormatted := r.RequestTime.Format("02/Jan/2006 03:04:05") @@ -79,10 +89,5 @@ func AccessLog(r *AccessLogRecord, format string) { msg = string(jsonData) } } - lm := &LogMsg{ - Msg: strings.TrimSpace(msg), - When: time.Now(), - Level: levelLoggerImpl, - } - beeLogger.writeMsg(lm) + return msg } diff --git a/pkg/infrastructure/logs/access_log_test.go b/pkg/infrastructure/logs/access_log_test.go new file mode 100644 index 00000000..f78a00a0 --- /dev/null +++ b/pkg/infrastructure/logs/access_log_test.go @@ -0,0 +1,38 @@ +// Copyright 2020 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package logs + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestAccessLog_format(t *testing.T) { + alc := &AccessLogRecord{ + RequestTime: time.Date(2020, 9, 19, 21, 21, 21, 11, time.UTC), + } + + res := alc.format(apacheFormat) + println(res) + assert.Equal(t, " - - [19/Sep/2020 09:21:21] \" 0 0\" 0.000000 ", res) + + res = alc.format(jsonFormat) + assert.Equal(t, + "{\"remote_addr\":\"\",\"request_time\":\"2020-09-19T21:21:21.000000011Z\",\"request_method\":\"\",\"request\":\"\",\"server_protocol\":\"\",\"host\":\"\",\"status\":0,\"body_bytes_sent\":0,\"elapsed_time\":0,\"http_referrer\":\"\",\"http_user_agent\":\"\",\"remote_user\":\"\"}\n", res) + + AccessLog(alc, jsonFormat) +} diff --git a/pkg/infrastructure/logs/conn_test.go b/pkg/infrastructure/logs/conn_test.go index bb377d41..ca9ea1c7 100644 --- a/pkg/infrastructure/logs/conn_test.go +++ b/pkg/infrastructure/logs/conn_test.go @@ -18,6 +18,9 @@ import ( "net" "os" "testing" + "time" + + "github.com/stretchr/testify/assert" ) // ConnTCPListener takes a TCP listener and accepts n TCP connections @@ -45,6 +48,7 @@ func TestConn(t *testing.T) { log.Informational("informational") } +// need to rewrite this test, it's not stable func TestReconnect(t *testing.T) { // Setup connection listener newConns := make(chan net.Conn) @@ -77,3 +81,17 @@ func TestReconnect(t *testing.T) { t.Error("Did not reconnect") } } + +func TestConnWriter_Format(t *testing.T) { + lg := &LogMsg{ + Level: LevelDebug, + Msg: "Hello, world", + When: time.Date(2020, 9, 19, 20, 12, 37, 9, time.UTC), + FilePath: "/user/home/main.go", + LineNumber: 13, + Prefix: "Cus", + } + cw := NewConn().(*connWriter) + res := cw.Format(lg) + assert.Equal(t, "[D] Cus Hello, world", res) +} diff --git a/pkg/infrastructure/logs/console.go b/pkg/infrastructure/logs/console.go index f99ef11b..66e2c7ea 100644 --- a/pkg/infrastructure/logs/console.go +++ b/pkg/infrastructure/logs/console.go @@ -59,7 +59,7 @@ type consoleWriter struct { func (c *consoleWriter) Format(lm *LogMsg) string { msg := lm.OldStyleFormat() if c.Colorful { - msg = strings.Replace(lm.Msg, levelPrefix[lm.Level], colors[lm.Level](levelPrefix[lm.Level]), 1) + msg = strings.Replace(msg, levelPrefix[lm.Level], colors[lm.Level](levelPrefix[lm.Level]), 1) } h, _, _ := formatTimeHeader(lm.When) bytes := append(append(h, msg...), '\n') @@ -72,6 +72,10 @@ func (c *consoleWriter) SetFormatter(f LogFormatter) { // NewConsole creates ConsoleWriter returning as LoggerInterface. func NewConsole() Logger { + return newConsole() +} + +func newConsole() *consoleWriter { cw := &consoleWriter{ lg: newLogWriter(ansicolor.NewAnsiColorWriter(os.Stdout)), Level: LevelDebug, diff --git a/pkg/infrastructure/logs/console_test.go b/pkg/infrastructure/logs/console_test.go index 4bc45f57..e345ba40 100644 --- a/pkg/infrastructure/logs/console_test.go +++ b/pkg/infrastructure/logs/console_test.go @@ -17,6 +17,8 @@ package logs import ( "testing" "time" + + "github.com/stretchr/testify/assert" ) // Try each log level in decreasing order of priority. @@ -62,3 +64,19 @@ func TestConsoleAsync(t *testing.T) { time.Sleep(1 * time.Millisecond) } } + +func TestFormat(t *testing.T) { + log := newConsole() + lm := &LogMsg{ + Level: LevelDebug, + Msg: "Hello, world", + When: time.Date(2020, 9, 19, 20, 12, 37, 9, time.UTC), + FilePath: "/user/home/main.go", + LineNumber: 13, + Prefix: "Cus", + } + res := log.Format(lm) + assert.Equal(t, "2020/09/19 20:12:37.000 \x1b[1;44m[D]\x1b[0m Cus Hello, world\n", res) + err := log.WriteMsg(lm) + assert.Nil(t, err) +} diff --git a/pkg/infrastructure/logs/file_test.go b/pkg/infrastructure/logs/file_test.go index 494d0a9e..6612ebe6 100644 --- a/pkg/infrastructure/logs/file_test.go +++ b/pkg/infrastructure/logs/file_test.go @@ -22,6 +22,8 @@ import ( "strconv" "testing" "time" + + "github.com/stretchr/testify/assert" ) func TestFilePerm(t *testing.T) { @@ -428,3 +430,18 @@ func BenchmarkFileOnGoroutine(b *testing.B) { } os.Remove("test4.log") } + +func TestFileLogWriter_Format(t *testing.T) { + lg := &LogMsg{ + Level: LevelDebug, + Msg: "Hello, world", + When: time.Date(2020, 9, 19, 20, 12, 37, 9, time.UTC), + FilePath: "/user/home/main.go", + LineNumber: 13, + Prefix: "Cus", + } + + fw := newFileWriter().(*fileLogWriter) + res := fw.Format(lg) + assert.Equal(t, "2020/09/19 20:12:37.000 [D] Cus Hello, world\n", res) +} diff --git a/pkg/infrastructure/logs/formatter_test.go b/pkg/infrastructure/logs/formatter_test.go index f9320b8d..a97765ac 100644 --- a/pkg/infrastructure/logs/formatter_test.go +++ b/pkg/infrastructure/logs/formatter_test.go @@ -1,11 +1,78 @@ +// Copyright 2020 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package logs import ( + "encoding/json" + "errors" "strconv" "testing" "time" + + "github.com/stretchr/testify/assert" ) +type CustomFormatter struct{} + +func (c *CustomFormatter) Format(lm *LogMsg) string { + return "hello, msg: " + lm.Msg +} + +type TestLogger struct { + Formatter string `json:"formatter"` + Expected string + formatter LogFormatter +} + +func (t *TestLogger) Init(config string) error { + er := json.Unmarshal([]byte(config), t) + t.formatter, _ = GetFormatter(t.Formatter) + return er +} + +func (t *TestLogger) WriteMsg(lm *LogMsg) error { + msg := t.formatter.Format(lm) + if msg != t.Expected { + return errors.New("not equal") + } + return nil +} + +func (t *TestLogger) Destroy() { + panic("implement me") +} + +func (t *TestLogger) Flush() { + panic("implement me") +} + +func (t *TestLogger) SetFormatter(f LogFormatter) { + panic("implement me") +} + +func TestCustomFormatter(t *testing.T) { + RegisterFormatter("custom", &CustomFormatter{}) + tl := &TestLogger{ + Expected: "hello, msg: world", + } + assert.Nil(t, tl.Init(`{"formatter": "custom"}`)) + assert.Nil(t, tl.WriteMsg(&LogMsg{ + Msg: "world", + })) +} + func TestPatternLogFormatter(t *testing.T) { tes := &PatternLogFormatter{ Pattern: "%F:%n|%w%t>> %m", diff --git a/pkg/infrastructure/logs/jianliao.go b/pkg/infrastructure/logs/jianliao.go index 9757a7d5..c82a0957 100644 --- a/pkg/infrastructure/logs/jianliao.go +++ b/pkg/infrastructure/logs/jianliao.go @@ -44,7 +44,9 @@ func (s *JLWriter) Init(config string) error { } func (s *JLWriter) Format(lm *LogMsg) string { - return lm.OldStyleFormat() + msg := lm.OldStyleFormat() + msg = fmt.Sprintf("%s %s", lm.When.Format("2006-01-02 15:04:05"), msg) + return msg } func (s *JLWriter) SetFormatter(f LogFormatter) { diff --git a/pkg/infrastructure/logs/jianliao_test.go b/pkg/infrastructure/logs/jianliao_test.go new file mode 100644 index 00000000..a1b2d076 --- /dev/null +++ b/pkg/infrastructure/logs/jianliao_test.go @@ -0,0 +1,36 @@ +// Copyright 2020 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package logs + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestJLWriter_Format(t *testing.T) { + lg := &LogMsg{ + Level: LevelDebug, + Msg: "Hello, world", + When: time.Date(2020, 9, 19, 20, 12, 37, 9, time.UTC), + FilePath: "/user/home/main.go", + LineNumber: 13, + Prefix: "Cus", + } + jl := newJLWriter().(*JLWriter) + res := jl.Format(lg) + assert.Equal(t, "2020-09-19 20:12:37 [D] Cus Hello, world", res) +} diff --git a/pkg/infrastructure/logs/log.go b/pkg/infrastructure/logs/log.go index 480cecab..cec8d51d 100644 --- a/pkg/infrastructure/logs/log.go +++ b/pkg/infrastructure/logs/log.go @@ -37,7 +37,6 @@ import ( "fmt" "log" "os" - "path" "runtime" "strings" "sync" @@ -135,18 +134,6 @@ type nameLogger struct { name string } -type LogMsg struct { - Level int - Msg string - When time.Time - FilePath string - LineNumber int - Args []interface{} - Prefix string - enableFullFilePath bool - enableFuncCallDepth bool -} - var logMsgPool *sync.Pool // NewLogger returns a new BeeLogger. @@ -187,27 +174,6 @@ func (bl *BeeLogger) Async(msgLen ...int64) *BeeLogger { return bl } -// OldStyleFormat you should never invoke this -func (lm *LogMsg) OldStyleFormat() string { - msg := lm.Msg - - if len(lm.Args) > 0 { - lm.Msg = fmt.Sprintf(lm.Msg, lm.Args...) - } - - msg = lm.Prefix + " " + msg - - if lm.enableFuncCallDepth { - if !lm.enableFullFilePath { - _, lm.FilePath = path.Split(lm.FilePath) - } - msg = fmt.Sprintf("[%s:%d] %s", lm.FilePath, lm.LineNumber, msg) - } - - msg = levelPrefix[lm.Level] + " " + msg - return msg -} - // SetLogger provides a given logger adapter into BeeLogger with config string. // config must in in JSON format like {"interval":360}} func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error { diff --git a/pkg/infrastructure/logs/log_msg.go b/pkg/infrastructure/logs/log_msg.go new file mode 100644 index 00000000..f96fa72f --- /dev/null +++ b/pkg/infrastructure/logs/log_msg.go @@ -0,0 +1,55 @@ +// Copyright 2020 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package logs + +import ( + "fmt" + "path" + "time" +) + +type LogMsg struct { + Level int + Msg string + When time.Time + FilePath string + LineNumber int + Args []interface{} + Prefix string + enableFullFilePath bool + enableFuncCallDepth bool +} + +// OldStyleFormat you should never invoke this +func (lm *LogMsg) OldStyleFormat() string { + msg := lm.Msg + + if len(lm.Args) > 0 { + lm.Msg = fmt.Sprintf(lm.Msg, lm.Args...) + } + + msg = lm.Prefix + " " + msg + + if lm.enableFuncCallDepth { + filePath := lm.FilePath + if !lm.enableFullFilePath { + _, filePath = path.Split(filePath) + } + msg = fmt.Sprintf("[%s:%d] %s", filePath, lm.LineNumber, msg) + } + + msg = levelPrefix[lm.Level] + " " + msg + return msg +} diff --git a/pkg/infrastructure/logs/log_msg_test.go b/pkg/infrastructure/logs/log_msg_test.go new file mode 100644 index 00000000..f213ed42 --- /dev/null +++ b/pkg/infrastructure/logs/log_msg_test.go @@ -0,0 +1,44 @@ +// Copyright 2020 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package logs + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestLogMsg_OldStyleFormat(t *testing.T) { + lg := &LogMsg{ + Level: LevelDebug, + Msg: "Hello, world", + When: time.Date(2020, 9, 19, 20, 12, 37, 9, time.UTC), + FilePath: "/user/home/main.go", + LineNumber: 13, + Prefix: "Cus", + } + res := lg.OldStyleFormat() + assert.Equal(t, "[D] Cus Hello, world", res) + + lg.enableFuncCallDepth = true + res = lg.OldStyleFormat() + assert.Equal(t, "[D] [main.go:13] Cus Hello, world", res) + + lg.enableFullFilePath = true + + res = lg.OldStyleFormat() + assert.Equal(t, "[D] [/user/home/main.go:13] Cus Hello, world", res) +} diff --git a/pkg/infrastructure/logs/log_test.go b/pkg/infrastructure/logs/log_test.go new file mode 100644 index 00000000..66f59108 --- /dev/null +++ b/pkg/infrastructure/logs/log_test.go @@ -0,0 +1,27 @@ +// Copyright 2020 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package logs + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBeeLogger_DelLogger(t *testing.T) { + prefix := "My-Cus" + l := GetLogger(prefix) + assert.NotNil(t, l) +}