Compare commits
2 Commits
v1.4.1
...
tools/goct
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9138056c01 | ||
|
|
0b1884b6bd |
@@ -1,145 +0,0 @@
|
|||||||
package logx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/timex"
|
|
||||||
"go.opentelemetry.io/otel/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WithContext sets ctx to log, for keeping tracing information.
|
|
||||||
func WithContext(ctx context.Context) Logger {
|
|
||||||
return &contextLogger{
|
|
||||||
ctx: ctx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type contextLogger struct {
|
|
||||||
logEntry
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Error(v ...interface{}) {
|
|
||||||
l.err(fmt.Sprint(v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Errorf(format string, v ...interface{}) {
|
|
||||||
l.err(fmt.Sprintf(format, v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Errorv(v interface{}) {
|
|
||||||
l.err(fmt.Sprint(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Errorw(msg string, fields ...LogField) {
|
|
||||||
l.err(msg, fields...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Info(v ...interface{}) {
|
|
||||||
l.info(fmt.Sprint(v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Infof(format string, v ...interface{}) {
|
|
||||||
l.info(fmt.Sprintf(format, v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Infov(v interface{}) {
|
|
||||||
l.info(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Infow(msg string, fields ...LogField) {
|
|
||||||
l.info(msg, fields...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Slow(v ...interface{}) {
|
|
||||||
l.slow(fmt.Sprint(v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Slowf(format string, v ...interface{}) {
|
|
||||||
l.slow(fmt.Sprintf(format, v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Slowv(v interface{}) {
|
|
||||||
l.slow(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) Sloww(msg string, fields ...LogField) {
|
|
||||||
l.slow(msg, fields...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) WithContext(ctx context.Context) Logger {
|
|
||||||
if ctx == nil {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
l.ctx = ctx
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) WithDuration(duration time.Duration) Logger {
|
|
||||||
l.Duration = timex.ReprOfDuration(duration)
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) buildFields(fields ...LogField) []LogField {
|
|
||||||
if len(l.Duration) > 0 {
|
|
||||||
fields = append(fields, Field(durationKey, l.Duration))
|
|
||||||
}
|
|
||||||
|
|
||||||
traceID := traceIdFromContext(l.ctx)
|
|
||||||
if len(traceID) > 0 {
|
|
||||||
fields = append(fields, Field(traceKey, traceID))
|
|
||||||
}
|
|
||||||
|
|
||||||
spanID := spanIdFromContext(l.ctx)
|
|
||||||
if len(spanID) > 0 {
|
|
||||||
fields = append(fields, Field(spanKey, spanID))
|
|
||||||
}
|
|
||||||
|
|
||||||
val := l.ctx.Value(fieldsContextKey)
|
|
||||||
if val != nil {
|
|
||||||
if arr, ok := val.([]LogField); ok {
|
|
||||||
fields = append(fields, arr...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fields
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) err(v interface{}, fields ...LogField) {
|
|
||||||
if shallLog(ErrorLevel) {
|
|
||||||
getWriter().Error(v, l.buildFields(fields...)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) info(v interface{}, fields ...LogField) {
|
|
||||||
if shallLog(InfoLevel) {
|
|
||||||
getWriter().Info(v, l.buildFields(fields...)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *contextLogger) slow(v interface{}, fields ...LogField) {
|
|
||||||
if shallLog(ErrorLevel) {
|
|
||||||
getWriter().Slow(v, l.buildFields(fields...)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func spanIdFromContext(ctx context.Context) string {
|
|
||||||
spanCtx := trace.SpanContextFromContext(ctx)
|
|
||||||
if spanCtx.HasSpanID() {
|
|
||||||
return spanCtx.SpanID().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func traceIdFromContext(ctx context.Context) string {
|
|
||||||
spanCtx := trace.SpanContextFromContext(ctx)
|
|
||||||
if spanCtx.HasTraceID() {
|
|
||||||
return spanCtx.TraceID().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
package logx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/timex"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WithDuration returns a Logger which logs the given duration.
|
|
||||||
func WithDuration(d time.Duration) Logger {
|
|
||||||
return &durationLogger{
|
|
||||||
Duration: timex.ReprOfDuration(d),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type durationLogger logEntry
|
|
||||||
|
|
||||||
func (l *durationLogger) Error(v ...interface{}) {
|
|
||||||
l.err(fmt.Sprint(v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) Errorf(format string, v ...interface{}) {
|
|
||||||
l.err(fmt.Sprintf(format, v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) Errorv(v interface{}) {
|
|
||||||
l.err(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) Errorw(msg string, fields ...LogField) {
|
|
||||||
l.err(msg, fields...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) Info(v ...interface{}) {
|
|
||||||
l.info(fmt.Sprint(v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) Infof(format string, v ...interface{}) {
|
|
||||||
l.info(fmt.Sprintf(format, v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) Infov(v interface{}) {
|
|
||||||
l.info(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) Infow(msg string, fields ...LogField) {
|
|
||||||
l.info(msg, fields...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) Slow(v ...interface{}) {
|
|
||||||
l.slow(fmt.Sprint(v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) Slowf(format string, v ...interface{}) {
|
|
||||||
l.slow(fmt.Sprintf(format, v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) Slowv(v interface{}) {
|
|
||||||
l.slow(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) Sloww(msg string, fields ...LogField) {
|
|
||||||
l.slow(msg, fields...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) WithContext(ctx context.Context) Logger {
|
|
||||||
return &contextLogger{
|
|
||||||
ctx: ctx,
|
|
||||||
logEntry: logEntry{
|
|
||||||
Duration: l.Duration,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) WithDuration(duration time.Duration) Logger {
|
|
||||||
l.Duration = timex.ReprOfDuration(duration)
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) err(v interface{}, fields ...LogField) {
|
|
||||||
if shallLog(ErrorLevel) {
|
|
||||||
fields = append(fields, Field(durationKey, l.Duration))
|
|
||||||
getWriter().Error(v, fields...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) info(v interface{}, fields ...LogField) {
|
|
||||||
if shallLog(InfoLevel) {
|
|
||||||
fields = append(fields, Field(durationKey, l.Duration))
|
|
||||||
getWriter().Info(v, fields...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *durationLogger) slow(v interface{}, fields ...LogField) {
|
|
||||||
if shallLog(ErrorLevel) {
|
|
||||||
fields = append(fields, Field(durationKey, l.Duration))
|
|
||||||
getWriter().Slow(v, fields...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
package logx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"strings"
|
|
||||||
"sync/atomic"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"go.opentelemetry.io/otel"
|
|
||||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWithDurationError(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).Error("foo")
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationErrorf(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).Errorf("foo")
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationErrorv(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).Errorv("foo")
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationErrorw(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).Errorw("foo", Field("foo", "bar"))
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
assert.True(t, strings.Contains(w.String(), "foo"), w.String())
|
|
||||||
assert.True(t, strings.Contains(w.String(), "bar"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationInfo(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).Info("foo")
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationInfoConsole(t *testing.T) {
|
|
||||||
old := atomic.LoadUint32(&encoding)
|
|
||||||
atomic.StoreUint32(&encoding, plainEncodingType)
|
|
||||||
defer func() {
|
|
||||||
atomic.StoreUint32(&encoding, old)
|
|
||||||
}()
|
|
||||||
|
|
||||||
w := new(mockWriter)
|
|
||||||
o := writer.Swap(w)
|
|
||||||
defer writer.Store(o)
|
|
||||||
|
|
||||||
WithDuration(time.Second).Info("foo")
|
|
||||||
assert.True(t, strings.Contains(w.String(), "ms"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationInfof(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).Infof("foo")
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationInfov(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).Infov("foo")
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationInfow(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).Infow("foo", Field("foo", "bar"))
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
assert.True(t, strings.Contains(w.String(), "foo"), w.String())
|
|
||||||
assert.True(t, strings.Contains(w.String(), "bar"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationWithContextInfow(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
otp := otel.GetTracerProvider()
|
|
||||||
tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
|
|
||||||
otel.SetTracerProvider(tp)
|
|
||||||
defer otel.SetTracerProvider(otp)
|
|
||||||
|
|
||||||
ctx, _ := tp.Tracer("foo").Start(context.Background(), "bar")
|
|
||||||
WithDuration(time.Second).WithContext(ctx).Infow("foo", Field("foo", "bar"))
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
assert.True(t, strings.Contains(w.String(), "foo"), w.String())
|
|
||||||
assert.True(t, strings.Contains(w.String(), "bar"), w.String())
|
|
||||||
assert.True(t, strings.Contains(w.String(), "trace"), w.String())
|
|
||||||
assert.True(t, strings.Contains(w.String(), "span"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationSlow(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).Slow("foo")
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationSlowf(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).WithDuration(time.Hour).Slowf("foo")
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationSlowv(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).WithDuration(time.Hour).Slowv("foo")
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithDurationSloww(t *testing.T) {
|
|
||||||
w := new(mockWriter)
|
|
||||||
old := writer.Swap(w)
|
|
||||||
defer writer.Store(old)
|
|
||||||
|
|
||||||
WithDuration(time.Second).WithDuration(time.Hour).Sloww("foo", Field("foo", "bar"))
|
|
||||||
assert.True(t, strings.Contains(w.String(), "duration"), w.String())
|
|
||||||
assert.True(t, strings.Contains(w.String(), "foo"), w.String())
|
|
||||||
assert.True(t, strings.Contains(w.String(), "bar"), w.String())
|
|
||||||
}
|
|
||||||
@@ -6,8 +6,8 @@ var fieldsContextKey contextKey
|
|||||||
|
|
||||||
type contextKey struct{}
|
type contextKey struct{}
|
||||||
|
|
||||||
// WithFields returns a new context with the given fields.
|
// ContextWithFields returns a new context with the given fields.
|
||||||
func WithFields(ctx context.Context, fields ...LogField) context.Context {
|
func ContextWithFields(ctx context.Context, fields ...LogField) context.Context {
|
||||||
if val := ctx.Value(fieldsContextKey); val != nil {
|
if val := ctx.Value(fieldsContextKey); val != nil {
|
||||||
if arr, ok := val.([]LogField); ok {
|
if arr, ok := val.([]LogField); ok {
|
||||||
return context.WithValue(ctx, fieldsContextKey, append(arr, fields...))
|
return context.WithValue(ctx, fieldsContextKey, append(arr, fields...))
|
||||||
@@ -16,3 +16,9 @@ func WithFields(ctx context.Context, fields ...LogField) context.Context {
|
|||||||
|
|
||||||
return context.WithValue(ctx, fieldsContextKey, fields)
|
return context.WithValue(ctx, fieldsContextKey, fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithFields returns a new logger with the given fields.
|
||||||
|
// deprecated: use ContextWithFields instead.
|
||||||
|
func WithFields(ctx context.Context, fields ...LogField) context.Context {
|
||||||
|
return ContextWithFields(ctx, fields...)
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWithFields(t *testing.T) {
|
func TestContextWithFields(t *testing.T) {
|
||||||
ctx := WithFields(context.Background(), Field("a", 1), Field("b", 2))
|
ctx := ContextWithFields(context.Background(), Field("a", 1), Field("b", 2))
|
||||||
vals := ctx.Value(fieldsContextKey)
|
vals := ctx.Value(fieldsContextKey)
|
||||||
assert.NotNil(t, vals)
|
assert.NotNil(t, vals)
|
||||||
fields, ok := vals.([]LogField)
|
fields, ok := vals.([]LogField)
|
||||||
@@ -19,8 +19,8 @@ func TestWithFields(t *testing.T) {
|
|||||||
func TestWithFieldsAppend(t *testing.T) {
|
func TestWithFieldsAppend(t *testing.T) {
|
||||||
var dummyKey struct{}
|
var dummyKey struct{}
|
||||||
ctx := context.WithValue(context.Background(), dummyKey, "dummy")
|
ctx := context.WithValue(context.Background(), dummyKey, "dummy")
|
||||||
ctx = WithFields(ctx, Field("a", 1), Field("b", 2))
|
ctx = ContextWithFields(ctx, Field("a", 1), Field("b", 2))
|
||||||
ctx = WithFields(ctx, Field("c", 3), Field("d", 4))
|
ctx = ContextWithFields(ctx, Field("c", 3), Field("d", 4))
|
||||||
vals := ctx.Value(fieldsContextKey)
|
vals := ctx.Value(fieldsContextKey)
|
||||||
assert.NotNil(t, vals)
|
assert.NotNil(t, vals)
|
||||||
fields, ok := vals.([]LogField)
|
fields, ok := vals.([]LogField)
|
||||||
|
|||||||
@@ -31,8 +31,10 @@ type Logger interface {
|
|||||||
Slowv(interface{})
|
Slowv(interface{})
|
||||||
// Sloww logs a message at slow level.
|
// Sloww logs a message at slow level.
|
||||||
Sloww(string, ...LogField)
|
Sloww(string, ...LogField)
|
||||||
|
// WithCallerSkip returns a new logger with the given caller skip.
|
||||||
|
WithCallerSkip(skip int) Logger
|
||||||
// WithContext returns a new logger with the given context.
|
// WithContext returns a new logger with the given context.
|
||||||
WithContext(context.Context) Logger
|
WithContext(ctx context.Context) Logger
|
||||||
// WithDuration returns a new logger with the given duration.
|
// WithDuration returns a new logger with the given duration.
|
||||||
WithDuration(time.Duration) Logger
|
WithDuration(d time.Duration) Logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/sysx"
|
"github.com/zeromicro/go-zero/core/sysx"
|
||||||
)
|
)
|
||||||
|
|
||||||
const callerDepth = 5
|
const callerDepth = 4
|
||||||
|
|
||||||
var (
|
var (
|
||||||
timeFormat = "2006-01-02T15:04:05.000Z07:00"
|
timeFormat = "2006-01-02T15:04:05.000Z07:00"
|
||||||
@@ -29,15 +29,16 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
logEntry struct {
|
// LogField is a key-value pair that will be added to the log entry.
|
||||||
Timestamp string `json:"@timestamp"`
|
LogField struct {
|
||||||
Level string `json:"level"`
|
Key string
|
||||||
Duration string `json:"duration,omitempty"`
|
Value interface{}
|
||||||
Caller string `json:"caller,omitempty"`
|
|
||||||
Content interface{} `json:"content"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logEntryWithFields map[string]interface{}
|
// LogOption defines the method to customize the logging.
|
||||||
|
LogOption func(options *logOptions)
|
||||||
|
|
||||||
|
logEntry map[string]interface{}
|
||||||
|
|
||||||
logOptions struct {
|
logOptions struct {
|
||||||
gzipEnabled bool
|
gzipEnabled bool
|
||||||
@@ -47,15 +48,6 @@ type (
|
|||||||
maxSize int
|
maxSize int
|
||||||
rotationRule string
|
rotationRule string
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogField is a key-value pair that will be added to the log entry.
|
|
||||||
LogField struct {
|
|
||||||
Key string
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogOption defines the method to customize the logging.
|
|
||||||
LogOption func(options *logOptions)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Alert alerts v in alert level, and the message is written to error log.
|
// Alert alerts v in alert level, and the message is written to error log.
|
||||||
@@ -85,35 +77,35 @@ func DisableStat() {
|
|||||||
|
|
||||||
// Error writes v into error log.
|
// Error writes v into error log.
|
||||||
func Error(v ...interface{}) {
|
func Error(v ...interface{}) {
|
||||||
errorTextSync(fmt.Sprint(v...))
|
writeError(fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorf writes v with format into error log.
|
// Errorf writes v with format into error log.
|
||||||
func Errorf(format string, v ...interface{}) {
|
func Errorf(format string, v ...interface{}) {
|
||||||
errorTextSync(fmt.Errorf(format, v...).Error())
|
writeError(fmt.Errorf(format, v...).Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrorStack writes v along with call stack into error log.
|
// ErrorStack writes v along with call stack into error log.
|
||||||
func ErrorStack(v ...interface{}) {
|
func ErrorStack(v ...interface{}) {
|
||||||
// there is newline in stack string
|
// there is newline in stack string
|
||||||
stackSync(fmt.Sprint(v...))
|
writeStack(fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrorStackf writes v along with call stack in format into error log.
|
// ErrorStackf writes v along with call stack in format into error log.
|
||||||
func ErrorStackf(format string, v ...interface{}) {
|
func ErrorStackf(format string, v ...interface{}) {
|
||||||
// there is newline in stack string
|
// there is newline in stack string
|
||||||
stackSync(fmt.Sprintf(format, v...))
|
writeStack(fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorv writes v into error log with json content.
|
// Errorv writes v into error log with json content.
|
||||||
// No call stack attached, because not elegant to pack the messages.
|
// No call stack attached, because not elegant to pack the messages.
|
||||||
func Errorv(v interface{}) {
|
func Errorv(v interface{}) {
|
||||||
errorAnySync(v)
|
writeError(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorw writes msg along with fields into error log.
|
// Errorw writes msg along with fields into error log.
|
||||||
func Errorw(msg string, fields ...LogField) {
|
func Errorw(msg string, fields ...LogField) {
|
||||||
errorFieldsSync(msg, fields...)
|
writeError(msg, fields...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Field returns a LogField for the given key and value.
|
// Field returns a LogField for the given key and value.
|
||||||
@@ -156,22 +148,22 @@ func Field(key string, value interface{}) LogField {
|
|||||||
|
|
||||||
// Info writes v into access log.
|
// Info writes v into access log.
|
||||||
func Info(v ...interface{}) {
|
func Info(v ...interface{}) {
|
||||||
infoTextSync(fmt.Sprint(v...))
|
writeInfo(fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Infof writes v with format into access log.
|
// Infof writes v with format into access log.
|
||||||
func Infof(format string, v ...interface{}) {
|
func Infof(format string, v ...interface{}) {
|
||||||
infoTextSync(fmt.Sprintf(format, v...))
|
writeInfo(fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Infov writes v into access log with json content.
|
// Infov writes v into access log with json content.
|
||||||
func Infov(v interface{}) {
|
func Infov(v interface{}) {
|
||||||
infoAnySync(v)
|
writeInfo(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Infow writes msg along with fields into access log.
|
// Infow writes msg along with fields into access log.
|
||||||
func Infow(msg string, fields ...LogField) {
|
func Infow(msg string, fields ...LogField) {
|
||||||
infoFieldsSync(msg, fields...)
|
writeInfo(msg, fields...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must checks if err is nil, otherwise logs the error and exits.
|
// Must checks if err is nil, otherwise logs the error and exits.
|
||||||
@@ -244,42 +236,42 @@ func SetUp(c LogConf) (err error) {
|
|||||||
|
|
||||||
// Severe writes v into severe log.
|
// Severe writes v into severe log.
|
||||||
func Severe(v ...interface{}) {
|
func Severe(v ...interface{}) {
|
||||||
severeSync(fmt.Sprint(v...))
|
writeSevere(fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Severef writes v with format into severe log.
|
// Severef writes v with format into severe log.
|
||||||
func Severef(format string, v ...interface{}) {
|
func Severef(format string, v ...interface{}) {
|
||||||
severeSync(fmt.Sprintf(format, v...))
|
writeSevere(fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slow writes v into slow log.
|
// Slow writes v into slow log.
|
||||||
func Slow(v ...interface{}) {
|
func Slow(v ...interface{}) {
|
||||||
slowTextSync(fmt.Sprint(v...))
|
writeSlow(fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slowf writes v with format into slow log.
|
// Slowf writes v with format into slow log.
|
||||||
func Slowf(format string, v ...interface{}) {
|
func Slowf(format string, v ...interface{}) {
|
||||||
slowTextSync(fmt.Sprintf(format, v...))
|
writeSlow(fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slowv writes v into slow log with json content.
|
// Slowv writes v into slow log with json content.
|
||||||
func Slowv(v interface{}) {
|
func Slowv(v interface{}) {
|
||||||
slowAnySync(v)
|
writeSlow(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sloww writes msg along with fields into slow log.
|
// Sloww writes msg along with fields into slow log.
|
||||||
func Sloww(msg string, fields ...LogField) {
|
func Sloww(msg string, fields ...LogField) {
|
||||||
slowFieldsSync(msg, fields...)
|
writeSlow(msg, fields...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stat writes v into stat log.
|
// Stat writes v into stat log.
|
||||||
func Stat(v ...interface{}) {
|
func Stat(v ...interface{}) {
|
||||||
statSync(fmt.Sprint(v...))
|
writeStat(fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statf writes v with format into stat log.
|
// Statf writes v with format into stat log.
|
||||||
func Statf(format string, v ...interface{}) {
|
func Statf(format string, v ...interface{}) {
|
||||||
statSync(fmt.Sprintf(format, v...))
|
writeStat(fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithCooldownMillis customizes logging on writing call stack interval.
|
// WithCooldownMillis customizes logging on writing call stack interval.
|
||||||
@@ -324,6 +316,10 @@ func WithRotation(r string) LogOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addCaller(fields ...LogField) []LogField {
|
||||||
|
return append(fields, Field(callerKey, getCaller(callerDepth)))
|
||||||
|
}
|
||||||
|
|
||||||
func createOutput(path string) (io.WriteCloser, error) {
|
func createOutput(path string) (io.WriteCloser, error) {
|
||||||
if len(path) == 0 {
|
if len(path) == 0 {
|
||||||
return nil, ErrLogPathNotSet
|
return nil, ErrLogPathNotSet
|
||||||
@@ -339,24 +335,6 @@ func createOutput(path string) (io.WriteCloser, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func errorAnySync(v interface{}) {
|
|
||||||
if shallLog(ErrorLevel) {
|
|
||||||
getWriter().Error(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func errorFieldsSync(content string, fields ...LogField) {
|
|
||||||
if shallLog(ErrorLevel) {
|
|
||||||
getWriter().Error(content, fields...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func errorTextSync(msg string) {
|
|
||||||
if shallLog(ErrorLevel) {
|
|
||||||
getWriter().Error(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getWriter() Writer {
|
func getWriter() Writer {
|
||||||
w := writer.Load()
|
w := writer.Load()
|
||||||
if w == nil {
|
if w == nil {
|
||||||
@@ -372,24 +350,6 @@ func handleOptions(opts []LogOption) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func infoAnySync(val interface{}) {
|
|
||||||
if shallLog(InfoLevel) {
|
|
||||||
getWriter().Info(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func infoFieldsSync(content string, fields ...LogField) {
|
|
||||||
if shallLog(InfoLevel) {
|
|
||||||
getWriter().Info(content, fields...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func infoTextSync(msg string) {
|
|
||||||
if shallLog(InfoLevel) {
|
|
||||||
getWriter().Info(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupLogLevel(c LogConf) {
|
func setupLogLevel(c LogConf) {
|
||||||
switch c.Level {
|
switch c.Level {
|
||||||
case levelInfo:
|
case levelInfo:
|
||||||
@@ -424,12 +384,6 @@ func setupWithVolume(c LogConf) error {
|
|||||||
return setupWithFiles(c)
|
return setupWithFiles(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func severeSync(msg string) {
|
|
||||||
if shallLog(SevereLevel) {
|
|
||||||
getWriter().Severe(fmt.Sprintf("%s\n%s", msg, string(debug.Stack())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func shallLog(level uint32) bool {
|
func shallLog(level uint32) bool {
|
||||||
return atomic.LoadUint32(&logLevel) <= level
|
return atomic.LoadUint32(&logLevel) <= level
|
||||||
}
|
}
|
||||||
@@ -438,32 +392,38 @@ func shallLogStat() bool {
|
|||||||
return atomic.LoadUint32(&disableStat) == 0
|
return atomic.LoadUint32(&disableStat) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func slowAnySync(v interface{}) {
|
func writeError(val interface{}, fields ...LogField) {
|
||||||
if shallLog(ErrorLevel) {
|
if shallLog(ErrorLevel) {
|
||||||
getWriter().Slow(v)
|
getWriter().Error(val, addCaller(fields...)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func slowFieldsSync(content string, fields ...LogField) {
|
func writeInfo(val interface{}, fields ...LogField) {
|
||||||
if shallLog(ErrorLevel) {
|
if shallLog(InfoLevel) {
|
||||||
getWriter().Slow(content, fields...)
|
getWriter().Info(val, addCaller(fields...)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func slowTextSync(msg string) {
|
func writeSevere(msg string) {
|
||||||
if shallLog(ErrorLevel) {
|
if shallLog(SevereLevel) {
|
||||||
getWriter().Slow(msg)
|
getWriter().Severe(fmt.Sprintf("%s\n%s", msg, string(debug.Stack())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func stackSync(msg string) {
|
func writeSlow(val interface{}, fields ...LogField) {
|
||||||
|
if shallLog(ErrorLevel) {
|
||||||
|
getWriter().Slow(val, addCaller(fields...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeStack(msg string) {
|
||||||
if shallLog(ErrorLevel) {
|
if shallLog(ErrorLevel) {
|
||||||
getWriter().Stack(fmt.Sprintf("%s\n%s", msg, string(debug.Stack())))
|
getWriter().Stack(fmt.Sprintf("%s\n%s", msg, string(debug.Stack())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func statSync(msg string) {
|
func writeStat(msg string) {
|
||||||
if shallLogStat() && shallLog(InfoLevel) {
|
if shallLogStat() && shallLog(InfoLevel) {
|
||||||
getWriter().Stat(msg)
|
getWriter().Stat(msg, addCaller()...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -461,13 +461,13 @@ func TestStructedLogWithDuration(t *testing.T) {
|
|||||||
defer writer.Store(old)
|
defer writer.Store(old)
|
||||||
|
|
||||||
WithDuration(time.Second).Info(message)
|
WithDuration(time.Second).Info(message)
|
||||||
var entry logEntry
|
var entry map[string]interface{}
|
||||||
if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
|
if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
assert.Equal(t, levelInfo, entry.Level)
|
assert.Equal(t, levelInfo, entry[levelKey])
|
||||||
assert.Equal(t, message, entry.Content)
|
assert.Equal(t, message, entry[contentKey])
|
||||||
assert.Equal(t, "1000.0ms", entry.Duration)
|
assert.Equal(t, "1000.0ms", entry[durationKey])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetLevel(t *testing.T) {
|
func TestSetLevel(t *testing.T) {
|
||||||
@@ -531,6 +531,7 @@ func TestSetup(t *testing.T) {
|
|||||||
MustSetup(LogConf{
|
MustSetup(LogConf{
|
||||||
ServiceName: "any",
|
ServiceName: "any",
|
||||||
Mode: "console",
|
Mode: "console",
|
||||||
|
TimeFormat: timeFormat,
|
||||||
})
|
})
|
||||||
MustSetup(LogConf{
|
MustSetup(LogConf{
|
||||||
ServiceName: "any",
|
ServiceName: "any",
|
||||||
@@ -553,7 +554,15 @@ func TestSetup(t *testing.T) {
|
|||||||
Encoding: plainEncoding,
|
Encoding: plainEncoding,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer os.RemoveAll("CD01CB7D-2705-4F3F-889E-86219BF56F10")
|
||||||
assert.NotNil(t, setupWithVolume(LogConf{}))
|
assert.NotNil(t, setupWithVolume(LogConf{}))
|
||||||
|
assert.Nil(t, setupWithVolume(LogConf{
|
||||||
|
ServiceName: "CD01CB7D-2705-4F3F-889E-86219BF56F10",
|
||||||
|
}))
|
||||||
|
assert.Nil(t, setupWithVolume(LogConf{
|
||||||
|
ServiceName: "CD01CB7D-2705-4F3F-889E-86219BF56F10",
|
||||||
|
Rotation: sizeRotationRule,
|
||||||
|
}))
|
||||||
assert.NotNil(t, setupWithFiles(LogConf{}))
|
assert.NotNil(t, setupWithFiles(LogConf{}))
|
||||||
assert.Nil(t, setupWithFiles(LogConf{
|
assert.Nil(t, setupWithFiles(LogConf{
|
||||||
ServiceName: "any",
|
ServiceName: "any",
|
||||||
@@ -583,6 +592,8 @@ func TestDisable(t *testing.T) {
|
|||||||
var opt logOptions
|
var opt logOptions
|
||||||
WithKeepDays(1)(&opt)
|
WithKeepDays(1)(&opt)
|
||||||
WithGzip()(&opt)
|
WithGzip()(&opt)
|
||||||
|
WithMaxBackups(1)(&opt)
|
||||||
|
WithMaxSize(1024)(&opt)
|
||||||
assert.Nil(t, Close())
|
assert.Nil(t, Close())
|
||||||
assert.Nil(t, Close())
|
assert.Nil(t, Close())
|
||||||
}
|
}
|
||||||
@@ -711,14 +722,16 @@ func put(b []byte) {
|
|||||||
func doTestStructedLog(t *testing.T, level string, w *mockWriter, write func(...interface{})) {
|
func doTestStructedLog(t *testing.T, level string, w *mockWriter, write func(...interface{})) {
|
||||||
const message = "hello there"
|
const message = "hello there"
|
||||||
write(message)
|
write(message)
|
||||||
var entry logEntry
|
|
||||||
|
var entry map[string]interface{}
|
||||||
if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
|
if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
assert.Equal(t, level, entry.Level)
|
|
||||||
val, ok := entry.Content.(string)
|
assert.Equal(t, level, entry[levelKey])
|
||||||
|
val, ok := entry[contentKey]
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.True(t, strings.Contains(val, message))
|
assert.True(t, strings.Contains(val.(string), message))
|
||||||
}
|
}
|
||||||
|
|
||||||
func doTestStructedLogConsole(t *testing.T, w *mockWriter, write func(...interface{})) {
|
func doTestStructedLogConsole(t *testing.T, w *mockWriter, write func(...interface{})) {
|
||||||
|
|||||||
172
core/logx/richlogger.go
Normal file
172
core/logx/richlogger.go
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
package logx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/timex"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithCallerSkip returns a Logger with given caller skip.
|
||||||
|
func WithCallerSkip(skip int) Logger {
|
||||||
|
if skip <= 0 {
|
||||||
|
return new(richLogger)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &richLogger{
|
||||||
|
callerSkip: skip,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithContext sets ctx to log, for keeping tracing information.
|
||||||
|
func WithContext(ctx context.Context) Logger {
|
||||||
|
return &richLogger{
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDuration returns a Logger with given duration.
|
||||||
|
func WithDuration(d time.Duration) Logger {
|
||||||
|
return &richLogger{
|
||||||
|
fields: []LogField{Field(durationKey, timex.ReprOfDuration(d))},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type richLogger struct {
|
||||||
|
ctx context.Context
|
||||||
|
callerSkip int
|
||||||
|
fields []LogField
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Error(v ...interface{}) {
|
||||||
|
l.err(fmt.Sprint(v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Errorf(format string, v ...interface{}) {
|
||||||
|
l.err(fmt.Sprintf(format, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Errorv(v interface{}) {
|
||||||
|
l.err(fmt.Sprint(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Errorw(msg string, fields ...LogField) {
|
||||||
|
l.err(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Info(v ...interface{}) {
|
||||||
|
l.info(fmt.Sprint(v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Infof(format string, v ...interface{}) {
|
||||||
|
l.info(fmt.Sprintf(format, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Infov(v interface{}) {
|
||||||
|
l.info(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Infow(msg string, fields ...LogField) {
|
||||||
|
l.info(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Slow(v ...interface{}) {
|
||||||
|
l.slow(fmt.Sprint(v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Slowf(format string, v ...interface{}) {
|
||||||
|
l.slow(fmt.Sprintf(format, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Slowv(v interface{}) {
|
||||||
|
l.slow(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) Sloww(msg string, fields ...LogField) {
|
||||||
|
l.slow(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) WithCallerSkip(skip int) Logger {
|
||||||
|
if skip <= 0 {
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
l.callerSkip = skip
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) WithContext(ctx context.Context) Logger {
|
||||||
|
l.ctx = ctx
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) WithDuration(duration time.Duration) Logger {
|
||||||
|
l.fields = append(l.fields, Field(durationKey, timex.ReprOfDuration(duration)))
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) buildFields(fields ...LogField) []LogField {
|
||||||
|
fields = append(l.fields, fields...)
|
||||||
|
fields = append(fields, Field(callerKey, getCaller(callerDepth+l.callerSkip)))
|
||||||
|
|
||||||
|
if l.ctx == nil {
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
traceID := traceIdFromContext(l.ctx)
|
||||||
|
if len(traceID) > 0 {
|
||||||
|
fields = append(fields, Field(traceKey, traceID))
|
||||||
|
}
|
||||||
|
|
||||||
|
spanID := spanIdFromContext(l.ctx)
|
||||||
|
if len(spanID) > 0 {
|
||||||
|
fields = append(fields, Field(spanKey, spanID))
|
||||||
|
}
|
||||||
|
|
||||||
|
val := l.ctx.Value(fieldsContextKey)
|
||||||
|
if val != nil {
|
||||||
|
if arr, ok := val.([]LogField); ok {
|
||||||
|
fields = append(fields, arr...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) err(v interface{}, fields ...LogField) {
|
||||||
|
if shallLog(ErrorLevel) {
|
||||||
|
getWriter().Error(v, l.buildFields(fields...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) info(v interface{}, fields ...LogField) {
|
||||||
|
if shallLog(InfoLevel) {
|
||||||
|
getWriter().Info(v, l.buildFields(fields...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *richLogger) slow(v interface{}, fields ...LogField) {
|
||||||
|
if shallLog(ErrorLevel) {
|
||||||
|
getWriter().Slow(v, l.buildFields(fields...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func spanIdFromContext(ctx context.Context) string {
|
||||||
|
spanCtx := trace.SpanContextFromContext(ctx)
|
||||||
|
if spanCtx.HasSpanID() {
|
||||||
|
return spanCtx.SpanID().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceIdFromContext(ctx context.Context) string {
|
||||||
|
spanCtx := trace.SpanContextFromContext(ctx)
|
||||||
|
if spanCtx.HasTraceID() {
|
||||||
|
return spanCtx.TraceID().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package logx
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -201,7 +202,7 @@ func TestLogWithFields(t *testing.T) {
|
|||||||
writer.Store(old)
|
writer.Store(old)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ctx := WithFields(context.Background(), Field("foo", "bar"))
|
ctx := ContextWithFields(context.Background(), Field("foo", "bar"))
|
||||||
l := WithContext(ctx)
|
l := WithContext(ctx)
|
||||||
SetLevel(InfoLevel)
|
SetLevel(InfoLevel)
|
||||||
l.Info(testlog)
|
l.Info(testlog)
|
||||||
@@ -211,6 +212,31 @@ func TestLogWithFields(t *testing.T) {
|
|||||||
assert.Equal(t, "bar", val.Foo)
|
assert.Equal(t, "bar", val.Foo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLogWithCallerSkip(t *testing.T) {
|
||||||
|
w := new(mockWriter)
|
||||||
|
old := writer.Swap(w)
|
||||||
|
writer.lock.RLock()
|
||||||
|
defer func() {
|
||||||
|
writer.lock.RUnlock()
|
||||||
|
writer.Store(old)
|
||||||
|
}()
|
||||||
|
|
||||||
|
l := WithCallerSkip(1).WithCallerSkip(0)
|
||||||
|
p := func(v string) {
|
||||||
|
l.Info(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, line := getFileLine()
|
||||||
|
p(testlog)
|
||||||
|
assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
|
||||||
|
|
||||||
|
w.Reset()
|
||||||
|
l = WithCallerSkip(0).WithCallerSkip(1)
|
||||||
|
file, line = getFileLine()
|
||||||
|
p(testlog)
|
||||||
|
assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
|
||||||
|
}
|
||||||
|
|
||||||
func validate(t *testing.T, body string, expectedTrace, expectedSpan bool) {
|
func validate(t *testing.T, body string, expectedTrace, expectedSpan bool) {
|
||||||
var val mockValue
|
var val mockValue
|
||||||
dec := json.NewDecoder(strings.NewReader(body))
|
dec := json.NewDecoder(strings.NewReader(body))
|
||||||
@@ -42,11 +42,18 @@ func captureOutput(f func()) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getContent(jsonStr string) string {
|
func getContent(jsonStr string) string {
|
||||||
var entry logEntry
|
var entry map[string]interface{}
|
||||||
json.Unmarshal([]byte(jsonStr), &entry)
|
json.Unmarshal([]byte(jsonStr), &entry)
|
||||||
val, ok := entry.Content.(string)
|
|
||||||
if ok {
|
val, ok := entry[contentKey]
|
||||||
return val
|
if !ok {
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
return ""
|
|
||||||
|
str, ok := val.(string)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,13 +256,11 @@ func buildFields(fields ...LogField) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func output(writer io.Writer, level string, val interface{}, fields ...LogField) {
|
func output(writer io.Writer, level string, val interface{}, fields ...LogField) {
|
||||||
fields = append(fields, Field(callerKey, getCaller(callerDepth)))
|
|
||||||
|
|
||||||
switch atomic.LoadUint32(&encoding) {
|
switch atomic.LoadUint32(&encoding) {
|
||||||
case plainEncodingType:
|
case plainEncodingType:
|
||||||
writePlainAny(writer, level, val, buildFields(fields...)...)
|
writePlainAny(writer, level, val, buildFields(fields...)...)
|
||||||
default:
|
default:
|
||||||
entry := make(logEntryWithFields)
|
entry := make(logEntry)
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
entry[field.Key] = field.Value
|
entry[field.Key] = field.Value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// BuildVersion is the version of goctl.
|
// BuildVersion is the version of goctl.
|
||||||
const BuildVersion = "1.4.0"
|
const BuildVersion = "1.4.1"
|
||||||
|
|
||||||
var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-bata": 2, "beta": 3, "released": 4, "": 5}
|
var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-bata": 2, "beta": 3, "released": 4, "": 5}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user