logit

package module
v1.5.10 Latest Latest
Warning

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

Go to latest
Published: Jan 18, 2024 License: Apache-2.0 Imports: 13 Imported by: 19

README

📝 logit

Go Doc License Coverage Test

logit 是一个基于级别控制的高性能纯结构化日志库,可以应用于所有的 GoLang 应用程序中。

Read me in English

🥇 功能特性
  • 兼容标准库 Handler 的扩展设计,并且提供了更高的性能。
  • 支持日志级别控制,一共有四个日志级别,分别是 debug,info,warn,error。
  • 支持键值对形式的结构化日志记录,同时对格式化操作也有支持。
  • 支持以 Text/Json 形式输出日志信息,方便对日志进行解析。
  • 支持异步回写日志,提供高性能缓冲写出器模块,减少 IO 的访问次数。
  • 提供调优使用的全局配置,对一些高级配置更贴合实际业务的需求。
  • 加入 Context 机制,更优雅地使用日志,并支持业务分组划分。
  • 支持拦截器模式,可以从 context 注入外部常量或变量,简化日志输出流程。
  • 支持错误监控,可以很方便地进行错误统计和告警。
  • 支持日志按大小自动分割,并支持按照时间和数量自动清理。
  • 支持多种配置文件序列化成 option,比如 json/yaml/toml/bson,然后创建日志记录器。

历史版本的特性请查看 HISTORY.md。未来版本的新特性和计划请查看 FUTURE.md

由于 Go1.21 增加了 slog 日志包,基本确定了 Go 风格的日志 API,所以 logit v1.5.0 版本开始也调整为类似的风格,并且提供更多的功能和更高的性能。

🚀 安装方式
$ go get -u github.com/FishGoddess/logit
📖 参考案例
package main

import (
	"context"
	"fmt"

	"github.com/FishGoddess/logit"
)

func main() {
	// Use default logger to log.
	// By default, logs will be output to stdout.
	// logit.Default() returns the default logger, but we also provide some common logging functions.
	logit.Info("hello from logit", "key", 123)
	logit.Default().Info("hello from logit", "key", 123)

	// Use a new logger to log.
	// By default, logs will be output to stdout.
	logger := logit.NewLogger()

	logger.Debug("new version of logit", "version", "1.5.0-alpha", "date", 20231122)
	logger.Error("new version of logit", "version", "1.5.0-alpha", "date", 20231122)

	type user struct {
		ID   int64  `json:"id"`
		Name string `json:"name"`
	}

	u := user{123456, "fishgoddess"}
	logger.Info("user information", "user", u, "pi", 3.14)

	// Yep, I know you want to output logs to a file, try WithFile option.
	// The path in WithFile is where the log file will be stored.
	// Also, it's a good choice to call logger.Close() when program shutdown.
	logger = logit.NewLogger(logit.WithFile("./logit.log"))
	defer logger.Close()

	logger.Info("check where I'm logged", "file", "logit.log")

	// What if I want to use default logger and output logs to a file? Try SetDefault.
	// It sets a logger to default and you can use it by package functions or Default().
	logit.SetDefault(logger)
	logit.Warn("this is from default logger", "pi", 3.14, "default", true)

	// If you want to change level of logger to info, try WithInfoLevel.
	// Other levels is similar to info level.
	logger = logit.NewLogger(logit.WithInfoLevel())

	logger.Debug("debug logs will be ignored")
	logger.Info("info logs can be logged")

	// If you want to pass logger by context, use NewContext and FromContext.
	ctx := logit.NewContext(context.Background(), logger)

	logger = logit.FromContext(ctx)
	logger.Info("logger from context", "from", "context")

	// Don't want to panic when new a logger? Try NewLoggerGracefully.
	logger, err := logit.NewLoggerGracefully(logit.WithFile(""))
	if err != nil {
		fmt.Println("new logger gracefully failed:", err)
	}
}

