logit

package module
v0.5.8 Latest Latest
Warning

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

Go to latest
Published: Oct 1, 2022 License: Apache-2.0 Imports: 11 Imported by: 0

README

📝 logit

Go Doc License Coverage Test

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

Read me in English

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

更多 logit 生态的东西请查看 GitHub / 码云

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

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

import (
	"context"
	"io"
	"os"

	"github.com/go-logit/logit"
	"github.com/go-logit/logit/support/global"
)

func main() {
	// Create a new logger for use.
	// Default level is debug, so all logs will be logged.
	// Invoke Close() isn't necessary in all situations.
	// If logger's writer has buffer or something like that, it's better to invoke Close() for syncing buffer or something else.
	logger := logit.NewLogger()
	//defer logger.Close()

	// Then, you can log anything you want.
	// Remember, logs will be ignored if their level is smaller than logger's level.
	// Log() will do some finishing work, so this invocation is necessary.
	logger.Debug("This is a debug message").Log()
	logger.Info("This is an info message").Log()
	logger.Warn("This is a warn message").Log()
	logger.Error("This is an error message").Log()
	logger.Error("This is a %s message, with format", "error").Log() // Format with params.

	// As you know, we provide some levels: debug, info, warn, error, off.
	// The lowest is debug and the highest is off.
	// If you want to change the level of your logger, do it at creating.
	logger = logit.NewLogger(logit.Options().WithWarnLevel())
	logger.Debug("This is a debug message, but ignored").Log()
	logger.Info("This is an info message, but ignored").Log()
	logger.Warn("This is a warn message, not ignored").Log()
	logger.Error("This is an error message, not ignored").Log()

	// Also, we provide some "old school" log method :)
	// (Don't mistake~ I love old school~)
	logger.Printf("This is a log %s, and it's for compatibility", "printed")
	logger.Print("This is a log printed, and it's for compatibility", 123)
	logger.Println("This is a log printed, and it's for compatibility", 666)

	// If you want to log with some fields, try this:
	user := struct {
		ID   int64  `json:"id"`
		Name string `json:"name"`
		Age  int    `json:"age"`
	}{
		ID:   666,
		Name: "FishGoddess",
		Age:  3,
	}
	logger.Warn("This is a structured message").Any("user", user).Json("userJson", user).Log()
	logger.Error("This is a structured message").Error("err", io.EOF).Int("trace", 123).Log()

	// You may notice logit.Options() which returns an options list.
	// Here is some of them:
	options := logit.Options()
	options.WithCaller()                          // Let logs carry caller information.
	options.WithLevelKey("lvl")                   // Change logger's level key to "lvl".
	options.WithWriter(os.Stderr)                 // Change logger's writer to os.Stderr without buffer or batch.
	options.WithBufferWriter(os.Stderr)           // Change logger's writer to os.Stderr with buffer.
	options.WithBatchWriter(os.Stderr)            // Change logger's writer to os.Stderr with batch.
	options.WithErrorWriter(os.Stderr)            // Change logger's error writer to os.Stderr without buffer or batch.
	options.WithTimeFormat("2006-01-02 15:04:05") // Change the format of time (Only the log's time will apply it).

	// You can bind context with logger and use it as long as you can get the context.
	ctx := logit.NewContext(context.Background(), logger)
	logger = logit.FromContext(ctx)
	logger.Info("Logger from context").Log()

	// You can initialize the global logger if you don't want to use an independent logger.
	// WithCallerDepth will set the depth of caller, and default is core.CallerDepth.
	// Functions in global logger are wrapped so depth of caller should be increased 1.
	// You can specify your depth if you wrap again or have something else reasons.
	logger = logit.NewLogger(options.WithCallerDepth(global.CallerDepth + 1))
	logit.SetGlobal(logger)
	logit.Info("Info from logit").Log()

	// We don't recommend you to call logit.SetGlobal unless you really need to call.
	// Instead, we recommend you to call logger.SetToGlobal to set one logger to global if you need.
	logger.SetToGlobal()
	logit.Println("Println from logit")
}

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

🔥 性能测试
$ make bench
$ make benchfile
测试(输出到内存) 单位时间内运行次数 (越大越好) 每个操作消耗时间 (越小越好) B/op (越小越好) allocs/op (越小越好)
logit 707851   1704 ns/op       0 B/op     0 allocs/op
zerolog 706714   1585 ns/op       0 B/op     0 allocs/op
zap 389608   4688 ns/op   865 B/op     8 allocs/op
logrus   69789 17142 ns/op 8885 B/op 136 allocs/op
测试(输出到文件) 单位时间内运行次数 (越大越好) 每个操作消耗时间 (越小越好) B/op (越小越好) allocs/op (越小越好)
logit 636033   1822 ns/op       0 B/op     0 allocs/op
logit-不缓冲 354542   3502 ns/op       0 B/op     0 allocs/op
zerolog 354676   3440 ns/op       0 B/op     0 allocs/op
zap 195354   6843 ns/op   865 B/op     8 allocs/op
logrus   58030 21088 ns/op 8885 B/op 136 allocs/op

