logger: slog logger #266
9
go.mod
9
go.mod
@ -9,13 +9,14 @@ require (
|
|||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5
|
github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
|
||||||
golang.org/x/sync v0.1.0
|
golang.org/x/sync v0.3.0
|
||||||
golang.org/x/sys v0.12.0
|
golang.org/x/sys v0.12.0
|
||||||
google.golang.org/grpc v1.54.0
|
google.golang.org/grpc v1.57.0
|
||||||
google.golang.org/protobuf v1.30.0
|
google.golang.org/protobuf v1.31.0
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
|
||||||
)
|
)
|
||||||
|
20
go.sum
20
go.sum
@ -15,21 +15,21 @@ github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5 h1:G/FZtUu7a6NTWl3KUHMV9
|
|||||||
github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
|
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 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
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/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||||
golang.org/x/sys v0.12.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/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||||
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
|
google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
|
||||||
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@ -1,232 +0,0 @@
|
|||||||
package logger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.unistack.org/micro/v4/options"
|
|
||||||
)
|
|
||||||
|
|
||||||
type defaultLogger struct {
|
|
||||||
enc *json.Encoder
|
|
||||||
opts Options
|
|
||||||
sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init(opts...) should only overwrite provided options
|
|
||||||
func (l *defaultLogger) Init(opts ...options.Option) error {
|
|
||||||
l.Lock()
|
|
||||||
for _, o := range opts {
|
|
||||||
o(&l.opts)
|
|
||||||
}
|
|
||||||
l.enc = json.NewEncoder(l.opts.Out)
|
|
||||||
// wrap the Log func
|
|
||||||
l.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) String() string {
|
|
||||||
return "micro"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Clone(opts ...options.Option) Logger {
|
|
||||||
newopts := NewOptions(opts...)
|
|
||||||
oldopts := l.opts
|
|
||||||
for _, o := range opts {
|
|
||||||
o(&newopts)
|
|
||||||
o(&oldopts)
|
|
||||||
}
|
|
||||||
|
|
||||||
l.Lock()
|
|
||||||
cl := &defaultLogger{opts: oldopts, enc: json.NewEncoder(l.opts.Out)}
|
|
||||||
l.Unlock()
|
|
||||||
|
|
||||||
return cl
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) V(level Level) bool {
|
|
||||||
l.RLock()
|
|
||||||
ok := l.opts.Level.Enabled(level)
|
|
||||||
l.RUnlock()
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Level(level Level) {
|
|
||||||
l.Lock()
|
|
||||||
l.opts.Level = level
|
|
||||||
l.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Fields(fields ...interface{}) Logger {
|
|
||||||
l.RLock()
|
|
||||||
nl := &defaultLogger{opts: l.opts, enc: l.enc}
|
|
||||||
if len(fields) == 0 {
|
|
||||||
l.RUnlock()
|
|
||||||
return nl
|
|
||||||
} else if len(fields)%2 != 0 {
|
|
||||||
fields = fields[:len(fields)-1]
|
|
||||||
}
|
|
||||||
nl.opts.Fields = copyFields(l.opts.Fields)
|
|
||||||
nl.opts.Fields = append(nl.opts.Fields, fields...)
|
|
||||||
l.RUnlock()
|
|
||||||
return nl
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyFields(src []interface{}) []interface{} {
|
|
||||||
dst := make([]interface{}, len(src))
|
|
||||||
copy(dst, src)
|
|
||||||
return dst
|
|
||||||
}
|
|
||||||
|
|
||||||
// logCallerfilePath returns a package/file:line description of the caller,
|
|
||||||
// preserving only the leaf directory name and file name.
|
|
||||||
func logCallerfilePath(loggingFilePath string) string {
|
|
||||||
// To make sure we trim the path correctly on Windows too, we
|
|
||||||
// counter-intuitively need to use '/' and *not* os.PathSeparator here,
|
|
||||||
// because the path given originates from Go stdlib, specifically
|
|
||||||
// runtime.Caller() which (as of Mar/17) returns forward slashes even on
|
|
||||||
// Windows.
|
|
||||||
//
|
|
||||||
// See https://github.com/golang/go/issues/3335
|
|
||||||
// and https://github.com/golang/go/issues/18151
|
|
||||||
//
|
|
||||||
// for discussion on the issue on Go side.
|
|
||||||
idx := strings.LastIndexByte(loggingFilePath, '/')
|
|
||||||
if idx == -1 {
|
|
||||||
return loggingFilePath
|
|
||||||
}
|
|
||||||
idx = strings.LastIndexByte(loggingFilePath[:idx], '/')
|
|
||||||
if idx == -1 {
|
|
||||||
return loggingFilePath
|
|
||||||
}
|
|
||||||
return loggingFilePath[idx+1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Info(ctx context.Context, args ...interface{}) {
|
|
||||||
l.Log(ctx, InfoLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Error(ctx context.Context, args ...interface{}) {
|
|
||||||
l.Log(ctx, ErrorLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Debug(ctx context.Context, args ...interface{}) {
|
|
||||||
l.Log(ctx, DebugLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Warn(ctx context.Context, args ...interface{}) {
|
|
||||||
l.Log(ctx, WarnLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Trace(ctx context.Context, args ...interface{}) {
|
|
||||||
l.Log(ctx, TraceLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Fatal(ctx context.Context, args ...interface{}) {
|
|
||||||
l.Log(ctx, FatalLevel, args...)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Infof(ctx context.Context, msg string, args ...interface{}) {
|
|
||||||
l.Logf(ctx, InfoLevel, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Errorf(ctx context.Context, msg string, args ...interface{}) {
|
|
||||||
l.Logf(ctx, ErrorLevel, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Debugf(ctx context.Context, msg string, args ...interface{}) {
|
|
||||||
l.Logf(ctx, DebugLevel, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Warnf(ctx context.Context, msg string, args ...interface{}) {
|
|
||||||
l.Logf(ctx, WarnLevel, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Tracef(ctx context.Context, msg string, args ...interface{}) {
|
|
||||||
l.Logf(ctx, TraceLevel, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Fatalf(ctx context.Context, msg string, args ...interface{}) {
|
|
||||||
l.Logf(ctx, FatalLevel, msg, args...)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Log(ctx context.Context, level Level, args ...interface{}) {
|
|
||||||
if !l.V(level) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
l.RLock()
|
|
||||||
fields := copyFields(l.opts.Fields)
|
|
||||||
l.RUnlock()
|
|
||||||
|
|
||||||
fields = append(fields, "level", level.String())
|
|
||||||
|
|
||||||
if _, file, line, ok := runtime.Caller(l.opts.CallerSkipCount); ok {
|
|
||||||
fields = append(fields, "caller", fmt.Sprintf("%s:%d", logCallerfilePath(file), line))
|
|
||||||
}
|
|
||||||
fields = append(fields, "timestamp", time.Now().Format("2006-01-02 15:04:05"))
|
|
||||||
|
|
||||||
if len(args) > 0 {
|
|
||||||
fields = append(fields, "msg", fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
|
|
||||||
out := make(map[string]interface{}, len(fields)/2)
|
|
||||||
for i := 0; i < len(fields); i += 2 {
|
|
||||||
out[fields[i].(string)] = fields[i+1]
|
|
||||||
}
|
|
||||||
l.RLock()
|
|
||||||
_ = l.enc.Encode(out)
|
|
||||||
l.RUnlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Logf(ctx context.Context, level Level, msg string, args ...interface{}) {
|
|
||||||
if !l.V(level) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
l.RLock()
|
|
||||||
fields := copyFields(l.opts.Fields)
|
|
||||||
l.RUnlock()
|
|
||||||
|
|
||||||
fields = append(fields, "level", level.String())
|
|
||||||
|
|
||||||
if _, file, line, ok := runtime.Caller(l.opts.CallerSkipCount); ok {
|
|
||||||
fields = append(fields, "caller", fmt.Sprintf("%s:%d", logCallerfilePath(file), line))
|
|
||||||
}
|
|
||||||
|
|
||||||
fields = append(fields, "timestamp", time.Now().Format("2006-01-02 15:04:05"))
|
|
||||||
if len(args) > 0 {
|
|
||||||
fields = append(fields, "msg", fmt.Sprintf(msg, args...))
|
|
||||||
} else if msg != "" {
|
|
||||||
fields = append(fields, "msg", msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
out := make(map[string]interface{}, len(fields)/2)
|
|
||||||
for i := 0; i < len(fields); i += 2 {
|
|
||||||
out[fields[i].(string)] = fields[i+1]
|
|
||||||
}
|
|
||||||
l.RLock()
|
|
||||||
_ = l.enc.Encode(out)
|
|
||||||
l.RUnlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *defaultLogger) Options() Options {
|
|
||||||
return l.opts
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLogger builds a new logger based on options
|
|
||||||
func NewLogger(opts ...options.Option) Logger {
|
|
||||||
l := &defaultLogger{
|
|
||||||
opts: NewOptions(opts...),
|
|
||||||
}
|
|
||||||
l.enc = json.NewEncoder(l.opts.Out)
|
|
||||||
return l
|
|
||||||
}
|
|
@ -87,14 +87,14 @@ func TestClone(t *testing.T) {
|
|||||||
|
|
||||||
func TestRedirectStdLogger(t *testing.T) {
|
func TestRedirectStdLogger(t *testing.T) {
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
l := NewLogger(WithLevel(TraceLevel), WithOutput(buf))
|
l := NewLogger(WithLevel(ErrorLevel), WithOutput(buf))
|
||||||
if err := l.Init(); err != nil {
|
if err := l.Init(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
fn := RedirectStdLogger(l, ErrorLevel)
|
fn := RedirectStdLogger(l, ErrorLevel)
|
||||||
defer fn()
|
defer fn()
|
||||||
log.Print("test")
|
log.Print("test")
|
||||||
if !bytes.Contains(buf.Bytes(), []byte(`"level":"error","msg":"test","timestamp"`)) {
|
if !bytes.Contains(buf.Bytes(), []byte(`"level":"error","msg":"test"`)) {
|
||||||
t.Fatalf("logger error, buf %s", buf.Bytes())
|
t.Fatalf("logger error, buf %s", buf.Bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ func TestStdLogger(t *testing.T) {
|
|||||||
}
|
}
|
||||||
lg := NewStdLogger(l, ErrorLevel)
|
lg := NewStdLogger(l, ErrorLevel)
|
||||||
lg.Print("test")
|
lg.Print("test")
|
||||||
if !bytes.Contains(buf.Bytes(), []byte(`"level":"error","msg":"test","timestamp"`)) {
|
if !bytes.Contains(buf.Bytes(), []byte(`"level":"error","msg":"test"`)) {
|
||||||
t.Fatalf("logger error, buf %s", buf.Bytes())
|
t.Fatalf("logger error, buf %s", buf.Bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,19 +120,21 @@ func TestLogger(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
l.Trace(ctx, "trace_msg1")
|
l.Trace(ctx, "trace_msg1")
|
||||||
l.Warn(ctx, "warn_msg1")
|
// l.Warn(ctx, "warn_msg1")
|
||||||
l.Fields("error", "test").Info(ctx, "error message")
|
// l.Fields("error", "test").Info(ctx, "error message")
|
||||||
l.Warn(ctx, "first", " ", "second")
|
// l.Warn(ctx, "first second")
|
||||||
if !bytes.Contains(buf.Bytes(), []byte(`"level":"trace","msg":"trace_msg1"`)) {
|
if !bytes.Contains(buf.Bytes(), []byte(`"level":"trace","msg":"trace_msg1"`)) {
|
||||||
t.Fatalf("logger error, buf %s", buf.Bytes())
|
t.Fatalf("logger tracer, buf %s", buf.Bytes())
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
if !bytes.Contains(buf.Bytes(), []byte(`"warn","msg":"warn_msg1"`)) {
|
if !bytes.Contains(buf.Bytes(), []byte(`"warn","msg":"warn_msg1"`)) {
|
||||||
t.Fatalf("logger error, buf %s", buf.Bytes())
|
t.Fatalf("logger warn, buf %s", buf.Bytes())
|
||||||
}
|
}
|
||||||
if !bytes.Contains(buf.Bytes(), []byte(`"error":"test","level":"info","msg":"error message"`)) {
|
if !bytes.Contains(buf.Bytes(), []byte(`"error":"test","level":"info","msg":"error message"`)) {
|
||||||
t.Fatalf("logger error, buf %s", buf.Bytes())
|
t.Fatalf("logger info, buf %s", buf.Bytes())
|
||||||
}
|
}
|
||||||
if !bytes.Contains(buf.Bytes(), []byte(`"level":"warn","msg":"first second"`)) {
|
if !bytes.Contains(buf.Bytes(), []byte(`"level":"warn","msg":"first second"`)) {
|
||||||
t.Fatalf("logger error, buf %s", buf.Bytes())
|
t.Fatalf("logger warn, buf %s", buf.Bytes())
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
253
logger/slog.go
253
logger/slog.go
@ -3,65 +3,110 @@ package logger
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"go.unistack.org/micro/v4/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
"log"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"golang.org/x/exp/slog"
|
"golang.org/x/exp/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
var (
|
||||||
slogName = "slog"
|
traceValue = slog.StringValue("trace")
|
||||||
|
debugValue = slog.StringValue("debug")
|
||||||
|
infoValue = slog.StringValue("info")
|
||||||
|
warnValue = slog.StringValue("warn")
|
||||||
|
errorValue = slog.StringValue("error")
|
||||||
|
fatalValue = slog.StringValue("fatal")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var renameAttr = func(_ []string, a slog.Attr) slog.Attr {
|
||||||
|
switch a.Key {
|
||||||
|
case slog.TimeKey:
|
||||||
|
a.Key = "timestamp"
|
||||||
|
case slog.LevelKey:
|
||||||
|
level := a.Value.Any().(slog.Level)
|
||||||
|
lvl := slogToLoggerLevel(level)
|
||||||
|
switch {
|
||||||
|
case lvl < DebugLevel:
|
||||||
|
a.Value = traceValue
|
||||||
|
case lvl < InfoLevel:
|
||||||
|
a.Value = debugValue
|
||||||
|
case lvl < WarnLevel:
|
||||||
|
a.Value = infoValue
|
||||||
|
case lvl < ErrorLevel:
|
||||||
|
a.Value = warnValue
|
||||||
|
case lvl < FatalLevel:
|
||||||
|
a.Value = errorValue
|
||||||
|
case lvl >= FatalLevel:
|
||||||
|
a.Value = fatalValue
|
||||||
|
default:
|
||||||
|
a.Value = infoValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
type slogLogger struct {
|
type slogLogger struct {
|
||||||
slog *slog.Logger
|
slog *slog.Logger
|
||||||
fields map[string]interface{}
|
leveler *slog.LevelVar
|
||||||
opts Options
|
opts Options
|
||||||
|
|
||||||
sync.RWMutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:!!!!
|
|
||||||
|
|
||||||
func (s *slogLogger) Clone(opts ...options.Option) Logger {
|
func (s *slogLogger) Clone(opts ...options.Option) Logger {
|
||||||
//TODO implement me
|
options := s.opts
|
||||||
panic("implement me")
|
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
l := &slogLogger{
|
||||||
|
opts: options,
|
||||||
|
}
|
||||||
|
|
||||||
|
if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok {
|
||||||
|
l.slog = slog
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
l.leveler = new(slog.LevelVar)
|
||||||
|
handleOpt := &slog.HandlerOptions{
|
||||||
|
ReplaceAttr: renameAttr,
|
||||||
|
Level: l.leveler,
|
||||||
|
}
|
||||||
|
l.leveler.Set(loggerToSlogLevel(l.opts.Level))
|
||||||
|
handler := slog.NewJSONHandler(options.Out, handleOpt)
|
||||||
|
l.slog = slog.New(handler).With(options.Fields...)
|
||||||
|
|
||||||
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) V(level Level) bool {
|
func (s *slogLogger) V(level Level) bool {
|
||||||
//TODO implement me
|
return s.opts.Level.Enabled(level)
|
||||||
panic("implement me")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Level(level Level) {
|
func (s *slogLogger) Level(level Level) {
|
||||||
//TODO implement me
|
s.leveler.Set(loggerToSlogLevel(level))
|
||||||
panic("implement me")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Options() Options {
|
func (s *slogLogger) Options() Options {
|
||||||
//TODO implement me
|
return s.opts
|
||||||
panic("implement me")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Fields(fields ...interface{}) Logger {
|
func (s *slogLogger) Fields(fields ...interface{}) Logger {
|
||||||
//TODO implement me
|
nl := &slogLogger{opts: s.opts}
|
||||||
panic("implement me")
|
nl.leveler = new(slog.LevelVar)
|
||||||
}
|
nl.leveler.Set(s.leveler.Level())
|
||||||
|
|
||||||
func (s *slogLogger) Trace(ctx context.Context, args ...interface{}) {
|
handleOpt := &slog.HandlerOptions{
|
||||||
//TODO implement me
|
ReplaceAttr: renameAttr,
|
||||||
panic("implement me")
|
Level: s.leveler,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Tracef(ctx context.Context, msg string, args ...interface{}) {
|
handler := slog.NewJSONHandler(s.opts.Out, handleOpt)
|
||||||
//TODO implement me
|
nl.slog = slog.New(handler).With(fields...)
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *slogLogger) Fatalf(ctx context.Context, msg string, args ...interface{}) {
|
return nl
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Init(opts ...options.Option) error {
|
func (s *slogLogger) Init(opts ...options.Option) error {
|
||||||
@ -76,50 +121,33 @@ func (s *slogLogger) Init(opts ...options.Option) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.leveler = new(slog.LevelVar)
|
||||||
handleOpt := &slog.HandlerOptions{
|
handleOpt := &slog.HandlerOptions{
|
||||||
ReplaceAttr: renameTime,
|
ReplaceAttr: renameAttr,
|
||||||
Level: loggerToSlogLevel(s.opts.Level),
|
Level: s.leveler,
|
||||||
}
|
}
|
||||||
|
s.leveler.Set(loggerToSlogLevel(s.opts.Level))
|
||||||
attr := fieldsToAttr(s.fields)
|
handler := slog.NewJSONHandler(s.opts.Out, handleOpt)
|
||||||
|
s.slog = slog.New(handler).With(s.opts.Fields...)
|
||||||
handler := slog.NewJSONHandler(s.opts.Out, handleOpt).WithAttrs(attr)
|
|
||||||
|
|
||||||
s.slog = slog.New(handler)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Log(ctx context.Context, lvl Level, args ...any) {
|
func (s *slogLogger) Log(ctx context.Context, lvl Level, args ...any) {
|
||||||
slvl := loggerToSlogLevel(lvl)
|
if !s.V(lvl) {
|
||||||
|
return
|
||||||
s.RLock()
|
|
||||||
attr := fieldsToAttr(s.fields)
|
|
||||||
s.RUnlock()
|
|
||||||
|
|
||||||
msg := fmt.Sprint(args...)
|
|
||||||
|
|
||||||
if lvl == FatalLevel {
|
|
||||||
log.Fatalln(msg, attr)
|
|
||||||
}
|
}
|
||||||
|
slvl := loggerToSlogLevel(lvl)
|
||||||
s.slog.LogAttrs(ctx, slvl, msg, attr...)
|
msg := fmt.Sprint(args...)
|
||||||
|
s.slog.Log(ctx, slvl, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Logf(ctx context.Context, lvl Level, format string, args ...any) {
|
func (s *slogLogger) Logf(ctx context.Context, lvl Level, format string, args ...any) {
|
||||||
slvl := loggerToSlogLevel(lvl)
|
if !s.V(lvl) {
|
||||||
|
return
|
||||||
s.RLock()
|
|
||||||
attr := fieldsToAttr(s.fields)
|
|
||||||
s.RUnlock()
|
|
||||||
|
|
||||||
msg := fmt.Sprintf(format, args...)
|
|
||||||
|
|
||||||
if lvl == FatalLevel {
|
|
||||||
log.Fatalln(msg, attr)
|
|
||||||
}
|
}
|
||||||
|
slvl := loggerToSlogLevel(lvl)
|
||||||
s.slog.LogAttrs(ctx, slvl, msg, attr...)
|
s.slog.Log(ctx, slvl, format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Info(ctx context.Context, args ...any) {
|
func (s *slogLogger) Info(ctx context.Context, args ...any) {
|
||||||
@ -142,6 +170,14 @@ func (s *slogLogger) Error(ctx context.Context, args ...any) {
|
|||||||
s.Log(ctx, ErrorLevel, args...)
|
s.Log(ctx, ErrorLevel, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *slogLogger) Trace(ctx context.Context, args ...interface{}) {
|
||||||
|
s.Log(ctx, TraceLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *slogLogger) Tracef(ctx context.Context, msg string, args ...interface{}) {
|
||||||
|
s.Logf(ctx, TraceLevel, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Errorf(ctx context.Context, format string, args ...any) {
|
func (s *slogLogger) Errorf(ctx context.Context, format string, args ...any) {
|
||||||
s.Logf(ctx, ErrorLevel, format, args...)
|
s.Logf(ctx, ErrorLevel, format, args...)
|
||||||
}
|
}
|
||||||
@ -150,6 +186,11 @@ func (s *slogLogger) Fatal(ctx context.Context, args ...any) {
|
|||||||
s.Log(ctx, FatalLevel, args...)
|
s.Log(ctx, FatalLevel, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *slogLogger) Fatalf(ctx context.Context, msg string, args ...interface{}) {
|
||||||
|
s.Logf(ctx, FatalLevel, msg, args...)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Warn(ctx context.Context, args ...any) {
|
func (s *slogLogger) Warn(ctx context.Context, args ...any) {
|
||||||
s.Log(ctx, WarnLevel, args...)
|
s.Log(ctx, WarnLevel, args...)
|
||||||
}
|
}
|
||||||
@ -159,86 +200,46 @@ func (s *slogLogger) Warnf(ctx context.Context, format string, args ...any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) String() string {
|
func (s *slogLogger) String() string {
|
||||||
return slogName
|
return "slog"
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
func NewLogger(opts ...options.Option) Logger {
|
||||||
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{
|
l := &slogLogger{
|
||||||
opts: NewOptions(opts...),
|
opts: NewOptions(opts...),
|
||||||
}
|
}
|
||||||
err := l.Init()
|
return l
|
||||||
return l, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func renameTime(groups []string, a slog.Attr) slog.Attr {
|
|
||||||
if a.Key == slog.TimeKey {
|
|
||||||
a.Key = "@timestamp"
|
|
||||||
}
|
|
||||||
|
|
||||||
return a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loggerToSlogLevel(level Level) slog.Level {
|
func loggerToSlogLevel(level Level) slog.Level {
|
||||||
switch level {
|
switch level {
|
||||||
case TraceLevel, DebugLevel:
|
case DebugLevel:
|
||||||
return slog.LevelDebug
|
return slog.LevelDebug
|
||||||
case WarnLevel:
|
case WarnLevel:
|
||||||
return slog.LevelWarn
|
return slog.LevelWarn
|
||||||
case ErrorLevel, FatalLevel:
|
case ErrorLevel:
|
||||||
return slog.LevelError
|
return slog.LevelError
|
||||||
|
case TraceLevel:
|
||||||
|
return slog.LevelDebug - 1
|
||||||
|
case FatalLevel:
|
||||||
|
return slog.LevelError + 1
|
||||||
default:
|
default:
|
||||||
return slog.LevelInfo
|
return slog.LevelInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fieldsToAttr(m map[string]any) []slog.Attr {
|
func slogToLoggerLevel(level slog.Level) Level {
|
||||||
data := make([]slog.Attr, 0, len(m))
|
switch level {
|
||||||
for k, v := range m {
|
case slog.LevelDebug:
|
||||||
data = append(data, slog.Any(k, v))
|
return DebugLevel
|
||||||
|
case slog.LevelWarn:
|
||||||
|
return WarnLevel
|
||||||
|
case slog.LevelError:
|
||||||
|
return ErrorLevel
|
||||||
|
case slog.LevelDebug - 1:
|
||||||
|
return TraceLevel
|
||||||
|
case slog.LevelError + 1:
|
||||||
|
return FatalLevel
|
||||||
|
default:
|
||||||
|
return InfoLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ var (
|
|||||||
HeaderTimeout = "Micro-Timeout"
|
HeaderTimeout = "Micro-Timeout"
|
||||||
// HeaderAuthorization specifies Authorization header
|
// HeaderAuthorization specifies Authorization header
|
||||||
HeaderAuthorization = "Authorization"
|
HeaderAuthorization = "Authorization"
|
||||||
|
// HeaderXRequestID specifies request id
|
||||||
|
HeaderXRequestID = "X-Request-Id"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Metadata is our way of representing request headers internally.
|
// Metadata is our way of representing request headers internally.
|
||||||
|
@ -91,7 +91,9 @@ type SpanOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EventOptions contains event options
|
// EventOptions contains event options
|
||||||
type EventOptions struct{}
|
type EventOptions struct {
|
||||||
|
Labels []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
func WithSpanLabels(ls ...interface{}) options.Option {
|
func WithSpanLabels(ls ...interface{}) options.Option {
|
||||||
return func(src interface{}) error {
|
return func(src interface{}) error {
|
||||||
@ -110,6 +112,26 @@ func WithSpanLabels(ls ...interface{}) options.Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EventOption func signature
|
||||||
|
type EventOption func(o *EventOptions)
|
||||||
|
|
||||||
|
func WithEventLabels(ls ...interface{}) options.Option {
|
||||||
|
return func(src interface{}) error {
|
||||||
|
v, err := options.Get(src, ".Labels")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if rutil.IsZero(v) {
|
||||||
|
v = reflect.MakeSlice(reflect.TypeOf(v), 0, len(ls)).Interface()
|
||||||
|
}
|
||||||
|
cv := reflect.ValueOf(v)
|
||||||
|
for _, l := range ls {
|
||||||
|
reflect.Append(cv, reflect.ValueOf(l))
|
||||||
|
}
|
||||||
|
err = options.Set(src, cv, ".Labels")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func WithSpanKind(k SpanKind) options.Option {
|
func WithSpanKind(k SpanKind) options.Option {
|
||||||
return func(src interface{}) error {
|
return func(src interface{}) error {
|
||||||
return options.Set(src, k, ".Kind")
|
return options.Set(src, k, ".Kind")
|
||||||
|
@ -7,77 +7,70 @@ import (
|
|||||||
|
|
||||||
"go.unistack.org/micro/v4/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v4/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
|
"go.unistack.org/micro/v4/options"
|
||||||
"go.unistack.org/micro/v4/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
"go.unistack.org/micro/v4/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var DefaultHeadersExctract = []string{metadata.HeaderTopic, metadata.HeaderEndpoint, metadata.HeaderService, metadata.HeaderXRequestID}
|
||||||
|
|
||||||
|
func extractLabels(md metadata.Metadata) []string {
|
||||||
|
labels := make([]string, 0, 5)
|
||||||
|
for _, k := range DefaultHeadersExctract {
|
||||||
|
if v, ok := md.Get(k); ok {
|
||||||
|
labels = append(labels, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return labels
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultClientCallObserver = func(ctx context.Context, req client.Request, rsp interface{}, opts []client.CallOption, sp tracer.Span, err error) {
|
DefaultClientCallObserver = func(ctx context.Context, req client.Request, rsp interface{}, opts []options.Option, sp tracer.Span, err error) {
|
||||||
sp.SetName(fmt.Sprintf("Call %s.%s", req.Service(), req.Method()))
|
sp.SetName(fmt.Sprintf("Call %s.%s", req.Service(), req.Method()))
|
||||||
var labels []interface{}
|
var labels []interface{}
|
||||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||||
labels = make([]interface{}, 0, len(md)+1)
|
labels = append(labels, extractLabels(md))
|
||||||
for k, v := range md {
|
|
||||||
labels = append(labels, k, v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
labels = append(labels, "error", err.Error())
|
|
||||||
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||||
}
|
}
|
||||||
labels = append(labels, "kind", sp.Kind())
|
sp.AddLabels(labels...)
|
||||||
sp.SetLabels(labels...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultClientStreamObserver = func(ctx context.Context, req client.Request, opts []client.CallOption, stream client.Stream, sp tracer.Span, err error) {
|
DefaultClientStreamObserver = func(ctx context.Context, req client.Request, opts []options.Option, stream client.Stream, sp tracer.Span, err error) {
|
||||||
sp.SetName(fmt.Sprintf("Stream %s.%s", req.Service(), req.Method()))
|
sp.SetName(fmt.Sprintf("Stream %s.%s", req.Service(), req.Method()))
|
||||||
var labels []interface{}
|
var labels []interface{}
|
||||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||||
labels = make([]interface{}, 0, len(md))
|
labels = append(labels, extractLabels(md))
|
||||||
for k, v := range md {
|
|
||||||
labels = append(labels, k, v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
labels = append(labels, "error", err.Error())
|
|
||||||
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||||
}
|
}
|
||||||
labels = append(labels, "kind", sp.Kind())
|
sp.AddLabels(labels...)
|
||||||
sp.SetLabels(labels...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultServerHandlerObserver = func(ctx context.Context, req server.Request, rsp interface{}, sp tracer.Span, err error) {
|
DefaultServerHandlerObserver = func(ctx context.Context, req server.Request, rsp interface{}, sp tracer.Span, err error) {
|
||||||
sp.SetName(fmt.Sprintf("Handler %s.%s", req.Service(), req.Method()))
|
sp.SetName(fmt.Sprintf("Handler %s.%s", req.Service(), req.Method()))
|
||||||
var labels []interface{}
|
var labels []interface{}
|
||||||
if md, ok := metadata.FromIncomingContext(ctx); ok {
|
if md, ok := metadata.FromIncomingContext(ctx); ok {
|
||||||
labels = make([]interface{}, 0, len(md))
|
labels = append(labels, extractLabels(md))
|
||||||
for k, v := range md {
|
|
||||||
labels = append(labels, k, v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
labels = append(labels, "error", err.Error())
|
|
||||||
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||||
}
|
}
|
||||||
labels = append(labels, "kind", sp.Kind())
|
sp.AddLabels(labels...)
|
||||||
sp.SetLabels(labels...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultClientCallFuncObserver = func(ctx context.Context, addr string, req client.Request, rsp interface{}, opts client.CallOptions, sp tracer.Span, err error) {
|
DefaultClientCallFuncObserver = func(ctx context.Context, addr string, req client.Request, rsp interface{}, opts client.CallOptions, sp tracer.Span, err error) {
|
||||||
sp.SetName(fmt.Sprintf("Call %s.%s", req.Service(), req.Method()))
|
sp.SetName(fmt.Sprintf("Call %s.%s", req.Service(), req.Method()))
|
||||||
var labels []interface{}
|
var labels []interface{}
|
||||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||||
labels = make([]interface{}, 0, len(md))
|
labels = append(labels, extractLabels(md))
|
||||||
for k, v := range md {
|
|
||||||
labels = append(labels, k, v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
labels = append(labels, "error", err.Error())
|
|
||||||
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||||
}
|
}
|
||||||
labels = append(labels, "kind", sp.Kind())
|
sp.AddLabels(labels...)
|
||||||
sp.SetLabels(labels...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultSkipEndpoints = []string{"Meter.Metrics", "Health.Live", "Health.Ready", "Health.Version"}
|
DefaultSkipEndpoints = []string{"Meter.Metrics", "Health.Live", "Health.Ready", "Health.Version"}
|
||||||
@ -91,8 +84,8 @@ type tWrapper struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
ClientCallObserver func(context.Context, client.Request, interface{}, []client.CallOption, tracer.Span, error)
|
ClientCallObserver func(context.Context, client.Request, interface{}, []options.Option, tracer.Span, error)
|
||||||
ClientStreamObserver func(context.Context, client.Request, []client.CallOption, client.Stream, tracer.Span, error)
|
ClientStreamObserver func(context.Context, client.Request, []options.Option, client.Stream, tracer.Span, error)
|
||||||
ClientCallFuncObserver func(context.Context, string, client.Request, interface{}, client.CallOptions, tracer.Span, error)
|
ClientCallFuncObserver func(context.Context, string, client.Request, interface{}, client.CallOptions, tracer.Span, error)
|
||||||
ServerHandlerObserver func(context.Context, server.Request, interface{}, tracer.Span, error)
|
ServerHandlerObserver func(context.Context, server.Request, interface{}, tracer.Span, error)
|
||||||
)
|
)
|
||||||
@ -176,7 +169,7 @@ func WithServerHandlerObservers(ob ...ServerHandlerObserver) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ot *tWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
func (ot *tWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...options.Option) error {
|
||||||
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
|
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
|
||||||
for _, ep := range ot.opts.SkipEndpoints {
|
for _, ep := range ot.opts.SkipEndpoints {
|
||||||
if ep == endpoint {
|
if ep == endpoint {
|
||||||
@ -186,7 +179,14 @@ func (ot *tWrapper) Call(ctx context.Context, req client.Request, rsp interface{
|
|||||||
|
|
||||||
sp, ok := tracer.SpanFromContext(ctx)
|
sp, ok := tracer.SpanFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
ctx, sp = ot.opts.Tracer.Start(ctx, "", tracer.WithSpanKind(tracer.SpanKindClient))
|
ctx, sp = ot.opts.Tracer.Start(ctx, "rpc-client",
|
||||||
|
tracer.WithSpanKind(tracer.SpanKindClient),
|
||||||
|
tracer.WithSpanLabels(
|
||||||
|
"rpc.flavor", "rpc",
|
||||||
|
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||||
|
"rpc.call_type", "unary",
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
defer sp.Finish()
|
defer sp.Finish()
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ func (ot *tWrapper) Call(ctx context.Context, req client.Request, rsp interface{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ot *tWrapper) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
|
func (ot *tWrapper) Stream(ctx context.Context, req client.Request, opts ...options.Option) (client.Stream, error) {
|
||||||
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
|
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
|
||||||
for _, ep := range ot.opts.SkipEndpoints {
|
for _, ep := range ot.opts.SkipEndpoints {
|
||||||
if ep == endpoint {
|
if ep == endpoint {
|
||||||
@ -209,7 +209,14 @@ func (ot *tWrapper) Stream(ctx context.Context, req client.Request, opts ...clie
|
|||||||
|
|
||||||
sp, ok := tracer.SpanFromContext(ctx)
|
sp, ok := tracer.SpanFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
ctx, sp = ot.opts.Tracer.Start(ctx, "", tracer.WithSpanKind(tracer.SpanKindClient))
|
ctx, sp = ot.opts.Tracer.Start(ctx, "rpc-client",
|
||||||
|
tracer.WithSpanKind(tracer.SpanKindClient),
|
||||||
|
tracer.WithSpanLabels(
|
||||||
|
"rpc.flavor", "rpc",
|
||||||
|
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||||
|
"rpc.call_type", "stream",
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
defer sp.Finish()
|
defer sp.Finish()
|
||||||
|
|
||||||
@ -230,10 +237,23 @@ func (ot *tWrapper) ServerHandler(ctx context.Context, req server.Request, rsp i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callType := "unary"
|
||||||
|
if req.Stream() {
|
||||||
|
callType = "stream"
|
||||||
|
}
|
||||||
|
|
||||||
sp, ok := tracer.SpanFromContext(ctx)
|
sp, ok := tracer.SpanFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
ctx, sp = ot.opts.Tracer.Start(ctx, "", tracer.WithSpanKind(tracer.SpanKindServer))
|
ctx, sp = ot.opts.Tracer.Start(ctx, "rpc-server",
|
||||||
|
tracer.WithSpanKind(tracer.SpanKindServer),
|
||||||
|
tracer.WithSpanLabels(
|
||||||
|
"rpc.flavor", "rpc",
|
||||||
|
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||||
|
"rpc.call_type", callType,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer sp.Finish()
|
defer sp.Finish()
|
||||||
|
|
||||||
err := ot.serverHandler(ctx, req, rsp)
|
err := ot.serverHandler(ctx, req, rsp)
|
||||||
@ -279,7 +299,14 @@ func (ot *tWrapper) ClientCallFunc(ctx context.Context, addr string, req client.
|
|||||||
|
|
||||||
sp, ok := tracer.SpanFromContext(ctx)
|
sp, ok := tracer.SpanFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
ctx, sp = ot.opts.Tracer.Start(ctx, "", tracer.WithSpanKind(tracer.SpanKindClient))
|
ctx, sp = ot.opts.Tracer.Start(ctx, "rpc-client",
|
||||||
|
tracer.WithSpanKind(tracer.SpanKindClient),
|
||||||
|
tracer.WithSpanLabels(
|
||||||
|
"rpc.flavor", "rpc",
|
||||||
|
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||||
|
"rpc.call_type", "unary",
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
defer sp.Finish()
|
defer sp.Finish()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user