logger: slog logger #266
3
go.mod
3
go.mod
@ -9,12 +9,13 @@ require (
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/sys v0.7.0
|
||||
golang.org/x/sys v0.12.0
|
||||
google.golang.org/grpc v1.54.0
|
||||
google.golang.org/protobuf v1.30.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
)
|
||||
|
3
go.sum
3
go.sum
@ -13,11 +13,14 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5 h1:G/FZtUu7a6NTWl3KUHMV9jkLAh/Rvtf03NWMHaEDl+E=
|
||||
github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
||||
|
259
logger/slog.go
Normal file
259
logger/slog.go
Normal file
@ -0,0 +1,259 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"go.unistack.org/micro/v4/options"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
const (
|
||||
slogName = "slog"
|
||||
)
|
||||
|
||||
type slogLogger struct {
|
||||
slog *slog.Logger
|
||||
fields map[string]interface{}
|
||||
opts Options
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
//TODO:!!!!
|
||||
|
||||
func (s *slogLogger) Clone(opts ...options.Option) Logger {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *slogLogger) V(level Level) bool {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *slogLogger) Level(level Level) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *slogLogger) Options() Options {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *slogLogger) Fields(fields ...interface{}) Logger {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *slogLogger) Trace(ctx context.Context, args ...interface{}) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *slogLogger) Tracef(ctx context.Context, msg string, args ...interface{}) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *slogLogger) Fatalf(ctx context.Context, msg string, args ...interface{}) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *slogLogger) Init(opts ...options.Option) error {
|
||||
for _, o := range opts {
|
||||
if err := o(&s.opts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok {
|
||||
s.slog = slog
|
||||
return nil
|
||||
}
|
||||
|
||||
handleOpt := &slog.HandlerOptions{
|
||||
ReplaceAttr: renameTime,
|
||||
Level: loggerToSlogLevel(s.opts.Level),
|
||||
}
|
||||
|
||||
attr := fieldsToAttr(s.fields)
|
||||
|
||||
handler := slog.NewJSONHandler(s.opts.Out, handleOpt).WithAttrs(attr)
|
||||
|
||||
s.slog = slog.New(handler)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *slogLogger) Log(ctx context.Context, lvl Level, args ...any) {
|
||||
slvl := loggerToSlogLevel(lvl)
|
||||
|
||||
s.RLock()
|
||||
attr := fieldsToAttr(s.fields)
|
||||
s.RUnlock()
|
||||
|
||||
msg := fmt.Sprint(args...)
|
||||
|
||||
if lvl == FatalLevel {
|
||||
log.Fatalln(msg, attr)
|
||||
}
|
||||
|
||||
if slvl == slog.LevelError {
|
||||
l := s.slog.With(slog.Any("ProcStatus", "ERROR"), slog.Any("ErrorText", msg))
|
||||
l.LogAttrs(ctx, slvl, "", attr...)
|
||||
return
|
||||
}
|
||||
|
||||
s.slog.LogAttrs(ctx, slvl, msg, attr...)
|
||||
}
|
||||
|
||||
func (s *slogLogger) Logf(ctx context.Context, lvl Level, format string, args ...any) {
|
||||
slvl := loggerToSlogLevel(lvl)
|
||||
|
||||
s.RLock()
|
||||
attr := fieldsToAttr(s.fields)
|
||||
s.RUnlock()
|
||||
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
|
||||
if lvl == FatalLevel {
|
||||
log.Fatalln(msg, attr)
|
||||
}
|
||||
|
||||
if slvl == slog.LevelError {
|
||||
l := s.slog.With(slog.Any("ProcStatus", "ERROR"), slog.Any("ErrorText", msg))
|
||||
l.LogAttrs(ctx, slvl, "", attr...)
|
||||
return
|
||||
}
|
||||
|
||||
s.slog.LogAttrs(ctx, slvl, msg, attr...)
|
||||
}
|
||||
|
||||
func (s *slogLogger) Info(ctx context.Context, args ...any) {
|
||||
s.Log(ctx, InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (s *slogLogger) Infof(ctx context.Context, format string, args ...interface{}) {
|
||||
s.Logf(ctx, InfoLevel, format, args...)
|
||||
}
|
||||
|
||||
func (s *slogLogger) Debug(ctx context.Context, args ...any) {
|
||||
s.Log(ctx, DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (s *slogLogger) Debugf(ctx context.Context, format string, args ...any) {
|
||||
s.Logf(ctx, DebugLevel, format, args...)
|
||||
}
|
||||
|
||||
func (s *slogLogger) Error(ctx context.Context, args ...any) {
|
||||
s.Log(ctx, ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (s *slogLogger) Errorf(ctx context.Context, format string, args ...any) {
|
||||
s.Logf(ctx, ErrorLevel, format, args...)
|
||||
}
|
||||
|
||||
func (s *slogLogger) Fatal(ctx context.Context, args ...any) {
|
||||
s.Log(ctx, FatalLevel, args...)
|
||||
}
|
||||
|
||||
func (s *slogLogger) Warn(ctx context.Context, args ...any) {
|
||||
s.Log(ctx, WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (s *slogLogger) Warnf(ctx context.Context, format string, args ...any) {
|
||||
s.Logf(ctx, WarnLevel, format, args...)
|
||||
}
|
||||
|
||||
func (s *slogLogger) String() string {
|
||||
return slogName
|
||||
}
|
||||
|
||||
/*
|
||||
func (s *slogLogger) Fields(fields map[string]interface{}) Logger {
|
||||
nfields := make(map[string]interface{}, len(s.fields))
|
||||
|
||||
s.Lock()
|
||||
for k, v := range s.fields {
|
||||
nfields[k] = v
|
||||
}
|
||||
s.Unlock()
|
||||
|
||||
for k, v := range fields {
|
||||
nfields[k] = v
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(nfields))
|
||||
for k := range nfields {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
attr := make([]slog.Attr, 0, len(nfields))
|
||||
for _, k := range keys {
|
||||
attr = append(attr, slog.Any(k, fields[k]))
|
||||
}
|
||||
|
||||
handleOpt := &slog.HandlerOptions{
|
||||
ReplaceAttr: renameTime,
|
||||
Level: loggerToSlogLevel(s.opts.Level),
|
||||
}
|
||||
|
||||
handler := slog.NewJSONHandler(s.opts.Out, handleOpt).WithAttrs(attr)
|
||||
|
||||
zl := &slogLogger{
|
||||
slog: slog.New(handler),
|
||||
opts: s.opts,
|
||||
fields: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
return zl
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
func NewSlogLogger(opts ...options.Option) (Logger, error) {
|
||||
l := &slogLogger{
|
||||
opts: NewOptions(opts...),
|
||||
}
|
||||
err := l.Init()
|
||||
return l, err
|
||||
}
|
||||
|
||||
func renameTime(groups []string, a slog.Attr) slog.Attr {
|
||||
if a.Key == slog.TimeKey {
|
||||
a.Key = "@timestamp"
|
||||
}
|
||||
if a.Key == slog.MessageKey {
|
||||
a.Key = "message"
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func loggerToSlogLevel(level Level) slog.Level {
|
||||
switch level {
|
||||
case TraceLevel, DebugLevel:
|
||||
return slog.LevelDebug
|
||||
case WarnLevel:
|
||||
return slog.LevelWarn
|
||||
case ErrorLevel, FatalLevel:
|
||||
return slog.LevelError
|
||||
default:
|
||||
return slog.LevelInfo
|
||||
}
|
||||
}
|
||||
|
||||
func fieldsToAttr(m map[string]any) []slog.Attr {
|
||||
data := make([]slog.Attr, 0, len(m))
|
||||
for k, v := range m {
|
||||
data = append(data, slog.Any(k, v))
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
Loading…
Reference in New Issue
Block a user