更多使用案例请查看 _examples 目录。

🔥 性能测试
$ make bench
goos: linux
goarch: amd64
cpu: AMD EPYC 7K62 48-Core Processor

BenchmarkLogitLogger-2                   1486184               810 ns/op               0 B/op          0 allocs/op
BenchmarkLogitLoggerTextHandler-2        1000000              1080 ns/op               0 B/op          0 allocs/op
BenchmarkLogitLoggerJsonHandler-2         847864              1393 ns/op             120 B/op          3 allocs/op
BenchmarkLogitLoggerPrint-2              1222302               981 ns/op              48 B/op          1 allocs/op
BenchmarkSlogLoggerTextHandler-2          725522              1629 ns/op               0 B/op          0 allocs/op
BenchmarkSlogLoggerJsonHandler-2          583214              2030 ns/op             120 B/op          3 allocs/op
BenchmarkZeroLogLogger-2                 1929276               613 ns/op               0 B/op          0 allocs/op
BenchmarkZapLogger-2                      976855              1168 ns/op             216 B/op          2 allocs/op
BenchmarkLogrusLogger-2                   231723              4927 ns/op            2080 B/op         32 allocs/op

BenchmarkLogitFile-2                      624774              1935 ns/op               0 B/op          0 allocs/op
BenchmarkLogitFileWithBuffer-2           1378076               873 ns/op               0 B/op          0 allocs/op
BenchmarkLogitFileWithBatch-2            1367479               883 ns/op               0 B/op          0 allocs/op
BenchmarkSlogFile-2                       407590              2944 ns/op               0 B/op          0 allocs/op
BenchmarkZeroLogFile-2                    634375              1810 ns/op               0 B/op          0 allocs/op
BenchmarkZapFile-2                        382790              2641 ns/op             216 B/op          2 allocs/op
BenchmarkLogrusFile-2                     174944              6491 ns/op            2080 B/op         32 allocs/op

注:WithBuffer 和 WithBatch 分别是使用了缓冲器和批量写入的方式进行测试。

测试文件:_examples/performance_test.go

👥 贡献者

如果您觉得 logit 缺少您需要的功能,请不要犹豫,马上参与进来,发起一个 issue

Star History Chart

Documentation

Overview

Package logit provides an easy way to use foundation for your logging operations.

1. basic:

// Use default logger to log.
// By default, logs will be output to stdout.
// logit.Default() returns the default logger, but we also provide some common logging functions.
logit.Info("hello from logit", "key", 123)
logit.Default().Info("hello from logit", "key", 123)

// Use a new logger to log.
// By default, logs will be output to stdout.
logger := logit.NewLogger()

logger.Debug("new version of logit", "version", "1.5.0-alpha", "date", 20231122)
logger.Error("new version of logit", "version", "1.5.0-alpha", "date", 20231122)

type user struct {
	ID   int64  `json:"id"`
	Name string `json:"name"`
}

u := user{123456, "fishgoddess"}
logger.Info("user information", "user", u, "pi", 3.14)

// Yep, I know you want to output logs to a file, try WithFile option.
// The path in WithFile is where the log file will be stored.
// Also, it's a good choice to call logger.Close() when program shutdown.
logger = logit.NewLogger(logit.WithFile("./logit.log"))
defer logger.Close()

logger.Info("check where I'm logged", "file", "logit.log")

// What if I want to use default logger and output logs to a file? Try SetDefault.
// It sets a logger to default and you can use it by package functions or Default().
logit.SetDefault(logger)
logit.Warn("this is from default logger", "pi", 3.14, "default", true)

// If you want to change level of logger to info, try WithInfoLevel.
// Other levels is similar to info level.
logger = logit.NewLogger(logit.WithInfoLevel())

logger.Debug("debug logs will be ignored")
logger.Info("info logs can be logged")

