zerr: integration with slog logger

This commit is contained in:
Tigor Hutasuhut 2024-08-28 11:01:20 +07:00
parent 4c951daa41
commit f1b7598e1e
7 changed files with 104 additions and 54 deletions

View file

@ -1,7 +1,10 @@
package zcaller
import (
"log/slog"
"os"
"runtime"
"strings"
)
// Current returns the ProgramCounter of the caller.
@ -38,3 +41,48 @@ func Frame(pc uintptr) runtime.Frame {
frame, _ := frames.Next()
return frame
}
// 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)
}
return ca.Frame().LogValue()
}
func (ca Caller) Frame() RuntimeFrame {
return RuntimeFrame{Frame(uintptr(ca))}
}
type RuntimeFrame struct {
runtime.Frame
}
func (ru RuntimeFrame) LogValue() slog.Value {
return slog.GroupValue(
slog.String("file", ru.ShortFile()),
slog.Int("line", ru.Line),
slog.String("function", ru.ShortFunction()),
)
}
func (f RuntimeFrame) 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 RuntimeFrame) ShortFunction() string {
split := strings.Split(f.Function, string(os.PathSeparator))
return split[len(split)-1]
}

View file

@ -11,6 +11,7 @@ import (
"connectrpc.com/connect"
"github.com/pborman/indent"
"gitlab.bareksa.com/backend/zen/core/zcaller"
"gitlab.bareksa.com/backend/zen/core/zoptions"
)
@ -91,6 +92,9 @@ func (mu *Err) Error() string {
// LogValue returns log fields to be consumed by logger.
func (mu *Err) LogValue() slog.Value {
if len(mu.errs) == 0 {
return slog.AnyValue(nil)
}
attrs := make([]slog.Attr, 0, 8)
if len(mu.message) > 0 {
attrs = append(attrs, slog.String("message", mu.message))
@ -98,13 +102,46 @@ func (mu *Err) LogValue() slog.Value {
if len(mu.publicMessage) > 0 {
attrs = append(attrs, slog.String("public", mu.message))
}
if len(mu.id) > 0 {
attrs = append(attrs, slog.String("id", mu.id))
}
if mu.code != connect.CodeUnknown && mu.code != connect.CodeInternal {
attrs = append(attrs, slog.String("code", mu.code.String()))
}
if mu.sequence.IsRoot() {
if mu.caller != 0 {
attrs = append(attrs, slog.Attr{Key: "caller", Value: zcaller.Caller(mu.caller).LogValue()})
}
attrs = append(attrs, slog.Attr{Key: "error", Value: mu.RootErrorLog()})
return slog.GroupValue(attrs...)
}
func (mu *Err) LogRecord() slog.Record {
record := slog.NewRecord(mu.GetTime(), slog.LevelError, mu.GetMessage(), mu.GetCaller())
code := mu.GetCode()
if public := mu.GetPublicMessage(); public != "" {
record.AddAttrs(slog.String("public", public))
}
if code != 0 && code != connect.CodeUnknown && code != connect.CodeInternal {
record.AddAttrs(slog.String("code", code.String()))
}
if id := mu.GetID(); id != "" {
record.AddAttrs(slog.String("id", id))
}
if len(mu.GetDetails()) > 0 {
record.AddAttrs(slog.Group("details", mu.GetDetails()...))
}
record.AddAttrs(slog.Attr{Key: "error", Value: mu.RootErrorLog()})
return record
}
func (mu *Err) RootErrorLog() slog.Value {
if len(mu.errs) == 0 {
return slog.AnyValue(nil)
}
if len(mu.errs) == 1 {
return errorValuer{mu.errs[0]}.LogValue()
}
attrs := make([]slog.Attr, 0, len(mu.errs))
i := 0
for _, err := range mu.errs {
if err == nil {

View file

@ -13,6 +13,8 @@ type Error interface {
error
// LogValue returns log fields to be consumed by logger.
LogValue() slog.Value
// LogRecord returns log records to be consumed by logger.
LogRecord() slog.Record
// Code sets error code.
Code(code connect.Code) Error

View file

@ -1,53 +1 @@
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]
}

11
core/zlog/error.go Normal file
View file

@ -0,0 +1,11 @@
package zlog
import (
"context"
"gitlab.bareksa.com/backend/zen/core/zerr"
)
func (zl *ZLog) LogError(ctx context.Context, err zerr.Error) {
LogRecord(ctx, err.LogRecord())
}

View file

@ -12,6 +12,7 @@ import (
"github.com/fatih/color"
"github.com/mattn/go-isatty"
"github.com/tidwall/pretty"
"gitlab.bareksa.com/backend/zen/core/zcaller"
"gitlab.bareksa.com/backend/zen/internal/bufferpool"
)
@ -122,7 +123,7 @@ func (lo *ZLog) Handle(ctx context.Context, record slog.Record) error {
defer buf.Close()
if record.PC != 0 && lo.opts.HandlerOptions.AddSource {
f := frame{Caller(record.PC).Frame()}
f := zcaller.Caller(record.PC).Frame()
levelColor.Fprint(buf, f.ShortFile())
levelColor.Fprint(buf, ":")
levelColor.Fprint(buf, f.Line)

View file

@ -0,0 +1,3 @@
package ztelemetry
type ServiceMetadata struct{}