zlog: update implementations
This commit is contained in:
parent
bfaf829142
commit
0256f75bfb
40
core/zcaller/zcaller.go
Normal file
40
core/zcaller/zcaller.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package zcaller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Current returns the ProgramCounter of the caller.
|
||||||
|
//
|
||||||
|
// It gives information about the function that called
|
||||||
|
// this.
|
||||||
|
//
|
||||||
|
// Returns 0 if caller information is not available.
|
||||||
|
func Current() uintptr {
|
||||||
|
return Get(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get works just like Current, but it allows you to
|
||||||
|
// specify the number of frames to skip.
|
||||||
|
//
|
||||||
|
// For reference, current is equivalent to Get(3).
|
||||||
|
// (use Get(2) because Current wraps this function and has to add +1 to the skip value)
|
||||||
|
//
|
||||||
|
// Returns 0 if caller information is not available.
|
||||||
|
func Get(skip int) uintptr {
|
||||||
|
pcs := make([]uintptr, 1)
|
||||||
|
n := runtime.Callers(skip, pcs)
|
||||||
|
if n == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return pcs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frame creates a runtime.Frame from a ProgramCounter.
|
||||||
|
//
|
||||||
|
// Return zero value if the frame is not available.
|
||||||
|
func Frame(pc uintptr) runtime.Frame {
|
||||||
|
frames := runtime.CallersFrames([]uintptr{pc})
|
||||||
|
frame, _ := frames.Next()
|
||||||
|
return frame
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ func newJsonHandlerPool(handlerOption *slog.HandlerOptions) *jsonHandlerPool {
|
||||||
New: func() any {
|
New: func() any {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
return &jsonHandler{
|
return &jsonHandler{
|
||||||
Buffer: buf,
|
buf: buf,
|
||||||
pool: handlerPool,
|
pool: handlerPool,
|
||||||
JSONHandler: slog.NewJSONHandler(buf, handlerOption),
|
JSONHandler: slog.NewJSONHandler(buf, handlerOption),
|
||||||
}
|
}
|
||||||
|
@ -34,15 +34,15 @@ func (jhp *jsonHandlerPool) Get() *jsonHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
type jsonHandler struct {
|
type jsonHandler struct {
|
||||||
*bytes.Buffer
|
buf *bytes.Buffer
|
||||||
pool *jsonHandlerPool
|
pool *jsonHandlerPool
|
||||||
*slog.JSONHandler
|
*slog.JSONHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *jsonHandler) Put() {
|
func (j *jsonHandler) Put() {
|
||||||
// Only put back to pool if buffer is smaller than 4MB in RAM size.
|
// Only put back to pool if buffer is smaller than 4MB in RAM size.
|
||||||
if j.Buffer.Cap() < 1024*1024*4 {
|
if j.buf.Cap() < 1024*1024*4 {
|
||||||
j.Buffer.Reset()
|
j.buf.Reset()
|
||||||
j.pool.Put(j)
|
j.pool.Put(j)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,53 @@
|
||||||
package zlog
|
package zlog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gitlab.bareksa.com/backend/zen/core/zcaller"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Caller represents the caller of a function.
|
||||||
|
//
|
||||||
|
// It gives helper methods to get the caller's information.
|
||||||
|
type Caller uintptr
|
||||||
|
|
||||||
|
func (ca Caller) LogValue() slog.Value {
|
||||||
|
if ca == 0 {
|
||||||
|
return slog.AnyValue(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
f := frame{ca.Frame()}
|
||||||
|
|
||||||
|
return slog.GroupValue(
|
||||||
|
slog.String("file", f.ShortFile()),
|
||||||
|
slog.Int("line", f.Line),
|
||||||
|
slog.String("function", f.ShortFunction()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ca Caller) Frame() runtime.Frame {
|
||||||
|
return zcaller.Frame(uintptr(ca))
|
||||||
|
}
|
||||||
|
|
||||||
|
type frame struct {
|
||||||
|
runtime.Frame
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f frame) ShortFile() string {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return f.File
|
||||||
|
}
|
||||||
|
if after, found := strings.CutPrefix(f.File, wd); found {
|
||||||
|
return strings.TrimPrefix(after, string(os.PathSeparator))
|
||||||
|
}
|
||||||
|
return f.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f frame) ShortFunction() string {
|
||||||
|
split := strings.Split(f.Function, string(os.PathSeparator))
|
||||||
|
return split[len(split)-1]
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,14 @@
|
||||||
package zlog
|
package zlog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Null is a no-op log handler.
|
||||||
|
type Null struct{}
|
||||||
|
|
||||||
|
func (Null) Enabled(context.Context, slog.Level) bool { return false }
|
||||||
|
func (Null) Handle(context.Context, slog.Record) error { return nil }
|
||||||
|
func (Null) WithAttrs([]slog.Attr) slog.Handler { return Null{} }
|
||||||
|
func (nu Null) WithGroup(string) slog.Handler { return Null{} }
|
||||||
|
|
|
@ -5,8 +5,10 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
"github.com/tidwall/pretty"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WriteLocker interface {
|
type WriteLocker interface {
|
||||||
|
@ -27,15 +29,15 @@ type writeLocker struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Log struct {
|
type Log struct {
|
||||||
level slog.Level
|
level slog.Level
|
||||||
bufPool *bufferPool
|
bufPool *bufferPool
|
||||||
jsonPool *jsonHandlerPool
|
jsonPool *jsonHandlerPool
|
||||||
withAttrs []slog.Attr
|
withAttrs []slog.Attr
|
||||||
withGroup []string
|
withGroup []string
|
||||||
handlerOption *slog.HandlerOptions
|
opts *slog.HandlerOptions
|
||||||
pretty bool
|
pretty bool
|
||||||
color bool
|
color bool
|
||||||
writer WriteLocker
|
writer WriteLocker
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone clones the Logger, replacing the output writer with w.
|
// Clone clones the Logger, replacing the output writer with w.
|
||||||
|
@ -53,14 +55,14 @@ func (log *Log) Clone(w io.Writer) *Log {
|
||||||
withGroup := make([]string, len(log.withGroup))
|
withGroup := make([]string, len(log.withGroup))
|
||||||
copy(withGroup, log.withGroup)
|
copy(withGroup, log.withGroup)
|
||||||
return &Log{
|
return &Log{
|
||||||
level: log.level,
|
level: log.level,
|
||||||
withAttrs: withAttrs,
|
withAttrs: withAttrs,
|
||||||
withGroup: withGroup,
|
withGroup: withGroup,
|
||||||
handlerOption: log.handlerOption,
|
opts: log.opts,
|
||||||
pretty: log.pretty,
|
pretty: log.pretty,
|
||||||
bufPool: newBufferPool(),
|
bufPool: newBufferPool(),
|
||||||
jsonPool: newJsonHandlerPool(log.handlerOption),
|
jsonPool: newJsonHandlerPool(log.opts),
|
||||||
writer: output,
|
writer: output,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,19 +96,51 @@ func (lo *Log) Handle(ctx context.Context, record slog.Record) error {
|
||||||
buf := lo.bufPool.Get()
|
buf := lo.bufPool.Get()
|
||||||
defer lo.bufPool.Put(buf)
|
defer lo.bufPool.Put(buf)
|
||||||
|
|
||||||
panic("not implemented")
|
if record.PC != 0 && lo.opts.AddSource {
|
||||||
|
f := frame{Caller(record.PC).Frame()}
|
||||||
|
levelColor.Fprint(buf, f.ShortFile())
|
||||||
|
levelColor.Fprint(buf, ":")
|
||||||
|
levelColor.Fprint(buf, f.Line)
|
||||||
|
levelColor.Fprint(buf, " -- ")
|
||||||
|
levelColor.Fprint(buf, f.ShortFunction())
|
||||||
|
buf.WriteByte('\n')
|
||||||
|
}
|
||||||
|
|
||||||
// if record.PC != 0 && pr.opts.AddSource {
|
if !record.Time.IsZero() {
|
||||||
// frame := caller.From(record.PC).Frame
|
const format = `[` + time.DateTime + `] `
|
||||||
// levelColor.Fprint(buf, frame.File)
|
b := record.Time.AppendFormat(nil, format)
|
||||||
// levelColor.Fprint(buf, ":")
|
buf.Write(b)
|
||||||
// levelColor.Fprint(buf, frame.Line)
|
}
|
||||||
// levelColor.Fprint(buf, " -- ")
|
|
||||||
// split := strings.Split(frame.Function, string(os.PathSeparator))
|
buf.WriteByte('[')
|
||||||
// fnName := split[len(split)-1]
|
levelColor.Add(color.Bold).Fprint(buf, record.Level.String())
|
||||||
// levelColor.Fprint(buf, fnName)
|
buf.WriteString("] ")
|
||||||
// buf.WriteByte('\n')
|
|
||||||
// }
|
if record.Message != "" {
|
||||||
|
buf.WriteString(record.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteByte('\n')
|
||||||
|
|
||||||
|
jHandler := lo.jsonPool.Get()
|
||||||
|
defer jHandler.Put()
|
||||||
|
|
||||||
|
_ = jHandler.Handle(ctx, record)
|
||||||
|
if jHandler.buf.Len() > 3 { // Skip empty objects like "{}\n"
|
||||||
|
jsonData := jHandler.buf.Bytes()
|
||||||
|
jsonData = pretty.Pretty(jsonData)
|
||||||
|
if lo.color {
|
||||||
|
jsonData = pretty.Color(jsonData, nil)
|
||||||
|
}
|
||||||
|
buf.Write(jsonData)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteByte('\n')
|
||||||
|
|
||||||
|
lo.writer.Lock()
|
||||||
|
defer lo.writer.Unlock()
|
||||||
|
_, err := buf.WriteTo(lo.writer)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithAttrs implements the slog.Handler interface.
|
// WithAttrs implements the slog.Handler interface.
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ 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
|
github.com/fatih/color v1.17.0
|
||||||
|
github.com/tidwall/pretty v1.2.1
|
||||||
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
|
||||||
)
|
)
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -11,6 +11,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
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 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||||
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
Loading…
Reference in a new issue