// If you want to pass logger by context, use NewContext and FromContext.
ctx := logit.NewContext(context.Background(), logger)

logger = logit.FromContext(ctx)
logger.Info("logger from context", "from", "context")

// Don't want to panic when new a logger? Try NewLoggerGracefully.
logger, err := logit.NewLoggerGracefully(logit.WithFile(""))
if err != nil {
	fmt.Println("new logger gracefully failed:", err)
}

2. logger:

// Default() will return the default logger.
// You can new a logger or just use the default logger.
logger := logit.Default()
logger.Info("nothing carried")

// Use With() to carry some args in logger.
// All logs output by this logger will carry these args.
logger = logger.With("carry", 666, "who", "me")

logger.Info("see what are carried")
logger.Error("error carried", "err", io.EOF)

// Use WithGroup() to group args in logger.
// All logs output by this logger will group args.
logger = logger.WithGroup("xxx")

logger.Info("what group")
logger.Error("error group", "err", io.EOF)

// If you want to check if one level can be logged, try this:
if logger.DebugEnabled() {
	logger.Debug("debug enabled")
}

// We provide some old-school logging methods.
// They are using info level by default.
// If you want to change the level, see defaults.LevelPrint.
logger.Printf("printf %s log", "formatted")
logger.Print("print log")
logger.Println("println log")

// Some useful method:
logger.Sync()
logger.Close()

3. handler:

// By default, logit uses tape handler to output logs.
logger := logit.NewLogger()
logger.Info("default handler logging")

// You can change it to other handlers by options.
// For example, use json handler:
logger = logit.NewLogger(logit.WithJsonHandler())
logger.Info("using json handler")

// Or you want to use customized handlers, try Register.
newHandler := func(w io.Writer, opts *slog.HandlerOptions) slog.Handler {
	return slog.NewTextHandler(w, opts)
}

if err := handler.Register("demo", newHandler); err != nil {
	panic(err)
}

logger = logit.NewLogger(logit.WithHandler("demo"))
logger.Info("using demo handler")

// As you can see, our handler is slog's handler, so you can use any handlers implement this interface.
newHandler = func(w io.Writer, opts *slog.HandlerOptions) slog.Handler {
	return slog.NewJSONHandler(w, opts)
}

4. writer:

// A new logger outputs logs to stdout.
logger := logit.NewLogger()
logger.Debug("log to stdout")

// What if I want to output logs to stderr? Try WithStderr.
logger = logit.NewLogger(logit.WithStderr())
logger.Debug("log to stderr")

// Also, you can use WithWriter to specify your own writer.
logger = logit.NewLogger(logit.WithWriter(os.Stdout))
logger.Debug("log to writer")

// How to output logs to a file? Try WithFile and WithRotateFile.
// Rotate file is useful in production, see _examples/file.go.
logger = logit.NewLogger(logit.WithFile("logit.log"))
logger.Debug("log to file")

logger = logit.NewLogger(logit.WithRotateFile("logit.log"))
logger.Debug("log to rotate file")

5. file:

// AS we know, you can use WithFile to output logs to a file.
logger := logit.NewLogger(logit.WithFile("logit.log"))
logger.Debug("debug to file")

// However, a single file stored all logs isn't enough in production.
// Sometimes we want a log file has a limit size and count of files not greater than a number.
// So we provide a rotate file to do this thing.
logger = logit.NewLogger(logit.WithRotateFile("logit.log"))
defer logger.Close()

logger.Debug("debug to rotate file")

// Maybe you have noticed that WithRotateFile can pass some rotate.Option.
// These options are used to setup the rotate file.
opts := []rotate.Option{
	rotate.WithMaxSize(128 * rotate.MB),
	rotate.WithMaxAge(30 * rotate.Day),
	rotate.WithMaxBackups(60),
}

logger = logit.NewLogger(logit.WithRotateFile("logit.log", opts...))
defer logger.Close()

logger.Debug("debug to rotate file with rotate options")

// See rotate.File if you want to use this magic in other scenes.
file, err := rotate.New("logit.log")
if err != nil {
	panic(err)
}

defer file.Close()

6. option:

// As you can see, NewLogger can use some options to create a logger.
logger := logit.NewLogger(logit.WithDebugLevel())
logger.Debug("debug log")

// We provide some options for different scenes and all options have prefix "With".
// Change logger level:
logit.WithDebugLevel()
logit.WithInfoLevel()
logit.WithWarnLevel()
logit.WithDebugLevel()

// Change logger handler:
logit.WithHandler("xxx")
logit.WithTapeHandler()
logit.WithTextHandler()
logit.WithJsonHandler()

// Change handler writer:
logit.WithWriter(os.Stdout)
logit.WithStdout()
logit.WithStderr()
logit.WithFile("")
logit.WithRotateFile("")

// Some useful flags:
logit.WithSource()
logit.WithPID()

// More options can be found in logit package which have prefix "With".
// What's more? We provide a options pack that we think it's useful in production.
opts := logit.ProductionOptions()

logger = logit.NewLogger(opts...)
defer logger.Close()

logger.Info("log from production options")
logger.Error("error log from production options")

7. context:

// We provide a way for getting logger from a context.
// By default, the default logger will be returned if there is no logit.Logger in context.
ctx := context.Background()

logger := logit.FromContext(ctx)
logger.Debug("logger from context debug")

if logger == logit.Default() {
	logger.Info("logger from context is default logger")
}

// Use NewContext to set a logger to context.
// We use WithGroup here to make a difference to default logger.
logger = logit.NewLogger().WithGroup("context").With("user_id", 123456)
ctx = logit.NewContext(ctx, logger)

// Then you can get the logger from context.
logger = logit.FromContext(ctx)
logger.Debug("logger from context debug", "key", "value")

8. default:

// We set a defaults package that setups all shared fields.
// For example, if you want to customize the time getter:
defaults.CurrentTime = func() time.Time {
	// Return a fixed time for example.
	return time.Unix(666, 0).In(time.Local)
}

logit.Print("println log is info level")

// If you want change the level of old-school logging methods:
defaults.LevelPrint = slog.LevelDebug

logit.Print("println log is debug level now")

// More fields see defaults package.
defaults.HandleError = func(label string, err error) {
	fmt.Printf("%s: %+n\n", label, err)
}

9. config:

// newConfig reads config from a json file.
func newConfig() (*config.Config, error) {
	conf := new(config.Config)

	bs, err := os.ReadFile("config.json")
	if err != nil {
		return nil, err
	}

	err = json.Unmarshal(bs, conf)
	if err != nil {
		return nil, err
	}

	return conf, err
}

// We know you may use a configuration file in your program to setup some resources including logging.
// After thinking about serval kinds of configurations like "yaml", "toml" and "json", we decide to support all of them.
// As you can see, there are many tags on Config's fields like "yaml" and "toml", so you can unmarshal to a config from one of them.
conf, err := newConfig()
if err != nil {
	panic(err)
}

opts, err := conf.Options()
if err != nil {
	panic(err)
}

// Use options to create a logger.
logger := logit.NewLogger(opts...)
defer logger.Close()

logger.Info("logging from config", "conf", conf)

Index

Constants

View Source
const (
	// Version is the version string representation of logit.
	Version = "v1.5.10"
)

Variables

This section is empty.

Functions

func Close added in v0.6.0

func Close() error

Close closes the default logger and returns an error if failed.

func Debug added in v0.0.2

func Debug(msg string, args ...any)

Debug logs a log with msg and args in debug level.

func Error added in v0.0.2

func Error(msg string, args ...any)

Error logs a log with msg and args in error level.

func Info added in v0.0.2

func Info(msg string, args ...any)

Info logs a log with msg and args in info level.

