logging.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package warden
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "time"
  7. "google.golang.org/grpc"
  8. "google.golang.org/grpc/peer"
  9. "go-common/library/ecode"
  10. "go-common/library/log"
  11. "go-common/library/net/metadata"
  12. "go-common/library/stat"
  13. )
  14. var (
  15. statsClient = stat.RPCClient
  16. statsServer = stat.RPCServer
  17. )
  18. func logFn(code int, dt time.Duration) func(context.Context, ...log.D) {
  19. switch {
  20. case code < 0:
  21. return log.Errorv
  22. case dt >= time.Millisecond*500:
  23. // TODO: slowlog make it configurable.
  24. return log.Warnv
  25. case code > 0:
  26. return log.Warnv
  27. }
  28. return log.Infov
  29. }
  30. // clientLogging warden grpc logging
  31. func clientLogging() grpc.UnaryClientInterceptor {
  32. return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
  33. startTime := time.Now()
  34. var peerInfo peer.Peer
  35. opts = append(opts, grpc.Peer(&peerInfo))
  36. // invoker requests
  37. err := invoker(ctx, method, req, reply, cc, opts...)
  38. // after request
  39. code := ecode.Cause(err).Code()
  40. duration := time.Since(startTime)
  41. // monitor
  42. statsClient.Timing(method, int64(duration/time.Millisecond))
  43. statsClient.Incr(method, strconv.Itoa(code))
  44. var ip string
  45. if peerInfo.Addr != nil {
  46. ip = peerInfo.Addr.String()
  47. }
  48. logFields := []log.D{
  49. log.KV("ip", ip),
  50. log.KV("path", method),
  51. log.KV("ret", code),
  52. // TODO: it will panic if someone remove String method from protobuf message struct that auto generate from protoc.
  53. log.KV("args", req.(fmt.Stringer).String()),
  54. log.KV("ts", duration.Seconds()),
  55. log.KV("source", "grpc-access-log"),
  56. }
  57. if err != nil {
  58. logFields = append(logFields, log.KV("error", err.Error()), log.KV("stack", fmt.Sprintf("%+v", err)))
  59. }
  60. logFn(code, duration)(ctx, logFields...)
  61. return err
  62. }
  63. }
  64. // serverLogging warden grpc logging
  65. func serverLogging() grpc.UnaryServerInterceptor {
  66. return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
  67. startTime := time.Now()
  68. caller := metadata.String(ctx, metadata.Caller)
  69. var remoteIP string
  70. if peerInfo, ok := peer.FromContext(ctx); ok {
  71. remoteIP = peerInfo.Addr.String()
  72. }
  73. var quota float64
  74. if deadline, ok := ctx.Deadline(); ok {
  75. quota = time.Until(deadline).Seconds()
  76. }
  77. // call server handler
  78. resp, err := handler(ctx, req)
  79. // after server response
  80. code := ecode.Cause(err).Code()
  81. duration := time.Since(startTime)
  82. // monitor
  83. statsServer.Timing(caller, int64(duration/time.Millisecond), info.FullMethod)
  84. statsServer.Incr(caller, info.FullMethod, strconv.Itoa(code))
  85. logFields := []log.D{
  86. log.KV("user", caller),
  87. log.KV("ip", remoteIP),
  88. log.KV("path", info.FullMethod),
  89. log.KV("ret", code),
  90. // TODO: it will panic if someone remove String method from protobuf message struct that auto generate from protoc.
  91. log.KV("args", req.(fmt.Stringer).String()),
  92. log.KV("ts", duration.Seconds()),
  93. log.KV("timeout_quota", quota),
  94. log.KV("source", "grpc-access-log"),
  95. }
  96. if err != nil {
  97. logFields = append(logFields, log.KV("error", err.Error()), log.KV("stack", fmt.Sprintf("%+v", err)))
  98. }
  99. logFn(code, duration)(ctx, logFields...)
  100. return resp, err
  101. }
  102. }