From 30958a91f78a7dda9bb00cc249d63e05d3339d54 Mon Sep 17 00:00:00 2001 From: Kevin Wan Date: Fri, 3 Jun 2022 19:11:06 +0800 Subject: [PATCH] docs: add docs for logx (#1960) --- core/logx/readme-cn.md | 198 +++++++++++++++++++++++++++++++++++++++++ core/logx/readme.md | 198 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 396 insertions(+) create mode 100644 core/logx/readme-cn.md create mode 100644 core/logx/readme.md diff --git a/core/logx/readme-cn.md b/core/logx/readme-cn.md new file mode 100644 index 00000000..6abed344 --- /dev/null +++ b/core/logx/readme-cn.md @@ -0,0 +1,198 @@ + + +# logx + +[English](readme.md) | 简体中文 + +## logx 配置 + +```go +type LogConf struct { + ServiceName string `json:",optional"` + Mode string `json:",default=console,options=[console,file,volume]"` + Encoding string `json:",default=json,options=[json,plain]"` + TimeFormat string `json:",optional"` + Path string `json:",default=logs"` + Level string `json:",default=info,options=[info,error,severe]"` + Compress bool `json:",optional"` + KeepDays int `json:",optional"` + StackCooldownMillis int `json:",default=100"` +} +``` + +- `ServiceName`:设置服务名称,可选。在 `volume` 模式下,该名称用于生成日志文件。在 `rest/zrpc` 服务中,名称将被自动设置为 `rest`或`zrpc` 的名称。 +- `Mode`:输出日志的模式,默认是 `console` + - `console` 模式将日志写到 `stdout/stderr` + - `file` 模式将日志写到 `Path` 指定目录的文件中 + - `volume` 模式在 docker 中使用,将日志写入挂载的卷中 +- `Encoding`: 指示如何对日志进行编码,默认是 `json` + - `json`模式以 json 格式写日志 + - `plain`模式用纯文本写日志,并带有终端颜色显示 +- `TimeFormat`:自定义时间格式,可选。默认是 `2006-01-02T15:04:05.000Z07:00` +- `Path`:设置日志路径,默认为 `logs` +- `Level`: 用于过滤日志的日志级别。默认为 `info` + - `info`,所有日志都被写入 + - `error`, `info` 的日志被丢弃 + - `severe`, `info` 和 `error` 日志被丢弃,只有 `severe` 日志被写入 +- `Compress`: 是否压缩日志文件,只在 `file` 模式下工作 +- `KeepDays`:日志文件被保留多少天,在给定的天数之后,过期的文件将被自动删除。对 `console` 模式没有影响 +- `StackCooldownMillis`:多少毫秒后再次写入堆栈跟踪。用来避免堆栈跟踪日志过多 + +## 打印日志方法 + +```go +type Logger interface { + // Error logs a message at error level. + Error(...interface{}) + // Errorf logs a message at error level. + Errorf(string, ...interface{}) + // Errorv logs a message at error level. + Errorv(interface{}) + // Errorw logs a message at error level. + Errorw(string, ...LogField) + // Info logs a message at info level. + Info(...interface{}) + // Infof logs a message at info level. + Infof(string, ...interface{}) + // Infov logs a message at info level. + Infov(interface{}) + // Infow logs a message at info level. + Infow(string, ...LogField) + // Slow logs a message at slow level. + Slow(...interface{}) + // Slowf logs a message at slow level. + Slowf(string, ...interface{}) + // Slowv logs a message at slow level. + Slowv(interface{}) + // Sloww logs a message at slow level. + Sloww(string, ...LogField) + // WithContext returns a new logger with the given context. + WithContext(context.Context) Logger + // WithDuration returns a new logger with the given duration. + WithDuration(time.Duration) Logger +} +``` + +- `Error`, `Info`, `Slow`: 将任何类型的信息写进日志,使用 `fmt.Sprint(...)` 来转换为 `string` +- `Errorf`, `Infof`, `Slowf`: 将指定格式的信息写入日志 +- `Errorv`, `Infov`, `Slowv`: 将任何类型的信息写入日志,用 `json marshal` 编码 +- `Errorw`, `Infow`, `Sloww`: 写日志,并带上给定的 `key:value` 字段 +- `WithContext`:将给定的 ctx 注入日志信息,例如用于记录 `trace-id`和`span-id` +- `WithDuration`: 将指定的时间写入日志信息中,字段名为 `duration` + +## 与第三方日志库集成 + +- zap + - 实现:[https://github.com/zeromicro/zero-contrib/blob/main/logx/zapx/zap.go](https://github.com/zeromicro/zero-contrib/blob/main/logx/zapx/zap.go) + - 使用示例:[https://github.com/zeromicro/zero-examples/blob/main/logx/zaplog/main.go](https://github.com/zeromicro/zero-examples/blob/main/logx/zaplog/main.go) +- logrus + - 实现:[https://github.com/zeromicro/zero-contrib/blob/main/logx/logrusx/logrus.go](https://github.com/zeromicro/zero-contrib/blob/main/logx/logrusx/logrus.go) + - 使用示例:[https://github.com/zeromicro/zero-examples/blob/main/logx/logrus/main.go](https://github.com/zeromicro/zero-examples/blob/main/logx/logrus/main.go) + +对于其它的日志库,请参考上面示例实现,并欢迎提交 `PR` 到 [https://github.com/zeromicro/zero-contrib](https://github.com/zeromicro/zero-contrib) + +## 将日志写到指定的存储 + +`logx`定义了两个接口,方便自定义 `logx`,将日志写入任何存储。 + +- `logx.NewWriter(w io.Writer)` +- `logx.SetWriter(write logx.Writer)` + +例如,如果我们想把日志写进kafka,而不是控制台或文件,我们可以像下面这样做。 + +```go +type KafkaWriter struct { + Pusher *kq.Pusher +} + +func NewKafkaWriter(pusher *kq.Pusher) *KafkaWriter { + return &KafkaWriter{ + Pusher: pusher, + } +} + +func (w *KafkaWriter) Write(p []byte) (n int, err error) { + // writing log with newlines, trim them. + if err := w.Pusher.Push(strings.TrimSpace(string(p))); err != nil { + return 0, err + } + + return len(p), nil +} + +func main() { + func main() { + pusher := kq.NewPusher([]string{"localhost:9092"}, "go-zero") + defer pusher.Close() + + writer := logx.NewWriter(NewKafkaWriter(pusher)) + logx.SetWriter(writer) + + // more code +} +``` + +完整代码:[https://github.com/zeromicro/zero-examples/blob/main/logx/tokafka/main.go](https://github.com/zeromicro/zero-examples/blob/main/logx/tokafka/main.go) + +## 过滤敏感字段 + +如果我们需要防止 `password` 字段被记录下来,我们可以像下面这样实现。 + +```go +type ( + Message struct { + Name string + Password string + Message string + } + + SensitiveLogger struct { + logx.Writer + } +) + +func NewSensitiveLogger(writer logx.Writer) *SensitiveLogger { + return &SensitiveLogger{ + Writer: writer, + } +} + +func (l *SensitiveLogger) Info(msg interface{}, fields ...logx.LogField) { + if m, ok := msg.(Message); ok { + l.Writer.Info(Message{ + Name: m.Name, + Password: "******", + Message: m.Message, + }, fields...) + } else { + l.Writer.Info(msg, fields...) + } +} + +func main() { + // setup logx to make sure originalWriter not nil, + // the injected writer is only for filtering, like a middleware. + + originalWriter := logx.Reset() + writer := NewSensitiveLogger(originalWriter) + logx.SetWriter(writer) + + logx.Infov(Message{ + Name: "foo", + Password: "shouldNotAppear", + Message: "bar", + }) + + // more code +} +``` + +完整代码:[https://github.com/zeromicro/zero-examples/blob/main/logx/filterfields/main.go](https://github.com/zeromicro/zero-examples/blob/main/logx/filterfields/main.go) + +## 更多示例 + +[https://github.com/zeromicro/zero-examples/tree/main/logx](https://github.com/zeromicro/zero-examples/tree/main/logx) + +## Give a Star! ⭐ + +如果你正在使用或者觉得这个项目对你有帮助,请 **star** 支持,感谢! diff --git a/core/logx/readme.md b/core/logx/readme.md new file mode 100644 index 00000000..f05d9d09 --- /dev/null +++ b/core/logx/readme.md @@ -0,0 +1,198 @@ + + +# logx + +English | [简体中文](readme-cn.md) + +## logx configurations + +```go +type LogConf struct { + ServiceName string `json:",optional"` + Mode string `json:",default=console,options=[console,file,volume]"` + Encoding string `json:",default=json,options=[json,plain]"` + TimeFormat string `json:",optional"` + Path string `json:",default=logs"` + Level string `json:",default=info,options=[info,error,severe]"` + Compress bool `json:",optional"` + KeepDays int `json:",optional"` + StackCooldownMillis int `json:",default=100"` +} +``` + +- `ServiceName`: set the service name, optional. on `volume` mode, the name is used to generate the log files. Within `rest/zrpc` services, the name will be set to the name of `rest` or `zrpc` automatically. +- `Mode`: the mode to output the logs, default is `console`. + - `console` mode writes the logs to `stdout/stderr`. + - `file` mode writes the logs to the files specified by `Path`. + - `volume` mode is used in docker, to write logs into mounted volumes. +- `Encoding`: indicates how to encode the logs, default is `json`. + - `json` mode writes the logs in json format. + - `plain` mode writes the logs with plain text, with terminal color enabled. +- `TimeFormat`: customize the time format, optional. Default is `2006-01-02T15:04:05.000Z07:00`. +- `Path`: set the log path, default to `logs`. +- `Level`: the logging level to filter logs. Default is `info`. + - `info`, all logs are written. + - `error`, `info` logs are suppressed. + - `severe`, `info` and `error` logs are suppressed, only `severe` logs are written. +- `Compress`: whether or not to compress log files, only works with `file` mode. +- `KeepDays`: how many days that the log files are kept, after the given days, the outdated files will be deleted automatically. It has no effect on `console` mode. +- `StackCooldownMillis`: how many milliseconds to rewrite stacktrace again. It’s used to avoid stacktrace flooding. + +## Logging methods + +```go +type Logger interface { + // Error logs a message at error level. + Error(...interface{}) + // Errorf logs a message at error level. + Errorf(string, ...interface{}) + // Errorv logs a message at error level. + Errorv(interface{}) + // Errorw logs a message at error level. + Errorw(string, ...LogField) + // Info logs a message at info level. + Info(...interface{}) + // Infof logs a message at info level. + Infof(string, ...interface{}) + // Infov logs a message at info level. + Infov(interface{}) + // Infow logs a message at info level. + Infow(string, ...LogField) + // Slow logs a message at slow level. + Slow(...interface{}) + // Slowf logs a message at slow level. + Slowf(string, ...interface{}) + // Slowv logs a message at slow level. + Slowv(interface{}) + // Sloww logs a message at slow level. + Sloww(string, ...LogField) + // WithContext returns a new logger with the given context. + WithContext(context.Context) Logger + // WithDuration returns a new logger with the given duration. + WithDuration(time.Duration) Logger +} +``` + +- `Error`, `Info`, `Slow`: write any kind of messages into logs, with like `fmt.Sprint(…)`. +- `Errorf`, `Infof`, `Slowf`: write messages with given format into logs. +- `Errorv`, `Infov`, `Slowv`: write any kind of messages into logs, with json marshalling to encode them. +- `Errorw`, `Infow`, `Sloww`: write the string message with given `key:value` fields. +- `WithContext`: inject the given ctx into the log messages, typically used to log `trace-id` and `span-id`. +- `WithDuration`: write elapsed duration into the log messages, with key `duration`. + +## Integrating with third-party logging libs + +- zap + - implementation: [https://github.com/zeromicro/zero-contrib/blob/main/logx/zapx/zap.go](https://github.com/zeromicro/zero-contrib/blob/main/logx/zapx/zap.go) + - usage example: [https://github.com/zeromicro/zero-examples/blob/main/logx/zaplog/main.go](https://github.com/zeromicro/zero-examples/blob/main/logx/zaplog/main.go) +- logrus + - implementation: [https://github.com/zeromicro/zero-contrib/blob/main/logx/logrusx/logrus.go](https://github.com/zeromicro/zero-contrib/blob/main/logx/logrusx/logrus.go) + - usage example: [https://github.com/zeromicro/zero-examples/blob/main/logx/logrus/main.go](https://github.com/zeromicro/zero-examples/blob/main/logx/logrus/main.go) + +For more libs, please implement and PR to [https://github.com/zeromicro/zero-contrib](https://github.com/zeromicro/zero-contrib) + +## Write the logs to specific stores + +`logx` defined two interfaces to let you customize `logx` to write logs into any stores. + +- `logx.NewWriter(w io.Writer)` +- `logx.SetWriter(writer logx.Writer)` + +For example, if we want to write the logs into kafka instead of console or files, we can do it like below: + +```go +type KafkaWriter struct { + Pusher *kq.Pusher +} + +func NewKafkaWriter(pusher *kq.Pusher) *KafkaWriter { + return &KafkaWriter{ + Pusher: pusher, + } +} + +func (w *KafkaWriter) Write(p []byte) (n int, err error) { + // writing log with newlines, trim them. + if err := w.Pusher.Push(strings.TrimSpace(string(p))); err != nil { + return 0, err + } + + return len(p), nil +} + +func main() { + func main() { + pusher := kq.NewPusher([]string{"localhost:9092"}, "go-zero") + defer pusher.Close() + + writer := logx.NewWriter(NewKafkaWriter(pusher)) + logx.SetWriter(writer) + + // more code +} +``` + +Complete code: [https://github.com/zeromicro/zero-examples/blob/main/logx/tokafka/main.go](https://github.com/zeromicro/zero-examples/blob/main/logx/tokafka/main.go) + +## Filtering sensitive fields + +If we need to prevent the `password` fields from logging, we can do it like below: + +```go +type ( + Message struct { + Name string + Password string + Message string + } + + SensitiveLogger struct { + logx.Writer + } +) + +func NewSensitiveLogger(writer logx.Writer) *SensitiveLogger { + return &SensitiveLogger{ + Writer: writer, + } +} + +func (l *SensitiveLogger) Info(msg interface{}, fields ...logx.LogField) { + if m, ok := msg.(Message); ok { + l.Writer.Info(Message{ + Name: m.Name, + Password: "******", + Message: m.Message, + }, fields...) + } else { + l.Writer.Info(msg, fields...) + } +} + +func main() { + // setup logx to make sure originalWriter not nil, + // the injected writer is only for filtering, like a middleware. + + originalWriter := logx.Reset() + writer := NewSensitiveLogger(originalWriter) + logx.SetWriter(writer) + + logx.Infov(Message{ + Name: "foo", + Password: "shouldNotAppear", + Message: "bar", + }) + + // more code +} +``` + +Complete code: [https://github.com/zeromicro/zero-examples/blob/main/logx/filterfields/main.go](https://github.com/zeromicro/zero-examples/blob/main/logx/filterfields/main.go) + +## More examples + +[https://github.com/zeromicro/zero-examples/tree/main/logx](https://github.com/zeromicro/zero-examples/tree/main/logx) + +## Give a Star! ⭐ + +If you like or are using this project to learn or start your solution, please give it a star. Thanks!