func NewContext added in v0.4.10

func NewContext(ctx context.Context, logger *Logger) context.Context

NewContext wraps context with logger and returns a new context.

func Print added in v0.6.0

func Print(args ...interface{})

Print logs a log with args in print level. It a old-school way to log.

func Printf added in v0.6.0

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

Printf logs a log with format and args in print level. It a old-school way to log.

func Println added in v0.6.0

func Println(args ...interface{})

Println logs a log with args in print level. It a old-school way to log.

func SetDefault added in v1.5.10

func SetDefault(logger *Logger)

SetDefault sets logger as the default logger.

func Sync added in v0.6.0

func Sync() error

Sync syncs the default logger and returns an error if failed.

func Warn added in v0.0.4

func Warn(msg string, args ...any)

Warn logs a log with msg and args in warn level.

Types

type Logger

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

Logger is the entry of logging in logit. It has several levels including debug, info, warn and error. It's also a syncer or closer if handler is a syncer or closer.

func Default added in v1.5.10

func Default() *Logger

Default returns the default logger.

func FromContext added in v0.4.10

func FromContext(ctx context.Context) *Logger

FromContext gets logger from context and returns the default logger if missed.

func NewLogger

func NewLogger(opts ...Option) *Logger

NewLogger creates a logger with given options or panics if failed. If you don't want to panic on failing, use NewLoggerGracefully instead.

func NewLoggerGracefully added in v1.5.10

func NewLoggerGracefully(opts ...Option) (*Logger, error)

NewLoggerGracefully creates a logger with given options or returns an error if failed. It's a more graceful way to create a logger than NewLogger function.

func (*Logger) Close added in v0.4.10

func (l *Logger) Close() error

Close closes the logger and returns an error if failed.

func (*Logger) Debug

func (l *Logger) Debug(msg string, args ...any)

Debug logs a log with msg and args in debug level.

func (*Logger) DebugEnabled added in v1.5.10

func (l *Logger) DebugEnabled() bool

DebugEnabled reports whether the logger should ignore logs whose level is lower than debug.

func (*Logger) Error

func (l *Logger) Error(msg string, args ...any)

Error logs a log with msg and args in error level.

func (*Logger) ErrorEnabled added in v1.5.10

func (l *Logger) ErrorEnabled() bool

ErrorEnabled reports whether the logger should ignore logs whose level is lower than error.

func (*Logger) Info

func (l *Logger) Info(msg string, args ...any)

Info logs a log with msg and args in info level.

func (*Logger) InfoEnabled added in v1.5.10

func (l *Logger) InfoEnabled() bool

InfoEnabled reports whether the logger should ignore logs whose level is lower than info.

func (*Logger) Print added in v0.4.15

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

Print logs a log with args in print level. It a old-school way to log.

func (*Logger) PrintEnabled added in v1.5.10

func (l *Logger) PrintEnabled() bool

PrintEnabled reports whether the logger should ignore logs whose level is lower than print.

func (*Logger) Printf added in v0.4.15

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

Printf logs a log with format and args in print level. It a old-school way to log.

func (*Logger) Println added in v0.4.15

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

Println logs a log with args in print level. It a old-school way to log.

func (*Logger) Sync added in v0.6.0

func (l *Logger) Sync() error

Sync syncs the logger and returns an error if failed.

func (*Logger) Warn added in v0.0.4

func (l *Logger) Warn(msg string, args ...any)

Warn logs a log with msg and args in warn level.

func (*Logger) WarnEnabled added in v1.5.10

func (l *Logger) WarnEnabled() bool

WarnEnabled reports whether the logger should ignore logs whose level is lower than warn.

func (*Logger) With added in v1.5.10

func (l *Logger) With(args ...any) *Logger

With returns a new logger with args. All logs from the new logger will carry the given args. See slog.Handler.WithAttrs.

func (*Logger) WithGroup added in v1.5.10

