mirror of https://github.com/zhufuyi/sponge
feat: print error message according to error code
This commit is contained in:
parent
65e013ee3e
commit
ef814cf96a
|
@ -24,6 +24,13 @@ var (
|
|||
"/health": {},
|
||||
}
|
||||
|
||||
// Print error by specified codes
|
||||
printErrorBySpecifiedCodes = map[int]bool{
|
||||
http.StatusInternalServerError: true,
|
||||
http.StatusBadGateway: true,
|
||||
http.StatusServiceUnavailable: true,
|
||||
}
|
||||
|
||||
emptyBody = []byte("")
|
||||
contentMark = []byte(" ...... ")
|
||||
)
|
||||
|
@ -81,6 +88,15 @@ func WithIgnoreRoutes(routes ...string) Option {
|
|||
}
|
||||
}
|
||||
|
||||
// WithPrintErrorByCodes set print error by specified codes
|
||||
func WithPrintErrorByCodes(code ...int) Option {
|
||||
return func(o *options) {
|
||||
for _, c := range code {
|
||||
printErrorBySpecifiedCodes[c] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRequestIDFromContext name is field in context, default value is request_id
|
||||
func WithRequestIDFromContext() Option {
|
||||
return func(o *options) {
|
||||
|
@ -154,19 +170,14 @@ func Logging(opts ...Option) gin.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
// print input information before processing
|
||||
buf := bytes.Buffer{}
|
||||
_, _ = buf.ReadFrom(c.Request.Body)
|
||||
|
||||
fields := []zap.Field{
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.String()),
|
||||
}
|
||||
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.ByteString("body", getRequestBody(&buf, o.maxLength)),
|
||||
)
|
||||
sizeField := zap.Skip()
|
||||
bodyField := zap.Skip()
|
||||
if c.Request.Method == http.MethodPost || c.Request.Method == http.MethodPut ||
|
||||
c.Request.Method == http.MethodPatch || c.Request.Method == http.MethodDelete {
|
||||
sizeField = zap.Int("size", buf.Len())
|
||||
bodyField = zap.ByteString("body", getRequestBody(&buf, o.maxLength))
|
||||
}
|
||||
|
||||
reqID := ""
|
||||
|
@ -174,14 +185,24 @@ func Logging(opts ...Option) gin.HandlerFunc {
|
|||
if v, isExist := c.Get(ContextRequestIDKey); isExist {
|
||||
if requestID, ok := v.(string); ok {
|
||||
reqID = requestID
|
||||
fields = append(fields, zap.String(ContextRequestIDKey, reqID))
|
||||
}
|
||||
}
|
||||
} else if o.requestIDFrom == 2 {
|
||||
reqID = c.Request.Header.Get(HeaderXRequestIDKey)
|
||||
fields = append(fields, zap.String(ContextRequestIDKey, reqID))
|
||||
}
|
||||
o.log.Info("<<<<", fields...)
|
||||
reqIDField := zap.Skip()
|
||||
if reqID != "" {
|
||||
reqIDField = zap.String(ContextRequestIDKey, reqID)
|
||||
}
|
||||
|
||||
// print input information before processing
|
||||
o.log.Info("<<<<",
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.String()),
|
||||
sizeField,
|
||||
bodyField,
|
||||
reqIDField,
|
||||
)
|
||||
|
||||
c.Request.Body = io.NopCloser(&buf)
|
||||
|
||||
|
@ -192,19 +213,22 @@ func Logging(opts ...Option) gin.HandlerFunc {
|
|||
// processing requests
|
||||
c.Next()
|
||||
|
||||
// print return message after processing
|
||||
fields = []zap.Field{
|
||||
zap.Int("code", c.Writer.Status()),
|
||||
// print response message after processing
|
||||
httpCode := c.Writer.Status()
|
||||
fields := []zap.Field{
|
||||
zap.Int("code", httpCode),
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.Path),
|
||||
zap.Int64("time_us", time.Since(start).Microseconds()),
|
||||
zap.Int("size", newWriter.body.Len()),
|
||||
zap.ByteString("body", getResponseBody(newWriter.body, o.maxLength)),
|
||||
reqIDField,
|
||||
}
|
||||
if reqID != "" {
|
||||
fields = append(fields, zap.String(ContextRequestIDKey, reqID))
|
||||
if printErrorBySpecifiedCodes[httpCode] {
|
||||
o.log.WithOptions(zap.AddStacktrace(zap.PanicLevel)).Error(">>>>", fields...)
|
||||
} else {
|
||||
o.log.Info(">>>>", fields...)
|
||||
}
|
||||
o.log.Info(">>>>", fields...)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,21 +256,28 @@ func SimpleLog(opts ...Option) gin.HandlerFunc {
|
|||
} else if o.requestIDFrom == 2 {
|
||||
reqID = c.Request.Header.Get(HeaderXRequestIDKey)
|
||||
}
|
||||
reqIDField := zap.Skip()
|
||||
if reqID != "" {
|
||||
reqIDField = zap.String(ContextRequestIDKey, reqID)
|
||||
}
|
||||
|
||||
// processing requests
|
||||
c.Next()
|
||||
|
||||
// print return message after processing
|
||||
httpCode := c.Writer.Status()
|
||||
fields := []zap.Field{
|
||||
zap.Int("code", c.Writer.Status()),
|
||||
zap.Int("code", httpCode),
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.String()),
|
||||
zap.Int64("time_us", time.Since(start).Microseconds()),
|
||||
zap.Int("size", c.Writer.Size()),
|
||||
reqIDField,
|
||||
}
|
||||
if reqID != "" {
|
||||
fields = append(fields, zap.String(ContextRequestIDKey, reqID))
|
||||
if printErrorBySpecifiedCodes[httpCode] {
|
||||
o.log.WithOptions(zap.AddStacktrace(zap.PanicLevel)).Error("Gin response", fields...)
|
||||
} else {
|
||||
o.log.Info("Gin response", fields...)
|
||||
}
|
||||
o.log.Info("Gin msg", fields...)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/response"
|
||||
"github.com/go-dev-frame/sponge/pkg/httpcli"
|
||||
|
@ -20,7 +22,7 @@ func runLogHTTPServer() string {
|
|||
serverAddr, requestAddr := utils.GetLocalHTTPAddrPairs()
|
||||
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.Default()
|
||||
r := gin.New()
|
||||
r.Use(RequestID())
|
||||
|
||||
// default Print Log
|
||||
|
@ -33,6 +35,7 @@ func runLogHTTPServer() string {
|
|||
WithRequestIDFromHeader(),
|
||||
WithRequestIDFromContext(),
|
||||
WithIgnoreRoutes("/ping"), // ignore path /ping
|
||||
WithPrintErrorByCodes(409),
|
||||
))
|
||||
|
||||
// custom zap log
|
||||
|
@ -45,17 +48,22 @@ func runLogHTTPServer() string {
|
|||
logger.Info("test request id", GCtxRequestIDField(c))
|
||||
response.Success(c, "hello world")
|
||||
}
|
||||
helloFunErr := func(c *gin.Context) {
|
||||
logger.Info("test request id", GCtxRequestIDField(c))
|
||||
response.Output(c, 500, "hello world error")
|
||||
}
|
||||
|
||||
pingFun := func(c *gin.Context) {
|
||||
response.Success(c, "ping")
|
||||
}
|
||||
|
||||
r.GET("/hello", helloFun)
|
||||
r.GET("/ping", pingFun)
|
||||
r.GET("/hello", helloFun)
|
||||
r.DELETE("/hello", helloFun)
|
||||
r.POST("/hello", helloFun)
|
||||
r.PUT("/hello", helloFun)
|
||||
r.PATCH("/hello", helloFun)
|
||||
r.POST("/helloErr", helloFunErr)
|
||||
|
||||
go func() {
|
||||
err := r.Run(serverAddr)
|
||||
|
@ -149,26 +157,38 @@ func TestRequest(t *testing.T) {
|
|||
t.Errorf("got: %s, want: %s", got, wantHello)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("post hello error", func(t *testing.T) {
|
||||
err := httpcli.Post(result, requestAddr+"/helloErr", &User{"foobar"})
|
||||
assert.Equal(t, true, strings.Contains(err.Error(), "500"))
|
||||
})
|
||||
}
|
||||
|
||||
func runLogHTTPServer2() string {
|
||||
serverAddr, requestAddr := utils.GetLocalHTTPAddrPairs()
|
||||
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.Default()
|
||||
r := gin.New()
|
||||
r.Use(RequestID())
|
||||
r.Use(SimpleLog(
|
||||
WithLog(logger.Get()),
|
||||
WithMaxLen(200),
|
||||
WithRequestIDFromContext(),
|
||||
WithRequestIDFromHeader(),
|
||||
WithPrintErrorByCodes(409),
|
||||
))
|
||||
|
||||
pingFun := func(c *gin.Context) {
|
||||
response.Success(c, "ping")
|
||||
helloFun := func(c *gin.Context) {
|
||||
logger.Info("test request id", GCtxRequestIDField(c))
|
||||
response.Success(c, "hello world")
|
||||
}
|
||||
helloFunErr := func(c *gin.Context) {
|
||||
logger.Info("test request id", GCtxRequestIDField(c))
|
||||
response.Output(c, 500, "hello world error")
|
||||
}
|
||||
|
||||
r.GET("/ping", pingFun)
|
||||
r.GET("/hello", helloFun)
|
||||
r.GET("/helloErr", helloFunErr)
|
||||
|
||||
go func() {
|
||||
err := r.Run(serverAddr)
|
||||
|
@ -184,16 +204,18 @@ func runLogHTTPServer2() string {
|
|||
|
||||
func TestRequest2(t *testing.T) {
|
||||
requestAddr := runLogHTTPServer2()
|
||||
result := &httpcli.StdResult{}
|
||||
t.Run("get ping", func(t *testing.T) {
|
||||
err := httpcli.Get(result, requestAddr+"/ping")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
got := result.Data.(string)
|
||||
if got != "ping" {
|
||||
t.Errorf("got: %s, want: ping", got)
|
||||
}
|
||||
wantHello := "hello world"
|
||||
|
||||
t.Run("get hello", func(t *testing.T) {
|
||||
result := &httpcli.StdResult{}
|
||||
err := httpcli.Get(result, requestAddr+"/hello", httpcli.WithParams(map[string]interface{}{"id": "100"}))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, wantHello, result.Data.(string))
|
||||
})
|
||||
|
||||
t.Run("get hello error", func(t *testing.T) {
|
||||
result := &httpcli.StdResult{}
|
||||
err := httpcli.Get(result, requestAddr+"/helloErr")
|
||||
assert.Equal(t, true, strings.Contains(err.Error(), "500"))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,9 +6,12 @@ import (
|
|||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/go-dev-frame/sponge/pkg/errcode"
|
||||
zapLog "github.com/go-dev-frame/sponge/pkg/logger"
|
||||
)
|
||||
|
||||
|
@ -28,6 +31,11 @@ func UnaryClientLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryClientInter
|
|||
}
|
||||
|
||||
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
||||
// ignore printing of the specified method
|
||||
if ignoreLogMethods[method] {
|
||||
return invoker(ctx, method, req, reply, cc, opts...)
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
|
||||
var reqIDField zap.Field
|
||||
|
@ -39,16 +47,21 @@ func UnaryClientLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryClientInter
|
|||
|
||||
err := invoker(ctx, method, req, reply, cc, opts...)
|
||||
|
||||
statusCode := status.Code(err)
|
||||
fields := []zap.Field{
|
||||
zap.String("code", status.Code(err).String()),
|
||||
zap.String("code", statusCode.String()),
|
||||
zap.Error(err),
|
||||
zap.String("type", "unary"),
|
||||
zap.String("method", method),
|
||||
zap.Int64("time_us", time.Since(startTime).Microseconds()),
|
||||
reqIDField,
|
||||
}
|
||||
if err != nil && printErrorBySpecifiedCodes[statusCode] {
|
||||
logger.WithOptions(zap.AddStacktrace(zapcore.PanicLevel)).Error("invoker error", fields...)
|
||||
} else {
|
||||
logger.Info("invoker result", fields...)
|
||||
}
|
||||
|
||||
logger.Info("invoker result", fields...)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +79,11 @@ func StreamClientLog(logger *zap.Logger, opts ...LogOption) grpc.StreamClientInt
|
|||
|
||||
return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string,
|
||||
streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
|
||||
// ignore printing of the specified method
|
||||
if ignoreLogMethods[method] {
|
||||
return streamer(ctx, desc, cc, method, opts...)
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
|
||||
var reqIDField zap.Field
|
||||
|
@ -77,46 +95,55 @@ func StreamClientLog(logger *zap.Logger, opts ...LogOption) grpc.StreamClientInt
|
|||
|
||||
clientStream, err := streamer(ctx, desc, cc, method, opts...)
|
||||
|
||||
statusCode := status.Code(err)
|
||||
fields := []zap.Field{
|
||||
zap.String("code", status.Code(err).String()),
|
||||
zap.String("code", statusCode.String()),
|
||||
zap.Error(err),
|
||||
zap.String("type", "stream"),
|
||||
zap.String("method", method),
|
||||
zap.Int64("time_us", time.Since(startTime).Microseconds()),
|
||||
reqIDField,
|
||||
}
|
||||
if err != nil && printErrorBySpecifiedCodes[statusCode] {
|
||||
logger.WithOptions(zap.AddStacktrace(zapcore.PanicLevel)).Error("streamer invoker error", fields...)
|
||||
} else {
|
||||
logger.Info("streamer invoker result", fields...)
|
||||
}
|
||||
|
||||
logger.Info("invoker result", fields...)
|
||||
return clientStream, err
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------- server interceptor ----------------------------------
|
||||
|
||||
var defaultMaxLength = 300 // max length of response data to print
|
||||
var ignoreLogMethods = map[string]struct{}{} // ignore printing methods
|
||||
var defaultMaxLength = 300 // max length of response data to print
|
||||
var defaultMarshalFn = func(reply interface{}) []byte {
|
||||
data, _ := json.Marshal(reply)
|
||||
return data
|
||||
}
|
||||
var ignoreLogMethods = map[string]bool{ // ignore printing methods
|
||||
"/grpc.health.v1.Health/Check": true,
|
||||
}
|
||||
var printErrorBySpecifiedCodes = map[codes.Code]bool{
|
||||
codes.Internal: true,
|
||||
codes.Unavailable: true,
|
||||
errcode.StatusInternalServerError.Code(): true,
|
||||
errcode.StatusServiceUnavailable.Code(): true,
|
||||
}
|
||||
|
||||
// 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,
|
||||
maxLength: defaultMaxLength,
|
||||
marshalFn: defaultMarshalFn,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,13 +169,12 @@ func WithReplaceGRPCLogger() LogOption {
|
|||
}
|
||||
}
|
||||
|
||||
// WithLogFields adding a custom print field
|
||||
func WithLogFields(kvs map[string]interface{}) LogOption {
|
||||
// WithPrintErrorByCodes set print error by grpc codes
|
||||
func WithPrintErrorByCodes(code ...codes.Code) LogOption {
|
||||
return func(o *logOptions) {
|
||||
if len(kvs) == 0 {
|
||||
return
|
||||
for _, c := range code {
|
||||
printErrorBySpecifiedCodes[c] = true
|
||||
}
|
||||
o.fields = kvs
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,7 +193,7 @@ func WithMarshalFn(fn func(reply interface{}) []byte) LogOption {
|
|||
func WithLogIgnoreMethods(fullMethodNames ...string) LogOption {
|
||||
return func(o *logOptions) {
|
||||
for _, method := range fullMethodNames {
|
||||
o.ignoreMethods[method] = struct{}{}
|
||||
ignoreLogMethods[method] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +202,6 @@ func WithLogIgnoreMethods(fullMethodNames ...string) LogOption {
|
|||
func UnaryServerLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryServerInterceptor {
|
||||
o := defaultLogOptions()
|
||||
o.apply(opts...)
|
||||
ignoreLogMethods = o.ignoreMethods
|
||||
|
||||
if logger == nil {
|
||||
logger, _ = zap.NewProduction()
|
||||
|
@ -187,7 +212,7 @@ func UnaryServerLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryServerInter
|
|||
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
// ignore printing of the specified method
|
||||
if _, ok := ignoreLogMethods[info.FullMethod]; ok {
|
||||
if ignoreLogMethods[info.FullMethod] {
|
||||
return handler(ctx, req)
|
||||
}
|
||||
|
||||
|
@ -211,8 +236,9 @@ func UnaryServerLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryServerInter
|
|||
data = append(data[:o.maxLength], contentMark...)
|
||||
}
|
||||
|
||||
statusCode := status.Code(err)
|
||||
fields = []zap.Field{
|
||||
zap.String("code", status.Code(err).String()),
|
||||
zap.String("code", statusCode.String()),
|
||||
zap.Error(err),
|
||||
zap.String("type", "unary"),
|
||||
zap.String("method", info.FullMethod),
|
||||
|
@ -222,7 +248,11 @@ func UnaryServerLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryServerInter
|
|||
if requestID != "" {
|
||||
fields = append(fields, zap.String(ContextRequestIDKey, requestID))
|
||||
}
|
||||
logger.Info(">>>>", fields...)
|
||||
if err != nil && printErrorBySpecifiedCodes[statusCode] {
|
||||
logger.WithOptions(zap.AddStacktrace(zapcore.PanicLevel)).Error(">>>>", fields...)
|
||||
} else {
|
||||
logger.Info(">>>>", fields...)
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
@ -232,7 +262,6 @@ func UnaryServerLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryServerInter
|
|||
func UnaryServerSimpleLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryServerInterceptor {
|
||||
o := defaultLogOptions()
|
||||
o.apply(opts...)
|
||||
ignoreLogMethods = o.ignoreMethods
|
||||
|
||||
if logger == nil {
|
||||
logger, _ = zap.NewProduction()
|
||||
|
@ -243,7 +272,7 @@ func UnaryServerSimpleLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryServe
|
|||
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
// ignore printing of the specified method
|
||||
if _, ok := ignoreLogMethods[info.FullMethod]; ok {
|
||||
if ignoreLogMethods[info.FullMethod] {
|
||||
return handler(ctx, req)
|
||||
}
|
||||
|
||||
|
@ -252,17 +281,24 @@ func UnaryServerSimpleLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryServe
|
|||
|
||||
resp, err := handler(ctx, req)
|
||||
|
||||
requestIDField := zap.Skip()
|
||||
if requestID != "" {
|
||||
requestIDField = zap.String(ContextRequestIDKey, requestID)
|
||||
}
|
||||
statusCode := status.Code(err)
|
||||
fields := []zap.Field{
|
||||
zap.String("code", status.Code(err).String()),
|
||||
zap.String("code", statusCode.String()),
|
||||
zap.Error(err),
|
||||
zap.String("type", "unary"),
|
||||
zap.String("method", info.FullMethod),
|
||||
zap.Int64("time_us", time.Since(startTime).Microseconds()),
|
||||
requestIDField,
|
||||
}
|
||||
if requestID != "" {
|
||||
fields = append(fields, zap.String(ContextRequestIDKey, requestID))
|
||||
if err != nil && printErrorBySpecifiedCodes[statusCode] {
|
||||
logger.WithOptions(zap.AddStacktrace(zapcore.PanicLevel)).Error("gRPC response error", fields...)
|
||||
} else {
|
||||
logger.Info("gRPC response", fields...)
|
||||
}
|
||||
logger.Info("[GRPC] response", fields...)
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
@ -272,7 +308,6 @@ func UnaryServerSimpleLog(logger *zap.Logger, opts ...LogOption) grpc.UnaryServe
|
|||
func StreamServerLog(logger *zap.Logger, opts ...LogOption) grpc.StreamServerInterceptor {
|
||||
o := defaultLogOptions()
|
||||
o.apply(opts...)
|
||||
ignoreLogMethods = o.ignoreMethods
|
||||
|
||||
if logger == nil {
|
||||
logger, _ = zap.NewProduction()
|
||||
|
@ -283,34 +318,40 @@ func StreamServerLog(logger *zap.Logger, opts ...LogOption) grpc.StreamServerInt
|
|||
|
||||
return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||
// ignore printing of the specified method
|
||||
if _, ok := ignoreLogMethods[info.FullMethod]; ok {
|
||||
if ignoreLogMethods[info.FullMethod] {
|
||||
return handler(srv, stream)
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
requestID := ServerCtxRequestID(stream.Context())
|
||||
|
||||
requestIDField := zap.Skip()
|
||||
if requestID != "" {
|
||||
requestIDField = zap.String(ContextRequestIDKey, requestID)
|
||||
}
|
||||
fields := []zap.Field{
|
||||
zap.String("type", "stream"),
|
||||
zap.String("method", info.FullMethod),
|
||||
}
|
||||
if requestID != "" {
|
||||
fields = append(fields, zap.String(ContextRequestIDKey, requestID))
|
||||
requestIDField,
|
||||
}
|
||||
logger.Info("<<<<", fields...)
|
||||
|
||||
err := handler(srv, stream)
|
||||
|
||||
statusCode := status.Code(err)
|
||||
fields = []zap.Field{
|
||||
zap.String("code", status.Code(err).String()),
|
||||
zap.String("code", statusCode.String()),
|
||||
zap.Error(err),
|
||||
zap.String("type", "stream"),
|
||||
zap.String("method", info.FullMethod),
|
||||
zap.Int64("time_us", time.Since(startTime).Microseconds()),
|
||||
requestIDField,
|
||||
}
|
||||
if requestID != "" {
|
||||
fields = append(fields, zap.String(ContextRequestIDKey, requestID))
|
||||
if err != nil && printErrorBySpecifiedCodes[statusCode] {
|
||||
logger.WithOptions(zap.AddStacktrace(zapcore.PanicLevel)).Error(">>>>", fields...)
|
||||
} else {
|
||||
logger.Info(">>>>", fields...)
|
||||
}
|
||||
logger.Info(">>>>", fields...)
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -320,7 +361,6 @@ func StreamServerLog(logger *zap.Logger, opts ...LogOption) grpc.StreamServerInt
|
|||
func StreamServerSimpleLog(logger *zap.Logger, opts ...LogOption) grpc.StreamServerInterceptor {
|
||||
o := defaultLogOptions()
|
||||
o.apply(opts...)
|
||||
ignoreLogMethods = o.ignoreMethods
|
||||
|
||||
if logger == nil {
|
||||
logger, _ = zap.NewProduction()
|
||||
|
@ -331,25 +371,34 @@ func StreamServerSimpleLog(logger *zap.Logger, opts ...LogOption) grpc.StreamSer
|
|||
|
||||
return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||
// ignore printing of the specified method
|
||||
if _, ok := ignoreLogMethods[info.FullMethod]; ok {
|
||||
if ignoreLogMethods[info.FullMethod] {
|
||||
return handler(srv, stream)
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
requestID := ServerCtxRequestID(stream.Context())
|
||||
|
||||
requestIDField := zap.Skip()
|
||||
if requestID != "" {
|
||||
requestIDField = zap.String(ContextRequestIDKey, requestID)
|
||||
}
|
||||
|
||||
err := handler(srv, stream)
|
||||
|
||||
statusCode := status.Code(err)
|
||||
fields := []zap.Field{
|
||||
zap.String("code", status.Code(err).String()),
|
||||
zap.String("code", statusCode.String()),
|
||||
zap.Error(err),
|
||||
zap.String("type", "stream"),
|
||||
zap.String("method", info.FullMethod),
|
||||
zap.Int64("time_us", time.Since(startTime).Microseconds()),
|
||||
requestIDField,
|
||||
}
|
||||
if requestID != "" {
|
||||
fields = append(fields, zap.String(ContextRequestIDKey, requestID))
|
||||
if err != nil && printErrorBySpecifiedCodes[statusCode] {
|
||||
logger.WithOptions(zap.AddStacktrace(zapcore.PanicLevel)).Error("gRPC response error", fields...)
|
||||
} else {
|
||||
logger.Info("gRPC response", fields...)
|
||||
}
|
||||
logger.Info("[GRPC] response", fields...)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-dev-frame/sponge/pkg/errcode"
|
||||
"github.com/go-dev-frame/sponge/pkg/logger"
|
||||
)
|
||||
|
||||
|
@ -14,7 +15,7 @@ func TestUnaryClientLog(t *testing.T) {
|
|||
time.Sleep(time.Millisecond * 200)
|
||||
cli := newUnaryRPCClient(addr,
|
||||
UnaryClientRequestID(),
|
||||
UnaryClientLog(logger.Get(), WithReplaceGRPCLogger()),
|
||||
UnaryClientLog(logger.Get(), WithReplaceGRPCLogger(), WithPrintErrorByCodes(errcode.StatusInvalidParams.Code())),
|
||||
)
|
||||
_ = sayHelloMethod(context.Background(), cli)
|
||||
}
|
||||
|
@ -23,6 +24,15 @@ func TestUnaryServerLog(t *testing.T) {
|
|||
addr := newUnaryRPCServer(
|
||||
UnaryServerRequestID(),
|
||||
UnaryServerLog(logger.Get(), WithReplaceGRPCLogger()),
|
||||
)
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
cli := newUnaryRPCClient(addr)
|
||||
_ = sayHelloMethod(context.Background(), cli)
|
||||
}
|
||||
|
||||
func TestUnaryServerSimpleLog(t *testing.T) {
|
||||
addr := newUnaryRPCServer(
|
||||
UnaryServerRequestID(),
|
||||
UnaryServerSimpleLog(logger.Get(), WithReplaceGRPCLogger()),
|
||||
)
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
|
@ -45,12 +55,11 @@ 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"),
|
||||
WithLogIgnoreMethods("/proto.Greeter/SayHello"),
|
||||
),
|
||||
)
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
|
@ -63,11 +72,9 @@ func TestStreamServerLog(t *testing.T) {
|
|||
StreamServerRequestID(),
|
||||
StreamServerLog(logger.Get(),
|
||||
WithReplaceGRPCLogger(),
|
||||
WithLogFields(map[string]interface{}{}),
|
||||
),
|
||||
StreamServerSimpleLog(logger.Get(),
|
||||
WithReplaceGRPCLogger(),
|
||||
WithLogFields(map[string]interface{}{}),
|
||||
),
|
||||
)
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
|
|
Loading…
Reference in New Issue