zlog

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 26, 2024 License: MIT Imports: 13 Imported by: 0

README

zlog

1. Overview

A logging library designed to provide a chainable API for logging operations, built on top of the Uber Zap with Zerolog (https://github.com/rs/zerolog) style.

2. Quick Start

zlog.Info().Msg("an example")

{"level":"INFO","ts":"2024-11-12T14:16:47.522+0800","caller":"cmd/main.go:20","msg":"an example"}

3. Usage

3.1 Initialization
// package level initialization with default option
zlog.Init(zlog.DefaultOption())
zlog.Info().Msg("an example")


// object level initialization with default option
logger := zlog.New(zlog.DefaultOption())


// initialization with user defined option
logger := zlog.New(zlogOption{
    Dir:            "logs",
    Filename:       "access.log",
    DisableConsole: false,
    Rotation:       true,
    MaxSize:        20,
    MaxAge:         30,
    SkipLevel:      2,
    Writer:         os.Stderr,
})

3.2 Chainable Option API
// example of production envrionment initialization
opt := zlog.DefaultOption().
        SetDir(config.Dir).
        SetFilename(config.LogFile).
        SetWriter(os.Stdout).
        SetDisableConsole(true)

logger := zlog.New(opt)
3.3 Chainable Logging API
// logging with message
logger.Info().
    Str("trace_id", "1234").
    Str("account_id", "abc").
    Int("account_status", 1).
    Msg("query account")
    
    
// logging with formatted message
logger.Info().
    Str("trace_id", "1234").
    Str("account_id", "abc").
    Int("account_status", 1).
    Msgf("query account[%d]", "aid")
    
    
// logging without message
logger.Info().
    Str("trace_id", "1234").
    Str("account_id", "abc").
    Int("account_status", 1).
    Send()
    
  
// logging with error
// {"level":"ERROR","ts":"2024-11-12T14:11:50.488+0800","caller":"runtime/proc.go:271","msg":"query account","trace_id":"1234","account_id":"abc","account_status":1,"error":"record not found"}
logger.Error().
    Str("trace_id", "1234").
    Str("account_id", "abc").
    Int("account_status", 1).
    Err(errors.New("record not found")).
    Msg("failed to query account")
3.4 Log Pre-defined Context
logger := zlog.New(zlog.DefaultOption())

logger = logger.With("machine_id", 3).
    With("service", "gateway").
    With("router", "card")

logger.Info().Str("trace_id", "1234").Str("card_number", "12345").Msg("update card")


// {"level":"INFO","ts":"2024-11-12T14:27:02.551+0800","caller":"cmd/main.go:26","msg":"update card","machine_id":3,"service":"gateway","router":"card","trace_id":"1234","card_number":"12345"}
3.5 Passed Standard Context
logger := zlog.New(zlog.DefaultOption())

ctx := context.Background()
ctx = context.WithValue(ctx, "trace_id", "t123")
ctx = context.WithValue(ctx, "token", "jwt_abc")
ctx = context.WithValue(ctx, "api_key", "key_vip_acc")

logger.AddCtxHook(func(ctx context.Context) map[string]interface{} {
		return map[string]interface{}{
                    "trace_id": ctx.Value("trace_id"),
                    "token":    ctx.Value("token"),
                    "api_key":  ctx.Value("api_key"),
		}
    }
)

logger.Info(ctx).Str("account_id", "1234").Str("card_number", "12345").Msg("update card")

// {"level":"INFO","ts":"2024-11-12T14:46:59.926+0800","caller":"cmd/main.go:38","msg":"update card","trace_id":"t123","token":"jwt_abc","api_key":"key_vip_acc","account_id":"1234","card_number":"12345"}
3.6 Passed Gin Context
logger := zlog.New(zlog.DefaultOption())

ctx := &gin.Context{}
ctx.Set("trace_id", "t123")
ctx.Set("client_id", "c123")
ctx.Set("customer_id", "customer_123")
ctx.Set("account_id", "a123")

logger.AddCtxHook(func(ctx context.Context) map[string]interface{} {
		c := ctx.(*gin.Context)
		traceId, _ := c.Get("trace_id")
		clientId, _ := c.Get("client_id")
		customerId, _ := c.Get("customer_id")
		accountId, _ := c.Get("account_id")

		return map[string]interface{}{
            "trace_id":    traceId,
            "client_id":   clientId,
            "customer_id": customerId,
            "account_id":  accountId,
		}
})

logger.Info(ctx).Str("account_id", "1234").Str("card_number", "12345").Msg("update card")

// {"level":"INFO","ts":"2024-11-14T10:16:33.876+0800","caller":"cmd/main.go:44","msg":"update card","trace_id":"t123","client_id":"c123","customer_id":"customer_123","account_id":"a123","account_id":"1234","card_number":"12345"}

4. Comparation

4.1 Versus Zap
// zap
logger.Info("create card, allowed card currency",
    zap.String("direct_id", ca.DirectId),
    zap.String("account_id", ca.AccountId),
    zap.String("allowed_card_currency", allowedCardCurrency),
    zap.String("req_card_currency", reqCardCurrency),
)

logger.Info("create card, allowed card currency", zap.String("direct_id", ca.DirectId), zap.String("account_id", ca.AccountId), zap.String("allowed_card_currency", allowedCardCurrency), zap.String("req_card_currency", reqCardCurrency))


// shorter, less embedded and much more clear
// no worries about commas and brackets
logger.Info().
		Str("direct_id", ca.DirectId).
		Str("account_id", ca.AccountId).
		Str("allowed_card_currency", allowedCardCurrency).
		Str("req_card_currency", reqCardCurrency).
		Msg("create card, allowed card currency")

logger.Info().Str("direct_id", ca.DirectId).Str("account_id", ca.AccountId).Str("allowed_card_currency", allowedCardCurrency).Str("req_card_currency", reqCardCurrency).Msg("create card, allowed card currency")

4.2 Versus Current Project
// current
var (
	Lg      *zap.Logger
	TraceLg TraceLogger
	PingLg  *zap.Logger
	Clg     *Clog
)

Lg.Info("example log")
TraceLg.InfoWithCtx(ctx, "example log")
Clg.Info(ctx, "example log")


// more compatible and pluggable
logger.Info().Msg("example log")
logger.Info(ctx).Msg("example log with context")

also:

  • decoupling log library and developer usage
  • less initialization steps, less option with more expansible and unified

5. Performance

[Apple M3 Pro]

goos: darwin
goarch: arm64

# 2 cores
BenchmarkLogEmpty-2                     	 2997499	       391.2 ns/op	     256 B/op	       2 allocs/op
BenchmarkLog-2                          	 2344003	       563.6 ns/op	     256 B/op	       2 allocs/op
BenchmarkLog4Fields-2                   	 2338986	       510.7 ns/op	     256 B/op	       2 allocs/op
BenchmarkLog10Fields-2                  	 1883809	       629.2 ns/op	     256 B/op	       2 allocs/op
BenchmarkLog10FieldsComplex-2           	 1684208	       710.9 ns/op	     280 B/op	       3 allocs/op
BenchmarkLog10FieldsComplexAny-2        	  405367	      2949 ns/op	    1121 B/op	      23 allocs/op
BenchmarkLogPredefinedContextFields-2   	 2649936	       453.6 ns/op	     256 B/op	       2 allocs/op
BenchmarkLogPassedContextFields-2       	 1736319	       689.7 ns/op	     976 B/op	       6 allocs/op
BenchmarkLogPassedGinContextFields-2    	 1257981	       955.6 ns/op	    1361 B/op	       6 allocs/op

# 4 cores
BenchmarkLogEmpty-4                     	 5674430	       196.0 ns/op	     256 B/op	       2 allocs/op
BenchmarkLog-4                          	 4684784	       255.5 ns/op	     256 B/op	       2 allocs/op
BenchmarkLog4Fields-4                   	 4941025	       242.9 ns/op	     256 B/op	       2 allocs/op
BenchmarkLog10Fields-4                  	 4140194	       289.7 ns/op	     256 B/op	       2 allocs/op
BenchmarkLog10FieldsComplex-4           	 3581312	       379.0 ns/op	     280 B/op	       3 allocs/op
BenchmarkLog10FieldsComplexAny-4        	  798502	      1471 ns/op	    1124 B/op	      23 allocs/op
BenchmarkLogPredefinedContextFields-4   	 5403194	       221.4 ns/op	     256 B/op	       2 allocs/op
BenchmarkLogPassedContextFields-4       	 3036115	       395.2 ns/op	     978 B/op	       6 allocs/op
BenchmarkLogPassedGinContextFields-4    	 2135607	       561.6 ns/op	    1363 B/op	       6 allocs/op

# 6 cores
BenchmarkLogEmpty-6                     	 7051023	       160.5 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog-6                          	 5981791	       201.9 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog4Fields-6                   	 6301800	       198.6 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog10Fields-6                  	 5392446	       223.0 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog10FieldsComplex-6           	 4270286	       246.2 ns/op	     281 B/op	       3 allocs/op
BenchmarkLog10FieldsComplexAny-6        	 1000000	      1093 ns/op	    1128 B/op	      23 allocs/op
BenchmarkLogPredefinedContextFields-6   	 6509941	       176.9 ns/op	     257 B/op	       2 allocs/op
BenchmarkLogPassedContextFields-6       	 3420057	       353.7 ns/op	     980 B/op	       6 allocs/op
BenchmarkLogPassedGinContextFields-6    	 2341536	       502.4 ns/op	    1366 B/op	       6 allocs/op

# 8 cores
BenchmarkLogEmpty-8                     	 6564950	       171.6 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog-8                          	 5764022	       207.3 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog4Fields-8                   	 5854122	       201.6 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog10Fields-8                  	 5214798	       233.6 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog10FieldsComplex-8           	 4589498	       263.1 ns/op	     281 B/op	       3 allocs/op
BenchmarkLog10FieldsComplexAny-8        	 1000000	      1090 ns/op	    1133 B/op	      23 allocs/op
BenchmarkLogPredefinedContextFields-8   	 6285962	       189.6 ns/op	     257 B/op	       2 allocs/op
BenchmarkLogPassedContextFields-8       	 3472855	       343.9 ns/op	     980 B/op	       6 allocs/op
BenchmarkLogPassedGinContextFields-8    	 2423517	       491.9 ns/op	    1366 B/op	       6 allocs/op

# 10 cores
BenchmarkLogEmpty-10                      	 6244230	       191.7 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog-10                           	 5582205	       213.8 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog4Fields-10                    	 5682394	       214.8 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog10Fields-10                   	 4737988	       246.5 ns/op	     258 B/op	       2 allocs/op
BenchmarkLog10FieldsComplex-10            	 4265218	       267.5 ns/op	     282 B/op	       3 allocs/op
BenchmarkLog10FieldsComplexAny-10         	 1000000	      1088 ns/op	    1136 B/op	      23 allocs/op
BenchmarkLogPredefinedContextFields-10    	 6228145	       195.6 ns/op	     257 B/op	       2 allocs/op
BenchmarkLogPassedContextFields-10        	 3502688	       338.5 ns/op	     981 B/op	       6 allocs/op
BenchmarkLogPassedGinContextFields-10     	 2381913	       501.8 ns/op	    1367 B/op	       6 allocs/op

# 12 cores
BenchmarkLogEmpty-12                      	 6676146	       170.5 ns/op	     257 B/op	       2 allocs/op
BenchmarkLog-12                           	 5818592	       206.7 ns/op	     258 B/op	       2 allocs/op
BenchmarkLog4Fields-12                    	 5759398	       206.3 ns/op	     258 B/op	       2 allocs/op
BenchmarkLog10Fields-12                   	 4973750	       239.9 ns/op	     258 B/op	       2 allocs/op
BenchmarkLog10FieldsComplex-12            	 4503340	       268.2 ns/op	     282 B/op	       3 allocs/op
BenchmarkLog10FieldsComplexAny-12         	 1000000	      1053 ns/op	    1139 B/op	      23 allocs/op
BenchmarkLogPredefinedContextFields-12    	 6240646	       190.2 ns/op	     258 B/op	       2 allocs/op
BenchmarkLogPassedContextFields-12        	 3544420	       373.8 ns/op	     982 B/op	       6 allocs/op
BenchmarkLogPassedGinContextFields-12     	 2345589	       509.7 ns/op	    1369 B/op	       6 allocs/op

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Init

func Init(opt Option)

func Printf

func Printf(format string, args ...interface{})

func Println

func Println(args ...interface{})

func Sync

func Sync() error

Types

type CtxHook

type CtxHook func(ctx context.Context) map[string]interface{}

type Event

type Event struct {
	// contains filtered or unexported fields
}

func Debug

func Debug(ctx ...context.Context) *Event

func Error

func Error(ctx ...context.Context) *Event

func Fatal

func Fatal(ctx ...context.Context) *Event

func Info

func Info(ctx ...context.Context) *Event

func Warn

func Warn(ctx ...context.Context) *Event

func (*Event) Any

func (e *Event) Any(key string, val interface{}) *Event

func (*Event) Bool

func (e *Event) Bool(key string, val bool) *Event

func (*Event) Err

func (e *Event) Err(err error) *Event

func (*Event) Float64

func (e *Event) Float64(key string, val float64) *Event

func (*Event) Int

func (e *Event) Int(key string, val int) *Event

func (*Event) Int64

func (e *Event) Int64(key string, val int64) *Event

func (*Event) Msg

func (e *Event) Msg(msg string)

func (*Event) Msgf

func (e *Event) Msgf(format string, args ...interface{})

func (*Event) Send

func (e *Event) Send()

func (*Event) Str

func (e *Event) Str(key string, val string) *Event

func (*Event) Time added in v1.0.2

func (e *Event) Time(key string, val time.Time) *Event

type Logger

type Logger struct {
	// contains filtered or unexported fields
}

func AddCtxHook

func AddCtxHook(fn CtxHook) *Logger

func New

func New(opt Option) *Logger

func With

func With(key string, val interface{}) *Logger

func (*Logger) AddCtxHook

func (l *Logger) AddCtxHook(fn CtxHook) *Logger

func (*Logger) Debug

func (l *Logger) Debug(ctx ...context.Context) *Event

func (*Logger) Error

func (l *Logger) Error(ctx ...context.Context) *Event

func (*Logger) Fatal

func (l *Logger) Fatal(ctx ...context.Context) *Event

func (*Logger) Info

func (l *Logger) Info(ctx ...context.Context) *Event

func (*Logger) Printf

func (l *Logger) Printf(format string, args ...interface{})

func (*Logger) Println

func (l *Logger) Println(args ...interface{})

func (*Logger) Sync

func (l *Logger) Sync() error

func (*Logger) Warn

func (l *Logger) Warn(ctx ...context.Context) *Event

func (*Logger) With

func (l *Logger) With(key string, val interface{}) *Logger

type Option

type Option struct {
	Dir            string
	Filename       string
	DisableConsole bool
	DailyRotation  bool
	MaxSize        int // in MB
	MaxAge         int // in day
	SkipLevel      int
	Timezone       *time.Location
	Writer         io.Writer
	Pretty         bool
}

func DefaultOption

func DefaultOption() Option

DefaultOption with Asia/Shanghai timezone has no daily rotation and only enables console output.

func (Option) SetDailyRotation

func (o Option) SetDailyRotation(rotation bool) Option

func (Option) SetDir

func (o Option) SetDir(dir string) Option

func (Option) SetDisableConsole

func (o Option) SetDisableConsole(disable bool) Option

func (Option) SetFilename

func (o Option) SetFilename(filename string) Option

func (Option) SetMaxAge

func (o Option) SetMaxAge(age int) Option

func (Option) SetMaxSize

func (o Option) SetMaxSize(size int) Option

func (Option) SetPretty added in v1.1.0

func (o Option) SetPretty(pretty bool) Option

func (Option) SetSkipLevel

func (o Option) SetSkipLevel(level int) Option

func (Option) SetTimezone

func (o Option) SetTimezone(tz *time.Location) Option

func (Option) SetWriter

func (o Option) SetWriter(w io.Writer) Option

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL