Skip to content

Commit

Permalink
optimize print log
Browse files Browse the repository at this point in the history
  • Loading branch information
zhufuyi committed Aug 31, 2024
1 parent 6316b65 commit e006f30
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 26 deletions.
4 changes: 3 additions & 1 deletion .github/RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ example:
ecode.StatusInvalidParams.ErrToHTTP("custom error message")
```

2. Adjust some code.
2. Optimize print log, grpc support custom marshal data.

3. Adjust some code.
25 changes: 12 additions & 13 deletions pkg/gin/middleware/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import (
"bytes"
"io"
"net/http"
"strings"
"time"

"github.com/gin-gonic/gin"
"go.uber.org/zap"
)

var contentMark = []byte(" ...... ")

var (
// Print body max length
defaultMaxLength = 300
Expand Down Expand Up @@ -102,17 +103,15 @@ func (w bodyLogWriter) Write(b []byte) (int, error) {
return w.ResponseWriter.Write(b)
}

func getBodyData(buf *bytes.Buffer, maxLen int) string {
var body string

if buf.Len() > maxLen {
body = string(buf.Bytes()[:maxLen]) + " ...... "
// If there is sensitive data that needs to be filtered out, such as plaintext passwords
} else {
body = buf.String()
// If there is sensitive information in the body, you can use WithIgnoreRoutes set the route to ignore logging
func getBodyData(buf *bytes.Buffer, maxLen int) []byte {
l := buf.Len()
if l == 0 {
return []byte("")
} else if l <= maxLen {
return buf.Bytes()[:l-1]
}

return body
return append(buf.Bytes()[:maxLen], contentMark...)
}

// Logging print request and response info
Expand Down Expand Up @@ -140,7 +139,7 @@ func Logging(opts ...Option) gin.HandlerFunc {
if c.Request.Method == http.MethodPost || c.Request.Method == http.MethodPut || c.Request.Method == http.MethodPatch || c.Request.Method == http.MethodDelete {
fields = append(fields,
zap.Int("size", buf.Len()),
zap.String("body", getBodyData(&buf, o.maxLength)),
zap.ByteString("body", getBodyData(&buf, o.maxLength)),
)
}

Expand Down Expand Up @@ -174,7 +173,7 @@ func Logging(opts ...Option) gin.HandlerFunc {
zap.String("url", c.Request.URL.Path),
zap.Int64("time_us", time.Since(start).Microseconds()),
zap.Int("size", newWriter.body.Len()),
zap.String("response", strings.TrimRight(getBodyData(newWriter.body, o.maxLength), "\n")),
zap.ByteString("body", getBodyData(newWriter.body, o.maxLength)),
}
if reqID != "" {
fields = append(fields, zap.String(ContextRequestIDKey, reqID))
Expand Down
21 changes: 15 additions & 6 deletions pkg/grpc/interceptor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,47 @@ import "github.com/zhufuyi/sponge/pkg/grpc/interceptor"
**grpc server-side**

```go
var logger *zap.Logger

