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())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handleOpt := &slog.HandlerOptions{
 | 
				
			||||||
 | 
							ReplaceAttr: renameAttr,
 | 
				
			||||||
 | 
							Level:       s.leveler,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *slogLogger) Trace(ctx context.Context, 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) Tracef(ctx context.Context, msg string, args ...interface{}) {
 | 
						return nl
 | 
				
			||||||
	//TODO implement me
 | 
					 | 
				
			||||||
	panic("implement me")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *slogLogger) Fatalf(ctx context.Context, msg string, args ...interface{}) {
 | 
					 | 
				
			||||||
	//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()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user