测试文件:_examples/performance_test.go

测试环境:R7-5800X CPU@3.8GHZ,32GB RAM,512GB SSD,Linux/Manjaro

👥 贡献者

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

📦 使用 logit 的项目
项目 作者 描述 链接
postar avino-plan 一个极易上手的低耦合通用邮件服务 Github / 码云
kafo FishGoddess 一个简单的轻量级分布式缓存中间件 Github / 码云

最后,我想感谢 JetBrains 公司的 free JetBrains Open Source license(s),因为 logit 是用该计划下的 Idea / GoLand 完成开发的。

Documentation

Overview

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

1. basic:

// Create a new logger for use.
// Default level is debug, so all logs will be logged.
// Invoke Close() isn't necessary in all situations.
// If logger's writer has buffer or something like that, it's better to invoke Close() for syncing buffer or something else.
logger := logit.NewLogger()
//defer logger.Close()

// Then, you can log anything you want.
// Remember, logs will be ignored if their level is smaller than logger's level.
// Log() will do some finishing work, so this invocation is necessary.
logger.Debug("This is a debug message").Log()
logger.Info("This is an info message").Log()
logger.Warn("This is a warn message").Log()
logger.Error("This is an error message").Log()
logger.Error("This is a %s message, with format", "error").Log() // Format with params.

// As you know, we provide some levels: debug, info, warn, error, off.
// The lowest is debug and the highest is off.
// If you want to change the level of your logger, do it at creating.
logger = logit.NewLogger(logit.Options().WithWarnLevel())
logger.Debug("This is a debug message, but ignored").Log()
logger.Info("This is an info message, but ignored").Log()
logger.Warn("This is a warn message, not ignored").Log()
logger.Error("This is an error message, not ignored").Log()

// Also, we provide some "old school" log method :)
// (Don't mistake~ I love old school~)
logger.Printf("This is a log %s, and it's for compatibility", "printed")
logger.Print("This is a log printed, and it's for compatibility", 123)
logger.Println("This is a log printed, and it's for compatibility", 666)