// set unary server logging
func getServerOptions() []grpc.ServerOption {
var options []grpc.ServerOption

options = append(options, grpc_middleware.WithUnaryServerChain(
interceptor.UnaryClientLog(
logger.Get(), // zap
// middleware.WithLogFields(map[string]interface{}{"serverName": "userExample"}), // additional print fields
middleware.WithLogIgnoreMethods("/proto.userExampleService/GetByID"), // ignore the specified method print, you can specify more than one
// if you don't want to log reply data, you can use interceptor.StreamServerSimpleLog instead of interceptor.UnaryServerLog,
interceptor.UnaryServerLog(
logger.Get(),
interceptor.WithReplaceGRPCLogger(),
//interceptor.WithMarshalFn(fn), // customised marshal function, default is jsonpb.Marshal
//interceptor.WithLogIgnoreMethods(fullMethodNames), // ignore methods logging
//interceptor.WithMaxLen(400), // logging max length, default 300
),
))

return options
}


// you can also set stream server logging
```

**grpc client-side**

```go
// set unary client logging
func getDialOptions() []grpc.DialOption {
var options []grpc.DialOption

option := grpc.WithUnaryInterceptor(
grpc_middleware.ChainUnaryClient(
interceptor.UnaryClientLog(logger.Get()),
interceptor.WithReplaceGRPCLogger(),
),
)
options = append(options, option)

return options
}

// you can also set stream client logging
```

<br>
Expand Down
41 changes: 35 additions & 6 deletions pkg/grpc/interceptor/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
zapLog "github.com/zhufuyi/sponge/pkg/logger"
)

var contentMark = []byte(" ...... ")

// ---------------------------------- client interceptor ----------------------------------

// UnaryClientLog client log unary interceptor
Expand Down Expand Up @@ -91,21 +93,30 @@ func StreamClientLog(logger *zap.Logger, opts ...LogOption) grpc.StreamClientInt

// ---------------------------------- server interceptor ----------------------------------

var defaultMaxLength = 300 // max length of response data to print
var ignoreLogMethods = map[string]struct{}{} // ignore printing methods
var defaultMarshalFn = func(reply interface{}) []byte {
data, _ := json.Marshal(reply)
return data
}

// LogOption log settings
type LogOption func(*logOptions)

type logOptions struct {
maxLength int
fields map[string]interface{}
ignoreMethods map[string]struct{}
isReplaceGRPCLogger bool
marshalFn func(reply interface{}) []byte // default json.Marshal
}

func defaultLogOptions() *logOptions {
return &logOptions{
maxLength: defaultMaxLength,
fields: make(map[string]interface{}),
ignoreMethods: make(map[string]struct{}),
marshalFn: defaultMarshalFn,
}
}

Expand All @@ -115,6 +126,15 @@ func (o *logOptions) apply(opts ...LogOption) {
}
}

// WithMaxLen logger content max length
func WithMaxLen(maxLen int) LogOption {
return func(o *logOptions) {
if maxLen > 0 {
o.maxLength = maxLen
}
}
}

// WithReplaceGRPCLogger replace grpc logger v2
func WithReplaceGRPCLogger() LogOption {
return func(o *logOptions) {
Expand All @@ -132,6 +152,15 @@ func WithLogFields(kvs map[string]interface{}) LogOption {
}
}

// WithMarshalFn custom response data marshal function
func WithMarshalFn(fn func(reply interface{}) []byte) LogOption {
return func(o *logOptions) {
if fn != nil {
o.marshalFn = fn
}
}
}

// WithLogIgnoreMethods ignore printing methods
// fullMethodName format: /packageName.serviceName/methodName,
// example /api.userExample.v1.userExampleService/GetByID
Expand Down Expand Up @@ -177,17 +206,17 @@ func UnaryServerLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryServerInter

resp, err := handler(ctx, req)

data, _ := json.Marshal(resp)
if len(data) > 300 {
data = append(data[:300], []byte("......")...)
data := o.marshalFn(resp)
if len(data) > o.maxLength {
data = append(data[:o.maxLength], contentMark...)
}

fields = []zap.Field{
zap.String("code", status.Code(err).String()),
zap.Error(err),
zap.String("type", "unary"),
zap.String("method", info.FullMethod),
zap.String("response", string(data)),
zap.ByteString("data", data),
zap.Int64("time_us", time.Since(startTime).Microseconds()),
}
if requestID != "" {
Expand Down Expand Up @@ -233,7 +262,7 @@ func UnaryServerSimpleLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryServe
if requestID != "" {
fields = append(fields, zap.String(ContextRequestIDKey, requestID))
}
logger.Info("[GRPC]", fields...)
logger.Info("[GRPC] response", fields...)

return resp, err
}
Expand Down Expand Up @@ -320,7 +349,7 @@ func StreamServerSimpleLog(logger *zap.Logger, opts ...LogOption) grpc.StreamSer
if requestID != "" {
fields = append(fields, zap.String(ContextRequestIDKey, requestID))
}
logger.Info("[GRPC]", fields...)
logger.Info("[GRPC] response", fields...)

return err
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/grpc/interceptor/logging_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package interceptor

import (
"encoding/json"
"testing"
"time"

Expand Down Expand Up @@ -42,7 +43,12 @@ func TestStreamClientLog(t *testing.T) {
func TestUnaryServerLog_ignore(t *testing.T) {
addr := newUnaryRPCServer(
UnaryServerLog(logger.Get(),
WithMaxLen(200),
WithLogFields(map[string]interface{}{"foo": "bar"}),
WithMarshalFn(func(reply interface{}) []byte {
data, _ := json.Marshal(reply)
return data
}),
WithLogIgnoreMethods("/api.user.v1.user/GetByID"),
),
)
Expand Down
5 changes: 5 additions & 0 deletions pkg/logger/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ func String(key string, val string) Field {
return zap.String(key, val)
}

// ByteString type
func ByteString(key string, val []byte) Field {
return zap.ByteString(key, val)
}

// Stringer type
func Stringer(key string, val fmt.Stringer) Field {
return zap.Stringer(key, val)
Expand Down
5 changes: 5 additions & 0 deletions pkg/logger/type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ func TestString(t *testing.T) {
assert.NotNil(t, field)
}

func TestByteString(t *testing.T) {
field := ByteString("key", []byte("bar"))
assert.NotNil(t, field)
}

func TestStringer(t *testing.T) {
field := Stringer("key", new(st))
assert.NotNil(t, field)
Expand Down

0 comments on commit e006f30

Please sign in to comment.