diff --git a/core/logx/config.go b/core/logx/config.go index eb79f4ee..dd96b6eb 100644 --- a/core/logx/config.go +++ b/core/logx/config.go @@ -7,7 +7,7 @@ type LogConf struct { Encoding string `json:",default=json,options=[json,plain]"` TimeFormat string `json:",optional"` Path string `json:",default=logs"` - Level string `json:",default=info,options=[info,error,severe]"` + Level string `json:",default=info,options=[debug,info,error,severe]"` Compress bool `json:",optional"` KeepDays int `json:",optional"` StackCooldownMillis int `json:",default=100"` diff --git a/core/logx/logger.go b/core/logx/logger.go index ca690766..ddb4ada7 100644 --- a/core/logx/logger.go +++ b/core/logx/logger.go @@ -7,6 +7,14 @@ import ( // A Logger represents a logger. type Logger interface { + // Debug logs a message at info level. + Debug(...interface{}) + // Debugf logs a message at info level. + Debugf(string, ...interface{}) + // Debugv logs a message at info level. + Debugv(interface{}) + // Debugw logs a message at info level. + Debugw(string, ...LogField) // Error logs a message at error level. Error(...interface{}) // Errorf logs a message at error level. diff --git a/core/logx/logs.go b/core/logx/logs.go index 28fd5c06..621b1ee3 100644 --- a/core/logx/logs.go +++ b/core/logx/logs.go @@ -64,6 +64,26 @@ func Close() error { return nil } +// Debug writes v into access log. +func Debug(v ...interface{}) { + writeDebug(fmt.Sprint(v...)) +} + +// Debugf writes v with format into access log. +func Debugf(format string, v ...interface{}) { + writeDebug(fmt.Sprintf(format, v...)) +} + +// Debugv writes v into access log with json content. +func Debugv(v interface{}) { + writeDebug(v) +} + +// Debugw writes msg along with fields into access log. +func Debugw(msg string, fields ...LogField) { + writeDebug(msg, fields...) +} + // Disable disables the logging. func Disable() { atomic.StoreUint32(&disableLog, 1) @@ -352,6 +372,8 @@ func handleOptions(opts []LogOption) { func setupLogLevel(c LogConf) { switch c.Level { + case levelDebug: + SetLevel(DebugLevel) case levelInfo: SetLevel(InfoLevel) case levelError: @@ -392,6 +414,12 @@ func shallLogStat() bool { return atomic.LoadUint32(&disableStat) == 0 } +func writeDebug(val interface{}, fields ...LogField) { + if shallLog(DebugLevel) { + getWriter().Debug(val, addCaller(fields...)...) + } +} + func writeError(val interface{}, fields ...LogField) { if shallLog(ErrorLevel) { getWriter().Error(val, addCaller(fields...)...) diff --git a/core/logx/logs_test.go b/core/logx/logs_test.go index 3be37648..70ec4c7f 100644 --- a/core/logx/logs_test.go +++ b/core/logx/logs_test.go @@ -35,6 +35,12 @@ func (mw *mockWriter) Alert(v interface{}) { output(&mw.builder, levelAlert, v) } +func (mw *mockWriter) Debug(v interface{}, fields ...LogField) { + mw.lock.Lock() + defer mw.lock.Unlock() + output(&mw.builder, levelDebug, v, fields...) +} + func (mw *mockWriter) Error(v interface{}, fields ...LogField) { mw.lock.Lock() defer mw.lock.Unlock() @@ -212,6 +218,46 @@ func TestStructedLogAlert(t *testing.T) { }) } +func TestStructedLogDebug(t *testing.T) { + w := new(mockWriter) + old := writer.Swap(w) + defer writer.Store(old) + + doTestStructedLog(t, levelDebug, w, func(v ...interface{}) { + Debug(v...) + }) +} + +func TestStructedLogDebugf(t *testing.T) { + w := new(mockWriter) + old := writer.Swap(w) + defer writer.Store(old) + + doTestStructedLog(t, levelDebug, w, func(v ...interface{}) { + Debugf(fmt.Sprint(v...)) + }) +} + +func TestStructedLogDebugv(t *testing.T) { + w := new(mockWriter) + old := writer.Swap(w) + defer writer.Store(old) + + doTestStructedLog(t, levelDebug, w, func(v ...interface{}) { + Debugv(fmt.Sprint(v...)) + }) +} + +func TestStructedLogDebugw(t *testing.T) { + w := new(mockWriter) + old := writer.Swap(w) + defer writer.Store(old) + + doTestStructedLog(t, levelDebug, w, func(v ...interface{}) { + Debugw(fmt.Sprint(v...), Field("foo", time.Second)) + }) +} + func TestStructedLogError(t *testing.T) { w := new(mockWriter) old := writer.Swap(w) diff --git a/core/logx/richlogger.go b/core/logx/richlogger.go index de52a80e..f73fddf9 100644 --- a/core/logx/richlogger.go +++ b/core/logx/richlogger.go @@ -40,6 +40,22 @@ type richLogger struct { fields []LogField } +func (l *richLogger) Debug(v ...interface{}) { + l.debug(fmt.Sprint(v...)) +} + +func (l *richLogger) Debugf(format string, v ...interface{}) { + l.debug(fmt.Sprintf(format, v...)) +} + +func (l *richLogger) Debugv(v interface{}) { + l.debug(v) +} + +func (l *richLogger) Debugw(msg string, fields ...LogField) { + l.debug(msg, fields...) +} + func (l *richLogger) Error(v ...interface{}) { l.err(fmt.Sprint(v...)) } @@ -135,6 +151,12 @@ func (l *richLogger) buildFields(fields ...LogField) []LogField { return fields } +func (l *richLogger) debug(v interface{}, fields ...LogField) { + if shallLog(DebugLevel) { + getWriter().Debug(v, l.buildFields(fields...)...) + } +} + func (l *richLogger) err(v interface{}, fields ...LogField) { if shallLog(ErrorLevel) { getWriter().Error(v, l.buildFields(fields...)...) diff --git a/core/logx/richlogger_test.go b/core/logx/richlogger_test.go index 08777752..7cf373a5 100644 --- a/core/logx/richlogger_test.go +++ b/core/logx/richlogger_test.go @@ -37,6 +37,41 @@ func TestTraceLog(t *testing.T) { validate(t, w.String(), true, true) } +func TestTraceDebug(t *testing.T) { + w := new(mockWriter) + old := writer.Swap(w) + writer.lock.RLock() + defer func() { + writer.lock.RUnlock() + writer.Store(old) + }() + + otp := otel.GetTracerProvider() + tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample())) + otel.SetTracerProvider(tp) + defer otel.SetTracerProvider(otp) + + ctx, span := tp.Tracer("foo").Start(context.Background(), "bar") + defer span.End() + + l := WithContext(ctx) + SetLevel(DebugLevel) + l.WithDuration(time.Second).Debug(testlog) + assert.True(t, strings.Contains(w.String(), traceKey)) + assert.True(t, strings.Contains(w.String(), spanKey)) + w.Reset() + l.WithDuration(time.Second).Debugf(testlog) + validate(t, w.String(), true, true) + w.Reset() + l.WithDuration(time.Second).Debugv(testlog) + validate(t, w.String(), true, true) + w.Reset() + l.WithDuration(time.Second).Debugw(testlog, Field("foo", "bar")) + validate(t, w.String(), true, true) + assert.True(t, strings.Contains(w.String(), "foo"), w.String()) + assert.True(t, strings.Contains(w.String(), "bar"), w.String()) +} + func TestTraceError(t *testing.T) { w := new(mockWriter) old := writer.Swap(w) diff --git a/core/logx/vars.go b/core/logx/vars.go index 26c4fd84..b95c3215 100644 --- a/core/logx/vars.go +++ b/core/logx/vars.go @@ -3,8 +3,10 @@ package logx import "errors" const ( - // InfoLevel logs everything - InfoLevel uint32 = iota + // DebugLevel logs everything + DebugLevel uint32 = iota + // InfoLevel does not include debugs + InfoLevel // ErrorLevel includes errors, slows, stacks ErrorLevel // SevereLevel only log severe messages @@ -37,6 +39,7 @@ const ( levelFatal = "fatal" levelSlow = "slow" levelStat = "stat" + levelDebug = "debug" backupFileDelimiter = "-" flags = 0x0 diff --git a/core/logx/writer.go b/core/logx/writer.go index 5f372566..16e96976 100644 --- a/core/logx/writer.go +++ b/core/logx/writer.go @@ -18,6 +18,7 @@ type ( Writer interface { Alert(v interface{}) Close() error + Debug(v interface{}, fields ...LogField) Error(v interface{}, fields ...LogField) Info(v interface{}, fields ...LogField) Severe(v interface{}) @@ -194,6 +195,10 @@ func (w *concreteWriter) Close() error { return w.statLog.Close() } +func (w *concreteWriter) Debug(v interface{}, fields ...LogField) { + output(w.infoLog, levelDebug, v, fields...) +} + func (w *concreteWriter) Error(v interface{}, fields ...LogField) { output(w.errorLog, levelError, v, fields...) } @@ -227,6 +232,9 @@ func (n nopWriter) Close() error { return nil } +func (n nopWriter) Debug(_ interface{}, _ ...LogField) { +} + func (n nopWriter) Error(_ interface{}, _ ...LogField) { }