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 {
|
||||
buf := new(bytes.Buffer)
|
||||
return &jsonHandler{
|
||||
Buffer: buf,
|
||||
buf: buf,
|
||||
pool: handlerPool,
|
||||
JSONHandler: slog.NewJSONHandler(buf, handlerOption),
|
||||
}
|
||||
|
@ -34,15 +34,15 @@ func (jhp *jsonHandlerPool) Get() *jsonHandler {
|
|||
}
|
||||
|
||||
type jsonHandler struct {
|
||||
*bytes.Buffer
|
||||
buf *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()
|
||||
if j.buf.Cap() < 1024*1024*4 {
|
||||
j.buf.Reset()
|
||||
j.pool.Put(j)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,53 @@
|
|||
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
|
||||
|
||||
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"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/tidwall/pretty"
|
||||
)
|
||||
|
||||
type WriteLocker interface {
|
||||
|
@ -32,7 +34,7 @@ type Log struct {
|
|||
jsonPool *jsonHandlerPool
|
||||
withAttrs []slog.Attr
|
||||
withGroup []string
|
||||
handlerOption *slog.HandlerOptions
|
||||
opts *slog.HandlerOptions
|
||||
pretty bool
|
||||
color bool
|
||||
writer WriteLocker
|
||||
|
@ -56,10 +58,10 @@ func (log *Log) Clone(w io.Writer) *Log {
|
|||
level: log.level,
|
||||
withAttrs: withAttrs,
|
||||
withGroup: withGroup,
|
||||
handlerOption: log.handlerOption,
|
||||
opts: log.opts,
|
||||
pretty: log.pretty,
|
||||
bufPool: newBufferPool(),
|
||||
jsonPool: newJsonHandlerPool(log.handlerOption),
|
||||
jsonPool: newJsonHandlerPool(log.opts),
|
||||
writer: output,
|
||||
}
|
||||
}
|
||||
|
@ -94,19 +96,51 @@ func (lo *Log) Handle(ctx context.Context, record slog.Record) error {
|
|||
buf := lo.bufPool.Get()
|
||||
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 {
|
||||
// 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')
|
||||
// }
|
||||
if !record.Time.IsZero() {
|
||||
const format = `[` + time.DateTime + `] `
|
||||
b := record.Time.AppendFormat(nil, format)
|
||||
buf.Write(b)
|
||||
}
|
||||
|
||||
buf.WriteByte('[')
|
||||
levelColor.Add(color.Bold).Fprint(buf, record.Level.String())
|
||||
buf.WriteString("] ")
|
||||
|
||||
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.
|
||||
|
|
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
|||
connectrpc.com/connect v1.16.2
|
||||
connectrpc.com/grpcreflect v1.2.0
|
||||
github.com/fatih/color v1.17.0
|
||||
github.com/tidwall/pretty v1.2.1
|
||||
golang.org/x/net v0.23.0
|
||||
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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
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/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
Loading…
Reference in a new issue