golang实现slog日志格式化与自定义构建插件库slog-formatter的使用
Golang实现Slog日志格式化与自定义构建插件库slog-formatter的使用
简介
slog-formatter
是一个为Go标准库slog
提供常见格式化器和构建自定义格式化器的插件库。它可以帮助你:
- 格式化日志属性(如时间、错误、HTTP请求等)
- 构建自定义的日志格式化逻辑
- 保护敏感信息(如PII、IP地址等)
安装
go get github.com/samber/slog-formatter
兼容性:Go >= 1.21
快速开始
以下示例展示了如何使用3个格式化器:匿名化数据、格式化错误和格式化用户:
import (
slogformatter "github.com/samber/slog-formatter"
"log/slog"
)
formatter1 := slogformatter.FormatByKey("very_private_data", func(v slog.Value) slog.Value {
return slog.StringValue("***********")
})
formatter2 := slogformatter.ErrorFormatter("error")
formatter3 := slogformatter.FormatByType(func(u User) slog.Value {
return slog.StringValue(fmt.Sprintf("%s %s", u.firstname, u.lastname))
})
logger := slog.New(
slogformatter.NewFormatterHandler(formatter1, formatter2, formatter3)(
slog.NewTextHandler(os.Stdout, nil),
),
)
err := fmt.Errorf("an error")
logger.Error("a message",
slog.Any("very_private_data", "abcd"),
slog.Any("user", user),
slog.Any("err", err))
// 输出:
// time=2023-04-10T14:00:0.000000+00:00 level=ERROR msg="a message" error.message="an error" error.type="*errors.errorString" user="John doe" very_private_data="********"
核心功能
处理器
- NewFormatterHandler: 主处理器,应用格式化器
- NewFormatterMiddleware: 与
slog-multi
中间件兼容 - RecoverHandlerError: 捕获处理链中的panic和错误
常见格式化器
- TimeFormatter: 将
time.Time
转换为可读字符串 - UnixTimestampFormatter: 将
time.Time
转换为Unix时间戳 - TimezoneConverter: 将
time.Time
转换为不同时区 - ErrorFormatter: 格式化Go错误
- HTTPRequestFormatter/HTTPResponseFormatter: 格式化HTTP请求/响应
- PIIFormatter: 隐藏个人身份信息(PII)
- IPAddressFormatter: 隐藏IP地址
- FlattenFormatterMiddleware: 递归扁平化属性
自定义格式化器
- Format: 对所有属性应用格式化器
- FormatByKind: 对匹配
slog.Kind
的属性应用格式化器 - FormatByType: 对匹配特定类型的属性应用格式化器
- FormatByKey: 对匹配键名的属性应用格式化器
- FormatByFieldType: 对匹配键名和类型的属性应用格式化器
- FormatByGroup: 对组内属性应用格式化器
- FormatByGroupKey: 对组内匹配键名的属性应用格式化器
- FormatByGroupKeyType: 对组内匹配键名和类型的属性应用格式化器
完整示例
1. 格式化时间和错误
logger := slog.New(
slogformatter.NewFormatterHandler(
slogformatter.TimeFormatter(time.DateTime, time.UTC),
slogformatter.ErrorFormatter("error"),
)(
slog.NewJSONHandler(os.Stdout, nil),
),
)
err := fmt.Errorf("database connection failed")
logger.Error("operation failed", slog.Any("error", err))
2. 保护敏感信息
logger := slog.New(
slogformatter.NewFormatterHandler(
slogformatter.PIIFormatter("user"),
slogformatter.IPAddressFormatter("ip"),
)(
slog.NewTextHandler(os.Stdout, nil),
),
)
logger.Info("user login",
slog.String("ip", "192.168.1.1"),
slog.Group("user",
slog.String("email", "user@example.com"),
slog.String("password", "secret123"),
))
3. 自定义类型格式化
type Product struct {
ID string
Name string
Price float64
}
logger := slog.New(
slogformatter.NewFormatterHandler(
slogformatter.FormatByType(func(p Product) slog.Value {
return slog.GroupValue(
slog.String("id", p.ID),
slog.String("name", p.Name),
)
}),
)(
slog.NewJSONHandler(os.Stdout, nil),
),
)
product := Product{ID: "123", Name: "Laptop", Price: 999.99}
logger.Info("new product", slog.Any("item", product))
4. HTTP请求日志记录
logger := slog.New(
slogformatter.NewFormatterHandler(
slogformatter.HTTPRequestFormatter(true),
slogformatter.HTTPResponseFormatter(true),
)(
slog.NewJSONHandler(os.Stdout, nil),
),
)
req, _ := http.NewRequest("GET", "https://api.example.com", nil)
res, _ := http.DefaultClient.Do(req)
logger.Info("API call",
slog.Any("request", req),
slog.Any("response", res))
注意事项
- 在某些情况下,考虑实现
slog.LogValuer
接口而不是使用此库 - 谨慎使用此库,日志处理可能非常消耗资源
- 在v2.0.0之前不会对导出API进行破坏性更改
slog-formatter
提供了强大的日志格式化能力,可以帮助你创建更清晰、更安全的日志输出。根据你的具体需求选择合适的格式化器组合使用。
更多关于golang实现slog日志格式化与自定义构建插件库slog-formatter的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现slog日志格式化与自定义构建插件库slog-formatter的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang Slog日志格式化与自定义构建插件库
Slog日志格式化基础
Go 1.21引入了新的结构化日志库slog,它提供了高性能的结构化日志记录功能。下面是一个基本的使用示例:
package main
import (
"log/slog"
"os"
)
func main() {
// 基本文本输出
textLogger := slog.New(slog.NewTextHandler(os.Stdout, nil))
textLogger.Info("hello world", "count", 3)
// JSON格式输出
jsonLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
jsonLogger.Info("hello world", "count", 3)
}
自定义日志格式化
要实现自定义格式化,我们需要创建自己的Handler:
package main
import (
"context"
"fmt"
"io"
"log/slog"
"os"
"time"
)
type CustomHandler struct {
handler slog.Handler
writer io.Writer
}
func (h *CustomHandler) Enabled(ctx context.Context, level slog.Level) bool {
return h.handler.Enabled(ctx, level)
}
func (h *CustomHandler) Handle(ctx context.Context, r slog.Record) error {
// 自定义格式
timeStr := r.Time.Format(time.DateTime)
msg := fmt.Sprintf("[%s] %s: %s", timeStr, r.Level, r.Message)
// 添加属性
r.Attrs(func(attr slog.Attr) bool {
msg += fmt.Sprintf(" %s=%v", attr.Key, attr.Value)
return true
})
msg += "\n"
_, err := h.writer.Write([]byte(msg))
return err
}
func (h *CustomHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return &CustomHandler{handler: h.handler.WithAttrs(attrs), writer: h.writer}
}
func (h *CustomHandler) WithGroup(name string) slog.Handler {
return &CustomHandler{handler: h.handler.WithGroup(name), writer: h.writer}
}
func NewCustomHandler(w io.Writer) *CustomHandler {
return &CustomHandler{
writer: w,
}
}
func main() {
logger := slog.New(NewCustomHandler(os.Stdout))
logger.Info("custom formatted message", "key1", "value1", "key2", 123)
}
使用slog-formatter插件库
slog-formatter
是一个第三方库,提供了更多灵活的格式化选项。首先安装:
go get github.com/samber/slog-formatter
使用示例:
package main
import (
"os"
"time"
"github.com/samber/slog-formatter"
"log/slog"
)
func main() {
// 1. 基础格式化器
logger := slog.New(
formatter.NewFormatterHandler(
formatter.TimeFormatter(time.DateTime),
formatter.LevelFormatter("LEVEL"),
formatter.MessageFormatter("MESSAGE"),
formatter.AttrsFormatter("ATTRS"),
)(
slog.NewJSONHandler(os.Stdout, nil),
),
)
logger.Info("hello world", "count", 3)
// 2. 彩色输出
logger = slog.New(
formatter.NewColorFormatter(
os.Stdout,
formatter.ColorFormatterOpts{
Time: formatter.ColorTime(time.DateTime),
Level: formatter.ColorLevel(),
Message: formatter.ColorMessage(),
},
),
)
logger.Info("colored message", "key", "value")
// 3. 自定义模板
logger = slog.New(
formatter.NewTemplateFormatter(
os.Stdout,
"{{.Time}} | {{.Level}} | {{.Message}} | {{range .Attrs}}{{.Key}}={{.Value}} {{end}}\n",
),
)
logger.Warn("template message", "user", "Alice", "age", 30)
}
高级自定义插件开发
如果你想开发自己的slog插件,可以遵循以下模式:
package myformatter
import (
"context"
"log/slog"
)
type MyFormatter struct {
next slog.Handler
// 添加你的配置字段
prefix string
}
func NewMyFormatter(next slog.Handler, prefix string) *MyFormatter {
return &MyFormatter{
next: next,
prefix: prefix,
}
}
func (f *MyFormatter) Enabled(ctx context.Context, level slog.Level) bool {
return f.next.Enabled(ctx, level)
}
func (f *MyFormatter) Handle(ctx context.Context, r slog.Record) error {
// 修改记录
r.Message = f.prefix + r.Message
// 可以添加或修改属性
r.AddAttrs(slog.String("formatted_by", "my_formatter"))
return f.next.Handle(ctx, r)
}
func (f *MyFormatter) WithAttrs(attrs []slog.Attr) slog.Handler {
return NewMyFormatter(f.next.WithAttrs(attrs), f.prefix)
}
func (f *MyFormatter) WithGroup(name string) slog.Handler {
return NewMyFormatter(f.next.WithGroup(name), f.prefix)
}
使用示例:
package main
import (
"log/slog"
"os"
"your/package/path/myformatter"
)
func main() {
logger := slog.New(
myformatter.NewMyFormatter(
slog.NewJSONHandler(os.Stdout, nil),
"[PREFIX] ",
),
)
logger.Info("custom formatted message")
}
总结
- Go的slog库提供了强大的结构化日志功能
- 可以通过实现slog.Handler接口来自定义日志格式
- 第三方库如slog-formatter提供了更多现成的格式化选项
- 开发自定义插件需要实现Handler接口并包装现有的Handler
选择哪种方式取决于你的需求:简单自定义可以直接实现Handler,复杂需求可以使用现有插件库,特定需求可以开发自己的插件。