Skip to content

Commit 0bfe8df

Browse files
authored
Merge pull request #15 from KyberNetwork/phu/allow-config-logger
feat: allow configuring logger
2 parents a09fffb + 30195fb commit 0bfe8df

File tree

5 files changed

+124
-14
lines changed

5 files changed

+124
-14
lines changed

pkg/observe/trace.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func EnsureTracerProvider() {
2626
constant.OtelDefaultServiceVersion)),
2727
))
2828
if err == nil {
29-
resources, err = resource.Merge(resources, extraResources)
29+
resources, _ = resource.Merge(resources, extraResources)
3030
}
3131
tracerProvider := sdktrace.NewTracerProvider(
3232
sdktrace.WithResource(resources),

pkg/server/grpcserver/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (s *Server) Register(services ...Service) error {
104104
func (s *Server) Serve(ctx context.Context) (err error) {
105105
stop := make(chan os.Signal, 1)
106106
errCh := make(chan error)
107-
signal.Notify(stop, os.Interrupt, os.Kill, syscall.SIGTERM)
107+
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
108108

109109
go func() {
110110
listener, err := net.Listen("tcp", s.cfg.GRPC.String())

pkg/server/middleware/logging/log.go

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"time"
66

77
"github.com/KyberNetwork/kutils/klog"
8+
"github.com/KyberNetwork/logger"
89
"google.golang.org/grpc/codes"
910
"google.golang.org/grpc/metadata"
1011
"google.golang.org/grpc/peer"
@@ -21,15 +22,30 @@ type InterceptorLogger interface {
2122
// LoggerFunc is a function that also implements InterceptorLogger interface.
2223
type LoggerFunc func(ctx context.Context, meta CallMeta, req any, resp any, err error, duration time.Duration)
2324

25+
// Log implements InterceptorLogger interface by triggering itself.
2426
func (f LoggerFunc) Log(ctx context.Context, meta CallMeta, req any, resp any, err error, duration time.Duration) {
2527
f(ctx, meta, req, resp, err, duration)
2628
}
2729

30+
// opt is the option struct for logging interceptors.
2831
type opt struct {
2932
ignoreReq map[string]struct{}
3033
ignoreResp map[string]struct{}
3134
}
3235

36+
// newOpt returns a new opt struct with the given option funcs.
37+
func newOpt(opts ...func(opt *opt)) *opt {
38+
opt := &opt{
39+
ignoreReq: make(map[string]struct{}),
40+
ignoreResp: make(map[string]struct{}),
41+
}
42+
for _, o := range opts {
43+
o(opt)
44+
}
45+
return opt
46+
}
47+
48+
// IgnoreReq ignores logging requests for commands with given specified full method names.
3349
func IgnoreReq(ignoreReq ...string) func(opt *opt) {
3450
return func(opt *opt) {
3551
for _, v := range ignoreReq {
@@ -38,6 +54,7 @@ func IgnoreReq(ignoreReq ...string) func(opt *opt) {
3854
}
3955
}
4056

57+
// IgnoreResp ignores logging responses for commands with given specified full method names.
4158
func IgnoreResp(ignoreResp ...string) func(opt *opt) {
4259
return func(opt *opt) {
4360
for _, v := range ignoreResp {
@@ -46,16 +63,17 @@ func IgnoreResp(ignoreResp ...string) func(opt *opt) {
4663
}
4764
}
4865

66+
// ignored is a string that indicates that the request or response is ignored.
4967
const ignored = "<...>"
5068

69+
// DefaultLogger is the default logging interceptor which logs requests and responses in plain format.
5170
func DefaultLogger(loggerFromCtx func(context.Context) Logger, opts ...func(opt *opt)) LoggerFunc {
52-
opt := &opt{
53-
ignoreReq: make(map[string]struct{}),
54-
ignoreResp: make(map[string]struct{}),
55-
}
56-
for _, o := range opts {
57-
o(opt)
71+
if loggerFromCtx == nil {
72+
loggerFromCtx = func(ctx context.Context) Logger {
73+
return klog.LoggerFromCtx(ctx)
74+
}
5875
}
76+
opt := newOpt(opts...)
5977
return func(ctx context.Context, meta CallMeta, req any, resp any, err error, duration time.Duration) {
6078
code := status.Code(err)
6179
if _, ok := opt.ignoreReq[meta.FullMethod]; ok {
@@ -74,8 +92,38 @@ func DefaultLogger(loggerFromCtx func(context.Context) Logger, opts ...func(opt
7492
}
7593
}
7694

77-
func KlogLogger(ctx context.Context) Logger {
78-
return klog.LoggerFromCtx(ctx)
95+
// FieldsLogger is the fields-enabled logging interceptor which logs requests and responses in JSON format.
96+
func FieldsLogger(loggerFromCtx func(context.Context) logger.Logger, opts ...func(opt *opt)) LoggerFunc {
97+
if loggerFromCtx == nil {
98+
loggerFromCtx = func(ctx context.Context) logger.Logger {
99+
return klog.LoggerFromCtx(ctx)
100+
}
101+
}
102+
opt := newOpt(opts...)
103+
return func(ctx context.Context, meta CallMeta, req any, resp any, err error, duration time.Duration) {
104+
code := status.Code(err)
105+
if _, ok := opt.ignoreReq[meta.FullMethod]; ok {
106+
req = ignored
107+
}
108+
if _, ok := opt.ignoreResp[meta.FullMethod]; ok {
109+
resp = ignored
110+
}
111+
from := metadata.ValueFromIncomingContext(ctx, common.HeaderXForwardedFor)
112+
if peerInfo, ok := peer.FromContext(ctx); ok {
113+
from = append(from, peerInfo.Addr.String())
114+
}
115+
logFields := logger.Fields{
116+
"cmd": meta.FullMethod,
117+
"code": code,
118+
"err": err,
119+
"req": req,
120+
"resp": resp,
121+
"dur": duration,
122+
"from": from,
123+
}
124+
log := loggerFromCtx(ctx).WithFields(logFields)
125+
Logf(log, code, "response sent")
126+
}
79127
}
80128

81129
// Logger is a logger with infof/warnf/errorf methods.

pkg/server/option.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package server
2+
3+
import (
4+
"context"
5+
6+
"google.golang.org/grpc"
7+
8+
"github.com/KyberNetwork/service-framework/pkg/server/grpcserver"
9+
"github.com/KyberNetwork/service-framework/pkg/server/middleware/logging"
10+
)
11+
12+
type option struct {
13+
services []grpcserver.Service // services to register
14+
loggingInterceptor logging.InterceptorLogger // to override default interceptor logger
15+
logger func(ctx context.Context) logging.Logger // to override logger used by default interceptor logger
16+
grpcServerOptions []grpc.ServerOption // additional grpc server options
17+
}
18+
19+
func (o *option) Build(optFns ...OptFn) *option {
20+
if o == nil {
21+
*o = option{}
22+
}
23+
for _, opt := range optFns {
24+
opt(o)
25+
}
26+
return o
27+
}
28+
29+
type OptFn func(*option)
30+
31+
func WithServices(services ...grpcserver.Service) OptFn {
32+
return func(o *option) {
33+
o.services = append(o.services, services...)
34+
}
35+
}
36+
37+
func WithLoggingInterceptor(interceptor logging.InterceptorLogger) OptFn {
38+
return func(o *option) {
39+
o.loggingInterceptor = interceptor
40+
}
41+
}
42+
43+
func WithLogger(logger func(ctx context.Context) logging.Logger) OptFn {
44+
return func(o *option) {
45+
o.logger = logger
46+
}
47+
}
48+
49+
func WithGRPCServerOptions(options ...grpc.ServerOption) OptFn {
50+
return func(o *option) {
51+
o.grpcServerOptions = append(o.grpcServerOptions, options...)
52+
}
53+
}

pkg/server/serve.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,27 @@ import (
3333

3434
var internalServerErr = status.New(codes.Internal, "Internal server error")
3535

36-
func Serve(ctx context.Context, cfg grpcserver.Config, services ...grpcserver.Service) {
36+
// Serve starts gRPC server and HTTP grpc gateway server. It blocks until os.Interrupt or syscall.SIGTERM.
37+
// Example usage:
38+
//
39+
// server.Serve(ctx, cfg, server.WithServices(service1, service2), server.WithLogger(myLoggerFactory))
40+
func Serve(ctx context.Context, cfg grpcserver.Config, opts ...OptFn) {
3741
defer shutdownKyberTrace()
3842

43+
opt := new(option).Build(opts...)
44+
3945
appMode := grpcserver.GetAppMode(cfg.Mode)
4046
isDevMode := appMode == grpcserver.Development
4147
unaryOpts := []grpc.UnaryServerInterceptor{
4248
trace.UnaryServerInterceptor(isDevMode, internalServerErr),
4349
}
4450
var streamOpts []grpc.StreamServerInterceptor
4551

46-
loggingLogger := logging.DefaultLogger(logging.KlogLogger,
47-
logging.IgnoreReq(cfg.Log.IgnoreReq...), logging.IgnoreResp(cfg.Log.IgnoreResp...))
52+
loggingLogger := opt.loggingInterceptor
53+
if loggingLogger == nil {
54+
loggingLogger = logging.DefaultLogger(opt.logger,
55+
logging.IgnoreReq(cfg.Log.IgnoreReq...), logging.IgnoreResp(cfg.Log.IgnoreResp...))
56+
}
4857
recoveryOpt := recovery.WithRecoveryHandler(func(err any) error {
4958
klog.WithFields(ctx, klog.Fields{"error": err}).Errorf("recovered from:\n%s", string(debug.Stack()))
5059
kmetric.IncPanicTotal(context.Background())
@@ -70,7 +79,7 @@ func Serve(ctx context.Context, cfg grpcserver.Config, services ...grpcserver.Se
7079
}
7180
s := grpcserver.NewServer(&cfg, appMode, serverOptions...)
7281

73-
if err := s.Register(services...); err != nil {
82+
if err := s.Register(opt.services...); err != nil {
7483
klog.Fatalf(ctx, "Error register servers %v", err)
7584
}
7685

0 commit comments

Comments
 (0)