// If you want to log with some fields, try this:
user := struct {
	ID   int64  `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}{
	ID:   666,
	Name: "FishGoddess",
	Age:  3,
}
logger.Warn("This is a structured message").Any("user", user).Json("userJson", user).Log()
logger.Error("This is a structured message").Error("err", io.EOF).Int("trace", 123).Log()

// You may notice logit.Options() which returns an options list.
// Here is some of them:
options := logit.Options()
options.WithCaller()                          // Let logs carry caller information.
options.WithLevelKey("lvl")                   // Change logger's level key to "lvl".
options.WithWriter(os.Stderr)                 // Change logger's writer to os.Stderr without buffer or batch.
options.WithBufferWriter(os.Stderr)           // Change logger's writer to os.Stderr with buffer.
options.WithBatchWriter(os.Stderr)            // Change logger's writer to os.Stderr with batch.
options.WithErrorWriter(os.Stderr)            // Change logger's error writer to os.Stderr without buffer or batch.
options.WithTimeFormat("2006-01-02 15:04:05") // Change the format of time (Only the log's time will apply it).

// You can bind context with logger and use it as long as you can get the context.
ctx := logit.NewContext(context.Background(), logger)
logger = logit.FromContext(ctx)
logger.Info("Logger from context").Log()

// You can initialize the global logger if you don't want to use an independent logger.
// WithCallerDepth will set the depth of caller, and default is core.CallerDepth.
// Functions in global logger are wrapped so depth of caller should be increased 1.
// You can specify your depth if you wrap again or have something else reasons.
logger = logit.NewLogger(options.WithCallerDepth(global.CallerDepth + 1))
logit.SetGlobal(logger)
logit.Info("Info from logit").Log()

// We don't recommend you to call logit.SetGlobal unless you really need to call.
// Instead, we recommend you to call logger.SetToGlobal to set one logger to global if you need.
logger.SetToGlobal()
logit.Println("Println from logit")

2. options:

// We provide some options for you.
options := logit.Options()
options.WithDebugLevel()
options.WithInfoLevel()
options.WithWarnLevel()
options.WithErrorLevel()
options.WithAppender(appender.Text())
options.WithDebugAppender(appender.Text())
options.WithInfoAppender(appender.Text())
options.WithWarnAppender(appender.Text())
options.WithErrorAppender(appender.Text())
options.WithPrintAppender(appender.Text())
options.WithWriter(os.Stderr)
options.WithBufferWriter(os.Stdout)
options.WithBatchWriter(os.Stdout)
options.WithDebugWriter(os.Stderr)
options.WithInfoWriter(os.Stderr)
options.WithWarnWriter(os.Stderr)
options.WithErrorWriter(os.Stderr)
options.WithPrintWriter(os.Stderr)
options.WithPID()
options.WithCaller()
options.WithMsgKey("msg")
options.WithTimeKey("time")
options.WithLevelKey("level")
options.WithPIDKey("pid")
options.WithFileKey("file")
options.WithLineKey("line")
options.WithFuncKey("func")
options.WithTimeFormat(appender.UnixTimeFormat) // UnixTimeFormat means time will be logged as unix time, an int64 number.
options.WithCallerDepth(3)                      // Set caller depth to 3 so the log will get the third depth caller.
options.WithInterceptors()

// Remember, these options is only used for creating a logger.
logger := logit.NewLogger(
	options.WithPID(),
	options.WithWriter(os.Stdout),
	options.WithTimeFormat("2006/01/02 15:04:05"),
	options.WithCaller(),
	options.WithCallerDepth(4),
	// ...
)

defer logger.Close()
logger.Info("check options").Log()

// You can use many options at the same time, but some of them is exclusive.
// So only the last one in order will take effect if you use them at the same time.
logit.NewLogger(
	options.WithDebugLevel(),
	options.WithInfoLevel(),
	options.WithWarnLevel(),
	options.WithErrorLevel(), // The level of logger is error.
)

// You can customize an option for your logger.
// Actually, Option is just a function like func(logger *Logger).
// So you can do what you want in creating a logger.
syncOption := func(logger *logit.Logger) {
	go func() {
		select {
		case <-time.Tick(time.Second):
			logger.Sync()
		}
	}()
}

logit.NewLogger(syncOption)

3. appender:

// We provide some ways to change the form of logs.
// Actually, appender is an interface with some common methods, see appender.Appender.
appender.Text()
appender.Json()

// Set appender to the one you want to use when creating a logger.
// Default appender is appender.Text().
logger := logit.NewLogger()
logger.Info("appender.Text()").Log()

// You can switch appender to the other one, such appender.Json().
logger = logit.NewLogger(logit.Options().WithAppender(appender.Json()))
logger.Info("appender.Json()").Log()

// Every level has its own appender, so you can append logs in different level with different appender.
logger = logit.NewLogger(
	logit.Options().WithDebugAppender(appender.Text()),
	logit.Options().WithInfoAppender(appender.Text()),
	logit.Options().WithWarnAppender(appender.Json()),
	logit.Options().WithErrorAppender(appender.Json()),
)

// Appender is an interface, so you can implement your own appender.
// However, we don't recommend you to do that.
// This interface may change in every version, so you will pay lots of extra attention to it.
// So you should implement it only if you really need to do.

// appender.TextWith can let you configure the escaping flags of text appender.
// Default will escape keys and values.
logger = logit.NewLogger(logit.Options().WithAppender(appender.Text()))
logger.Info("appender.Text() try \t \b \n and see?").Byte("byte\n", '\n').Rune("rune\n", '\n').String("1\t2\b3\n4", "1\t2\b3\n4").Log()
logger.Info("appender.Text() try \t \b \n and see?").Bytes("bytes\n", []byte{'\t', '\b', '\n'}).Runes("runes\n", []rune{'\t', '\b', '\n'}).Strings("1\t2\b3\n4", []string{"1\t2\b3\n4"}).Log()

logger = logit.NewLogger(logit.Options().WithAppender(appender.TextWith(true, false)))
logger.Info("appender.TextWith(true, false) try \t \b \n and see?").Byte("byte\n", '\n').Rune("rune\n", '\n').String("1\t2\b3\n4", "1\t2\b3\n4").Log()
logger.Info("appender.TextWith(true, false) try \t \b \n and see?").Bytes("bytes\n", []byte{'\t', '\b', '\n'}).Runes("runes\n", []rune{'\t', '\b', '\n'}).Strings("1\t2\b3\n4", []string{"1\t2\b3\n4"}).Log()

logger = logit.NewLogger(logit.Options().WithAppender(appender.TextWith(false, true)))
logger.Info("appender.TextWith(false, true) try \t \b \n and see?").Byte("byte\n", '\n').Rune("rune\n", '\n').String("1\t2\b3\n4", "1\t2\b3\n4").Log()
logger.Info("appender.TextWith(false, true) try \t \b \n and see?").Bytes("bytes\n", []byte{'\t', '\b', '\n'}).Runes("runes\n", []rune{'\t', '\b', '\n'}).Strings("1\t2\b3\n4", []string{"1\t2\b3\n4"}).Log()

logger = logit.NewLogger(logit.Options().WithAppender(appender.TextWith(false, false)))
logger.Info("appender.TextWith(true, true) try \t \b \n and see?").Byte("byte\n", '\n').Rune("rune\n", '\n').String("1\t2\b3\n4", "1\t2\b3\n4").Log()
logger.Info("appender.TextWith(true, true) try \t \b \n and see?").Bytes("bytes\n", []byte{'\t', '\b', '\n'}).Runes("runes\n", []rune{'\t', '\b', '\n'}).Strings("1\t2\b3\n4", []string{"1\t2\b3\n4"}).Log()

4. writer:

// As you know, writer in logit is customized, not io.Writer.
// The reason why we create a new Writer interface is we want a sync-able writer.
// Then, we notice a sync-able writer also need a close method to sync all data in buffer when closing.
// So, a new Writer is born:
//
//     type Writer interface {
//	       Syncer
//	       io.WriteCloser
//     }
//
// In package writer, we provide some writers for you.
writer.Wrap(os.Stdout)   // Wrap io.Writer to writer.Writer.
writer.Buffer(os.Stderr) // Wrap io.Writer to writer.Writer with buffer, which needs invoking Sync() or Close().

// Use the writer without buffer.
logger := logit.NewLogger(logit.Options().WithWriter(os.Stdout))
logger.Info("WriterWithoutBuffer").Log()

// Use the writer with buffer, which is good for io.
logger = logit.NewLogger(logit.Options().WithBufferWriter(os.Stdout))
logger.Info("WriterWithBuffer").Log()
logger.Sync() // Remember syncing data or syncing by Close().
logger.Close()

// Use the writer with batch, which is also good for io.
logger = logit.NewLogger(logit.Options().WithBatchWriter(os.Stdout))
logger.Info("WriterWithBatch").Log()
logger.Sync() // Remember syncing data or syncing by Close().
logger.Close()

// Every level has its own appender so you can append logs in different level with different appender.
logger = logit.NewLogger(
	logit.Options().WithBufferWriter(os.Stdout),
	logit.Options().WithBatchWriter(os.Stdout),
	logit.Options().WithWarnWriter(os.Stdout),
	logit.Options().WithErrorWriter(os.Stdout),
)

// Let me explain buffer writer and batch writer.
// Both of them are base on a byte buffer and merge some writes to one write.
// Buffer writer will write data in buffer to underlying writer if bytes in buffer are too much.
// Batch writer will write data in buffer to underlying writer if writes to buffer are too much.
//
// Let's see something more interesting:
// A buffer writer with buffer size 16 KB and a batch writer with batch count 64, whose performance is better?
//
// 1. Assume one log is 512 Bytes and its size is fixed
// In buffer writer, it will merge 32 writes to 1 writes (16KB / 512Bytes);
// In batch writer, it will always merge 64 writes to 1 writes;
// Batch writer wins the game! Less writes means it's better to IO.
//
// 2. Assume one log is 128 Bytes and its size is fixed
// In buffer writer, it will merge 128 writes to 1 writes (16KB / 128Bytes);
// In batch writer, it will always merge 64 writes to 1 writes;
// Buffer writer wins the game! Less writes means it's better to IO.
//
// 3. How about one log is 256 Bytes and its size is fixed
// In buffer writer, it will merge 64 writes to 1 writes (16KB / 256Bytes);
// In batch writer, it will always merge 64 writes to 1 writes;
// They are the same in writing times.
//
// Based on what we mentioned above, we can tell the performance of buffer writer is depends on the size of log, and the batch writer is more stable.
// Actually, the size of logs in production isn't fixed-size, so batch writer may be a better choice.
// However, the buffer in batch writer is out of our control, so it may grow too large if our logs are too large.
writer.Buffer(os.Stdout)
writer.Batch(os.Stdout)
writer.BufferWithSize(os.Stdout, 16*size.KB)
writer.BatchWithCount(os.Stdout, 64)

5. global:

// There are some global settings for optimizations, and you can set all of them in need.

// 1. LogMallocSize (The pre-malloc size of a new Log data)
// If your logs are extremely long, such as 4000 bytes, you can set it to 4096 to avoid re-malloc.
global.LogMallocSize = 4 * size.MB

// 2. WriterBufferSize (The default size of buffer writer)
// If your logs are extremely long, such as 16 KB, you can set it to 2048 to avoid re-malloc.
global.WriterBufferSize = 32 * size.KB

// 3. MarshalToJson (The marshal function which marshal interface{} to json data)
// Use std by default, and you can customize your marshal function.
global.MarshalToJson = json.Marshal

// After setting global settings, just use Logger as normal.
logger := logit.NewLogger()
defer logger.Close()

logger.Info("set global settings").Uint64("LogMallocSize", global.LogMallocSize).Uint64("WriterBufferSize", global.WriterBufferSize).Log()

6. context:

// By NewContext, you can bind a context with a logger and get it from context again.
// So you can use this logger from everywhere as long as you can get this context.
ctx := logit.NewContext(context.Background(), logit.NewLogger())

// FromContext returns the logger in context.
logger := logit.FromContext(ctx)
logger.Info("This is a message logged by logger from context").Log()

// Actually, you also have a chance to specify the key of logger in context.
// It gives you a way to discriminate different businesses in using logger.
// For example, you can create two loggers for your two different usages and
// set them to a context with different key, so you can get each logger from context with each key.
businessOneKey := "businessOne"
logger = logit.NewLogger(logit.Options().WithMsgKey("businessOneMsg"))
ctx = logit.NewContextWithKey(context.Background(), businessOneKey, logger)

businessTwoKey := "businessTwo"
logger = logit.NewLogger(logit.Options().WithMsgKey("businessTwoMsg"))
ctx = logit.NewContextWithKey(ctx, businessTwoKey, logger)

// Get different logger from the same context with different key.
logger = logit.FromContextWithKey(ctx, businessOneKey)
logger.Info("This is a message logged by logger from context with businessOneKey").Log()

logger = logit.FromContextWithKey(ctx, businessTwoKey)
logger.Info("This is a message logged by logger from context with businessTwoKey").Log()

7. caller:

// Let's create a logger without caller information.
logger := logit.NewLogger()
logger.Info("I am without caller").Log()

// We provide a way to add caller information to log even logger doesn't carry caller.
logger.Info("Invoke log.WithCaller()").WithCaller().Log()
logger.Close()

time.Sleep(time.Second)

// Now, let's create a logger with caller information.
logger = logit.NewLogger(logit.Options().WithCaller())
logger.Info("I am with caller").Log()

// We won't carry caller information twice or more if logger carries caller information already.
logger.Info("Invoke log.WithCaller() again").WithCaller().Log()
logger.Close()

8. interceptor:

// serverInterceptor is the global interceptor applied to all logs.
func serverInterceptor(ctx context.Context, log *logit.Log) {
	log.String("server", "logit.interceptor")
}

// traceInterceptor is the global interceptor applied to all logs.
func traceInterceptor(ctx context.Context, log *logit.Log) {
	trace, ok := ctx.Value("trace").(string)
	if !ok {
		trace = "unknown trace"
	}

	log.String("trace", trace)
}

// userInterceptor is the global interceptor applied to all logs.
func userInterceptor(ctx context.Context, log *logit.Log) {
	user, ok := ctx.Value("user").(string)
	if !ok {
		user = "unknown user"
	}

	log.String("user", user)
}

// businessInterceptor is the log-level interceptor applied to one/some logs.
func businessInterceptor(ctx context.Context, log *logit.Log) {
	business, ok := ctx.Value("business").(string)
	if !ok {
		business = "unknown business"
	}

	log.String("business", business)
}

// Use logit.Options().WithInterceptors to append some interceptors.
logger := logit.NewLogger(logit.Options().WithInterceptors(serverInterceptor, traceInterceptor, userInterceptor))
defer logger.Close()

// By default, context passed to interceptor is context.Background().
logger.Info("try interceptor - round one").Log()

// You can use WithContext to change context passed to interceptor.
ctx := context.WithValue(context.Background(), "trace", "666")
ctx = context.WithValue(ctx, "user", "FishGoddess")
logger.Info("try interceptor - round two").WithContext(ctx).Log()

// The interceptors appended to logger will apply to all logs.
// You can use Intercept to intercept one log rather than all logs.
logger.Info("try interceptor - round three").WithContext(ctx).Intercept(businessInterceptor).Log()

// Notice that WithContext should be called before Intercept if you want to pass this context to Intercept.
ctx = context.WithValue(ctx, "business", "logger")
logger.Info("try interceptor - round four").WithContext(ctx).Intercept(businessInterceptor).Log()

9. file:

func mustCreateFile(filePath string) *os.File {
	f, err := os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		panic(err)
	}

	return f
}

// Logger will log everything to console by default.
logger := logit.NewLogger()
logger.Info("I log everything to console.").Log()

// You can use WithWriter to change writer in logger.
logger = logit.NewLogger(logit.Options().WithWriter(os.Stdout))
logger.Info("I also log everything to console.").Log()

// As we know, we always log everything to file in production.
logFile := filepath.Join(os.TempDir(), "test.log")
fmt.Println(logFile)

logger = logit.NewLogger(logit.Options().WithWriter(mustCreateFile(logFile)))
logger.Info("I log everything to file.").String("logFile", logFile).Log()
logger.Close()

// Also, as you can see, there is a parameter called withBuffer in WithWriter option.
// It will use a buffer writer to write logs if withBuffer is true which will bring a huge performance improvement.
logFile = filepath.Join(os.TempDir(), "test_buffer.log")
fmt.Println(logFile)

logger = logit.NewLogger(logit.Options().WithWriter(mustCreateFile(logFile)))
logger.Info("I log everything to file with buffer.").String("logFile", logFile).Log()
logger.Close()

// We provide some high-performance file for you. Try these:
writer.BufferWithSize(os.Stdout, 128*size.KB)
writer.BatchWithCount(os.Stdout, 256)
logit.Options().WithBufferWriter(os.Stdout)
logit.Options().WithBatchWriter(os.Stdout)

// Wait a minute, we also provide a powerful file for you!
// See extension/file/file.go.
// It will rotate file and clean backups automatically.
// You can set maxSize, maxAge and maxBackups by options.
logFile = filepath.Join(os.TempDir(), "test_powerful.log")

f, err := file.New(logFile)
if err != nil {
	panic(err)
}

defer f.Close()

_, err = f.Write([]byte("xxx"))
if err != nil {
	panic(err)
}

10. error:

// uselessWriter is a demo writer to demonstrate the error handling function.
type uselessWriter struct{}

func (uw uselessWriter) Write(p []byte) (n int, err error) {
	return 0, errors.New("always error in writing")
}

// You can specify a function to handle errors happens in logger.
// For example, you can count these errors and report them to team members by email.
global.HandleError = func(name string, err error) {
	fmt.Printf("%s received an error: %+v\n", name, err)
}

// Let's log something to see what happen.
logger := logit.NewLogger(logit.Options().WithWriter(&uselessWriter{}))
logger.Info("See what happen?").Log()

11. config:

// We provide a config which can be converted to option in logit.
// It has many tags in fields, such json, yaml, toml, which means you can use config file to create logger.
// You just need to define your config file then unmarshal your config file to this config.
// Of course, you can embed this struct to your application config struct!
cfg := config.Config{
	Level:         config.LevelDebug,
	TimeKey:       "x.time",
	LevelKey:      "x.level",
	MsgKey:        "x.msg",
	PIDKey:        "x.pid",
	FileKey:       "x.file",
	LineKey:       "x.line",
	FuncKey:       "x.func",
	TimeFormat:    config.UnixTimeFormat,
	WithPID:       true,
	WithCaller:    true,
	CallerDepth:   0,
	AutoSync:      "10s",
	Appender:      config.AppenderText,
	DebugAppender: config.AppenderText,
	InfoAppender:  config.AppenderText,
	WarnAppender:  config.AppenderText,
	ErrorAppender: config.AppenderText,
	PrintAppender: config.AppenderJson,
	Writer: config.WriterConfig{
		Target:     config.WriterTargetStdout,
		Mode:       config.WriterModeDirect,
		BufferSize: "4MB",
		BatchCount: 1024,
		Filename:   "test.log",
		DirMode:    0755,
		FileMode:   0644,
		TimeFormat: "20060102150405",
		MaxSize:    "128MB",
		MaxAge:     "30d",
		MaxBackups: 32,
	},
	DebugWriter: config.WriterConfig{},
	InfoWriter:  config.WriterConfig{},
	WarnWriter:  config.WriterConfig{},
	ErrorWriter: config.WriterConfig{},
	PrintWriter: config.WriterConfig{},
}

// Once you got a config, use Options() to convert to option in logger.
opts, err := cfg.Options()
if err != nil {
	panic(err)
}

fmt.Println(opts)

// Then you can create your logger by options.
// Amazing!
logger := logit.NewLogger(opts...)
defer logger.Close()

logger.Info("My mother is a config").Any("config", cfg).Log()
logger.Info("See logger").Any("logger", logger).Log()

Index

Constants

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

Variables

This section is empty.

Functions

func Close added in v0.4.22

func Close() error

Close closes global logger and releases resources.

func NewContext

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

NewContext wraps context with logger and returns a new context.

func NewContextWithKey

func NewContextWithKey(ctx context.Context, key interface{}, logger *Logger) context.Context

NewContextWithKey wraps context with logger of key and returns a new context.

func Options

func Options() *options

Options returns all options provided.

func Print added in v0.4.22

func Print(params ...interface{})

Print prints a log if print level is enabled.

func Printf added in v0.4.22

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

Printf prints a log if print level is enabled.

func Println added in v0.4.22

func Println(params ...interface{})

Println prints a log if print level is enabled.

func SetGlobal added in v0.5.8

func SetGlobal(logger *Logger)

SetGlobal sets global logger to value returned from newLogger. We don't recommend you to call this function unless you really need to call. Instead, we recommend you to call logger.SetToGlobal to set one logger to global if you need.

func Sync added in v0.5.8

func Sync() error

Sync syncs data storing in global logger's writer.

Types

type Interceptor added in v0.4.22

type Interceptor = func(ctx context.Context, log *Log)

Interceptor intercepts log with context.

type Log

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

Log stores data of a whole logging message. Notice: All functions in Log is unsafe-concurrent.

func Debug added in v0.4.22

func Debug(msg string, params ...interface{}) *Log

Debug returns a Log with debug level if debug level is enabled.

func Error added in v0.4.22

func Error(msg string, params ...interface{}) *Log

Error returns a Log with error level if error level is enabled.

func Info added in v0.4.22

func Info(msg string, params ...interface{}) *Log

Info returns a Log with info level if info level is enabled.

func Warn added in v0.4.22

func Warn(msg string, params ...interface{}) *Log

Warn returns a Log with warn level if warn level is enabled.

func (*Log) Any

func (l *Log) Any(key string, value interface{}) *Log

Any adds an entry which key is string and value is interface{} type to l.

func (*Log) Bool

func (l *Log) Bool(key string, value bool) *Log

Bool adds an entry which key is string and value is bool type to l.

func (*Log) Bools

func (l *Log) Bools(key string, value []bool) *Log

Bools adds an entry which key is string and value is []bool type to l.

func (*Log) Byte

func (l *Log) Byte(key string, value byte) *Log

Byte adds an entry which key is string and value is byte type to l.

func (*Log) Bytes

func (l *Log) Bytes(key string, value []byte) *Log

Bytes adds an entry which key is string and value is []byte type to l.

func (*Log) Error

func (l *Log) Error(key string, value error) *Log

Error adds an entry which key is string and value is error type to l.

func (*Log) Errors

func (l *Log) Errors(key string, value []error) *Log

Errors adds an entry which key is string and value is []error type to l.

func (*Log) Float32

func (l *Log) Float32(key string, value float32) *Log

Float32 adds an entry which key is string and value is float32 type to l.

func (*Log) Float32s

func (l *Log) Float32s(key string, value []float32) *Log

Float32s adds an entry which key is string and value is []float32 type to l.

func (*Log) Float64

func (l *Log) Float64(key string, value float64) *Log

Float64 adds an entry which key is string and value is float64 type to l.

func (*Log) Float64s

func (l *Log) Float64s(key string, value []float64) *Log

Float64s adds an entry which key is string and value is []float64 type to l.

func (*Log) Int

func (l *Log) Int(key string, value int) *Log

Int adds an entry which key is string and value is int type to l.

func (*Log) Int16

func (l *Log) Int16(key string, value int16) *Log

Int16 adds an entry which key is string and value is int16 type to l.

func (*Log) Int16s

func (l *Log) Int16s(key string, value []int16) *Log

Int16s adds an entry which key is string and value is []int16 type to l.

func (*Log) Int32

func (l *Log) Int32(key string, value int32) *Log

Int32 adds an entry which key is string and value is int32 type to l.

func (*Log) Int32s

func (l *Log) Int32s(key string, value []int32) *Log

Int32s adds an entry which key is string and value is []int32 type to l.

func (*Log) Int64

func (l *Log) Int64(key string, value int64) *Log

Int64 adds an entry which key is string and value is int64 type to l.

func (*Log) Int64s

func (l *Log) Int64s(key string, value []int64) *Log

Int64s adds an entry which key is string and value is []int64 type to l.

func (*Log) Int8

func (l *Log) Int8(key string, value int8) *Log

Int8 adds an entry which key is string and value is int8 type to l.

func (*Log) Int8s

func (l *Log) Int8s(key string, value []int8) *Log

Int8s adds an entry which key is string and value is []int8 type to l.

func (*Log) Intercept added in v0.4.22

func (l *Log) Intercept(interceptors ...Interceptor) *Log

Intercept intercepts l with interceptors.

func (*Log) Ints

func (l *Log) Ints(key string, value []int) *Log

Ints adds an entry which key is string and value is []int type to l.

func (*Log) Json added in v0.4.19

func (l *Log) Json(key string, value interface{}) *Log

Json adds an entry which key is string and value is marshaled to a json string to l.

func (*Log) Log added in v0.5.8

func (l *Log) Log()

Log logs l.

func (*Log) Rune

func (l *Log) Rune(key string, value rune) *Log

Rune adds an entry which key is string and value is rune type to l.

func (*Log) Runes

func (l *Log) Runes(key string, value []rune) *Log

Runes adds an entry which key is string and value is []rune type to l.

func (*Log) String

func (l *Log) String(key string, value string) *Log

String adds an entry which key is string and value is string type to l.

func (*Log) Stringer

func (l *Log) Stringer(key string, value fmt.Stringer) *Log

Stringer adds an entry which key is string and value is fmt.Stringer type to l.

func (*Log) Stringers

func (l *Log) Stringers(key string, value []fmt.Stringer) *Log

Stringers adds an entry which key is string and value is []fmt.Stringer type to l.

func (*Log) Strings

func (l *Log) Strings(key string, value []string) *Log

Strings adds an entry which key is string and value is []string type to l.

func (*Log) Time

func (l *Log) Time(key string, value time.Time) *Log

Time adds an entry which key is string and value is time.Time type to l.

func (*Log) Times

func (l *Log) Times(key string, value []time.Time) *Log

Times adds an entry which key is string and value is []time.Time type to l.

func (*Log) Uint

func (l *Log) Uint(key string, value uint) *Log

Uint adds an entry which key is string and value is uint type to l.

func (*Log) Uint16

func (l *Log) Uint16(key string, value uint16) *Log

Uint16 adds an entry which key is string and value is uint16 type to l.

func (*Log) Uint16s

func (l *Log) Uint16s(key string, value []uint16) *Log

Uint16s adds an entry which key is string and value is []uint16 type to l.

func (*Log) Uint32

func (l *Log) Uint32(key string, value uint32) *Log

Uint32 adds an entry which key is string and value is uint32 type to l.

func (*Log) Uint32s

func (l *Log) Uint32s(key string, value []uint32) *Log

Uint32s adds an entry which key is string and value is []uint32 type to l.

func (*Log) Uint64

func (l *Log) Uint64(key string, value uint64) *Log

Uint64 adds an entry which key is string and value is uint64 type to l.

func (*Log) Uint64s

func (l *Log) Uint64s(key string, value []uint64) *Log

Uint64s adds an entry which key is string and value is []uint64 type to l.

func (*Log) Uint8

func (l *Log) Uint8(key string, value uint8) *Log

Uint8 adds an entry which key is string and value is uint8 type to l.

func (*Log) Uint8s

func (l *Log) Uint8s(key string, value []uint8) *Log

Uint8s adds an entry which key is string and value is []uint8 type to l.

func (*Log) Uints

func (l *Log) Uints(key string, value []uint) *Log

Uints adds an entry which key is string and value is []uint type to l.

func (*Log) WithCaller

func (l *Log) WithCaller() *Log

WithCaller adds some entries about caller information to l.

func (*Log) WithCallerOf added in v0.5.8

func (l *Log) WithCallerOf(depth int) *Log

WithCallerOf adds some entries about caller information to l.

func (*Log) WithContext added in v0.4.22

func (l *Log) WithContext(ctx context.Context) *Log

WithContext sets ctx to l.

func (*Log) WithPID added in v0.5.8

func (l *Log) WithPID() *Log

WithPID adds one entry about pid information to l.

func (*Log) WithTime added in v0.5.8

func (l *Log) WithTime(key string, value time.Time, format string) *Log

WithTime adds an entry which key is string and value is time.Time formatted type to l.

type Logger

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

Logger is the core of logging operations.

func FromContext

func FromContext(ctx context.Context) *Logger

FromContext gets logger from context and returns a discard logger if missing.

func FromContextWithKey

func FromContextWithKey(ctx context.Context, key interface{}) *Logger

FromContextWithKey gets logger from context with key and returns a discard logger if missing.

func NewLogger

func NewLogger(opts ...Option) *Logger

NewLogger returns a new Logger created with options.

func (*Logger) Close

func (l *Logger) Close() error

Close closes logger and releases resources. It will sync data and set level to offLevel. It will invoke close() if writer is io.Closer. So, it is recommended for you to invoke it habitually.

func (*Logger) Debug

func (l *Logger) Debug(msg string, params ...interface{}) *Log

Debug returns a Log with debug level if debug level is enabled.

func (*Logger) Error

func (l *Logger) Error(msg string, params ...interface{}) *Log

Error returns a Log with error level if error level is enabled.

func (*Logger) Info

func (l *Logger) Info(msg string, params ...interface{}) *Log

Info returns a Log with info level if info level is enabled.

func (*Logger) Print

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

Print prints a log if print level is enabled.

func (*Logger) Printf

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

Printf prints a log if print level is enabled.

func (*Logger) Println

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

Println prints a log if print level is enabled.

func (*Logger) SetToGlobal added in v0.5.8

func (l *Logger) SetToGlobal()

SetToGlobal clones a new logger of current logger and sets it to global. Depth of caller will increase 1 due to wrapping functions.

func (*Logger) Sync added in v0.5.8

func (l *Logger) Sync() error

Sync syncs data storing in logger's writer. You can use an option to sync automatically, see options. Close a logger will also invoke Sync(), so you can use an option or Close() to sync instead. However, you still need to sync manually if you want your logs to be stored immediately.

func (*Logger) Warn

func (l *Logger) Warn(msg string, params ...interface{}) *Log

Warn returns a Log with warn level if warn level is enabled.

type Option

type Option func(logger *Logger)

Option is a function that applies to logger.

func (Option) Apply added in v0.5.8

func (o Option) Apply(logger *Logger)

Apply applies option to logger.

Directories

Path Synopsis
core
extension
support

Jump to

Keyboard shortcuts

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