zlog: update implementation
This commit is contained in:
parent
6561784b28
commit
bfaf829142
|
@ -193,12 +193,12 @@ func (mu *Err) GetID() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mu *Err) Log(ctx context.Context) Error {
|
func (mu *Err) Log(ctx context.Context) Error {
|
||||||
mu.logger.Log(ctx, mu)
|
mu.logger.LogError(ctx, mu)
|
||||||
return mu
|
return mu
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mu *Err) Notify(ctx context.Context, opts ...zoptions.NotifyOption) Error {
|
func (mu *Err) Notify(ctx context.Context, opts ...zoptions.NotifyOption) Error {
|
||||||
mu.notifier.Notify(ctx, mu, opts...)
|
mu.notifier.NotifyError(ctx, mu, opts...)
|
||||||
return mu
|
return mu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,11 +23,11 @@ type Wrapper interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Logger interface {
|
type Logger interface {
|
||||||
Log(ctx context.Context, err Error)
|
LogError(ctx context.Context, err Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Notifier interface {
|
type Notifier interface {
|
||||||
Notify(ctx context.Context, err Error, opts ...zoptions.NotifyOption)
|
NotifyError(ctx context.Context, err Error, opts ...zoptions.NotifyOption)
|
||||||
}
|
}
|
||||||
|
|
||||||
type WrapperFunc func(input WrapInitialInput) Error
|
type WrapperFunc func(input WrapInitialInput) Error
|
||||||
|
|
75
core/zlog/buffer.go
Normal file
75
core/zlog/buffer.go
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package zlog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log/slog"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type jsonHandlerPool struct {
|
||||||
|
*sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newJsonHandlerPool(handlerOption *slog.HandlerOptions) *jsonHandlerPool {
|
||||||
|
var handlerPool *jsonHandlerPool
|
||||||
|
generator := &sync.Pool{
|
||||||
|
New: func() any {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
return &jsonHandler{
|
||||||
|
Buffer: buf,
|
||||||
|
pool: handlerPool,
|
||||||
|
JSONHandler: slog.NewJSONHandler(buf, handlerOption),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
handlerPool = &jsonHandlerPool{
|
||||||
|
generator,
|
||||||
|
}
|
||||||
|
return handlerPool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jhp *jsonHandlerPool) Get() *jsonHandler {
|
||||||
|
handler := jhp.Pool.Get().(*jsonHandler)
|
||||||
|
return handler
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonHandler struct {
|
||||||
|
*bytes.Buffer
|
||||||
|
pool *jsonHandlerPool
|
||||||
|
*slog.JSONHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *jsonHandler) Put() {
|
||||||
|
// Only put back to pool if buffer is smaller than 4MB in RAM size.
|
||||||
|
if j.Buffer.Cap() < 1024*1024*4 {
|
||||||
|
j.Buffer.Reset()
|
||||||
|
j.pool.Put(j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type bufferPool struct {
|
||||||
|
*sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBufferPool() *bufferPool {
|
||||||
|
return &bufferPool{
|
||||||
|
&sync.Pool{
|
||||||
|
New: func() any {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
buf.Grow(1024)
|
||||||
|
return buf
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *bufferPool) Get() *bytes.Buffer {
|
||||||
|
return bp.Pool.Get().(*bytes.Buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *bufferPool) Put(buf *bytes.Buffer) {
|
||||||
|
if buf.Cap() < 1024*1024*4 {
|
||||||
|
buf.Reset()
|
||||||
|
bp.Pool.Put(buf)
|
||||||
|
}
|
||||||
|
}
|
1
core/zlog/caller.go
Normal file
1
core/zlog/caller.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package zlog
|
1
core/zlog/null.go
Normal file
1
core/zlog/null.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package zlog
|
|
@ -1,7 +1,141 @@
|
||||||
package zlog
|
package zlog
|
||||||
|
|
||||||
import notifyv1 "gitlab.bareksa.com/backend/zen/internal/gen/proto/notify/v1"
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"sync"
|
||||||
|
|
||||||
func log() {
|
"github.com/fatih/color"
|
||||||
notifyv1.Payload
|
)
|
||||||
|
|
||||||
|
type WriteLocker interface {
|
||||||
|
io.Writer
|
||||||
|
sync.Locker
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapLocker(w io.Writer) WriteLocker {
|
||||||
|
if wl, ok := w.(WriteLocker); ok {
|
||||||
|
return wl
|
||||||
|
}
|
||||||
|
return &writeLocker{Writer: w}
|
||||||
|
}
|
||||||
|
|
||||||
|
type writeLocker struct {
|
||||||
|
io.Writer
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type Log struct {
|
||||||
|
level slog.Level
|
||||||
|
bufPool *bufferPool
|
||||||
|
jsonPool *jsonHandlerPool
|
||||||
|
withAttrs []slog.Attr
|
||||||
|
withGroup []string
|
||||||
|
handlerOption *slog.HandlerOptions
|
||||||
|
pretty bool
|
||||||
|
color bool
|
||||||
|
writer WriteLocker
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone clones the Logger, replacing the output writer with w.
|
||||||
|
//
|
||||||
|
// If w is nil, the clone shares the original Logger's output writer.
|
||||||
|
func (log *Log) Clone(w io.Writer) *Log {
|
||||||
|
var output WriteLocker
|
||||||
|
if w == nil {
|
||||||
|
output = log.writer
|
||||||
|
} else {
|
||||||
|
output = WrapLocker(w)
|
||||||
|
}
|
||||||
|
withAttrs := make([]slog.Attr, len(log.withAttrs))
|
||||||
|
copy(withAttrs, log.withAttrs)
|
||||||
|
withGroup := make([]string, len(log.withGroup))
|
||||||
|
copy(withGroup, log.withGroup)
|
||||||
|
return &Log{
|
||||||
|
level: log.level,
|
||||||
|
withAttrs: withAttrs,
|
||||||
|
withGroup: withGroup,
|
||||||
|
handlerOption: log.handlerOption,
|
||||||
|
pretty: log.pretty,
|
||||||
|
bufPool: newBufferPool(),
|
||||||
|
jsonPool: newJsonHandlerPool(log.handlerOption),
|
||||||
|
writer: output,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enabled implements the slog.Handler interface.
|
||||||
|
func (lo *Log) Enabled(ctx context.Context, lvl slog.Level) bool {
|
||||||
|
return lvl >= lo.level
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle implements the slog.Handler interface.
|
||||||
|
func (lo *Log) Handle(ctx context.Context, record slog.Record) error {
|
||||||
|
if !lo.pretty {
|
||||||
|
j := lo.jsonPool.Get()
|
||||||
|
defer j.Put()
|
||||||
|
return j.Handle(ctx, record)
|
||||||
|
}
|
||||||
|
|
||||||
|
var levelColor *color.Color
|
||||||
|
switch {
|
||||||
|
case record.Level >= slog.LevelError:
|
||||||
|
levelColor = color.New(color.FgRed)
|
||||||
|
case record.Level >= slog.LevelWarn:
|
||||||
|
levelColor = color.New(color.FgYellow)
|
||||||
|
case record.Level >= slog.LevelInfo:
|
||||||
|
levelColor = color.New(color.FgGreen)
|
||||||
|
default:
|
||||||
|
levelColor = color.New(color.FgWhite)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = levelColor
|
||||||
|
|
||||||
|
buf := lo.bufPool.Get()
|
||||||
|
defer lo.bufPool.Put(buf)
|
||||||
|
|
||||||
|
panic("not implemented")
|
||||||
|
|
||||||
|
// if record.PC != 0 && pr.opts.AddSource {
|
||||||
|
// frame := caller.From(record.PC).Frame
|
||||||
|
// levelColor.Fprint(buf, frame.File)
|
||||||
|
// levelColor.Fprint(buf, ":")
|
||||||
|
// levelColor.Fprint(buf, frame.Line)
|
||||||
|
// levelColor.Fprint(buf, " -- ")
|
||||||
|
// split := strings.Split(frame.Function, string(os.PathSeparator))
|
||||||
|
// fnName := split[len(split)-1]
|
||||||
|
// levelColor.Fprint(buf, fnName)
|
||||||
|
// buf.WriteByte('\n')
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAttrs implements the slog.Handler interface.
|
||||||
|
func (lo *Log) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||||
|
l := lo.Clone(nil)
|
||||||
|
l.withAttrs = append(l.withAttrs, attrs...)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithGroup implements the slog.Handler interface.
|
||||||
|
func (lo *Log) WithGroup(name string) slog.Handler {
|
||||||
|
l := lo.Clone(nil)
|
||||||
|
l.withGroup = append(l.withGroup, name)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
type replaceAttrFunc = func([]string, slog.Attr) slog.Attr
|
||||||
|
|
||||||
|
// wrapReplaceAttr disables adding Time, Level, Source, Message
|
||||||
|
// fields when pretty mode is enabled.
|
||||||
|
func (lo *Log) wrapReplaceAttr(f replaceAttrFunc) replaceAttrFunc {
|
||||||
|
return func(s []string, a slog.Attr) slog.Attr {
|
||||||
|
if !lo.pretty {
|
||||||
|
return f(s, a)
|
||||||
|
}
|
||||||
|
switch a.Key {
|
||||||
|
case slog.TimeKey, slog.LevelKey, slog.SourceKey, slog.MessageKey:
|
||||||
|
return slog.Attr{}
|
||||||
|
}
|
||||||
|
return f(s, a)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package zoptions
|
package zoptions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
@ -236,9 +237,14 @@ func NewNamedReaderFromFile(path string, mimetype string) NamedReader {
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rc = &errorReader{err}
|
rc = &errorReader{err}
|
||||||
|
} else {
|
||||||
|
if stat, err := f.Stat(); err == nil && stat.IsDir() {
|
||||||
|
f.Close()
|
||||||
|
rc = &errorReader{fmt.Errorf("file %s is a directory", path)}
|
||||||
} else {
|
} else {
|
||||||
rc = f
|
rc = f
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return &namedReader{
|
return &namedReader{
|
||||||
filename: path,
|
filename: path,
|
||||||
mimeType: mimetype,
|
mimeType: mimetype,
|
||||||
|
|
8
go.mod
8
go.mod
|
@ -5,8 +5,14 @@ go 1.23
|
||||||
require (
|
require (
|
||||||
connectrpc.com/connect v1.16.2
|
connectrpc.com/connect v1.16.2
|
||||||
connectrpc.com/grpcreflect v1.2.0
|
connectrpc.com/grpcreflect v1.2.0
|
||||||
|
github.com/fatih/color v1.17.0
|
||||||
golang.org/x/net v0.23.0
|
golang.org/x/net v0.23.0
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.34.2
|
||||||
)
|
)
|
||||||
|
|
||||||
require golang.org/x/text v0.14.0 // indirect
|
require (
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
golang.org/x/sys v0.18.0 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
|
)
|
||||||
|
|
11
go.sum
11
go.sum
|
@ -2,10 +2,21 @@ connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE=
|
||||||
connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc=
|
connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc=
|
||||||
connectrpc.com/grpcreflect v1.2.0 h1:Q6og1S7HinmtbEuBvARLNwYmTbhEGRpHDhqrPNlmK+U=
|
connectrpc.com/grpcreflect v1.2.0 h1:Q6og1S7HinmtbEuBvARLNwYmTbhEGRpHDhqrPNlmK+U=
|
||||||
connectrpc.com/grpcreflect v1.2.0/go.mod h1:nwSOKmE8nU5u/CidgHtPYk1PFI3U9ignz7iDMxOYkSY=
|
connectrpc.com/grpcreflect v1.2.0/go.mod h1:nwSOKmE8nU5u/CidgHtPYk1PFI3U9ignz7iDMxOYkSY=
|
||||||
|
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||||
|
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||||
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||||
|
|
Loading…
Reference in a new issue