Skip to content
This repository has been archived by the owner on May 8, 2024. It is now read-only.

Commit

Permalink
feat: imporve performance
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkgos committed Apr 15, 2024
1 parent 4d7f94d commit 1fa9b05
Show file tree
Hide file tree
Showing 15 changed files with 1,129 additions and 687 deletions.
222 changes: 222 additions & 0 deletions benchark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
package log_test

import (
"context"
"io"
"testing"

"github.com/things-go/log"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

func Benchmark_NativeLogger(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
cfg := zap.NewProductionConfig()
core := zapcore.NewCore(
zapcore.NewJSONEncoder(cfg.EncoderConfig),
zapcore.AddSync(io.Discard),
zapcore.InfoLevel,
)
logger := zap.New(core)
b.StartTimer()
for i := 0; i < b.N; i++ {
logger.Info("success",
zap.String("name", `jack`),
zap.Int("age", 18),
)
}
}

func newDiscardLogger() *log.Log {
return log.NewLogger(log.WithAdapter("custom", io.Discard))
}
func dfltCtx(ctx context.Context) log.Field {
return zap.String("dflt_key", "dflt_value")
}

func Benchmark_Logger(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
logger := newDiscardLogger()
b.StartTimer()
ctx := context.Background()
for i := 0; i < b.N; i++ {
logger.
InfoxContext(
ctx,
"success",
log.String("name", `jack`),
log.Int("age", 18),
dfltCtx(ctx),
)
}
}

func Benchmark_Logger_Use_Hook(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
logger := newDiscardLogger()
logger.SetDefaultValuer(dfltCtx)
b.StartTimer()
ctx := context.Background()
for i := 0; i < b.N; i++ {
logger.
InfoxContext(
ctx,
"success",
log.String("name", `jack`),
log.Int("age", 18),
)
}
}

func Benchmark_NativeSugar(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
cfg := zap.NewProductionConfig()
core := zapcore.NewCore(
zapcore.NewJSONEncoder(cfg.EncoderConfig),
zapcore.AddSync(io.Discard),
zapcore.InfoLevel,
)
logger := zap.New(core).Sugar()
b.StartTimer()
for i := 0; i < b.N; i++ {
logger.Infow("success",
"name", `jack`,
"age", 18,
)
}
}

func Benchmark_SugarKeyValuePair(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
logger := newDiscardLogger()
b.StartTimer()
ctx := context.Background()
for i := 0; i < b.N; i++ {
logger.InfowContext(ctx,
"success",
log.String("name", `jack`),
log.Int("age", 18),
dfltCtx(ctx),
)
}
}

func Benchmark_SugarKeyValuePair_Use_Hook(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
logger := newDiscardLogger()
logger.SetDefaultValuer(dfltCtx)
b.StartTimer()
ctx := context.Background()
for i := 0; i < b.N; i++ {
logger.InfowContext(ctx,
"success",
log.String("name", `jack`),
log.Int("age", 18),
)
}
}

func Benchmark_SugarKeyValuePair_Use_WithFields(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
logger := newDiscardLogger()
b.StartTimer()
ctx := context.Background()
for i := 0; i < b.N; i++ {
logger.With(
log.String("name", `jack`),
log.Int("age", 18),
dfltCtx(ctx),
).InfowContext(ctx, "success")
}
}

func Benchmark_SugarKeyValuePair_Use_WithFields_Hook(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
logger := newDiscardLogger()
logger.SetDefaultValuer(dfltCtx)
b.StartTimer()
ctx := context.Background()
for i := 0; i < b.N; i++ {
logger.With(
log.String("name", `jack`),
log.Int("age", 18),
).InfowContext(ctx, "success")
}
}

func Benchmark_SugarKeyValuePair_Use_WithValuer(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
logger := newDiscardLogger()
b.StartTimer()
ctx := context.Background()
for i := 0; i < b.N; i++ {
logger.WithValuer(
log.ImmutString("name", `jack`),
log.ImmutInt("age", 18),
dfltCtx,
).InfowContext(ctx, "success")
}
}

func Benchmark_SugarKeyValuePair_Use_WithValuer_Hook(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
logger := newDiscardLogger()
logger.SetDefaultValuer(dfltCtx)
b.StartTimer()
ctx := context.Background()
for i := 0; i < b.N; i++ {
logger.WithValuer(
log.ImmutString("name", `jack`),
log.ImmutInt("age", 18),
).InfowContext(ctx, "success")
}
}

func Benchmark_SugarFormat(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
logger := newDiscardLogger()
b.StartTimer()
ctx := context.Background()
for i := 0; i < b.N; i++ {
logger.WithValuer(
func(ctx context.Context) log.Field {
return log.String("name", `jack`)
},
func(ctx context.Context) log.Field {
return log.Int("age", 18)
},
dfltCtx,
).InfofContext(ctx,
"success",
)
}
}

func Benchmark_SugarFormat_Use_Hook(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
logger := newDiscardLogger()
logger.SetDefaultValuer(dfltCtx)
b.StartTimer()
ctx := context.Background()
for i := 0; i < b.N; i++ {
logger.WithValuer(
log.ImmutString("name", `jack`),
log.ImmutInt("age", 18),
).InfofContext(ctx,
"success",
)
}
}
102 changes: 102 additions & 0 deletions defalt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package log

import (
"context"

"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

var defaultLogger = NewLoggerWith(zap.NewNop(), zap.NewAtomicLevel())

// ReplaceGlobals replaces the global Log only once.
func ReplaceGlobals(logger *Log) { defaultLogger = logger }

// SetLevelWithText alters the logging level.
// ParseAtomicLevel set the logging level based on a lowercase or all-caps ASCII
// representation of the log level.
// If the provided ASCII representation is
// invalid an error is returned.
func SetLevelWithText(text string) error { return defaultLogger.SetLevelWithText(text) }

// SetLevel alters the logging level.
func SetLevel(lv zapcore.Level) *Log { return defaultLogger.SetLevel(lv) }

// GetLevel returns the minimum enabled log level.
func GetLevel() Level { return defaultLogger.GetLevel() }

// Enabled returns true if the given level is at or above this level.
func Enabled(lvl Level) bool { return defaultLogger.Enabled(lvl) }

// V returns true if the given level is at or above this level.
// same as Enabled
func V(lvl int) bool { return defaultLogger.V(lvl) }

// SetDefaultValuer set default field function, which hold always until you call WithContext.
// suggest
func SetDefaultValuer(vs ...Valuer) *Log {
return defaultLogger.SetDefaultValuer(vs...)
}

// WithValuer with field function.
func WithValuer(vs ...Valuer) *Log {
return defaultLogger.WithValuer(vs...)
}

// WithNewValuer return log with new Valuer function without default Valuer.
func WithNewValuer(fs ...Valuer) *Log {
return defaultLogger.WithNewValuer(fs...)
}

// WithContext return log with inject context.
//
// Deprecated: Use XXXContext to inject context. such as DebugContext.
func WithContext(ctx context.Context) *Log {
return defaultLogger.WithContext(ctx)
}

// Sugar wraps the Logger to provide a more ergonomic, but slightly slower,
// API. Sugaring a Logger is quite inexpensive, so it's reasonable for a
// single application to use both Loggers and SugaredLoggers, converting
// between them on the boundaries of performance-sensitive code.
func Sugar() *zap.SugaredLogger { return defaultLogger.Sugar() }

// Logger return internal logger
func Logger() *zap.Logger { return defaultLogger.Logger() }

// With adds a variadic number of fields to the logging context. It accepts a
// mix of strongly-typed Field objects and loosely-typed key-value pairs. When
// processing pairs, the first element of the pair is used as the field key
// and the second as the field value.
//
// For example,
//
// sugaredLogger.With(
// "hello", "world",
// "failure", errors.New("oh no"),
// "count", 42,
// "user", User{Name: "alice"},
// )
//
// is the equivalent of
//
// unsugared.With(
// String("hello", "world"),
// String("failure", "oh no"),
// Stack(),
// Int("count", 42),
// Object("user", User{Name: "alice"}),
// )
//
// Note that the keys in key-value pairs should be strings. In development,
// passing a non-string key panics. In production, the logger is more
// forgiving: a separate error is logged, but the key-value pair is skipped
// and execution continues. Passing an orphaned key triggers similar behavior:
// panics in development and errors in production.
func With(fields ...Field) *Log { return defaultLogger.With(fields...) }

// Named adds a sub-scope to the logger's name. See Log.Named for details.
func Named(name string) *Log { return defaultLogger.Named(name) }

// Sync flushes any buffered log entries.
func Sync() error { return defaultLogger.Sync() }
Loading

0 comments on commit 1fa9b05

Please sign in to comment.