func (l *Logger) WithGroup(name string) *Logger

WithGroup returns a new logger with group name. All logs from the new logger will be grouped by the name. See slog.Handler.WithGroup.

type Option added in v0.4.10

type Option func(conf *config)

Option sets some fields to config.

func ProductionOptions added in v1.5.10

func ProductionOptions() []Option

ProductionOptions returns some options that we think they are useful in production. We recommend you to use them, so we provide this convenient way to create such a logger.

func WithBatch added in v1.5.10

func WithBatch(batchSize uint64) Option

WithBatch sets a batch writer to config. You should specify a batch size in count. The remained logs in batch may discard if you kill the process without syncing or closing the logger.

func WithBuffer added in v1.5.10

func WithBuffer(bufferSize uint64) Option

WithBuffer sets a buffer writer to config. You should specify a buffer size in bytes. The remained data in buffer may discard if you kill the process without syncing or closing the logger.

func WithDebugLevel added in v1.5.10

func WithDebugLevel() Option

WithDebugLevel sets debug level to config.

func WithErrorLevel added in v1.5.10

func WithErrorLevel() Option

WithErrorLevel sets error level to config.

func WithFile added in v1.5.10

func WithFile(path string) Option

WithFile sets file to config. All logs will be written to a file in path. It will create all directories in path if not existed. The permission bits can be specified by defaults package. See defaults.FileDirMode and defaults.FileMode. If you want to customize the way open dir or file, see defaults.OpenFileDir and defaults.OpenFile.

func WithHandler added in v1.5.10

func WithHandler(handler string) Option

WithHandler sets handler to config. See RegisterHandler.

func WithInfoLevel added in v1.5.10

func WithInfoLevel() Option

WithInfoLevel sets info level to config.

func WithJsonHandler added in v1.5.10

func WithJsonHandler() Option

WithJsonHandler sets json handler to config.

func WithPID added in v1.5.10

func WithPID() Option

WithPID sets withPID=true to config. All logs will carry the process id.

func WithReplaceAttr added in v1.5.10

func WithReplaceAttr(replaceAttr func(groups []string, attr slog.Attr) slog.Attr) Option

WithReplaceAttr sets replaceAttr to config.

func WithRotateFile added in v1.5.10

func WithRotateFile(path string, opts ...rotate.Option) Option

WithRotateFile sets rotate file to config. All logs will be written to a rotate file in path. A rotate file is useful in production, see rotate.File. The permission bits can be specified by defaults package. See defaults.FileDirMode and defaults.FileMode. Use rotate.Option to customize your rotate file.

func WithSource added in v1.5.10

func WithSource() Option

WithSource sets withSource=true to config. All logs will carry their caller information like file and line.

func WithStderr added in v1.5.10

func WithStderr() Option

WithStderr sets os.Stderr to config. All logs will be written to stderr.

func WithStdout added in v1.5.10

func WithStdout() Option

WithStdout sets os.Stdout to config. All logs will be written to stdout.

func WithSyncTimer added in v1.5.10

func WithSyncTimer(d time.Duration) Option

WithSyncTimer sets a sync timer duration to config. It will call Sync() so it depends on the handler used by logger.

func WithTapeHandler added in v1.5.10

func WithTapeHandler() Option

WithTapeHandler sets tape handler to config.

func WithTextHandler added in v1.5.10

func WithTextHandler() Option

WithTextHandler sets text handler to config.

func WithWarnLevel added in v1.5.10

func WithWarnLevel() Option

WithWarnLevel sets warn level to config.

func WithWriter added in v1.5.10

func WithWriter(w io.Writer) Option

WithWriter sets writer to config. The writer is for writing logs.

type Syncer added in v1.5.10

type Syncer interface {
	Sync() error
}

Syncer is an interface that syncs data to somewhere.

Directories

Path Synopsis
extension

Jump to

Keyboard shortcuts

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