feat: add log debug level (#2411)
This commit is contained in:
@@ -7,7 +7,7 @@ type LogConf struct {
|
|||||||
Encoding string `json:",default=json,options=[json,plain]"`
|
Encoding string `json:",default=json,options=[json,plain]"`
|
||||||
TimeFormat string `json:",optional"`
|
TimeFormat string `json:",optional"`
|
||||||
Path string `json:",default=logs"`
|
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"`
|
Compress bool `json:",optional"`
|
||||||
KeepDays int `json:",optional"`
|
KeepDays int `json:",optional"`
|
||||||
StackCooldownMillis int `json:",default=100"`
|
StackCooldownMillis int `json:",default=100"`
|
||||||
|
|||||||
@@ -7,6 +7,14 @@ import (
|
|||||||
|
|
||||||
// A Logger represents a logger.
|
// A Logger represents a logger.
|
||||||
type Logger interface {
|
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 logs a message at error level.
|
||||||
Error(...interface{})
|
Error(...interface{})
|
||||||
// Errorf logs a message at error level.
|
// Errorf logs a message at error level.
|
||||||
|
|||||||
@@ -64,6 +64,26 @@ func Close() error {
|
|||||||
return nil
|
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.
|
// Disable disables the logging.
|
||||||
func Disable() {
|
func Disable() {
|
||||||
atomic.StoreUint32(&disableLog, 1)
|
atomic.StoreUint32(&disableLog, 1)
|
||||||
@@ -352,6 +372,8 @@ func handleOptions(opts []LogOption) {
|
|||||||
|
|
||||||
func setupLogLevel(c LogConf) {
|
func setupLogLevel(c LogConf) {
|
||||||
switch c.Level {
|
switch c.Level {
|
||||||
|
case levelDebug:
|
||||||
|
SetLevel(DebugLevel)
|
||||||
case levelInfo:
|
case levelInfo:
|
||||||
SetLevel(InfoLevel)
|
SetLevel(InfoLevel)
|
||||||
case levelError:
|
case levelError:
|
||||||
@@ -392,6 +414,12 @@ func shallLogStat() bool {
|
|||||||
return atomic.LoadUint32(&disableStat) == 0
|
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) {
|
func writeError(val interface{}, fields ...LogField) {
|
||||||
if shallLog(ErrorLevel) {
|
if shallLog(ErrorLevel) {
|
||||||
getWriter().Error(val, addCaller(fields...)...)
|
getWriter().Error(val, addCaller(fields...)...)
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ func (mw *mockWriter) Alert(v interface{}) {
|
|||||||
output(&mw.builder, levelAlert, v)
|
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) {
|
func (mw *mockWriter) Error(v interface{}, fields ...LogField) {
|
||||||
mw.lock.Lock()
|
mw.lock.Lock()
|
||||||
defer mw.lock.Unlock()
|
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) {
|
func TestStructedLogError(t *testing.T) {
|
||||||
w := new(mockWriter)
|
w := new(mockWriter)
|
||||||
old := writer.Swap(w)
|
old := writer.Swap(w)
|
||||||
|
|||||||
@@ -40,6 +40,22 @@ type richLogger struct {
|
|||||||
fields []LogField
|
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{}) {
|
func (l *richLogger) Error(v ...interface{}) {
|
||||||
l.err(fmt.Sprint(v...))
|
l.err(fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
@@ -135,6 +151,12 @@ func (l *richLogger) buildFields(fields ...LogField) []LogField {
|
|||||||
return fields
|
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) {
|
func (l *richLogger) err(v interface{}, fields ...LogField) {
|
||||||
if shallLog(ErrorLevel) {
|
if shallLog(ErrorLevel) {
|
||||||
getWriter().Error(v, l.buildFields(fields...)...)
|
getWriter().Error(v, l.buildFields(fields...)...)
|
||||||
|
|||||||
@@ -37,6 +37,41 @@ func TestTraceLog(t *testing.T) {
|
|||||||
validate(t, w.String(), true, true)
|
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) {
|
func TestTraceError(t *testing.T) {
|
||||||
w := new(mockWriter)
|
w := new(mockWriter)
|
||||||
old := writer.Swap(w)
|
old := writer.Swap(w)
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package logx
|
|||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// InfoLevel logs everything
|
// DebugLevel logs everything
|
||||||
InfoLevel uint32 = iota
|
DebugLevel uint32 = iota
|
||||||
|
// InfoLevel does not include debugs
|
||||||
|
InfoLevel
|
||||||
// ErrorLevel includes errors, slows, stacks
|
// ErrorLevel includes errors, slows, stacks
|
||||||
ErrorLevel
|
ErrorLevel
|
||||||
// SevereLevel only log severe messages
|
// SevereLevel only log severe messages
|
||||||
@@ -37,6 +39,7 @@ const (
|
|||||||
levelFatal = "fatal"
|
levelFatal = "fatal"
|
||||||
levelSlow = "slow"
|
levelSlow = "slow"
|
||||||
levelStat = "stat"
|
levelStat = "stat"
|
||||||
|
levelDebug = "debug"
|
||||||
|
|
||||||
backupFileDelimiter = "-"
|
backupFileDelimiter = "-"
|
||||||
flags = 0x0
|
flags = 0x0
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type (
|
|||||||
Writer interface {
|
Writer interface {
|
||||||
Alert(v interface{})
|
Alert(v interface{})
|
||||||
Close() error
|
Close() error
|
||||||
|
Debug(v interface{}, fields ...LogField)
|
||||||
Error(v interface{}, fields ...LogField)
|
Error(v interface{}, fields ...LogField)
|
||||||
Info(v interface{}, fields ...LogField)
|
Info(v interface{}, fields ...LogField)
|
||||||
Severe(v interface{})
|
Severe(v interface{})
|
||||||
@@ -194,6 +195,10 @@ func (w *concreteWriter) Close() error {
|
|||||||
return w.statLog.Close()
|
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) {
|
func (w *concreteWriter) Error(v interface{}, fields ...LogField) {
|
||||||
output(w.errorLog, levelError, v, fields...)
|
output(w.errorLog, levelError, v, fields...)
|
||||||
}
|
}
|
||||||
@@ -227,6 +232,9 @@ func (n nopWriter) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n nopWriter) Debug(_ interface{}, _ ...LogField) {
|
||||||
|
}
|
||||||
|
|
||||||
func (n nopWriter) Error(_ interface{}, _ ...LogField) {
|
func (n nopWriter) Error(_ interface{}, _ ...LogField) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user